fix 1148 allow name repetition at wim,wim_accounts
[osm/RO.git] / RO / osm_ro / nfvo.py
index 6a06a4c..829697c 100644 (file)
@@ -20,7 +20,7 @@
 # For those usages not covered by the Apache License, Version 2.0 please
 # contact with: nfvlabs@tid.es
 ##
 # For those usages not covered by the Apache License, Version 2.0 please
 # contact with: nfvlabs@tid.es
 ##
-
 '''
 NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
 '''
 '''
 NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
 '''
@@ -29,12 +29,17 @@ __date__ ="$16-sep-2014 22:05:01$"
 
 # import imp
 import json
 
 # import imp
 import json
+import string
 import yaml
 import yaml
+from random import choice as random_choice
 from osm_ro import utils
 from osm_ro.utils import deprecated
 from osm_ro.vim_thread import vim_thread
 import osm_ro.console_proxy_thread as cli
 from osm_ro import utils
 from osm_ro.utils import deprecated
 from osm_ro.vim_thread import vim_thread
 import osm_ro.console_proxy_thread as cli
-from osm_ro import vimconn
+from osm_ro_plugin.vim_dummy import VimDummyConnector
+from osm_ro_plugin.sdn_dummy import SdnDummyConnector
+from osm_ro_plugin.sdn_failing import SdnFailingConnector
+from osm_ro_plugin import vimconn, sdnconn
 import logging
 import collections
 import math
 import logging
 import collections
 import math
@@ -44,13 +49,7 @@ from osm_ro.db_base import db_base_Exception
 from osm_ro import nfvo_db
 from threading import Lock
 import time as t
 from osm_ro import nfvo_db
 from threading import Lock
 import time as t
-# TODO py3 BEGIN
 from osm_ro.sdn import Sdn, SdnException as ovimException
 from osm_ro.sdn import Sdn, SdnException as ovimException
-# from lib_osm_openvim.ovim import ovimException
-# from unittest.mock  import MagicMock
-# class ovimException(Exception):
-#    pass
-# TODO py3 END
 
 from Crypto.PublicKey import RSA
 
 
 from Crypto.PublicKey import RSA
 
@@ -62,9 +61,6 @@ from pkg_resources import iter_entry_points
 
 
 # WIM
 
 
 # WIM
-from .wim import sdnconn
-from .wim.wimconn_fake import FakeConnector
-from .wim.failing_connector import FailingConnector
 from .http_tools import errors as httperrors
 from .wim.engine import WimEngine
 from .wim.persistence import WimPersistence
 from .http_tools import errors as httperrors
 from .wim.engine import WimEngine
 from .wim.persistence import WimPersistence
@@ -100,6 +96,7 @@ last_task_id = 0.0
 db = None
 db_lock = Lock()
 
 db = None
 db_lock = Lock()
 
+worker_id = None
 
 class NfvoException(httperrors.HttpMappedError):
     """Common Class for NFVO errors"""
 
 class NfvoException(httperrors.HttpMappedError):
     """Common Class for NFVO errors"""
@@ -113,12 +110,12 @@ def _load_plugin(name, type="vim"):
     except Exception as e:
         logger.critical("Cannot load osm_{}: {}".format(name, e))
         if name:
     except Exception as e:
         logger.critical("Cannot load osm_{}: {}".format(name, e))
         if name:
-            plugins[name] = FailingConnector("Cannot load osm_{}: {}".format(name, e))
+            plugins[name] = SdnFailingConnector("Cannot load osm_{}: {}".format(name, e))
     if name and name not in plugins:
         error_text = "Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been" \
                      " registered".format(t=type, n=name)
         logger.critical(error_text)
     if name and name not in plugins:
         error_text = "Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been" \
                      " registered".format(t=type, n=name)
         logger.critical(error_text)
-        plugins[name] = FailingConnector(error_text)
+        plugins[name] = SdnFailingConnector(error_text)
         # raise NfvoException("Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been registered".
         #                     format(t=type, n=name), httperrors.Bad_Request)
 
         # raise NfvoException("Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been registered".
         #                     format(t=type, n=name), httperrors.Bad_Request)
 
@@ -144,20 +141,31 @@ def new_task(name, params, depends=None):
 def is_task_id(id):
     return True if id[:5] == "TASK-" else False
 
 def is_task_id(id):
     return True if id[:5] == "TASK-" else False
 
-
-def get_non_used_vim_name(datacenter_name, datacenter_id, tenant_name, tenant_id):
-    name = datacenter_name[:16]
-    if name not in vim_threads["names"]:
-        vim_threads["names"].append(name)
-        return name
-    if tenant_name:
-        name = datacenter_name[:16] + "." + tenant_name[:16]
-        if name not in vim_threads["names"]:
-            vim_threads["names"].append(name)
-            return name
-    name = datacenter_id
-    vim_threads["names"].append(name)
-    return name
+def get_process_id():
+    """
+    Obtain a unique ID for this process. If running from inside docker, it will get docker ID. If not it
+    will provide a random one
+    :return: Obtained ID
+    """
+    # Try getting docker id. If fails, get pid
+    try:
+        with open("/proc/self/cgroup", "r") as f:
+            for text_id_ in f.readlines():
+                if "docker/" not in text_id_:
+                    continue
+                _, _, text_id = text_id_.rpartition("/")
+                text_id = text_id.replace("\n", "")[:12]
+                if text_id:
+                    return text_id
+    except Exception:
+        pass
+    # Return a random id
+    return "".join(random_choice("0123456789abcdef") for _ in range(12))
+
+def get_non_used_vim_name(datacenter_name, datacenter_id):
+    return "{}:{}:{}".format(
+        worker_id[:12], datacenter_id.replace("-", "")[:32], datacenter_name[:16]
+    )
 
 # -- Move
 def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id):
 
 # -- Move
 def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id):
@@ -175,7 +183,7 @@ def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id):
 
 
 def start_service(mydb, persistence=None, wim=None):
 
 
 def start_service(mydb, persistence=None, wim=None):
-    global db, global_config, plugins, ovim
+    global db, global_config, plugins, ovim, worker_id
     db = nfvo_db.nfvo_db(lock=db_lock)
     mydb.lock = db_lock
     db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
     db = nfvo_db.nfvo_db(lock=db_lock)
     mydb.lock = db_lock
     db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
@@ -183,8 +191,11 @@ def start_service(mydb, persistence=None, wim=None):
     persistence = persistence or  WimPersistence(db)
 
     try:
     persistence = persistence or  WimPersistence(db)
 
     try:
-        if "rosdn_fake" not in plugins:
-            plugins["rosdn_fake"] = FakeConnector
+        worker_id = get_process_id()
+        if "rosdn_dummy" not in plugins:
+            plugins["rosdn_dummy"] = SdnDummyConnector
+        if "rovim_dummy" not in plugins:
+            plugins["rovim_dummy"] = VimDummyConnector
         # starts ovim library
         ovim = Sdn(db, plugins)
 
         # starts ovim library
         ovim = Sdn(db, plugins)
 
@@ -221,14 +232,14 @@ def start_service(mydb, persistence=None, wim=None):
             try:
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
             try:
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
-                myvim = plugins[plugin_name].vimconnector(
+                myvim = plugins[plugin_name](
                     uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                     tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
                     url=vim['vim_url'], url_admin=vim['vim_url_admin'],
                     user=vim['user'], passwd=vim['passwd'],
                     config=extra, persistent_info=vim_persistent_info[thread_id]
                 )
                     uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                     tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
                     url=vim['vim_url'], url_admin=vim['vim_url_admin'],
                     user=vim['user'], passwd=vim['passwd'],
                     config=extra, persistent_info=vim_persistent_info[thread_id]
                 )
-            except vimconn.vimconnException as e:
+            except vimconn.VimConnException as e:
                 myvim = e
                 logger.error("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'],
                                                                                vim['datacenter_id'], e))
                 myvim = e
                 logger.error("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'],
                                                                                vim['datacenter_id'], e))
@@ -237,8 +248,7 @@ def start_service(mydb, persistence=None, wim=None):
                                                                                   vim['datacenter_id'], e))
                 # raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, e),
                 #                     httperrors.Internal_Server_Error)
                                                                                   vim['datacenter_id'], e))
                 # raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, e),
                 #                     httperrors.Internal_Server_Error)
