Merge remote-tracking branch 'upstream/master' into gerrit-submission
[osm/RO.git] / osm_ro / httpserver.py
index 374676e..613fb08 100644 (file)
 '''
 HTTP server implementing the openmano API. It will answer to POST, PUT, GET methods in the appropriate URLs
 and will use the nfvo.py module to run the appropriate method.
-Every YAML/JSON file is checked against a schema in openmano_schemas.py module.  
+Every YAML/JSON file is checked against a schema in openmano_schemas.py module.
 '''
 __author__="Alfonso Tierno, Gerardo Garcia"
 __date__ ="$17-sep-2014 09:07:15$"
 
 import bottle
 import yaml
-import json
 import threading
-import time
 import logging
 
-from jsonschema import validate as js_v, exceptions as js_e
 from openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
                             nsd_schema_v01, nsd_schema_v02, nsd_schema_v03, scenario_edit_schema, \
                             scenario_action_schema, instance_scenario_action_schema, instance_scenario_create_schema_v01, \
@@ -45,6 +42,14 @@ from openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
                             object_schema, netmap_new_schema, netmap_edit_schema, sdn_controller_schema, sdn_controller_edit_schema, \
                             sdn_port_mapping_schema, sdn_external_port_schema
 
+from .http_tools import errors as httperrors
+from .http_tools.request_processing import (
+    format_out,
+    format_in,
+    filter_query_string
+)
+from .wim.http_handler import WimHandler
+
 import nfvo
 import utils
 from db_base import db_base_Exception
@@ -56,42 +61,6 @@ global logger
 url_base="/openmano"
 logger = None
 
-HTTP_Bad_Request =          400
-HTTP_Unauthorized =         401 
-HTTP_Not_Found =            404 
-HTTP_Forbidden =            403
-HTTP_Method_Not_Allowed =   405 
-HTTP_Not_Acceptable =       406
-HTTP_Service_Unavailable =  503 
-HTTP_Internal_Server_Error= 500 
-
-def delete_nulls(var):
-    if type(var) is dict:
-        for k in var.keys():
-            if var[k] is None: del var[k]
-            elif type(var[k]) is dict or type(var[k]) is list or type(var[k]) is tuple: 
-                if delete_nulls(var[k]): del var[k]
-        if len(var) == 0: return True
-    elif type(var) is list or type(var) is tuple:
-        for k in var:
-            if type(k) is dict: delete_nulls(k)
-        if len(var) == 0: return True
-    return False
-
-def convert_datetime2str(var):
-    '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
-    It enters recursively in the dict var finding this kind of variables
-    '''
-    if type(var) is dict:
-        for k,v in var.items():
-            if type(v) is float and k in ("created_at", "modified_at"):
-                var[k] = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(v) )
-            elif type(v) is dict or type(v) is list or type(v) is tuple: 
-                convert_datetime2str(v)
-        if len(var) == 0: return True
-    elif type(var) is list or type(var) is tuple:
-        for v in var:
-            convert_datetime2str(v)
 
 def log_to_logger(fn):
     '''
@@ -102,15 +71,16 @@ def log_to_logger(fn):
     def _log_to_logger(*args, **kwargs):
         actual_response = fn(*args, **kwargs)
         # modify this to log exactly what you need:
-        logger.info('FROM %s %s %s %s' % (bottle.request.remote_addr,
+        logger.info('FROM %s %s %s %s'bottle.request.remote_addr,
                                         bottle.request.method,
                                         bottle.request.url,
-                                        bottle.response.status))
+                                        bottle.response.status)
         return actual_response
     return _log_to_logger
 
 class httpserver(threading.Thread):
-    def __init__(self, db, admin=False, host='localhost', port=9090):
+    def __init__(self, db, admin=False, host='localhost', port=9090,
+                 wim_persistence=None, wim_engine=None):
         #global url_base
         global mydb
         global logger
@@ -127,186 +97,37 @@ class httpserver(threading.Thread):
             #self.url_preffix = 'http://' + host + ':' + str(port) + url_base
             mydb = db
         #self.first_usable_connection_index = 10
-        #self.next_connection_index = self.first_usable_connection_index #The next connection index to be used 
+        #self.next_connection_index = self.first_usable_connection_index #The next connection index to be used
         #Ensure that when the main program exits the thread will also exit
+
+        self.handlers = [
+            WimHandler(db, wim_persistence, wim_engine, url_base)
+        ]
+
         self.daemon = True
         self.setDaemon(True)
-         
-    def run(self):
+
+    def run(self, debug=False, quiet=True):
         bottle.install(log_to_logger)
