fix underlay VNFD-VLD networks.
[osm/RO.git] / RO / osm_ro / nfvo.py
index 36109cb..23c5f1c 100644 (file)
@@ -30,6 +30,7 @@ __date__ ="$16-sep-2014 22:05:01$"
 # import imp
 import json
 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
@@ -63,7 +64,7 @@ from pkg_resources import iter_entry_points
 
 # WIM
 from .wim import sdnconn
-from .wim.wimconn_fake import FakeConnector
+from .wim.wimconn_dummy import DummyConnector
 from .wim.failing_connector import FailingConnector
 from .http_tools import errors as httperrors
 from .wim.engine import WimEngine
@@ -100,6 +101,7 @@ last_task_id = 0.0
 db = None
 db_lock = Lock()
 
+worker_id = None
 
 class NfvoException(httperrors.HttpMappedError):
     """Common Class for NFVO errors"""
@@ -144,20 +146,29 @@ def new_task(name, params, depends=None):
 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:
+            text_id_ = f.readline()
+            _, _, 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):
@@ -175,7 +186,7 @@ def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id):
 
 
 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'])
@@ -183,8 +194,9 @@ def start_service(mydb, persistence=None, wim=None):
     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"] = DummyConnector
         # starts ovim library
         ovim = Sdn(db, plugins)
 
@@ -237,8 +249,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)
-            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()
@@ -252,7 +263,7 @@ def start_service(mydb, persistence=None, wim=None):
                 _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
@@ -977,6 +988,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
 
             # 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)
@@ -989,6 +1001,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
+                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"):
@@ -1181,7 +1194,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                                 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"]
 
@@ -1216,6 +1229,10 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                             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
@@ -2433,7 +2450,6 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                 elif vld.get("vim-network-name"):
                     db_sce_net["vim_network_name"] = get_str(vld, "vim-network-name", 255)
 
-                
                 # 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
@@ -2447,7 +2463,7 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                                               "'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],
@@ -2474,7 +2490,7 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                             "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"
@@ -2963,7 +2979,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)
-        else:
+        if not thread:
             where_={"td.nfvo_tenant_id": tenant_id}
             if datacenter_id_name:
                 if utils.check_valid_uuid(datacenter_id_name):
@@ -2975,7 +2991,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(
-                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_)
@@ -2983,7 +2999,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"]
+                datacenter_name = datacenters[0]["datacenter_name"]
                 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
@@ -3793,6 +3816,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
     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.
@@ -3840,6 +3864,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                 "created": True,  # TODO py3
                 "sdn": True,
             })
+            vnf_net2wim_instance[net_uuid] = sdn_net_id
 
         db_net = {
             "uuid": net_uuid,
@@ -4076,7 +4101,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']]
-                instance_wim_net_id = None
+                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:
@@ -4853,8 +4878,10 @@ 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"],
+                            "instance_wim_net_id": vm_iface["instance_wim_net_id"],
                             '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']
                         }
@@ -5239,7 +5266,7 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None,
         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"]
@@ -5759,7 +5786,13 @@ def sdn_controller_create(mydb, tenant_id, sdn_controller):
     try:
         wim_id = ovim.new_of_controller(sdn_controller)
 
-        thread_name = get_non_used_vim_name(sdn_controller['name'], wim_id, wim_id, None)
+        # 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)
         new_thread = vim_thread(task_lock, plugins, thread_name, wim_id, None, db=db)
         new_thread.start()
         thread_id = wim_id
@@ -5823,6 +5856,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")
+                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):