-            thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['datacenter_id'], vim['vim_tenant_name'],
-                                                vim['vim_tenant_id'])
+            thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['datacenter_id'])
             new_thread = vim_thread(task_lock, plugins, thread_name, None,
                                     vim['datacenter_tenant_id'], db=db)
             new_thread.start()
             new_thread = vim_thread(task_lock, plugins, thread_name, None,
                                     vim['datacenter_tenant_id'], db=db)
             new_thread.start()
@@ -252,7 +262,7 @@ def start_service(mydb, persistence=None, wim=None):
                 _load_plugin(plugin_name, type="sdn")
 
             thread_id = wim['uuid']
                 _load_plugin(plugin_name, type="sdn")
 
             thread_id = wim['uuid']
-            thread_name = get_non_used_vim_name(wim['name'], wim['uuid'], wim['uuid'], None)
+            thread_name = get_non_used_vim_name(wim['name'], wim['uuid'])
             new_thread = vim_thread(task_lock, plugins, thread_name, wim['uuid'], None, db=db)
             new_thread.start()
             vim_threads["running"][thread_id] = new_thread
             new_thread = vim_thread(task_lock, plugins, thread_name, wim['uuid'], None, db=db)
             new_thread.start()
             vim_threads["running"][thread_id] = new_thread
@@ -421,7 +431,7 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da
                     persistent_info = {}
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
                     persistent_info = {}
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
-                vim_dict[vim['datacenter_id']] = plugins[plugin_name].vimconnector(
+                vim_dict[vim['datacenter_id']] = plugins[plugin_name](
                                 uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                                 tenant_id=vim.get('vim_tenant_id',vim_tenant),
                                 tenant_name=vim.get('vim_tenant_name',vim_tenant_name),
                                 uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                                 tenant_id=vim.get('vim_tenant_id',vim_tenant),
                                 tenant_name=vim.get('vim_tenant_name',vim_tenant_name),
@@ -434,7 +444,7 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da
                     logger.error("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)))
                     continue
                 http_code = httperrors.Internal_Server_Error
                     logger.error("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)))
                     continue
                 http_code = httperrors.Internal_Server_Error
-                if isinstance(e, vimconn.vimconnException):
+                if isinstance(e, vimconn.VimConnException):
                     http_code = e.http_code
                 raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), http_code)
         return vim_dict
                     http_code = e.http_code
                 raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), http_code)
         return vim_dict
@@ -464,7 +474,7 @@ def rollback(mydb,  vims, rollback_list):
                     vim.delete_network(item["uuid"])
                 elif item["what"]=="vm":
                     vim.delete_vminstance(item["uuid"])
                     vim.delete_network(item["uuid"])
                 elif item["what"]=="vm":
                     vim.delete_vminstance(item["uuid"])
-            except vimconn.vimconnException as e:
+            except vimconn.VimConnException as e:
                 logger.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item['what'], item["uuid"], str(e))
                 undeleted_items.append("{} {} from VIM {}".format(item['what'], item["uuid"], vim["name"]))
             except db_base_Exception as e:
                 logger.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item['what'], item["uuid"], str(e))
                 undeleted_items.append("{} {} from VIM {}".format(item['what'], item["uuid"], vim["name"]))
             except db_base_Exception as e:
@@ -641,14 +651,14 @@ def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vi
                 vim_images = vim.get_image_list(filter_dict)
                 #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
                 if len(vim_images) > 1:
                 vim_images = vim.get_image_list(filter_dict)
                 #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
                 if len(vim_images) > 1:
-                    raise vimconn.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict)), httperrors.Conflict)
+                    raise vimconn.VimConnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict)), httperrors.Conflict)
                 elif len(vim_images) == 0:
                 elif len(vim_images) == 0:
-                    raise vimconn.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict)))
+                    raise vimconn.VimConnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict)))
                 else:
                     #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
                     image_vim_id = vim_images[0]['id']
 
                 else:
                     #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
                     image_vim_id = vim_images[0]['id']
 
-        except vimconn.vimconnNotFoundException as e:
+        except vimconn.VimConnNotFoundException as e:
             #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
             try:
                 #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
             #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
             try:
                 #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
@@ -658,15 +668,15 @@ def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vi
                     image_created="true"
                 else:
                     #If we reach this point, then the image has image name, and optionally checksum, and could not be found
                     image_created="true"
                 else:
                     #If we reach this point, then the image has image name, and optionally checksum, and could not be found
-                    raise vimconn.vimconnException(str(e))
-            except vimconn.vimconnException as e:
+                    raise vimconn.VimConnException(str(e))
+            except vimconn.VimConnException as e:
                 if return_on_error:
                     logger.error("Error creating image at VIM '%s': %s", vim["name"], str(e))
                     raise
                 image_vim_id = None
                 logger.warn("Error creating image at VIM '%s': %s", vim["name"], str(e))
                 continue
                 if return_on_error:
                     logger.error("Error creating image at VIM '%s': %s", vim["name"], str(e))
                     raise
                 image_vim_id = None
                 logger.warn("Error creating image at VIM '%s': %s", vim["name"], str(e))
                 continue
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             if return_on_error:
                 logger.error("Error contacting VIM to know if the image exists at VIM: %s", str(e))
                 raise
             if return_on_error:
                 logger.error("Error contacting VIM to know if the image exists at VIM: %s", str(e))
                 raise
@@ -804,7 +814,7 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_
             try:
                 vim.get_flavor(flavor_vim_id)
                 continue #flavor exist
             try:
                 vim.get_flavor(flavor_vim_id)
                 continue #flavor exist
-            except vimconn.vimconnException:
+            except vimconn.VimConnException:
                 pass
         #create flavor at vim
         logger.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim["name"])
                 pass
         #create flavor at vim
         logger.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim["name"])
@@ -812,14 +822,14 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_
             flavor_vim_id = None
             flavor_vim_id=vim.get_flavor_id_from_data(flavor_dict)
             flavor_created="false"
             flavor_vim_id = None
             flavor_vim_id=vim.get_flavor_id_from_data(flavor_dict)
             flavor_created="false"
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             pass
         try:
             if not flavor_vim_id:
                 flavor_vim_id = vim.new_flavor(flavor_dict)
                 rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"flavor","uuid":flavor_vim_id})
                 flavor_created="true"
             pass
         try:
             if not flavor_vim_id:
                 flavor_vim_id = vim.new_flavor(flavor_dict)
                 rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"flavor","uuid":flavor_vim_id})
                 flavor_created="true"
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             if return_on_error:
                 logger.error("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
                 raise
             if return_on_error:
                 logger.error("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
                 raise
@@ -977,6 +987,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
 
             # table nets (internal-vld)
             net_id2uuid = {}  # for mapping interface with network
 
             # table nets (internal-vld)
             net_id2uuid = {}  # for mapping interface with network
+            net_id2index = {}  # for mapping interface with network
             for vld in vnfd.get("internal-vld").values():
                 net_uuid = str(uuid4())
                 uuid_list.append(net_uuid)
             for vld in vnfd.get("internal-vld").values():
                 net_uuid = str(uuid4())
                 uuid_list.append(net_uuid)
@@ -989,6 +1000,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                     "type": "bridge",   # TODO adjust depending on connection point type
                 }
                 net_id2uuid[vld.get("id")] = net_uuid
                     "type": "bridge",   # TODO adjust depending on connection point type
                 }
                 net_id2uuid[vld.get("id")] = net_uuid
+                net_id2index[vld.get("id")] = len(db_nets)
                 db_nets.append(db_net)
                 # ip-profile, link db_ip_profile with db_sce_net
                 if vld.get("ip-profile-ref"):
                 db_nets.append(db_net)
                 # ip-profile, link db_ip_profile with db_sce_net
                 if vld.get("ip-profile-ref"):
@@ -1181,7 +1193,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                                 raise KeyError()
 
                             if vdu_id in vdu_id2cp_name:
                                 raise KeyError()
 
                             if vdu_id in vdu_id2cp_name:
-                                vdu_id2cp_name[vdu_id] = None  # more than two connecdtion point for this VDU
+                                vdu_id2cp_name[vdu_id] = None  # more than two connection point for this VDU
                             else:
                                 vdu_id2cp_name[vdu_id] = db_interface["external_name"]
 
                             else:
                                 vdu_id2cp_name[vdu_id] = db_interface["external_name"]
 
@@ -1216,6 +1228,10 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                             if not icp:
                                 raise KeyError("is not referenced by any 'internal-vld'")
 
                             if not icp:
                                 raise KeyError("is not referenced by any 'internal-vld'")
 
+                            # set network type as data
+                            if iface.get("virtual-interface") and iface["virtual-interface"].get("type") in \
+                                    ("SR-IOV", "PCI-PASSTHROUGH"):
+                                db_nets[net_id2index[icp_vld.get("id")]]["type"] = "data"
                             db_interface["net_id"] = net_id2uuid[icp_vld.get("id")]
                             if str(icp_descriptor.get("port-security-enabled")).lower() == "false":
                                 db_interface["port_security"] = 0
                             db_interface["net_id"] = net_id2uuid[icp_vld.get("id")]
                             if str(icp_descriptor.get("port-security-enabled")).lower() == "false":
                                 db_interface["port_security"] = 0
@@ -1355,7 +1371,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
 
             if vnfd["mgmt-interface"].get("ip-address"):
                 mgmt_access["ip-address"] = str(vnfd["mgmt-interface"].get("ip-address"))
 
             if vnfd["mgmt-interface"].get("ip-address"):
                 mgmt_access["ip-address"] = str(vnfd["mgmt-interface"].get("ip-address"))
-            if vnfd["mgmt-interface"].get("cp"):
+            if vnfd["mgmt-interface"].get("cp") and vnfd.get("vdu"):
                 if vnfd["mgmt-interface"]["cp"] not in cp_name2iface_uuid:
                     raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'cp'['{cp}']. "
                                         "Reference to a non-existing connection-point".format(
                 if vnfd["mgmt-interface"]["cp"] not in cp_name2iface_uuid:
                     raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'cp'['{cp}']. "
                                         "Reference to a non-existing connection-point".format(
@@ -1532,7 +1548,7 @@ def new_vnf(mydb, tenant_id, vnf_descriptor):
         # Step 8. Adding the VNF to the NFVO DB
         vnf_id = mydb.new_vnf_as_a_whole(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
         return vnf_id
         # Step 8. Adding the VNF to the NFVO DB
         vnf_id = mydb.new_vnf_as_a_whole(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
         return vnf_id
-    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
+    except (db_base_Exception, vimconn.VimConnException, KeyError) as e:
         _, message = rollback(mydb, vims, rollback_list)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
         _, message = rollback(mydb, vims, rollback_list)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
@@ -1668,7 +1684,7 @@ def new_vnf_v02(mydb, tenant_id, vnf_descriptor):
         # Step 8. Adding the VNF to the NFVO DB
         vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
         return vnf_id
         # Step 8. Adding the VNF to the NFVO DB
         vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
         return vnf_id
-    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
+    except (db_base_Exception, vimconn.VimConnException, KeyError) as e:
         _, message = rollback(mydb, vims, rollback_list)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
         _, message = rollback(mydb, vims, rollback_list)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
@@ -1797,10 +1813,10 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
                     continue
                 try:
                     myvim.delete_flavor(flavor_vim["vim_id"])
                     continue
                 try:
                     myvim.delete_flavor(flavor_vim["vim_id"])
-                except vimconn.vimconnNotFoundException:
+                except vimconn.VimConnNotFoundException:
                     logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"],
                                 flavor_vim["datacenter_vim_id"] )
                     logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"],
                                 flavor_vim["datacenter_vim_id"] )
-                except vimconn.vimconnException as e:
+                except vimconn.VimConnException as e:
                     logger.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
                             flavor_vim["vim_id"], flavor_vim["datacenter_vim_id"], type(e).__name__, str(e))
                     undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"],
                     logger.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
                             flavor_vim["vim_id"], flavor_vim["datacenter_vim_id"], type(e).__name__, str(e))
                     undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"],
@@ -1830,9 +1846,9 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
                 myvim=vims[ image_vim["datacenter_id"] ]
                 try:
                     myvim.delete_image(image_vim["vim_id"])
                 myvim=vims[ image_vim["datacenter_id"] ]
                 try:
                     myvim.delete_image(image_vim["vim_id"])
-                except vimconn.vimconnNotFoundException as e:
+                except vimconn.VimConnNotFoundException as e:
                     logger.warn("VIM image %s not exist at datacenter %s", image_vim["vim_id"], image_vim["datacenter_id"] )
                     logger.warn("VIM image %s not exist at datacenter %s", image_vim["vim_id"], image_vim["datacenter_id"] )
-                except vimconn.vimconnException as e:
+                except vimconn.VimConnException as e:
                     logger.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
                             image_vim["vim_id"], image_vim["datacenter_id"], type(e).__name__, str(e))
                     undeletedItems.append("image {} from VIM {}".format(image_vim["vim_id"], image_vim["datacenter_id"] ))
                     logger.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
                             image_vim["vim_id"], image_vim["datacenter_id"], type(e).__name__, str(e))
                     undeletedItems.append("image {} from VIM {}".format(image_vim["vim_id"], image_vim["datacenter_id"] ))
@@ -1894,7 +1910,7 @@ def get_hosts(mydb, nfvo_tenant_id):
 
         #print 'datacenters '+ json.dumps(datacenter, indent=4)
         return datacenter
 
         #print 'datacenters '+ json.dumps(datacenter, indent=4)
         return datacenter
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code)
 
 
         raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code)
 
 
@@ -2435,45 +2451,48 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
 
                 # table sce_interfaces (vld:vnfd-connection-point-ref)
                 for iface in vld.get("vnfd-connection-point-ref").values():
 
                 # table sce_interfaces (vld:vnfd-connection-point-ref)
                 for iface in vld.get("vnfd-connection-point-ref").values():
+                    # Check if there are VDUs in the descriptor
                     vnf_index = str(iface['member-vnf-index-ref'])
                     vnf_index = str(iface['member-vnf-index-ref'])