-        bottle.run(host=self.host, port=self.port, debug=False, quiet=True)
-           
+        default_app = bottle.app()
+
+        for handler in self.handlers:
+            default_app.merge(handler.wsgi_app)
+
+        bottle.run(host=self.host, port=self.port, debug=debug, quiet=quiet)
+
+
 def run_bottle(db, host_='localhost', port_=9090):
-    '''used for launching in main thread, so that it can be debugged'''
-    global mydb
-    mydb = db
-    bottle.run(host=host_, port=port_, debug=True) #quiet=True
-    
+    '''Used for launching in main thread, so that it can be debugged'''
+    server = httpserver(db, host=host_, port=port_)
+    server.run(debug=True)  # quiet=True
+
 
 @bottle.route(url_base + '/', method='GET')
 def http_get():
-    #print 
+    #print
     return 'works' #TODO: to be completed
 
-#
-# Util functions
-#
-
-def change_keys_http2db(data, http_db, reverse=False):
-    '''Change keys of dictionary data acording to the key_dict values
-    This allow change from http interface names to database names.
-    When reverse is True, the change is otherwise
-    Attributes:
-        data: can be a dictionary or a list
-        http_db: is a dictionary with hhtp names as keys and database names as value
-        reverse: by default change is done from http api to database. If True change is done otherwise
-    Return: None, but data is modified'''
-    if type(data) is tuple or type(data) is list:
-        for d in data:
-            change_keys_http2db(d, http_db, reverse)
-    elif type(data) is dict or type(data) is bottle.FormsDict:
-        if reverse:
-            for k,v in http_db.items():
-                if v in data: data[k]=data.pop(v)
-        else:
-            for k,v in http_db.items():
-                if k in data: data[v]=data.pop(k)
-
-def format_out(data):
-    '''return string of dictionary data according to requested json, yaml, xml. By default json'''
-    logger.debug("OUT: " + yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) )
-    if 'application/yaml' in bottle.request.headers.get('Accept'):
-        bottle.response.content_type='application/yaml'
-        return yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) #, canonical=True, default_style='"'
-    else: #by default json
-        bottle.response.content_type='application/json'
-        #return data #json no style
-        return json.dumps(data, indent=4) + "\n"
-
-def format_in(default_schema, version_fields=None, version_dict_schema=None, confidential_data=False):
-    """
-    Parse the content of HTTP request against a json_schema
-    :param default_schema: The schema to be parsed by default if no version field is found in the client data. In None
-        no validation is done
-    :param version_fields: If provided it contains a tuple or list with the fields to iterate across the client data to
-        obtain the version
-    :param version_dict_schema: It contains a dictionary with the version as key, and json schema to apply as value.
-        It can contain a None as key, and this is apply if the client data version does not match any key
-    :return:  user_data, used_schema: if the data is successfully decoded and matches the schema.
-        Launch a bottle abort if fails
-    """
-    #print "HEADERS :" + str(bottle.request.headers.items())
-    try:
-        error_text = "Invalid header format "
-        format_type = bottle.request.headers.get('Content-Type', 'application/json')
-        if 'application/json' in format_type:
-            error_text = "Invalid json format "
-            #Use the json decoder instead of bottle decoder because it informs about the location of error formats with a ValueError exception
-            client_data = json.load(bottle.request.body)
-            #client_data = bottle.request.json()
-        elif 'application/yaml' in format_type:
-            error_text = "Invalid yaml format "
-            client_data = yaml.load(bottle.request.body)
-        elif 'application/xml' in format_type:
-            bottle.abort(501, "Content-Type: application/xml not supported yet.")
-        else:
-            logger.warning('Content-Type ' + str(format_type) + ' not supported.')
-            bottle.abort(HTTP_Not_Acceptable, 'Content-Type ' + str(format_type) + ' not supported.')
-            return
-        # if client_data == None:
-        #    bottle.abort(HTTP_Bad_Request, "Content error, empty")
-        #    return
-        if confidential_data:
-            logger.debug('IN: %s', remove_clear_passwd (yaml.safe_dump(client_data, explicit_start=True, indent=4, default_flow_style=False,
-                                              tags=False, encoding='utf-8', allow_unicode=True)))
-        else:
-            logger.debug('IN: %s', yaml.safe_dump(client_data, explicit_start=True, indent=4, default_flow_style=False,
-                                              tags=False, encoding='utf-8', allow_unicode=True) )
-        # look for the client provider version
-        error_text = "Invalid content "
-        if not default_schema and not version_fields:
-            return client_data, None
-        client_version = None
-        used_schema = None
-        if version_fields != None:
-            client_version = client_data
-            for field in version_fields:
-                if field in client_version:
-                    client_version = client_version[field]
-                else:
-                    client_version=None
-                    break
-        if client_version == None:
-            used_schema = default_schema
-        elif version_dict_schema != None:
-            if client_version in version_dict_schema:
-                used_schema = version_dict_schema[client_version]
-            elif None in version_dict_schema:
-                used_schema = version_dict_schema[None]
-        if used_schema==None:
-            bottle.abort(HTTP_Bad_Request, "Invalid schema version or missing version field")
-            
-        js_v(client_data, used_schema)
-        return client_data, used_schema
-    except (TypeError, ValueError, yaml.YAMLError) as exc:
-        error_text += str(exc)
-        logger.error(error_text) 
-        bottle.abort(HTTP_Bad_Request, error_text)
-    except js_e.ValidationError as exc:
-        logger.error("validate_in error, jsonschema exception at '%s' '%s' ", str(exc.path), str(exc.message))
-        error_pos = ""
-        if len(exc.path)>0: error_pos=" at " + ":".join(map(json.dumps, exc.path))
-        bottle.abort(HTTP_Bad_Request, error_text + exc.message + error_pos)
-    #except:
-    #    bottle.abort(HTTP_Bad_Request, "Content error: Failed to parse Content-Type",  error_pos)
-    #    raise
-
-def filter_query_string(qs, http2db, allowed):
-    '''Process query string (qs) checking that contains only valid tokens for avoiding SQL injection
-    Attributes:
-        'qs': bottle.FormsDict variable to be processed. None or empty is considered valid
-        'http2db': dictionary with change from http API naming (dictionary key) to database naming(dictionary value)
-        'allowed': list of allowed string tokens (API http naming). All the keys of 'qs' must be one of 'allowed'
-    Return: A tuple with the (select,where,limit) to be use in a database query. All of then transformed to the database naming
-        select: list of items to retrieve, filtered by query string 'field=token'. If no 'field' is present, allowed list is returned
-        where: dictionary with key, value, taken from the query string token=value. Empty if nothing is provided
-        limit: limit dictated by user with the query string 'limit'. 100 by default
-    abort if not permited, using bottel.abort
-    '''
-    where={}
-    limit=100
-    select=[]
-    #if type(qs) is not bottle.FormsDict:
-    #    bottle.abort(HTTP_Internal_Server_Error, '!!!!!!!!!!!!!!invalid query string not a dictionary')
-    #    #bottle.abort(HTTP_Internal_Server_Error, "call programmer")
-    for k in qs:
-        if k=='field':
-            select += qs.getall(k)
-            for v in select:
-                if v not in allowed:
-                    bottle.abort(HTTP_Bad_Request, "Invalid query string at 'field="+v+"'")
-        elif k=='limit':
-            try:
-                limit=int(qs[k])
-            except:
-                bottle.abort(HTTP_Bad_Request, "Invalid query string at 'limit="+qs[k]+"'")
-        else:
-            if k not in allowed:
-                bottle.abort(HTTP_Bad_Request, "Invalid query string at '"+k+"="+qs[k]+"'")
-            if qs[k]!="null":  where[k]=qs[k]
-            else: where[k]=None 
-    if len(select)==0: select += allowed
-    #change from http api to database naming
-    for i in range(0,len(select)):
-        k=select[i]
-        if http2db and k in http2db: 
-            select[i] = http2db[k]
-    if http2db:
-        change_keys_http2db(where, http2db)
-    #print "filter_query_string", select,where,limit
-    
-    return select,where,limit
-
 @bottle.hook('after_request')
 def enable_cors():
     '''Don't know yet if really needed. Keep it just in case'''
