VCD feature 7193-provider_nerwork
[osm/RO.git] / osm_ro / nfvo.py
index 5a972e2..8637245 100644 (file)
@@ -20,7 +20,7 @@
 # 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
 '''
@@ -126,11 +126,12 @@ def get_non_used_vim_name(datacenter_name, datacenter_id, tenant_name, tenant_id
     if name not in vim_threads["names"]:
         vim_threads["names"].append(name)
         return 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 + "-" + tenant_id
+    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
 
@@ -237,7 +238,7 @@ def start_service(mydb, persistence=None, wim=None):
             except Exception as 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['vim_tenant_id'], vim['vim_tenant_name'],
+            thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['datacenter_id'], vim['vim_tenant_name'],
                                                 vim['vim_tenant_id'])
             new_thread = vim_thread.vim_thread(task_lock, thread_name, vim['datacenter_name'],
                                                vim['datacenter_tenant_id'], db=db, db_lock=db_lock, ovim=ovim)
@@ -305,6 +306,9 @@ def clean_db(mydb):
         nb_deleted += len(actions_to_delete)
         if len(actions_to_delete) < 100:
             break
+    # clean locks
+    mydb.update_rows("vim_wim_actions", UPDATE={"worker": None}, WHERE={"worker<>": None})
+
     if nb_deleted:
         logger.debug("Removed {} unused vim_wim_actions".format(nb_deleted))
 
@@ -804,7 +808,7 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_
         try:
             flavor_vim_id = None
             flavor_vim_id=vim.get_flavor_id_from_data(flavor_dict)
-            flavor_create="false"
+            flavor_created="false"
         except vimconn.vimconnException as e:
             pass
         try:
@@ -877,6 +881,21 @@ def _lookfor_or_create_image(db_image, mydb, descriptor):
         db_image["uuid"] = image_uuid
         return None
 
+def get_resource_allocation_params(quota_descriptor):
+    """
+    read the quota_descriptor from vnfd and fetch the resource allocation properties from the descriptor object
+    :param quota_descriptor: cpu/mem/vif/disk-io quota descriptor
+    :return: quota params for limit, reserve, shares from the descriptor object
+    """
+    quota = {}
+    if quota_descriptor.get("limit"):
+        quota["limit"] = int(quota_descriptor["limit"])
+    if quota_descriptor.get("reserve"):
+        quota["reserve"] = int(quota_descriptor["reserve"])
+    if quota_descriptor.get("shares"):
+        quota["shares"] = int(quota_descriptor["shares"])
+    return quota
+
 def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
     """
     Parses an OSM IM vnfd_catalog and insert at DB
@@ -888,7 +907,8 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
     try:
         myvnfd = vnfd_catalog.vnfd()
         try:
-            pybindJSONDecoder.load_ietf_json(vnf_descriptor, None, None, obj=myvnfd, path_helper=True)
+            pybindJSONDecoder.load_ietf_json(vnf_descriptor, None, None, obj=myvnfd, path_helper=True,
+                                             skip_unknown=True)
         except Exception as e:
             raise NfvoException("Error. Invalid VNF descriptor format " + str(e), httperrors.Bad_Request)
         db_vnfs = []
@@ -986,6 +1006,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
 
             # connection points vaiable declaration
             cp_name2iface_uuid = {}
+            cp_name2vdu_id = {}
             cp_name2vm_uuid = {}
             cp_name2db_interface = {}
             vdu_id2cp_name = {}  # stored only when one external connection point is presented at this VDU
@@ -993,6 +1014,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
             # table vms (vdus)
             vdu_id2uuid = {}
             vdu_id2db_table_index = {}
+            mgmt_access = {}
             for vdu in vnfd.get("vdu").itervalues():
 
                 for vdu_descriptor in vnfd_descriptor["vdu"]:
@@ -1146,6 +1168,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                             cp = vnfd.get("connection-point")[iface.get("external-connection-point-ref")]
                             db_interface["external_name"] = get_str(cp, "name", 255)
                             cp_name2iface_uuid[db_interface["external_name"]] = iface_uuid
+                            cp_name2vdu_id[db_interface["external_name"]] = vdu_id
                             cp_name2vm_uuid[db_interface["external_name"]] = vm_uuid
                             cp_name2db_interface[db_interface["external_name"]] = db_interface
                             for cp_descriptor in vnfd_descriptor["connection-point"]:
@@ -1260,6 +1283,23 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                                 numa["cores"] = max(db_flavor["vcpus"], 1)
                             else:
                                 numa["threads"] = max(db_flavor["vcpus"], 1)
+                            epa_vcpu_set = True
+                    if vdu["guest-epa"].get("cpu-quota") and not epa_vcpu_set:
+                        cpuquota = get_resource_allocation_params(vdu["guest-epa"].get("cpu-quota"))
+                        if cpuquota:
+                            extended["cpu-quota"] = cpuquota
+                    if vdu["guest-epa"].get("mem-quota"):
+                        vduquota = get_resource_allocation_params(vdu["guest-epa"].get("mem-quota"))
+                        if vduquota:
+                            extended["mem-quota"] = vduquota
+                    if vdu["guest-epa"].get("disk-io-quota"):
+                        diskioquota = get_resource_allocation_params(vdu["guest-epa"].get("disk-io-quota"))
+                        if diskioquota:
+                            extended["disk-io-quota"] = diskioquota
+                    if vdu["guest-epa"].get("vif-quota"):
+                        vifquota = get_resource_allocation_params(vdu["guest-epa"].get("vif-quota"))
+                        if vifquota:
+                            extended["vif-quota"] = vifquota
                 if numa:
                     extended["numas"] = [numa]
                 if extended:
@@ -1291,13 +1331,11 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                                             "'member-vdus':'{vdu}'. Reference to a non-existing vdu".format(
                                                 vnf=vnfd_id, pg=pg_name, vdu=vdu_id),
                                             httperrors.Bad_Request)
-                    if vdu_id2db_table_index[vdu_id]:
-                        db_vms[vdu_id2db_table_index[vdu_id]]["availability_zone"] = pg_name
+                    db_vms[vdu_id2db_table_index[vdu_id]]["availability_zone"] = pg_name
                     # TODO consider the case of isolation and not colocation
                     # if pg.get("strategy") == "ISOLATION":
 
             # VNF mgmt configuration
-            mgmt_access = {}
             if vnfd["mgmt-interface"].get("vdu-id"):
                 mgmt_vdu_id = get_str(vnfd["mgmt-interface"], "vdu-id", 255)
                 if mgmt_vdu_id not in vdu_id2uuid:
@@ -1306,6 +1344,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                                             vnf=vnfd_id, vdu=mgmt_vdu_id),
                                         httperrors.Bad_Request)
                 mgmt_access["vm_id"] = vdu_id2uuid[vnfd["mgmt-interface"]["vdu-id"]]
+                mgmt_access["vdu-id"] = vnfd["mgmt-interface"]["vdu-id"]
                 # if only one cp is defined by this VDU, mark this interface as of type "mgmt"
                 if vdu_id2cp_name.get(mgmt_vdu_id):
                     if cp_name2db_interface[vdu_id2cp_name[mgmt_vdu_id]]:
@@ -1313,7 +1352,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("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(
@@ -1321,20 +1360,26 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                                         httperrors.Bad_Request)
                 mgmt_access["vm_id"] = cp_name2vm_uuid[vnfd["mgmt-interface"]["cp"]]
                 mgmt_access["interface_id"] = cp_name2iface_uuid[vnfd["mgmt-interface"]["cp"]]
+                mgmt_access["vdu-id"] = cp_name2vdu_id[vnfd["mgmt-interface"]["cp"]]
                 # mark this interface as of type mgmt
                 if cp_name2db_interface[vnfd["mgmt-interface"]["cp"]]:
                     cp_name2db_interface[vnfd["mgmt-interface"]["cp"]]["type"] = "mgmt"
 
             default_user = get_str(vnfd.get("vnf-configuration", {}).get("config-access", {}).get("ssh-access", {}),
                                     "default-user", 64)
-
             if default_user:
                 mgmt_access["default_user"] = default_user
+
             required = get_str(vnfd.get("vnf-configuration", {}).get("config-access", {}).get("ssh-access", {}),
                                    "required", 6)
             if required:
                 mgmt_access["required"] = required
 
+            password_ = get_str(vnfd.get("vnf-configuration", {}).get("config-access", {}),
+                                   "password", 64)
+            if password_:
+                mgmt_access["password"] = password_
+
             if mgmt_access:
                 db_vnf["mgmt_access"] = yaml.safe_dump(mgmt_access, default_flow_style=True, width=256)
 
@@ -2265,7 +2310,7 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
     try:
         mynsd = nsd_catalog.nsd()
         try:
-            pybindJSONDecoder.load_ietf_json(nsd_descriptor, None, None, obj=mynsd)
+            pybindJSONDecoder.load_ietf_json(nsd_descriptor, None, None, obj=mynsd, skip_unknown=True)
         except Exception as e:
             raise NfvoException("Error. Invalid NS descriptor format: " + str(e), httperrors.Bad_Request)
         db_scenarios = []
@@ -2384,47 +2429,51 @@ 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").itervalues():
+                    # Check if there are VDUs in the descriptor
                     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").itervalues():
@@ -2440,7 +2489,6 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                 db_sce_vnffgs.append(db_sce_vnffg)
 
                 # deal with rsps
-                db_sce_rsps = []
                 for rsp in vnffg.get("rsp").itervalues():
                     sce_rsp_uuid = str(uuid4())
                     uuid_list.append(sce_rsp_uuid)
@@ -2451,7 +2499,6 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                         "id": get_str(rsp, "id", 255), # only useful to link with classifiers; will be removed later in the code
                     }
                     db_sce_rsps.append(db_sce_rsp)
-                    db_sce_rsp_hops = []
                     for iface in rsp.get("vnfd-connection-point-ref").itervalues():
                         vnf_index = str(iface['member-vnf-index-ref'])
                         if_order = int(iface['order'])
@@ -2504,7 +2551,6 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                         db_sce_rsp_hops.append(db_sce_rsp_hop)
 
                 # deal with classifiers
-                db_sce_classifiers = []
                 for classifier in vnffg.get("classifier").itervalues():
                     sce_classifier_uuid = str(uuid4())
                     uuid_list.append(sce_classifier_uuid)
@@ -2543,7 +2589,6 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
                     db_sce_classifier["sce_rsp_id"] = rsp["uuid"]
                     db_sce_classifiers.append(db_sce_classifier)
 
-                    db_sce_classifier_matches = []
                     for match in classifier.get("match-attributes").itervalues():
                         sce_classifier_match_uuid = str(uuid4())
                         uuid_list.append(sce_classifier_match_uuid)
@@ -2630,11 +2675,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)
+            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"]:
-                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
@@ -2664,10 +2710,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)
+                myProviderNetwork = sce_net.get('provider_network', None)
                 #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:
@@ -2992,6 +3039,7 @@ def update(d, u):
 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
@@ -3141,6 +3189,13 @@ def create_instance(mydb, tenant_id, instance_dict):
                     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 vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).iteritems():
                 for scenario_vm in scenario_vnf['vms']:
                     if vdu_id == scenario_vm['osm_id'] or vdu_id == scenario_vm["name"]:
@@ -3163,6 +3218,7 @@ def create_instance(mydb, tenant_id, instance_dict):
         # Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
         # However, this is not possible yet.
         for net_name, net_instance_desc in instance_dict.get("networks", {}).iteritems():
+
             for scenario_net in scenarioDict['nets']:
                 if net_name == scenario_net.get("name") or net_name == scenario_net.get("osm_id") or net_name == scenario_net.get("uuid"):
                     if "wim_account" in net_instance_desc and net_instance_desc["wim_account"] is not None:
@@ -3173,6 +3229,14 @@ def create_instance(mydb, tenant_id, instance_dict):
                             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']:
@@ -3185,10 +3249,12 @@ 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))
 
+
         # 1. Creating new nets (sce_nets) in the VIM"
         number_mgmt_networks = 0
         db_instance_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 = []
@@ -3203,7 +3269,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                             break
             if not involved_datacenters:
                 involved_datacenters.append(default_datacenter_id)
-            target_wim_account = scenario_net.get("wim_account", default_wim_account)
+            target_wim_account = sce_net.get("wim_account", default_wim_account)
 
             # --> WIM
             # TODO: use this information during network creation
@@ -3228,8 +3294,16 @@ def create_instance(mydb, tenant_id, instance_dict):
             # <-- WIM
 
             descriptor_net = {}
-            if instance_dict.get("networks") and instance_dict["networks"].get(sce_net["name"]):
-                descriptor_net = instance_dict["networks"][sce_net["name"]]
+            if instance_dict.get("networks"):
+                if sce_net.get("uuid") in instance_dict["networks"]:
+                    descriptor_net = instance_dict["networks"][sce_net["uuid"]]
+                    descriptor_net_name = sce_net["uuid"]
+                elif sce_net.get("osm_id") in instance_dict["networks"]:
+                    descriptor_net = instance_dict["networks"][sce_net["osm_id"]]
+                    descriptor_net_name = sce_net["osm_id"]
+                elif sce_net["name"] in instance_dict["networks"]:
+                    descriptor_net = instance_dict["networks"][sce_net["name"]]
+                    descriptor_net_name = sce_net["name"]
             net_name = descriptor_net.get("vim-network-name")
             # add datacenters from instantiation parameters
             if descriptor_net.get("sites"):
@@ -3239,6 +3313,22 @@ def create_instance(mydb, tenant_id, instance_dict):
             sce_net2instance[sce_net_uuid] = {}
             net2task_id['scenario'][sce_net_uuid] = {}
 
+            use_network = None
+            related_network = None
+            if descriptor_net.get("use-network"):
+                target_instance_nets = mydb.get_rows(
+                    SELECT="related",
+                    FROM="instance_nets",
+                    WHERE={"instance_scenario_id": descriptor_net["use-network"]["instance_scenario_id"],
+                           "osm_id":  descriptor_net["use-network"]["osm_id"]},
+                )
+                if not target_instance_nets:
+                    raise NfvoException(
+                        "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
 
@@ -3315,7 +3405,8 @@ def create_instance(mydb, tenant_id, instance_dict):
                 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), None, sce_net.get('provider_network', None), wim_account_name)
+
                     if lookfor_network:
                         task_extra["find"] = (lookfor_filter,)
                 elif lookfor_network:
@@ -3326,8 +3417,12 @@ def create_instance(mydb, tenant_id, instance_dict):
                 net_uuid = str(uuid4())
                 uuid_list.append(net_uuid)
                 sce_net2instance[sce_net_uuid][datacenter_id] = net_uuid
+                if not related_network:   # all db_instance_nets will have same related
+                    related_network = use_network or net_uuid
                 db_net = {
                     "uuid": net_uuid,
+                    "osm_id": sce_net.get("osm_id") or sce_net["name"],
+                    "related": related_network,
                     'vim_net_id': None,
                     "vim_name": net_vim_name,
                     "instance_scenario_id": instance_uuid,
@@ -3346,6 +3441,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                     "action": task_action,
                     "item": "instance_nets",
                     "item_id": net_uuid,
+                    "related": related_network,
                     "extra": yaml.safe_dump(task_extra, default_flow_style=True, width=256)
                 }
                 net2task_id['scenario'][sce_net_uuid][datacenter_id] = task_index
@@ -3426,6 +3522,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                         uuid_list.append(sfi_uuid)
                         db_sfi = {
                             "uuid": sfi_uuid,
+                            "related": sfi_uuid,
                             "instance_scenario_id": instance_uuid,
                             'sce_rsp_hop_id': cp['uuid'],
                             'datacenter_id': datacenter_id,
@@ -3441,6 +3538,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                             "status": "SCHEDULED",
                             "item": "instance_sfis",
                             "item_id": sfi_uuid,
+                            "related": sfi_uuid,
                             "extra": yaml.safe_dump({"params": extra_params, "depends_on": [dependencies[i]]},
                                                     default_flow_style=True, width=256)
                         }
@@ -3452,6 +3550,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                     uuid_list.append(sf_uuid)
                     db_sf = {
                         "uuid": sf_uuid,
+                        "related": sf_uuid,
                         "instance_scenario_id": instance_uuid,
                         'sce_rsp_hop_id': cp['uuid'],
                         'datacenter_id': datacenter_id,
@@ -3467,6 +3566,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                         "status": "SCHEDULED",
                         "item": "instance_sfs",
                         "item_id": sf_uuid,
+                        "related": sf_uuid,
                         "extra": yaml.safe_dump({"params": "", "depends_on": sfis_created},
                                                 default_flow_style=True, width=256)
                     }
@@ -3497,6 +3597,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                         uuid_list.append(classification_uuid)
                         db_classification = {
                             "uuid": classification_uuid,
+                            "related": classification_uuid,
                             "instance_scenario_id": instance_uuid,
                             'sce_classifier_match_id': match['uuid'],
                             'datacenter_id': datacenter_id,
@@ -3519,6 +3620,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                             "status": "SCHEDULED",
                             "item": "instance_classifications",
                             "item_id": classification_uuid,
+                            "related": classification_uuid,
                             "extra": yaml.safe_dump({"params": classification_params, "depends_on": [dependencies[i]]},
                                                     default_flow_style=True, width=256)
                         }
@@ -3531,6 +3633,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                 uuid_list.append(sfp_uuid)
                 db_sfp = {
                     "uuid": sfp_uuid,
+                    "related": sfp_uuid,
                     "instance_scenario_id": instance_uuid,
                     'sce_rsp_id': rsp['uuid'],
                     'datacenter_id': datacenter_id,
@@ -3546,6 +3649,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                     "status": "SCHEDULED",
                     "item": "instance_sfps",
                     "item_id": sfp_uuid,
+                    "related": sfp_uuid,
                     "extra": yaml.safe_dump({"params": "", "depends_on": sfs_created + classifications_created},
                                             default_flow_style=True, width=256)
                 }
@@ -3592,12 +3696,14 @@ 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
-    except (NfvoException, vimconn.vimconnException, db_base_Exception) as e:
+    except (NfvoException, vimconn.vimconnException, wimconn.WimConnectorError, db_base_Exception) as e:
         message = rollback(mydb, myvims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "database Exception"
         elif isinstance(e, vimconn.vimconnException):
             error_text = "VIM Exception"
+        elif isinstance(e, wimconn.WimConnectorError):
+            error_text = "WIM Exception"
         else:
             error_text = "Exception"
         error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
@@ -3659,6 +3765,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
         vnf_net2instance[sce_vnf['uuid']][net['uuid']] = net_uuid
         db_net = {
             "uuid": net_uuid,
+            "related": net_uuid,
             'vim_net_id': None,
             "vim_name": net_name,
             "instance_scenario_id": instance_uuid,
@@ -3689,6 +3796,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             "action": task_action,
             "item": "instance_nets",
             "item_id": net_uuid,
+            "related": net_uuid,
             "extra": yaml.safe_dump(task_extra, default_flow_style=True, width=256)
         }
         task_index += 1
@@ -3899,12 +4007,12 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             cloud_config_vm = unify_cloud_config({"key-pairs": params["instance_parameters"]["mgmt_keys"]},
                                                   cloud_config_vm)
 
-        if vm.get("instance_parameters") and vm["instance_parameters"].get("mgmt_keys"):
-            cloud_config_vm = unify_cloud_config({"key-pairs": vm["instance_parameters"]["mgmt_keys"]},
-                                                 cloud_config_vm)
-        # if ssh_access and ssh_access['required'] and ssh_access['default-user'] and tenant[0].get('RO_pub_key'):
-        #     RO_key = {"key-pairs": [tenant[0]['RO_pub_key']]}
-        #     cloud_config_vm = unify_cloud_config(cloud_config_vm, RO_key)
+        if vm.get("instance_parameters") and "mgmt_keys" in vm["instance_parameters"]:
+            if vm["instance_parameters"]["mgmt_keys"]:
+                cloud_config_vm = unify_cloud_config({"key-pairs": vm["instance_parameters"]["mgmt_keys"]},
+                                                     cloud_config_vm)
+            if RO_pub_key:
+                cloud_config_vm = unify_cloud_config(cloud_config_vm, {"key-pairs": [RO_pub_key]})
         if vm.get("boot_data"):
             cloud_config_vm = unify_cloud_config(vm["boot_data"], cloud_config_vm)
 
@@ -3928,6 +4036,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             uuid_list.append(vm_uuid)
             db_vm = {
                 "uuid": vm_uuid,
+                "related": vm_uuid,
                 'instance_vnf_id': vnf_uuid,
                 # TODO delete "vim_vm_id": vm_id,
                 "vm_id": vm["uuid"],
@@ -3967,6 +4076,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                 "status": "SCHEDULED",
                 "item": "instance_vms",
                 "item_id": vm_uuid,
+                "related": vm_uuid,
                 "extra": yaml.safe_dump({"params": task_params, "depends_on": task_depends_on},
                                         default_flow_style=True, width=256)
             }
@@ -4044,6 +4154,7 @@ def delete_instance(mydb, tenant_id, instance_id):
             "status": "SCHEDULED",
             "item": "instance_sfps",
             "item_id": sfp["uuid"],
+            "related": sfp["related"],
             "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
         }
         task_index += 1
@@ -4084,6 +4195,7 @@ def delete_instance(mydb, tenant_id, instance_id):
             "status": "SCHEDULED",
             "item": "instance_classifications",
             "item_id": classification["uuid"],
+            "related": classification["related"],
             "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
         }
         task_index += 1
@@ -4122,6 +4234,7 @@ def delete_instance(mydb, tenant_id, instance_id):
             "status": "SCHEDULED",
             "item": "instance_sfs",
             "item_id": sf["uuid"],
+            "related": sf["related"],
             "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
         }
         task_index += 1
@@ -4160,6 +4273,7 @@ def delete_instance(mydb, tenant_id, instance_id):
             "status": "SCHEDULED",
             "item": "instance_sfis",
             "item_id": sfi["uuid"],
+            "related": sfi["related"],
             "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
         }
         task_index += 1
@@ -4201,6 +4315,7 @@ def delete_instance(mydb, tenant_id, instance_id):
                 "status": "SCHEDULED",
                 "item": "instance_vms",
                 "item_id": vm["uuid"],
+                "related": vm["related"],
                 "extra": yaml.safe_dump({"params": vm["interfaces"], "depends_on": sfi_dependencies},
                                         default_flow_style=True, width=256)
             }
@@ -4255,6 +4370,7 @@ def delete_instance(mydb, tenant_id, instance_id):
             "status": "SCHEDULED",
             "item": "instance_nets",
             "item_id": net["uuid"],
+            "related": net["related"],
             "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
         }
         task_index += 1
@@ -4543,6 +4659,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                     for sce_vnf in instanceDict['vnfs']:
                         for vm in sce_vnf['vms']:
                             if vm["uuid"] == vdu_id:
+                                # TODO revise this should not be vm["uuid"]   instance_vms["vm_id"]
                                 vm_interfaces = vm["interfaces"]
                                 break
 
@@ -4554,6 +4671,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                         "status": "SCHEDULED",
                         "item": "instance_vms",
                         "item_id": vdu_id,
+                        "related": target_vm["related"],
                         "extra": yaml.safe_dump({"params": vm_interfaces},
                                                 default_flow_style=True, width=256)
                     }
@@ -4601,9 +4719,10 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                         pass
                     db_instance_vm = {
                         "uuid": vm_uuid,
+                        'related': vm_uuid,
                         'instance_vnf_id': target_vm['instance_vnf_id'],
                         'vm_id': target_vm['vm_id'],
-                        'vim_name': vm_name
+                        'vim_name': vm_name,
                     }
                     db_instance_vms.append(db_instance_vm)
 
@@ -4644,6 +4763,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                         "status": "SCHEDULED",
                         "item": "instance_vms",
                         "item_id": vm_uuid,
+                        "related": vm_uuid,
                         # ALF
                         # ALF
                         # TODO examinar parametros, quitar MAC o incrementar. Incrementar IP y colocar las dependencias con ACTION-asdfasd.
@@ -4682,27 +4802,33 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
         for vm in sce_vnf['vms']:
             if not action_over_all and sce_vnf['uuid'] not in input_vnfs and sce_vnf['vnf_name'] not in input_vnfs and \
                     sce_vnf['member_vnf_index'] not in input_vnfs and \
-                    vm['uuid'] not in input_vms and vm['name'] not in input_vms:
+                    vm['uuid'] not in input_vms and vm['name'] not in input_vms and \
+                    sce_vnf['member_vnf_index'] + "-" + vm['vdu_osm_id'] not in input_vms:  # TODO conside vm_count_index
                 continue
             try:
                 if "add_public_key" in action_dict:
-                    mgmt_access = {}
                     if sce_vnf.get('mgmt_access'):
                         mgmt_access = yaml.load(sce_vnf['mgmt_access'])
-                        ssh_access = mgmt_access['config-access']['ssh-access']
+                        if not input_vms and mgmt_access.get("vdu-id") != vm['vdu_osm_id']:
+                            continue
+                        default_user = mgmt_access.get("default-user")
+                        password = mgmt_access.get("password")
+                        if mgmt_access.get(vm['vdu_osm_id']):
+                            default_user = mgmt_access[vm['vdu_osm_id']].get("default-user", default_user)
+                            password = mgmt_access[vm['vdu_osm_id']].get("password", password)
+
                         tenant = mydb.get_rows_by_id('nfvo_tenants', nfvo_tenant)
                         try:
-                            if ssh_access['required'] and ssh_access['default-user']:
-                                if 'ip_address' in vm:
+                            if 'ip_address' in vm:
                                     mgmt_ip = vm['ip_address'].split(';')
-                                    password = mgmt_access['config-access'].get('password')
                                     priv_RO_key = decrypt_key(tenant[0]['encrypted_RO_priv_key'], tenant[0]['uuid'])
-                                    myvim.inject_user_key(mgmt_ip[0], ssh_access['default-user'],
+                                    data  = myvim.inject_user_key(mgmt_ip[0], action_dict.get('user', default_user),
                                                           action_dict['add_public_key'],
                                                           password=password, ro_key=priv_RO_key)
-                            else:
-                                raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']),
-                                                    httperrors.Internal_Server_Error)
+                                    vm_result[ vm['uuid'] ] = {"vim_result": 200,
+                                                    "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)
@@ -5104,7 +5230,13 @@ def datacenter_action(mydb, tenant_id, datacenter, action_dict):
     #get datacenter info
     datacenter_id, myvim  = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
 
-    if 'net-update' in action_dict:
+    if 'check-connectivity' in action_dict:
+        try:
+            myvim.check_vim_connectivity()
+        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
@@ -5462,7 +5594,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)
-            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'):