-                    # check correct parameters
-                    if vnf_index not in vnf_index2vnf_uuid:
-                        raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point"
-                                            "-ref':'member-vnf-index-ref':'{}'. Reference to a non-existing index at "
-                                            "'nsd':'constituent-vnfd'".format(
-                                                str(nsd["id"]), str(vld["id"]), str(iface["member-vnf-index-ref"])),
-                                            httperrors.Bad_Request)
-
-                    existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid', 'i.type as iface_type'),
-                                                    FROM="interfaces as i join vms on i.vm_id=vms.uuid",
-                                                    WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index],
-                                                           'external_name': get_str(iface, "vnfd-connection-point-ref",
-                                                                                    255)})
-                    if not existing_ifaces:
-                        raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point"
-                                            "-ref':'vnfd-connection-point-ref':'{}'. Reference to a non-existing "
-                                            "connection-point name at VNFD '{}'".format(
-                                                str(nsd["id"]), str(vld["id"]), str(iface["vnfd-connection-point-ref"]),
-                                                str(iface.get("vnfd-id-ref"))[:255]),
-                                            httperrors.Bad_Request)
-                    interface_uuid = existing_ifaces[0]["uuid"]
-                    if existing_ifaces[0]["iface_type"] == "data":
-                        db_sce_net["type"] = "data"
-                    sce_interface_uuid = str(uuid4())
-                    uuid_list.append(sce_net_uuid)
-                    iface_ip_address = None
-                    if iface.get("ip-address"):
-                        iface_ip_address = str(iface.get("ip-address"))
-                    db_sce_interface = {
-                        "uuid": sce_interface_uuid,
-                        "sce_vnf_id": vnf_index2scevnf_uuid[vnf_index],
-                        "sce_net_id": sce_net_uuid,
-                        "interface_id": interface_uuid,
-                        "ip_address": iface_ip_address,
-                    }
-                    db_sce_interfaces.append(db_sce_interface)
-                if not db_sce_net["type"]:
-                    db_sce_net["type"] = "bridge"
+                    existing_vdus = mydb.get_rows(SELECT=('vms.uuid'), FROM="vms", WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index]})
+                    if existing_vdus:
+                        # check correct parameters
+                        if vnf_index not in vnf_index2vnf_uuid:
+                            raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point"
+                                              "-ref':'member-vnf-index-ref':'{}'. Reference to a non-existing index at "
+                                              "'nsd':'constituent-vnfd'".format(
+                                                  str(nsd["id"]), str(vld["id"]), str(iface["member-vnf-index-ref"])),
+                                              httperrors.Bad_Request)
+
+                        existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid', 'i.type as iface_type'),
+                                                      FROM="interfaces as i join vms on i.vm_id=vms.uuid",
+                                                      WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index],
+                                                             'external_name': get_str(iface, "vnfd-connection-point-ref",
+                                                                                      255)})
+                        if not existing_ifaces:
+                            raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point"
+                                              "-ref':'vnfd-connection-point-ref':'{}'. Reference to a non-existing "
+                                              "connection-point name at VNFD '{}'".format(
+                                                  str(nsd["id"]), str(vld["id"]), str(iface["vnfd-connection-point-ref"]),
+                                                  str(iface.get("vnfd-id-ref"))[:255]),
+                                              httperrors.Bad_Request)
+                        interface_uuid = existing_ifaces[0]["uuid"]
+                        if existing_ifaces[0]["iface_type"] == "data":
+                            db_sce_net["type"] = "data"
+                        sce_interface_uuid = str(uuid4())
+                        uuid_list.append(sce_net_uuid)
+                        iface_ip_address = None
+                        if iface.get("ip-address"):
+                            iface_ip_address = str(iface.get("ip-address"))
+                        db_sce_interface = {
+                            "uuid": sce_interface_uuid,
+                            "sce_vnf_id": vnf_index2scevnf_uuid[vnf_index],
+                            "sce_net_id": sce_net_uuid,
+                            "interface_id": interface_uuid,
+                            "ip_address": iface_ip_address,
+                        }
+                        db_sce_interfaces.append(db_sce_interface)
+                        if not db_sce_net["type"]:
+                            db_sce_net["type"] = "bridge"
 
             # table sce_vnffgs (vnffgd)
             for vnffg in nsd.get("vnffgd").values():
 
             # table sce_vnffgs (vnffgd)
             for vnffg in nsd.get("vnffgd").values():
@@ -2675,11 +2694,12 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
             myNetDict["type"] = myNetType
             myNetDict["tenant_id"] = myvim_tenant
             myNetIPProfile = sce_net.get('ip_profile', None)
             myNetDict["type"] = myNetType
             myNetDict["tenant_id"] = myvim_tenant
             myNetIPProfile = sce_net.get('ip_profile', None)
+            myProviderNetwork = sce_net.get('provider_network', None)
             #TODO:
             #We should use the dictionary as input parameter for new_network
             #print myNetDict
             if not sce_net["external"]:
             #TODO:
             #We should use the dictionary as input parameter for new_network
             #print myNetDict
             if not sce_net["external"]:
-                network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile)
+                network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile, provider_network_profile=myProviderNetwork)
                 #print "New VIM network created for scenario %s. Network id:  %s" % (scenarioDict['name'],network_id)
                 sce_net['vim_id'] = network_id
                 auxNetDict['scenario'][sce_net['uuid']] = network_id
                 #print "New VIM network created for scenario %s. Network id:  %s" % (scenarioDict['name'],network_id)
                 sce_net['vim_id'] = network_id
                 auxNetDict['scenario'][sce_net['uuid']] = network_id
@@ -2710,10 +2730,11 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
                 myNetDict["type"] = myNetType
                 myNetDict["tenant_id"] = myvim_tenant
                 myNetIPProfile = net.get('ip_profile', None)
                 myNetDict["type"] = myNetType
                 myNetDict["tenant_id"] = myvim_tenant
                 myNetIPProfile = net.get('ip_profile', None)
+                myProviderNetwork = sce_net.get('provider_network', None)
                 #print myNetDict
                 #TODO:
                 #We should use the dictionary as input parameter for new_network
                 #print myNetDict
                 #TODO:
                 #We should use the dictionary as input parameter for new_network
-                network_id, _  = myvim.new_network(myNetName, myNetType, myNetIPProfile)
+                network_id, _  = myvim.new_network(myNetName, myNetType, myNetIPProfile, provider_network_profile=myProviderNetwork)
                 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
                 net['vim_id'] = network_id
                 if sce_vnf['uuid'] not in auxNetDict:
                 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
                 net['vim_id'] = network_id
                 if sce_vnf['uuid'] not in auxNetDict:
@@ -2854,7 +2875,7 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
         instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_scenario_name, instance_scenario_description, scenarioDict)
         return mydb.get_instance_scenario(instance_id)
 
         instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_scenario_name, instance_scenario_description, scenarioDict)
         return mydb.get_instance_scenario(instance_id)
 
-    except (db_base_Exception, vimconn.vimconnException) as e:
+    except (db_base_Exception, vimconn.VimConnException) as e:
         _, message = rollback(mydb, vims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
         _, message = rollback(mydb, vims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
@@ -2957,7 +2978,7 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i
         if datacenter_tenant_id:
             thread_id = datacenter_tenant_id
             thread = vim_threads["running"].get(datacenter_tenant_id)
         if datacenter_tenant_id:
             thread_id = datacenter_tenant_id
             thread = vim_threads["running"].get(datacenter_tenant_id)
-        else:
+        if not thread:
             where_={"td.nfvo_tenant_id": tenant_id}
             if datacenter_id_name:
                 if utils.check_valid_uuid(datacenter_id_name):
             where_={"td.nfvo_tenant_id": tenant_id}
             if datacenter_id_name:
                 if utils.check_valid_uuid(datacenter_id_name):
@@ -2969,7 +2990,7 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i
             if datacenter_tenant_id:
                 where_["dt.uuid"] = datacenter_tenant_id
             datacenters = mydb.get_rows(
             if datacenter_tenant_id:
                 where_["dt.uuid"] = datacenter_tenant_id
             datacenters = mydb.get_rows(
-                SELECT=("dt.uuid as datacenter_tenant_id",),
+                SELECT=("dt.uuid as datacenter_tenant_id, d.name as datacenter_name",),
                 FROM="datacenter_tenants as dt join tenants_datacenters as td on dt.uuid=td.datacenter_tenant_id "
                      "join datacenters as d on d.uuid=dt.datacenter_id",
                 WHERE=where_)
                 FROM="datacenter_tenants as dt join tenants_datacenters as td on dt.uuid=td.datacenter_tenant_id "
                      "join datacenters as d on d.uuid=dt.datacenter_id",
                 WHERE=where_)
@@ -2977,7 +2998,14 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i
                 raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
             elif datacenters:
                 thread_id = datacenters[0]["datacenter_tenant_id"]
                 raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
             elif datacenters:
                 thread_id = datacenters[0]["datacenter_tenant_id"]
+                datacenter_name = datacenters[0]["datacenter_name"]
                 thread = vim_threads["running"].get(thread_id)
                 thread = vim_threads["running"].get(thread_id)
+                if not thread:
+                    thread_name = get_non_used_vim_name(datacenter_name, datacenter_id)
+                    thread = vim_thread(task_lock, plugins, thread_name, None,
+                                        thread_id, db=mydb)
+                    thread.start()
+                    vim_threads["running"][thread_id] = thread
         if not thread:
             raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found)
         return thread_id, thread
         if not thread:
             raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found)
         return thread_id, thread
@@ -3048,6 +3076,7 @@ def _get_wim(db, wim_account_id):
 def create_instance(mydb, tenant_id, instance_dict):
     # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
     # logger.debug("Creating instance...")
 def create_instance(mydb, tenant_id, instance_dict):
     # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
     # logger.debug("Creating instance...")
+
     scenario = instance_dict["scenario"]
 
     # find main datacenter
     scenario = instance_dict["scenario"]
 
     # find main datacenter
@@ -3198,6 +3227,13 @@ def create_instance(mydb, tenant_id, instance_dict):
                     else:
                         update(scenario_net['ip_profile'], ipprofile_db)
 
                     else:
                         update(scenario_net['ip_profile'], ipprofile_db)
 
