VCD feature 7193-provider_nerwork
[osm/RO.git] / osm_ro / nfvo.py
index 15f04d6..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
 '''
@@ -1006,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
@@ -1013,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"]:
@@ -1166,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"]:
@@ -1282,13 +1285,21 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                                 numa["threads"] = max(db_flavor["vcpus"], 1)
                             epa_vcpu_set = True
                     if vdu["guest-epa"].get("cpu-quota") and not epa_vcpu_set:
-                        extended["cpu-quota"] = get_resource_allocation_params(vdu["guest-epa"].get("cpu-quota"))
+                        cpuquota = get_resource_allocation_params(vdu["guest-epa"].get("cpu-quota"))
+                        if cpuquota:
+                            extended["cpu-quota"] = cpuquota
                     if vdu["guest-epa"].get("mem-quota"):
-                        extended["mem-quota"] = get_resource_allocation_params(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"):
-                        extended["disk-io-quota"] = get_resource_allocation_params(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"):
-                        extended["vif-quota"] = get_resource_allocation_params(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:
@@ -1325,7 +1336,6 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                     # 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:
@@ -1334,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]]:
@@ -1341,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(
@@ -1349,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)
 
@@ -2412,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():
@@ -2654,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
@@ -2688,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:
@@ -3016,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
@@ -3165,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"]:
@@ -3187,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:
@@ -3197,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']:
@@ -3209,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 = []
@@ -3363,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:
@@ -3964,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)
 
@@ -4759,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)
@@ -5181,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
@@ -5539,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'):