@@ -327,7 +148,7 @@ def http_get_tenants():
     try:
         tenants = mydb.get_rows(FROM='nfvo_tenants', SELECT=select_,WHERE=where_,LIMIT=limit_)
         #change_keys_http2db(content, http2db_tenant, reverse=True)
-        convert_datetime2str(tenants)
+        utils.convert_float_timestamp2str(tenants)
         data={'tenants' : tenants}
         return format_out(data)
     except bottle.HTTPError:
@@ -337,7 +158,7 @@ def http_get_tenants():
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/tenants/<tenant_id>', method='GET')
@@ -354,10 +175,10 @@ def http_get_tenant_id(tenant_id):
         tenants = mydb.get_rows(FROM=from_, SELECT=select_,WHERE=where_)
         #change_keys_http2db(content, http2db_tenant, reverse=True)
         if len(tenants) == 0:
-            bottle.abort(HTTP_Not_Found, "No tenant found with {}='{}'".format(what, tenant_id))
+            bottle.abort(httperrors.Not_Found, "No tenant found with {}='{}'".format(what, tenant_id))
         elif len(tenants) > 1:
-            bottle.abort(HTTP_Bad_Request, "More than one tenant found with {}='{}'".format(what, tenant_id))
-        convert_datetime2str(tenants[0])
+            bottle.abort(httperrors.Bad_Request, "More than one tenant found with {}='{}'".format(what, tenant_id))
+        utils.convert_float_timestamp2str(tenants[0])
         data = {'tenant': tenants[0]}
         return format_out(data)
     except bottle.HTTPError:
@@ -367,7 +188,7 @@ def http_get_tenant_id(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/tenants', method='POST')
@@ -379,7 +200,7 @@ def http_post_tenants():
     r = utils.remove_extra_items(http_content, tenant_schema)
     if r:
         logger.debug("Remove received extra items %s", str(r))
-    try: 
+    try:
         data = nfvo.new_tenant(mydb, http_content['tenant'])
         return http_get_tenant_id(data)
     except bottle.HTTPError:
@@ -389,7 +210,7 @@ def http_post_tenants():
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/tenants/<tenant_id>', method='PUT')
@@ -401,11 +222,11 @@ def http_edit_tenant_id(tenant_id):
     r = utils.remove_extra_items(http_content, tenant_edit_schema)
     if r:
         logger.debug("Remove received extra items %s", str(r))
-    
+
     #obtain data, check that only one exist
-    try: 
+    try:
         tenant = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id)
-        #edit data 
+        #edit data
         tenant_id = tenant['uuid']
         where={'uuid': tenant['uuid']}
         mydb.update_rows('nfvo_tenants', http_content['tenant'], where)
@@ -417,7 +238,7 @@ def http_edit_tenant_id(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/tenants/<tenant_id>', method='DELETE')
@@ -434,7 +255,7 @@ def http_delete_tenant_id(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/datacenters', method='GET')
@@ -458,7 +279,7 @@ def http_get_datacenters(tenant_id):
             datacenters = mydb.get_rows(FROM='datacenters',
                                           SELECT=select_,WHERE=where_,LIMIT=limit_)
         #change_keys_http2db(content, http2db_tenant, reverse=True)
-        convert_datetime2str(datacenters)
+        utils.convert_float_timestamp2str(datacenters)
         data={'datacenters' : datacenters}
         return format_out(data)
     except bottle.HTTPError:
@@ -468,7 +289,7 @@ def http_get_datacenters(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/vim_accounts', method='GET')
@@ -542,11 +363,11 @@ def http_get_datacenter_id(tenant_id, datacenter_id):
                     SELECT=select_,
                     FROM=from_,
                     WHERE=where_)
-    
+
         if len(datacenters)==0:
-            bottle.abort( HTTP_Not_Found, "No datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
-        elif len(datacenters)>1: 
-            bottle.abort( HTTP_Bad_Request, "More than one datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
+            bottle.abort( httperrors.Not_Found, "No datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
+        elif len(datacenters)>1:
+            bottle.abort( httperrors.Bad_Request, "More than one datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
         datacenter = datacenters[0]
         if tenant_id != 'any':
             #get vim tenant info
@@ -586,7 +407,7 @@ def http_get_datacenter_id(tenant_id, datacenter_id):
             except Exception as e:
                 logger.error("Exception '%s' while trying to load config information", str(e))
         #change_keys_http2db(content, http2db_datacenter, reverse=True)
-        convert_datetime2str(datacenter)
+        utils.convert_float_timestamp2str(datacenter)
         data={'datacenter' : datacenter}
         return format_out(data)
     except bottle.HTTPError:
@@ -596,7 +417,7 @@ def http_get_datacenter_id(tenant_id, datacenter_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/datacenters', method='POST')
@@ -618,7 +439,7 @@ def http_post_datacenters():
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/datacenters/<datacenter_id_name>', method='PUT')
@@ -630,7 +451,7 @@ def http_edit_datacenter_id(datacenter_id_name):
     r = utils.remove_extra_items(http_content, datacenter_edit_schema)
     if r:
         logger.debug("Remove received extra items %s", str(r))
-    
+
     try:
         datacenter_id = nfvo.edit_datacenter(mydb, datacenter_id_name, http_content['datacenter'])
         return http_get_datacenter_id('any', datacenter_id)
@@ -641,7 +462,7 @@ def http_edit_datacenter_id(datacenter_id_name):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/sdn_controllers', method='POST')
 def http_post_sdn_controller(tenant_id):
@@ -662,7 +483,7 @@ def http_post_sdn_controller(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='PUT')
 def http_put_sdn_controller_update(tenant_id, controller_id):
@@ -687,7 +508,7 @@ def http_put_sdn_controller_update(tenant_id, controller_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/sdn_controllers', method='GET')
 def http_get_sdn_controller(tenant_id):
@@ -704,7 +525,7 @@ def http_get_sdn_controller(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='GET')
 def http_get_sdn_controller_id(tenant_id, controller_id):
@@ -720,7 +541,7 @@ def http_get_sdn_controller_id(tenant_id, controller_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='DELETE')
 def http_delete_sdn_controller_id(tenant_id, controller_id):
@@ -736,7 +557,7 @@ def http_delete_sdn_controller_id(tenant_id, controller_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='POST')
 def http_post_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
@@ -757,7 +578,7 @@ def http_post_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='GET')
 def http_get_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
@@ -774,7 +595,7 @@ def http_get_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='DELETE')
 def http_delete_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
@@ -790,7 +611,7 @@ def http_delete_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/networks', method='GET')  #deprecated
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='GET')
@@ -800,7 +621,7 @@ def http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
     logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
     #obtain data
     try:
-        datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter") 
+        datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter")
         where_= {"datacenter_id":datacenter_dict['uuid']}
         if netmap_id:
             if utils.check_valid_uuid(netmap_id):
@@ -809,14 +630,14 @@ def http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
                 where_["name"] = netmap_id
         netmaps =mydb.get_rows(FROM='datacenter_nets',
                                         SELECT=('name','vim_net_id as vim_id', 'uuid', 'type','multipoint','shared','description', 'created_at'),
-                                        WHERE=where_ ) 
-        convert_datetime2str(netmaps)
+                                        WHERE=where_ )
+        utils.convert_float_timestamp2str(netmaps)
         utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
         if netmap_id and len(netmaps)==1:
             data={'netmap' : netmaps[0]}
         elif netmap_id and len(netmaps)==0:
-            bottle.abort(HTTP_Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
-            return 
+            bottle.abort(httperrors.Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
+            return
         else:
             data={'netmaps' : netmaps}
         return format_out(data)
@@ -827,7 +648,7 @@ def http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='DELETE')
@@ -837,7 +658,7 @@ def http_delnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
     logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
     #obtain data
     try:
-        datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter") 
+        datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter")
         where_= {"datacenter_id":datacenter_dict['uuid']}
         if netmap_id:
             if utils.check_valid_uuid(netmap_id):
@@ -845,9 +666,9 @@ def http_delnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
             else:
                 where_["name"] = netmap_id
         #change_keys_http2db(content, http2db_tenant, reverse=True)
-        deleted = mydb.delete_row(FROM='datacenter_nets', WHERE= where_) 
+        deleted = mydb.delete_row(FROM='datacenter_nets', WHERE= where_)
         if deleted == 0 and netmap_id:
-            bottle.abort(HTTP_Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
+            bottle.abort(httperrors.Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
         if netmap_id:
             return format_out({"result": "netmap %s deleted" % netmap_id})
         else:
@@ -859,7 +680,7 @@ def http_delnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/upload', method='POST')
@@ -867,7 +688,7 @@ def http_uploadnetmap_datacenter_id(tenant_id, datacenter_id):
     logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
     try:
         netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, None)
-        convert_datetime2str(netmaps)
+        utils.convert_float_timestamp2str(netmaps)
         utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
         data={'netmaps' : netmaps}
         return format_out(data)
@@ -878,7 +699,7 @@ def http_uploadnetmap_datacenter_id(tenant_id, datacenter_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='POST')
@@ -893,7 +714,7 @@ def http_postnetmap_datacenter_id(tenant_id, datacenter_id):
     try:
         #obtain data, check that only one exist
         netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, http_content)
-        convert_datetime2str(netmaps)
+        utils.convert_float_timestamp2str(netmaps)
         utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
         data={'netmaps' : netmaps}
         return format_out(data)
@@ -904,7 +725,7 @@ def http_postnetmap_datacenter_id(tenant_id, datacenter_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='PUT')
@@ -916,7 +737,7 @@ def http_putnettmap_datacenter_id(tenant_id, datacenter_id, netmap_id):
     r = utils.remove_extra_items(http_content, netmap_edit_schema)
     if r:
         logger.debug("Remove received extra items %s", str(r))
-    
+
     #obtain data, check that only one exist
     try:
         nfvo.datacenter_edit_netmap(mydb, tenant_id, datacenter_id, netmap_id, http_content)
@@ -928,8 +749,8 @@ def http_putnettmap_datacenter_id(tenant_id, datacenter_id, netmap_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-    
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/action', method='POST')
 def http_action_datacenter_id(tenant_id, datacenter_id):
@@ -954,13 +775,13 @@ def http_action_datacenter_id(tenant_id, datacenter_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/datacenters/<datacenter_id>', method='DELETE')
 def http_delete_datacenter_id( datacenter_id):
     '''delete a tenant from database, can use both uuid or name'''
-    
+
     logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
     try:
         data = nfvo.delete_datacenter(mydb, datacenter_id)
@@ -972,7 +793,7 @@ def http_delete_datacenter_id( datacenter_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='POST')
@@ -996,7 +817,7 @@ def http_associate_datacenters(tenant_id, datacenter_id=None):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/vim_accounts/<vim_account_id>', method='PUT')
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='PUT')
@@ -1019,7 +840,7 @@ def http_vim_account_edit(tenant_id, vim_account_id=None, datacenter_id=None):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='DELETE')
@@ -1037,7 +858,7 @@ def http_deassociate_datacenters(tenant_id, datacenter_id=None, vim_account_id=N
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/attach', method='POST')
 def http_post_vim_net_sdn_attach(tenant_id, datacenter_id, network_id):
@@ -1053,7 +874,7 @@ def http_post_vim_net_sdn_attach(tenant_id, datacenter_id, network_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/detach', method='DELETE')
 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/detach/<port_id>', method='DELETE')
@@ -1069,8 +890,8 @@ def http_delete_vim_net_sdn_detach(tenant_id, datacenter_id, network_id, port_id
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-       
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='GET')
 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='GET')
 def http_get_vim_items(tenant_id, datacenter_id, item, name=None):
@@ -1085,7 +906,7 @@ def http_get_vim_items(tenant_id, datacenter_id, item, name=None):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='DELETE')
@@ -1101,7 +922,7 @@ def http_del_vim_items(tenant_id, datacenter_id, item, name):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='POST')
@@ -1118,7 +939,7 @@ def http_post_vim_items(tenant_id, datacenter_id, item):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/vnfs', method='GET')
@@ -1135,7 +956,7 @@ def http_get_vnfs(tenant_id):
         vnfs = mydb.get_rows(FROM='vnfs', SELECT=select_, WHERE=where_, LIMIT=limit_)
         # change_keys_http2db(content, http2db_vnf, reverse=True)
         utils.convert_str2boolean(vnfs, ('public',))
-        convert_datetime2str(vnfs)
+        utils.convert_float_timestamp2str(vnfs)
         data={'vnfs': vnfs}
         return format_out(data)
     except bottle.HTTPError:
@@ -1145,7 +966,7 @@ def http_get_vnfs(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='GET')
@@ -1155,7 +976,7 @@ def http_get_vnf_id(tenant_id,vnf_id):
     try:
         vnf = nfvo.get_vnf_id(mydb,tenant_id,vnf_id)
         utils.convert_str2boolean(vnf, ('public',))
-        convert_datetime2str(vnf)
+        utils.convert_float_timestamp2str(vnf)
         return format_out(vnf)
     except bottle.HTTPError:
         raise
@@ -1164,7 +985,7 @@ def http_get_vnf_id(tenant_id,vnf_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/vnfs', method='POST')
@@ -1187,7 +1008,7 @@ def http_post_vnfs(tenant_id):
             vnf_id = nfvo.new_vnf_v02(mydb,tenant_id,http_content)
         else:
             logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
-            bottle.abort(HTTP_Bad_Request, "Invalid schema version")
+            bottle.abort(httperrors.Bad_Request, "Invalid schema version")
         return http_get_vnf_id(tenant_id, vnf_id)
     except bottle.HTTPError:
         raise
@@ -1196,7 +1017,7 @@ def http_post_vnfs(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/v3/<tenant_id>/vnfd', method='POST')
@@ -1214,7 +1035,7 @@ def http_post_vnfs_v3(tenant_id):
         for vnfd_uuid in vnfd_uuid_list:
             vnf = nfvo.get_vnf_id(mydb, tenant_id, vnfd_uuid)
             utils.convert_str2boolean(vnf, ('public',))
-            convert_datetime2str(vnf)
+            utils.convert_float_timestamp2str(vnf)
             vnfd_list.append(vnf["vnf"])
         return format_out({"vnfd": vnfd_list})
     except bottle.HTTPError:
@@ -1224,13 +1045,13 @@ def http_post_vnfs_v3(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='DELETE')
 def http_delete_vnf_id(tenant_id, vnf_id):
     '''delete a vnf from database, and images and flavors in VIM when appropriate, can use both uuid or name'''
     logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    #check valid tenant_id and deletes the vnf, including images, 
+    #check valid tenant_id and deletes the vnf, including images,
     try:
         data = nfvo.delete_vnf(mydb,tenant_id,vnf_id)
         #print json.dumps(data, indent=4)
@@ -1242,7 +1063,7 @@ def http_delete_vnf_id(tenant_id, vnf_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 #@bottle.route(url_base + '/<tenant_id>/hosts/topology', method='GET')
@@ -1258,12 +1079,12 @@ def http_get_hosts(tenant_id, datacenter):
         else:
             #openmano-gui is using a hardcoded value for the datacenter
             result, data = nfvo.get_hosts_info(mydb, tenant_id) #, datacenter)
-        
+
         if result < 0:
             #print "http_get_hosts error %d %s" % (-result, data)
             bottle.abort(-result, data)
         else:
-            convert_datetime2str(data)
+            utils.convert_float_timestamp2str(data)
             #print json.dumps(data, indent=4)
             return format_out(data)
     except bottle.HTTPError:
@@ -1273,7 +1094,7 @@ def http_get_hosts(tenant_id, datacenter):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<path:path>', method='OPTIONS')
@@ -1297,7 +1118,7 @@ def http_post_deploy(tenant_id):
     #r = utils.remove_extra_items(http_content, used_schema)
     #if r is not None: print "http_post_deploy: Warning: remove extra items ", r
     #print "http_post_deploy input: ",  http_content
-    
+
     try:
         scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
         instance = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['name'], http_content['name'])
@@ -1310,7 +1131,7 @@ def http_post_deploy(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/topology/verify', method='POST')
@@ -1319,7 +1140,7 @@ def http_post_verify(tenant_id):
 #    '''post topology verify'''
 #    print "http_post_verify by tenant " + tenant_id + ' datacenter ' + datacenter
     logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    return 
+    return
 
 #
 # SCENARIOS
@@ -1342,7 +1163,7 @@ def http_post_scenarios(tenant_id):
             scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.3")
         else:
             logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
-            bottle.abort(HTTP_Bad_Request, "Invalid schema version")
+            bottle.abort(httperrors.Bad_Request, "Invalid schema version")
         #print json.dumps(data, indent=4)
         #return format_out(data)
         return http_get_scenario_id(tenant_id, scenario_id)
@@ -1353,7 +1174,7 @@ def http_post_scenarios(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/v3/<tenant_id>/nsd', method='POST')
 def http_post_nsds_v3(tenant_id):
@@ -1369,7 +1190,7 @@ def http_post_nsds_v3(tenant_id):
         nsd_list = []
         for nsd_uuid in nsd_uuid_list:
             scenario = mydb.get_scenario(nsd_uuid, tenant_id)
-            convert_datetime2str(scenario)
+            utils.convert_float_timestamp2str(scenario)
             nsd_list.append(scenario)
         data = {'nsd': nsd_list}
         return format_out(data)
@@ -1380,7 +1201,7 @@ def http_post_nsds_v3(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>/action', method='POST')
@@ -1424,7 +1245,7 @@ def http_post_scenario_action(tenant_id, scenario_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/scenarios', method='GET')
@@ -1434,14 +1255,14 @@ def http_get_scenarios(tenant_id):
     try:
         #check valid tenant_id
         if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
+            nfvo.check_tenant(mydb, tenant_id)
         #obtain data
         s,w,l=filter_query_string(bottle.request.query, None,
                                   ('uuid', 'name', 'osm_id', 'description', 'tenant_id', 'created_at', 'public'))
         if tenant_id != "any":
             w["OR"] = {"tenant_id": tenant_id, "public": True}
         scenarios = mydb.get_rows(SELECT=s, WHERE=w, LIMIT=l, FROM='scenarios')
-        convert_datetime2str(scenarios)
+        utils.convert_float_timestamp2str(scenarios)
         utils.convert_str2boolean(scenarios, ('public',) )
         data={'scenarios':scenarios}
         #print json.dumps(scenarios, indent=4)
@@ -1453,7 +1274,7 @@ def http_get_scenarios(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='GET')
@@ -1463,10 +1284,10 @@ def http_get_scenario_id(tenant_id, scenario_id):
     try:
         #check valid tenant_id
         if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
+            nfvo.check_tenant(mydb, tenant_id)
         #obtain data
         scenario = mydb.get_scenario(scenario_id, tenant_id)
-        convert_datetime2str(scenario)
+        utils.convert_float_timestamp2str(scenario)
         data={'scenario' : scenario}
         return format_out(data)
     except bottle.HTTPError:
@@ -1476,7 +1297,7 @@ def http_get_scenario_id(tenant_id, scenario_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='DELETE')
@@ -1498,7 +1319,7 @@ def http_delete_scenario_id(tenant_id, scenario_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='PUT')
@@ -1521,7 +1342,7 @@ def http_put_scenario_id(tenant_id, scenario_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 @bottle.route(url_base + '/<tenant_id>/instances', method='POST')
 def http_post_instances(tenant_id):
@@ -1535,17 +1356,17 @@ def http_post_instances(tenant_id):
     try:
         #check valid tenant_id
         if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
+            nfvo.check_tenant(mydb, tenant_id)
         data = nfvo.create_instance(mydb, tenant_id, http_content["instance"])
         return format_out(data)
     except bottle.HTTPError:
         raise
     except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_instances error {}: {}".format(e.http_code, str(e)))
+        logger.error("http_post_instances error {}: {}".format(e.http_code, str(e)), exc_info=True)
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 #
 # INSTANCES
@@ -1556,13 +1377,13 @@ def http_get_instances(tenant_id):
     try:
         #check valid tenant_id
         if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
+            nfvo.check_tenant(mydb, tenant_id)
         #obtain data
         s,w,l=filter_query_string(bottle.request.query, None, ('uuid', 'name', 'scenario_id', 'tenant_id', 'description', 'created_at'))
         if tenant_id != "any":
             w['tenant_id'] = tenant_id
         instances = mydb.get_rows(SELECT=s, WHERE=w, LIMIT=l, FROM='instance_scenarios')
-        convert_datetime2str(instances)
+        utils.convert_float_timestamp2str(instances)
         utils.convert_str2boolean(instances, ('public',) )
         data={'instances':instances}
         return format_out(data)
@@ -1573,7 +1394,7 @@ def http_get_instances(tenant_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='GET')
@@ -1584,7 +1405,7 @@ def http_get_instance_id(tenant_id, instance_id):
 
         #check valid tenant_id
         if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
+            nfvo.check_tenant(mydb, tenant_id)
         if tenant_id == "any":
             tenant_id = None
 
@@ -1598,7 +1419,7 @@ def http_get_instance_id(tenant_id, instance_id):
                         index = iface["ip_address"].find(";")
                         if index >= 0:
                             iface["ip_address"] = iface["ip_address"][:index]
-        convert_datetime2str(instance)
+        utils.convert_float_timestamp2str(instance)
         # print json.dumps(instance, indent=4)
         return format_out(instance)
     except bottle.HTTPError:
@@ -1608,7 +1429,7 @@ def http_get_instance_id(tenant_id, instance_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='DELETE')
@@ -1618,7 +1439,7 @@ def http_delete_instance_id(tenant_id, instance_id):
     try:
         #check valid tenant_id
         if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
+            nfvo.check_tenant(mydb, tenant_id)
         if tenant_id == "any":
             tenant_id = None
         #obtain data
@@ -1631,7 +1452,7 @@ def http_delete_instance_id(tenant_id, instance_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action', method='POST')
@@ -1651,13 +1472,13 @@ def http_post_instance_scenario_action(tenant_id, instance_id):
     try:
         #check valid tenant_id
         if tenant_id != "any":
-            nfvo.check_tenant(mydb, tenant_id) 
+            nfvo.check_tenant(mydb, tenant_id)
 
         #print "http_post_instance_scenario_action input: ", http_content
         #obtain data
         instance = mydb.get_instance_scenario(instance_id, tenant_id)
         instance_id = instance["uuid"]
-        
+
         data = nfvo.instance_action(mydb, tenant_id, instance_id, http_content)
         return format_out(data)
     except bottle.HTTPError:
@@ -1667,7 +1488,7 @@ def http_post_instance_scenario_action(tenant_id, instance_id):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
 
 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action', method='GET')
@@ -1693,34 +1514,17 @@ def http_get_instance_scenario_action(tenant_id, instance_id, action_id=None):
         bottle.abort(e.http_code, str(e))
     except Exception as e:
         logger.error("Unexpected exception: ", exc_info=True)
-        bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
-
-def remove_clear_passwd(data):
-    """
-    Removes clear passwords from the data received
-    :param data: data with clear password
-    :return: data without the password information
-    """
-
-    passw = ['password: ', 'passwd: ']
+        bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
 
-    for pattern in passw:
-        init = data.find(pattern)
-        while init != -1:
-            end = data.find('\n', init)
-            data = data[:init] + '{}******'.format(pattern) + data[end:]
-            init += 1
-            init = data.find(pattern, init)
-    return data
 
 @bottle.error(400)
-@bottle.error(401) 
-@bottle.error(404) 
+@bottle.error(401)
+@bottle.error(404)
 @bottle.error(403)
-@bottle.error(405) 
+@bottle.error(405)
 @bottle.error(406)
 @bottle.error(409)
-@bottle.error(503) 
+@bottle.error(503)
 @bottle.error(500)
 def error400(error):
     e={"error":{"code":error.status_code, "type":error.status, "description":error.body}}