+                if net_instance_desc.get('provider-network'):
+                    provider_network_db = net_instance_desc['provider-network']
+                    if 'provider_network' not in scenario_net:
+                        scenario_net['provider_network'] = provider_network_db
+                    else:
+                        update(scenario_net['provider_network'], provider_network_db)
+
             for vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).items():
                 for scenario_vm in scenario_vnf['vms']:
                     if vdu_id == scenario_vm['osm_id'] or vdu_id == scenario_vm["name"]:
             for vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).items():
                 for scenario_vm in scenario_vnf['vms']:
                     if vdu_id == scenario_vm['osm_id'] or vdu_id == scenario_vm["name"]:
@@ -3230,6 +3266,14 @@ def create_instance(mydb, tenant_id, instance_dict):
                             scenario_net['ip_profile'] = ipprofile_db
                         else:
                             update(scenario_net['ip_profile'], ipprofile_db)
                             scenario_net['ip_profile'] = ipprofile_db
                         else:
                             update(scenario_net['ip_profile'], ipprofile_db)
+                    if 'provider-network' in net_instance_desc:
+                        provider_network_db = net_instance_desc['provider-network']
+
+                        if 'provider-network' not in scenario_net:
+                            scenario_net['provider_network'] = provider_network_db
+                        else:
+                            update(scenario_net['provider-network'], provider_network_db)
+
             for interface in net_instance_desc.get('interfaces', ()):
                 if 'ip_address' in interface:
                     for vnf in scenarioDict['vnfs']:
             for interface in net_instance_desc.get('interfaces', ()):
                 if 'ip_address' in interface:
                     for vnf in scenarioDict['vnfs']:
@@ -3242,11 +3286,13 @@ def create_instance(mydb, tenant_id, instance_dict):
         # logger.debug("Creating instance scenario-dict MERGED:\n%s",
         #              yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))
 
         # logger.debug("Creating instance scenario-dict MERGED:\n%s",
         #              yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))
 
+
         # 1. Creating new nets (sce_nets) in the VIM"
         number_mgmt_networks = 0
         db_instance_nets = []
         db_instance_wim_nets = []
         for sce_net in scenarioDict['nets']:
         # 1. Creating new nets (sce_nets) in the VIM"
         number_mgmt_networks = 0
         db_instance_nets = []
         db_instance_wim_nets = []
         for sce_net in scenarioDict['nets']:
+
             sce_net_uuid = sce_net.get('uuid', sce_net["name"])
             # get involved datacenters where this network need to be created
             involved_datacenters = []
             sce_net_uuid = sce_net.get('uuid', sce_net["name"])
             # get involved datacenters where this network need to be created
             involved_datacenters = []
@@ -3263,28 +3309,6 @@ def create_instance(mydb, tenant_id, instance_dict):
                 involved_datacenters.append(default_datacenter_id)
             target_wim_account = sce_net.get("wim_account", default_wim_account)
 
                 involved_datacenters.append(default_datacenter_id)
             target_wim_account = sce_net.get("wim_account", default_wim_account)
 
-            # --> WIM
-            # TODO: use this information during network creation
-            wim_account_id = wim_account_name = None
-            if len(involved_datacenters) > 1 and 'uuid' in sce_net:
-                if target_wim_account is None or target_wim_account is True:  # automatic selection of WIM
-                    # OBS: sce_net without uuid are used internally to VNFs
-                    # and the assumption is that VNFs will not be split among
-                    # different datacenters
-                    wim_account = wim_engine.find_suitable_wim_account(
-                        involved_datacenters, tenant_id)
-                    wim_account_id = wim_account['uuid']
-                    wim_account_name = wim_account['name']
-                    wim_usage[sce_net['uuid']] = wim_account_id
-                elif isinstance(target_wim_account, str):     # manual selection of WIM
-                    wim_account.persist.get_wim_account_by(target_wim_account, tenant_id)
-                    wim_account_id = wim_account['uuid']
-                    wim_account_name = wim_account['name']
-                    wim_usage[sce_net['uuid']] = wim_account_id
-                else:  # not WIM usage
-                    wim_usage[sce_net['uuid']] = False
-            # <-- WIM
-
             descriptor_net = {}
             if instance_dict.get("networks"):
                 if sce_net.get("uuid") in instance_dict["networks"]:
             descriptor_net = {}
             if instance_dict.get("networks"):
                 if sce_net.get("uuid") in instance_dict["networks"]:
@@ -3317,14 +3341,39 @@ def create_instance(mydb, tenant_id, instance_dict):
                 )
                 if not target_instance_nets:
                     raise NfvoException(
                 )
                 if not target_instance_nets:
                     raise NfvoException(
-                        "Cannot find the target network at instance:networks[{}]:use-network".format(descriptor_net_name),
-                        httperrors.Bad_Request)
+                        "Cannot find the target network at instance:networks[{}]:use-network".format(
+                            descriptor_net_name), httperrors.Bad_Request)
                 else:
                     use_network = target_instance_nets[0]["related"]
 
             if sce_net["external"]:
                 number_mgmt_networks += 1
 
                 else:
                     use_network = target_instance_nets[0]["related"]
 
             if sce_net["external"]:
                 number_mgmt_networks += 1
 
+            # --> WIM
+            # TODO: use this information during network creation
+            wim_account_id = wim_account_name = None
+            if len(involved_datacenters) > 1 and 'uuid' in sce_net:
+                urls = [myvims[v].url for v in involved_datacenters]
+                if len(set(urls)) < 2:
+                    wim_usage[sce_net['uuid']] = False
+                elif target_wim_account is None or target_wim_account is True:  # automatic selection of WIM
+                    # OBS: sce_net without uuid are used internally to VNFs
+                    # and the assumption is that VNFs will not be split among
+                    # different datacenters
+                    wim_account = wim_engine.find_suitable_wim_account(
+                        involved_datacenters, tenant_id)
+                    wim_account_id = wim_account['uuid']
+                    wim_account_name = wim_account['name']
+                    wim_usage[sce_net['uuid']] = wim_account_id
+                elif isinstance(target_wim_account, str):     # manual selection of WIM
+                    wim_account.persist.get_wim_account_by(target_wim_account, tenant_id)
+                    wim_account_id = wim_account['uuid']
+                    wim_account_name = wim_account['name']
+                    wim_usage[sce_net['uuid']] = wim_account_id
+                else:  # not WIM usage
+                    wim_usage[sce_net['uuid']] = False
+            # <-- WIM
+
             for datacenter_id in involved_datacenters:
                 netmap_use = None
                 netmap_create = None
             for datacenter_id in involved_datacenters:
                 netmap_use = None
                 netmap_create = None
@@ -3398,7 +3447,9 @@ def create_instance(mydb, tenant_id, instance_dict):
                 task_extra = {}
                 if create_network:
                     task_action = "CREATE"
                 task_extra = {}
                 if create_network:
                     task_action = "CREATE"
-                    task_extra["params"] = (net_vim_name, net_type, sce_net.get('ip_profile', None), wim_account_name)
+                    task_extra["params"] = (net_vim_name, net_type, sce_net.get('ip_profile', None), False,
+                                            sce_net.get('provider_network', None), wim_account_name)
+
                     if lookfor_network:
                         task_extra["find"] = (lookfor_filter,)
                 elif lookfor_network:
                     if lookfor_network:
                         task_extra["find"] = (lookfor_filter,)
                 elif lookfor_network:
@@ -3431,7 +3482,11 @@ def create_instance(mydb, tenant_id, instance_dict):
                         "created": create_network, # TODO py3
                         "sdn": True,
                     })
                         "created": create_network, # TODO py3
                         "sdn": True,
                     })
+
                     task_wim_extra = {"params": [net_type, wim_account_name]}
                     task_wim_extra = {"params": [net_type, wim_account_name]}
+                    # add sdn interfaces
+                    if sce_net.get('provider_network') and sce_net['provider_network'].get("sdn-ports"):
+                        task_wim_extra["sdn-ports"] = sce_net['provider_network'].get("sdn-ports")
                     db_vim_action = {
                         "instance_action_id": instance_action_id,
                         "status": "SCHEDULED",
                     db_vim_action = {
                         "instance_action_id": instance_action_id,
                         "status": "SCHEDULED",
@@ -3640,7 +3695,8 @@ def create_instance(mydb, tenant_id, instance_dict):
                             "source_ip": match["source_ip"],
                             "destination_ip": match["destination_ip"],
                             "source_port": match["source_port"],
                             "source_ip": match["source_ip"],
                             "destination_ip": match["destination_ip"],
                             "source_port": match["source_port"],
-                            "destination_port": match["destination_port"]
+                            "destination_port": match["destination_port"],
+                            "logical_source_port": classifier["interface_id"]
                         }
                         db_vim_action = {
                             "instance_action_id": instance_action_id,
                         }
                         db_vim_action = {
                             "instance_action_id": instance_action_id,
@@ -3726,11 +3782,11 @@ def create_instance(mydb, tenant_id, instance_dict):
         returned_instance = mydb.get_instance_scenario(instance_uuid)
         returned_instance["action_id"] = instance_action_id
         return returned_instance
         returned_instance = mydb.get_instance_scenario(instance_uuid)
         returned_instance["action_id"] = instance_action_id
         return returned_instance
-    except (NfvoException, vimconn.vimconnException, sdnconn.SdnConnectorError, db_base_Exception) as e:
+    except (NfvoException, vimconn.VimConnException, sdnconn.SdnConnectorError, db_base_Exception) as e:
         message = rollback(mydb, myvims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "database Exception"
         message = rollback(mydb, myvims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "database Exception"
-        elif isinstance(e, vimconn.vimconnException):
+        elif isinstance(e, vimconn.VimConnException):
             error_text = "VIM Exception"
         elif isinstance(e, sdnconn.SdnConnectorError):
             error_text = "WIM Exception"
             error_text = "VIM Exception"
         elif isinstance(e, sdnconn.SdnConnectorError):
             error_text = "WIM Exception"
@@ -3766,6 +3822,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
     sce_net2wim_instance = params_out["sce_net2wim_instance"]
 
     vnf_net2instance = {}
     sce_net2wim_instance = params_out["sce_net2wim_instance"]
 
     vnf_net2instance = {}
+    vnf_net2wim_instance = {}
 
     # 2. Creating new nets (vnf internal nets) in the VIM"
     # For each vnf net, we create it and we add it to instanceNetlist.
 
     # 2. Creating new nets (vnf internal nets) in the VIM"
     # For each vnf net, we create it and we add it to instanceNetlist.
@@ -3813,6 +3870,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                 "created": True,  # TODO py3
                 "sdn": True,
             })
                 "created": True,  # TODO py3
                 "sdn": True,
             })
+            vnf_net2wim_instance[net_uuid] = sdn_net_id
 
         db_net = {
             "uuid": net_uuid,
 
         db_net = {
             "uuid": net_uuid,
@@ -4049,6 +4107,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             else:
                 netDict['net_id'] = "TASK-{}".format(net2task_id[sce_vnf['uuid']][iface['net_id']])
                 instance_net_id = vnf_net2instance[sce_vnf['uuid']][iface['net_id']]
             else:
                 netDict['net_id'] = "TASK-{}".format(net2task_id[sce_vnf['uuid']][iface['net_id']])
                 instance_net_id = vnf_net2instance[sce_vnf['uuid']][iface['net_id']]
+                instance_wim_net_id = vnf_net2wim_instance.get(instance_net_id)
                 task_depends_on.append(net2task_id[sce_vnf['uuid']][iface['net_id']])
             # skip bridge ifaces not connected to any net
             if 'net_id' not in netDict or netDict['net_id'] == None:
                 task_depends_on.append(net2task_id[sce_vnf['uuid']][iface['net_id']])
             # skip bridge ifaces not connected to any net
             if 'net_id' not in netDict or netDict['net_id'] == None:
@@ -4130,14 +4189,14 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                 db_vm_iface_instance.update(db_vm_iface)
                 if db_vm_iface_instance.get("ip_address"):  # increment ip_address
                     ip = db_vm_iface_instance.get("ip_address")
                 db_vm_iface_instance.update(db_vm_iface)
                 if db_vm_iface_instance.get("ip_address"):  # increment ip_address
                     ip = db_vm_iface_instance.get("ip_address")
-                    i = ip.rfind(".")
-                    if i > 0:
-                        try:
+                    try:
+                        i = ip.rfind(".")
+                        if i > 0:
                             i += 1
                             ip = ip[i:] + str(int(ip[:i]) + 1)
                             db_vm_iface_instance["ip_address"] = ip
                             i += 1
                             ip = ip[i:] + str(int(ip[:i]) + 1)
                             db_vm_iface_instance["ip_address"] = ip
-                        except:
-                            db_vm_iface_instance["ip_address"] = None
+                    except:
+                        db_vm_iface_instance["ip_address"] = None
                 db_instance_interfaces.append(db_vm_iface_instance)
                 myVMDict['networks'][iface_index]["uuid"] = iface_uuid
                 iface_index += 1
                 db_instance_interfaces.append(db_vm_iface_instance)
                 myVMDict['networks'][iface_index]["uuid"] = iface_uuid
                 iface_index += 1
@@ -4581,7 +4640,7 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan
     #         try:
     #             vm_dict.update(myvims[datacenter_key].refresh_vms_status(vm_list[datacenter_key]) )
     #             failed = False
     #         try:
     #             vm_dict.update(myvims[datacenter_key].refresh_vms_status(vm_list[datacenter_key]) )
     #             failed = False
-    #         except vimconn.vimconnException as e:
+    #         except vimconn.VimConnException as e:
     #             logger.error("VIM exception %s %s", type(e).__name__, str(e))
     #             failed_message = str(e)
     #     if failed:
     #             logger.error("VIM exception %s %s", type(e).__name__, str(e))
     #             failed_message = str(e)
     #     if failed:
@@ -4643,7 +4702,7 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan
     #         try:
     #             net_dict.update(myvims[datacenter_key].refresh_nets_status(net_list[datacenter_key]) )
     #             failed = False
     #         try:
     #             net_dict.update(myvims[datacenter_key].refresh_nets_status(net_list[datacenter_key]) )
     #             failed = False
-    #         except vimconn.vimconnException as e:
+    #         except vimconn.VimConnException as e:
     #             logger.error("VIM exception %s %s", type(e).__name__, str(e))
     #             failed_message = str(e)
     #     if failed:
     #             logger.error("VIM exception %s %s", type(e).__name__, str(e))
     #             failed_message = str(e)
     #     if failed:
@@ -4767,6 +4826,16 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                         "extra": yaml.safe_dump({"params": vm_interfaces},
                                                 default_flow_style=True, width=256)
                     }
                         "extra": yaml.safe_dump({"params": vm_interfaces},
                                                 default_flow_style=True, width=256)
                     }
+                    # get affected instance_interfaces (deleted on cascade) to check if a wim_network must be updated
+                    deleted_interfaces = mydb.get_rows(
+                        SELECT=("instance_wim_net_id", ),
+                        FROM="instance_interfaces",
+                        WHERE={"instance_vm_id": vdu_id, "instance_wim_net_id<>": None},
+                    )
+                    for deleted_interface in deleted_interfaces:
+                        db_vim_actions.append({"TO-UPDATE": {}, "WHERE": {
+                            "item": "instance_wim_nets", "item_id": deleted_interface["instance_wim_net_id"]}})
+
                     task_index += 1
                     db_vim_actions.append(db_vim_action)
                     vm_result["deleted"].append(vdu_id)
                     task_index += 1
                     db_vim_actions.append(db_vim_action)
                     vm_result["deleted"].append(vdu_id)
@@ -4825,26 +4894,31 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                             "uuid": iface_uuid,
                             'instance_vm_id': vm_uuid,
                             "instance_net_id": vm_iface["instance_net_id"],
                             "uuid": iface_uuid,
                             'instance_vm_id': vm_uuid,
                             "instance_net_id": vm_iface["instance_net_id"],
+                            "instance_wim_net_id": vm_iface["instance_wim_net_id"],
                             'interface_id': vm_iface['interface_id'],
                             'type': vm_iface['type'],
                             'interface_id': vm_iface['interface_id'],
                             'type': vm_iface['type'],
+                            'model': vm_iface['model'],
                             'floating_ip': vm_iface['floating_ip'],
                             'port_security': vm_iface['port_security']
                         }
                         db_instance_interfaces.append(db_vm_iface)
                             'floating_ip': vm_iface['floating_ip'],
                             'port_security': vm_iface['port_security']
                         }
                         db_instance_interfaces.append(db_vm_iface)
+                        if db_vm_iface["instance_wim_net_id"]:
+                            db_vim_actions.append({"TO-UPDATE": {}, "WHERE": {
+                                "item": "instance_wim_nets", "item_id": db_vm_iface["instance_wim_net_id"]}})
                     task_params_copy = deepcopy(task_params)
                     for iface in task_params_copy[5]:
                         iface["uuid"] = iface2iface[iface["uuid"]]
                         # increment ip_address
                     task_params_copy = deepcopy(task_params)
                     for iface in task_params_copy[5]:
                         iface["uuid"] = iface2iface[iface["uuid"]]
                         # increment ip_address
-                        if "ip_address" in iface:
-                            ip = iface.get("ip_address")
-                            i = ip.rfind(".")
-                            if i > 0:
-                                try:
+                        if iface.get("ip_address"):
+                            try:
+                                ip = iface["ip_address"]
+                                i = ip.rfind(".")
+                                if i > 0:
                                     i += 1
                                     ip = ip[i:] + str(int(ip[:i]) + 1)
                                     iface["ip_address"] = ip
                                     i += 1
                                     ip = ip[i:] + str(int(ip[:i]) + 1)
                                     iface["ip_address"] = ip
-                                except:
-                                    iface["ip_address"] = None
+                            except:
+                                iface["ip_address"] = None
                     if vm_name:
                         task_params_copy[0] = vm_name
                     db_vim_action = {
                     if vm_name:
                         task_params_copy[0] = vm_name
                     db_vim_action = {
@@ -4918,10 +4992,9 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                                                           action_dict['add_public_key'],
                                                           password=password, ro_key=priv_RO_key)
                                     vm_result[ vm['uuid'] ] = {"vim_result": 200,
                                                           action_dict['add_public_key'],
                                                           password=password, ro_key=priv_RO_key)
                                     vm_result[ vm['uuid'] ] = {"vim_result": 200,
-                                                       "description": "Public key injected",
-                                                       "name":vm['name']
+                                                    "description": "Public key injected",
+                                                    "name":vm['name']
                                                     }
                                                     }
-
                         except KeyError:
                             raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']),
                                                 httperrors.Internal_Server_Error)
                         except KeyError:
                             raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']),
                                                 httperrors.Internal_Server_Error)
@@ -4967,7 +5040,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                     else:
                         vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']}
                         vm_ok +=1
                     else:
                         vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']}
                         vm_ok +=1
-            except vimconn.vimconnException as e:
+            except vimconn.VimConnException as e:
                 vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
                 vm_error+=1
 
                 vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
                 vm_error+=1
 
@@ -5058,6 +5131,15 @@ def new_datacenter(mydb, datacenter_descriptor):
     datacenter_type = datacenter_descriptor.get("type", "openvim");
     # module_info = None
 
     datacenter_type = datacenter_descriptor.get("type", "openvim");
     # module_info = None
 
+    for url_field in ('vim_url', 'vim_url_admin'):
+        # It is common that users copy and paste the URL from the VIM website
+        # (example OpenStack), therefore a common mistake is to include blank
+        # characters at the end of the URL. Let's remove it and just in case,
+        # lets remove trailing slash as well.
+        url = datacenter_descriptor.get(url_field)
+        if url:
+            datacenter_descriptor[url_field] = url.strip(string.whitespace + '/')
+
     # load plugin
     plugin_name = "rovim_" + datacenter_type
     if plugin_name not in plugins:
     # load plugin
     plugin_name = "rovim_" + datacenter_type
     if plugin_name not in plugins:
@@ -5181,12 +5263,13 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None,
         else: #if vim_tenant==None:
             #create tenant at VIM if not provided
             try:
         else: #if vim_tenant==None:
             #create tenant at VIM if not provided
             try:
-                _, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter, vim_user=vim_username,
-                                                                   vim_passwd=vim_password)
+                _, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter_id, vim_user=vim_username,
+                                                       vim_passwd=vim_password)
                 datacenter_name = myvim["name"]
                 vim_tenant = myvim.new_tenant(vim_tenant_name, "created by openmano for datacenter "+datacenter_name)
                 datacenter_name = myvim["name"]
                 vim_tenant = myvim.new_tenant(vim_tenant_name, "created by openmano for datacenter "+datacenter_name)
-            except vimconn.vimconnException as e:
-                raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id, str(e)), httperrors.Internal_Server_Error)
+            except vimconn.VimConnException as e:
+                raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_name, e),
+                                    httperrors.Internal_Server_Error)
             datacenter_tenants_dict = {}
             datacenter_tenants_dict["created"]="true"
 
             datacenter_tenants_dict = {}
             datacenter_tenants_dict["created"]="true"
 
@@ -5212,13 +5295,13 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None,
         mydb.new_row('tenants_datacenters', tenants_datacenter_dict)
 
         # create thread
         mydb.new_row('tenants_datacenters', tenants_datacenter_dict)
 
         # create thread
-        thread_name = get_non_used_vim_name(datacenter_name, datacenter_id, tenant_dict['name'], tenant_dict['uuid'])
+        thread_name = get_non_used_vim_name(datacenter_name, datacenter_id)
         new_thread = vim_thread(task_lock, plugins, thread_name, None, datacenter_tenant_id, db=db)
         new_thread.start()
         thread_id = datacenter_tenants_dict["uuid"]
         vim_threads["running"][thread_id] = new_thread
         return thread_id
         new_thread = vim_thread(task_lock, plugins, thread_name, None, datacenter_tenant_id, db=db)
         new_thread.start()
         thread_id = datacenter_tenants_dict["uuid"]
         vim_threads["running"][thread_id] = new_thread
         return thread_id
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         raise NfvoException(str(e), httperrors.Bad_Request)
 
 
         raise NfvoException(str(e), httperrors.Bad_Request)
 
 
@@ -5244,7 +5327,7 @@ def edit_vim_account(mydb, nfvo_tenant, datacenter_tenant_id, datacenter_id=None
     if config:
         original_config_dict = yaml.load(original_config, Loader=yaml.Loader)
         original_config_dict.update(config)
     if config:
         original_config_dict = yaml.load(original_config, Loader=yaml.Loader)
         original_config_dict.update(config)
-        update["config"] = yaml.safe_dump(original_config_dict, default_flow_style=True, width=256)
+        update_["config"] = yaml.safe_dump(original_config_dict, default_flow_style=True, width=256)
     if name:
         update_['name'] = name
     if vim_tenant:
     if name:
         update_['name'] = name
     if vim_tenant:
@@ -5297,7 +5380,7 @@ def delete_vim_account(mydb, tenant_id, vim_account_id, datacenter=None):
                 try:
                     datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
                     myvim.delete_tenant(vim_tenant_dict['vim_tenant_id'])
                 try:
                     datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
                     myvim.delete_tenant(vim_tenant_dict['vim_tenant_id'])
-                except vimconn.vimconnException as e:
+                except vimconn.VimConnException as e:
                     warning = "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict['vim_tenant_id'], str(e))
                     logger.warn(warning)
         except db_base_Exception as e:
                     warning = "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict['vim_tenant_id'], str(e))
                     logger.warn(warning)
         except db_base_Exception as e:
@@ -5319,14 +5402,14 @@ def datacenter_action(mydb, tenant_id, datacenter, action_dict):
     if 'check-connectivity' in action_dict:
         try:
             myvim.check_vim_connectivity()
     if 'check-connectivity' in action_dict:
         try:
             myvim.check_vim_connectivity()
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
             raise NfvoException(str(e), e.http_code)
     elif 'net-update' in action_dict:
         try:
             nets = myvim.get_network_list(filter_dict={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
             #print content
             #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
             raise NfvoException(str(e), e.http_code)
     elif 'net-update' in action_dict:
         try:
             nets = myvim.get_network_list(filter_dict={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
             #print content
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
             raise NfvoException(str(e), httperrors.Internal_Server_Error)
         #update nets Change from VIM format to NFVO format
             #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
             raise NfvoException(str(e), httperrors.Internal_Server_Error)
         #update nets Change from VIM format to NFVO format
@@ -5385,7 +5468,7 @@ def datacenter_new_netmap(mydb, tenant_id, datacenter, action_dict=None):
 
     try:
         vim_nets = myvim.get_network_list(filter_dict=filter_dict)
 
     try:
         vim_nets = myvim.get_network_list(filter_dict=filter_dict)
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
         raise NfvoException(str(e), httperrors.Internal_Server_Error)
     if len(vim_nets)>1 and action_dict:
         #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
         raise NfvoException(str(e), httperrors.Internal_Server_Error)
     if len(vim_nets)>1 and action_dict:
@@ -5426,7 +5509,7 @@ def get_sdn_net_id(mydb, tenant_id, datacenter, network_id):
 
         datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
         network = myvim.get_network_list(filter_dict=filter_dict)
 
         datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
         network = myvim.get_network_list(filter_dict=filter_dict)
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         raise NfvoException("Not possible to get_sdn_net_id from VIM: {}".format(str(e)), e.http_code)
 
     # ensure the network is defined
         raise NfvoException("Not possible to get_sdn_net_id from VIM: {}".format(str(e)), e.http_code)
 
     # ensure the network is defined
@@ -5597,7 +5680,7 @@ def vim_action_get(mydb, tenant_id, datacenter, item, name):
                  datacenter)
         else:
             return {item: content}
                  datacenter)
         else:
             return {item: content}
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         print("vim_action Not possible to get_{}_list from VIM: {} ".format(item, str(e)))
         raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code)
 
         print("vim_action Not possible to get_{}_list from VIM: {} ".format(item, str(e)))
         raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code)
 
@@ -5661,7 +5744,7 @@ def vim_action_delete(mydb, tenant_id, datacenter, item, name):
             content = myvim.delete_image(item_id)
         else:
             raise NfvoException(item + "?", httperrors.Method_Not_Allowed)
             content = myvim.delete_image(item_id)
         else:
             raise NfvoException(item + "?", httperrors.Method_Not_Allowed)
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
         raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item, name, str(e)), e.http_code)
 
         #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
         raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item, name, str(e)), e.http_code)
 
@@ -5682,7 +5765,10 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor):
             net_public = net.pop("shared", False)
             net_ipprofile = net.pop("ip_profile", None)
             net_vlan = net.pop("vlan", None)
             net_public = net.pop("shared", False)
             net_ipprofile = net.pop("ip_profile", None)
             net_vlan = net.pop("vlan", None)
-            content, _ = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, vlan=net_vlan) #, **net)
+            net_provider_network_profile = None
+            if net_vlan:
+                net_provider_network_profile = {"segmentation-id": net_vlan}
+            content, _ = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, provider_network_profile=net_provider_network_profile) #, **net)
 
             #If the datacenter has a SDN controller defined and the network is of dataplane type, then create the sdn network
             if get_sdn_controller_id(mydb, datacenter) != None and (net_type == 'data' or net_type == 'ptp'):
 
             #If the datacenter has a SDN controller defined and the network is of dataplane type, then create the sdn network
             if get_sdn_controller_id(mydb, datacenter) != None and (net_type == 'data' or net_type == 'ptp'):
@@ -5720,21 +5806,30 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor):
             content = myvim.new_tenant(tenant["name"], tenant.get("description"))
         else:
             raise NfvoException(item + "?", httperrors.Method_Not_Allowed)
             content = myvim.new_tenant(tenant["name"], tenant.get("description"))
         else:
             raise NfvoException(item + "?", httperrors.Method_Not_Allowed)
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code)
 
     return vim_action_get(mydb, tenant_id, datacenter, item, content)
 
 def sdn_controller_create(mydb, tenant_id, sdn_controller):
         raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code)
 
     return vim_action_get(mydb, tenant_id, datacenter, item, content)
 
 def sdn_controller_create(mydb, tenant_id, sdn_controller):
-    wim_id = ovim.new_of_controller(sdn_controller)
+    try:
+        wim_id = ovim.new_of_controller(sdn_controller)
+
+        # Load plugin if not previously loaded
+        controller_type = sdn_controller.get("type")
+        plugin_name = "rosdn_" + controller_type
+        if plugin_name not in plugins:
+            _load_plugin(plugin_name, type="sdn")
 
 
-    thread_name = get_non_used_vim_name(sdn_controller['name'], wim_id, wim_id, None)
-    new_thread = vim_thread(task_lock, plugins, thread_name, wim_id, None, db=db)
-    new_thread.start()
-    thread_id = wim_id
-    vim_threads["running"][thread_id] = new_thread
-    logger.debug('New SDN controller created with uuid {}'.format(wim_id))
-    return wim_id
+        thread_name = get_non_used_vim_name(sdn_controller['name'], wim_id)
+        new_thread = vim_thread(task_lock, plugins, thread_name, wim_id, None, db=db)
+        new_thread.start()
+        thread_id = wim_id
+        vim_threads["running"][thread_id] = new_thread
+        logger.debug('New SDN controller created with uuid {}'.format(wim_id))
+        return wim_id
+    except ovimException as e:
+        raise NfvoException(e) from e
 
 def sdn_controller_update(mydb, tenant_id, controller_id, sdn_controller):
     data = ovim.edit_of_controller(controller_id, sdn_controller)
 
 def sdn_controller_update(mydb, tenant_id, controller_id, sdn_controller):
     data = ovim.edit_of_controller(controller_id, sdn_controller)
@@ -5790,6 +5885,8 @@ def datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, sdn_port_map
                 pci = port.get("pci")
                 element["switch_port"] = port.get("switch_port")
                 element["switch_mac"] = port.get("switch_mac")
                 pci = port.get("pci")
                 element["switch_port"] = port.get("switch_port")
                 element["switch_mac"] = port.get("switch_mac")
+                element["switch_dpid"] = port.get("switch_dpid")
+                element["switch_id"] = port.get("switch_id")
                 if not element["switch_port"] and not element["switch_mac"]:
                     raise NfvoException ("The mapping must contain 'switch_port' or 'switch_mac'", httperrors.Bad_Request)
                 for pci_expanded in utils.expand_brackets(pci):
                 if not element["switch_port"] and not element["switch_mac"]:
                     raise NfvoException ("The mapping must contain 'switch_port' or 'switch_mac'", httperrors.Bad_Request)
                 for pci_expanded in utils.expand_brackets(pci):
@@ -5877,6 +5974,10 @@ def create_RO_keypair(tenant_id):
         private_key = key.exportKey(passphrase=tenant_id, pkcs=8)
     except (ValueError, NameError) as e:
         raise NfvoException("Unable to create private key: {}".format(e), httperrors.Internal_Server_Error)
         private_key = key.exportKey(passphrase=tenant_id, pkcs=8)
     except (ValueError, NameError) as e:
         raise NfvoException("Unable to create private key: {}".format(e), httperrors.Internal_Server_Error)
+    if isinstance(public_key, bytes):
+        public_key = public_key.decode(encoding='UTF-8')
+    if isinstance(private_key, bytes):
+        private_key = private_key.decode(encoding='UTF-8')
     return public_key, private_key
 
 def decrypt_key (key, tenant_id):
     return public_key, private_key
 
 def decrypt_key (key, tenant_id):
@@ -5893,6 +5994,8 @@ def decrypt_key (key, tenant_id):
         unencrypted_key = key.exportKey('PEM')
         if isinstance(unencrypted_key, ValueError):
             raise NfvoException("Unable to decrypt the private key: {}".format(unencrypted_key), httperrors.Internal_Server_Error)
         unencrypted_key = key.exportKey('PEM')
         if isinstance(unencrypted_key, ValueError):
             raise NfvoException("Unable to decrypt the private key: {}".format(unencrypted_key), httperrors.Internal_Server_Error)
+        if isinstance(unencrypted_key, bytes):
+            unencrypted_key = unencrypted_key.decode(encoding='UTF-8')
     except ValueError as e:
         raise NfvoException("Unable to decrypt the private key: {}".format(e), httperrors.Internal_Server_Error)
     return unencrypted_key
     except ValueError as e:
         raise NfvoException("Unable to decrypt the private key: {}".format(e), httperrors.Internal_Server_Error)
     return unencrypted_key