X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_ro%2Fnfvo.py;h=c2f331be29b1f7614d6737698c89e3eb66cb89d5;hb=45140f51dbddc7084fdedf71fd888f691b851301;hp=bd9d3689f173df9330822865e4fc88cc6e14bb31;hpb=66eba6ece53cd85d0efbe8b4ff4f414c812b347b;p=osm%2FRO.git diff --git a/osm_ro/nfvo.py b/osm_ro/nfvo.py index bd9d3689..c2f331be 100644 --- a/osm_ro/nfvo.py +++ b/osm_ro/nfvo.py @@ -392,7 +392,7 @@ def rollback(mydb, vims, rollback_list): mydb.delete_row(FROM="datacenters_images", WHERE={"datacenter_vim_id": vim["id"], "vim_id":item["uuid"]}) elif item["what"]=="flavor": vim.delete_flavor(item["uuid"]) - mydb.delete_row(FROM="datacenters_flavors", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]}) + mydb.delete_row(FROM="datacenters_flavors", WHERE={"datacenter_vim_id": vim["id"], "vim_id":item["uuid"]}) elif item["what"]=="network": vim.delete_network(item["uuid"]) elif item["what"]=="vm": @@ -621,7 +621,7 @@ def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vi def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_vim=False, return_on_error = None): - temp_flavor_dict= {'disk':flavor_dict.get('disk',1), + temp_flavor_dict= {'disk':flavor_dict.get('disk',0), 'ram':flavor_dict.get('ram'), 'vcpus':flavor_dict.get('vcpus'), } @@ -828,7 +828,7 @@ 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) + pybindJSONDecoder.load_ietf_json(vnf_descriptor, None, None, obj=myvnfd, path_helper=True) except Exception as e: raise NfvoException("Error. Invalid VNF descriptor format " + str(e), HTTP_Bad_Request) db_vnfs = [] @@ -838,6 +838,8 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): db_interfaces = [] db_images = [] db_flavors = [] + db_ip_profiles_index = 0 + db_ip_profiles = [] uuid_list = [] vnfd_uuid_list = [] vnfd_catalog_descriptor = vnf_descriptor.get("vnfd:vnfd-catalog") @@ -869,6 +871,27 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): if vnfd_descriptor["id"] == str(vnfd["id"]): break + # table ip_profiles (ip-profiles) + ip_profile_name2db_table_index = {} + for ip_profile in vnfd.get("ip-profiles").itervalues(): + db_ip_profile = { + "ip_version": str(ip_profile["ip-profile-params"].get("ip-version", "ipv4")), + "subnet_address": str(ip_profile["ip-profile-params"].get("subnet-address")), + "gateway_address": str(ip_profile["ip-profile-params"].get("gateway-address")), + "dhcp_enabled": str(ip_profile["ip-profile-params"]["dhcp-params"].get("enabled", True)), + "dhcp_start_address": str(ip_profile["ip-profile-params"]["dhcp-params"].get("start-address")), + "dhcp_count": str(ip_profile["ip-profile-params"]["dhcp-params"].get("count")), + } + dns_list = [] + for dns in ip_profile["ip-profile-params"]["dns-server"].itervalues(): + dns_list.append(str(dns.get("address"))) + db_ip_profile["dns_address"] = ";".join(dns_list) + if ip_profile["ip-profile-params"].get('security-group'): + db_ip_profile["security_group"] = ip_profile["ip-profile-params"]['security-group'] + ip_profile_name2db_table_index[str(ip_profile["name"])] = db_ip_profiles_index + db_ip_profiles_index += 1 + db_ip_profiles.append(db_ip_profile) + # table nets (internal-vld) net_id2uuid = {} # for mapping interface with network for vld in vnfd.get("internal-vld").itervalues(): @@ -883,11 +906,36 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): } net_id2uuid[vld.get("id")] = net_uuid db_nets.append(db_net) + # ip-profile, link db_ip_profile with db_sce_net + if vld.get("ip-profile-ref"): + ip_profile_name = vld.get("ip-profile-ref") + if ip_profile_name not in ip_profile_name2db_table_index: + raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{}]':'vld[{}]':'ip-profile-ref':" + "'{}'. Reference to a non-existing 'ip_profiles'".format( + str(vnfd["id"]), str(vld["id"]), str(vld["ip-profile-ref"])), + HTTP_Bad_Request) + db_ip_profiles[ip_profile_name2db_table_index[ip_profile_name]]["net_id"] = net_uuid + else: #check no ip-address has been defined + for icp in vld.get("internal-connection-point").itervalues(): + if icp.get("ip-address"): + raise NfvoException("Error at 'vnfd[{}]':'vld[{}]':'internal-connection-point[{}]' " + "contains an ip-address but no ip-profile has been defined at VLD".format( + str(vnfd["id"]), str(vld["id"]), str(icp["id"])), + HTTP_Bad_Request) + + # connection points vaiable declaration + cp_name2iface_uuid = {} + cp_name2vm_uuid = {} + cp_name2db_interface = {} # table vms (vdus) vdu_id2uuid = {} vdu_id2db_table_index = {} for vdu in vnfd.get("vdu").itervalues(): + + for vdu_descriptor in vnfd_descriptor["vdu"]: + if vdu_descriptor["id"] == str(vdu["id"]): + break vm_uuid = str(uuid4()) uuid_list.append(vm_uuid) vdu_id = get_str(vdu, "id", 255) @@ -968,9 +1016,6 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): # table interfaces (internal/external interfaces) flavor_epa_interfaces = [] - cp_name2iface_uuid = {} - cp_name2vm_uuid = {} - cp_name2db_interface = {} vdu_id2cp_name = {} # stored only when one external connection point is presented at this VDU # for iface in chain(vdu.get("internal-interface").itervalues(), vdu.get("external-interface").itervalues()): for iface in vdu.get("interface").itervalues(): @@ -1041,27 +1086,43 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): HTTP_Bad_Request) elif iface.get("internal-connection-point-ref"): try: + for icp_descriptor in vdu_descriptor["internal-connection-point"]: + if icp_descriptor["id"] == str(iface.get("internal-connection-point-ref")): + break + else: + raise KeyError("does not exist at vdu:internal-connection-point") + icp = None + icp_vld = None for vld in vnfd.get("internal-vld").itervalues(): for cp in vld.get("internal-connection-point").itervalues(): if cp.get("id-ref") == iface.get("internal-connection-point-ref"): - db_interface["net_id"] = net_id2uuid[vld.get("id")] - for cp_descriptor in vnfd_descriptor["connection-point"]: - if cp_descriptor["name"] == db_interface["external_name"]: - break - if str(cp_descriptor.get("port-security-enabled")).lower() == "false": - db_interface["port_security"] = 0 - elif str(cp_descriptor.get("port-security-enabled")).lower() == "true": - db_interface["port_security"] = 1 - break - except KeyError: + if icp: + raise KeyError("is referenced by more than one 'internal-vld'") + icp = cp + icp_vld = vld + if not icp: + raise KeyError("is not referenced by any 'internal-vld'") + + 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 + elif str(icp_descriptor.get("port-security-enabled")).lower() == "true": + db_interface["port_security"] = 1 + if icp.get("ip-address"): + if not icp_vld.get("ip-profile-ref"): + raise NfvoException + db_interface["ip_address"] = str(icp.get("ip-address")) + except KeyError as e: raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'vdu[{vdu}]':" - "'interface[{iface}]':'vdu-internal-connection-point-ref':'{cp}' is not" - " referenced by any internal-vld".format( + "'interface[{iface}]':'internal-connection-point-ref':'{cp}'" + " {msg}".format( vnf=vnfd_id, vdu=vdu_id, iface=iface["name"], - cp=iface.get("vdu-internal-connection-point-ref")), + cp=iface.get("internal-connection-point-ref"), msg=str(e)), HTTP_Bad_Request) if iface.get("position") is not None: db_interface["created_at"] = int(iface.get("position")) - 1000 + if iface.get("mac-address"): + db_interface["mac"] = str(iface.get("mac-address")) db_interfaces.append(db_interface) # table flavors @@ -1069,9 +1130,9 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): "name": get_str(vdu, "name", 250) + "-flv", "vcpus": int(vdu["vm-flavor"].get("vcpu-count", 1)), "ram": int(vdu["vm-flavor"].get("memory-mb", 1)), - "disk": int(vdu["vm-flavor"].get("storage-gb", 1)), + "disk": int(vdu["vm-flavor"].get("storage-gb", 0)), } - # EPA TODO revise + # TODO revise the case of several numa-node-policy node extended = {} numa = {} if devices: @@ -1083,7 +1144,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): if vdu["guest-epa"].get("numa-node-policy"): # TODO or dedicated_int: numa_node_policy = vdu["guest-epa"].get("numa-node-policy") if numa_node_policy.get("node"): - numa_node = numa_node_policy["node"]['0'] + numa_node = numa_node_policy["node"].values()[0] if numa_node.get("num-cores"): numa["cores"] = numa_node["num-cores"] epa_vcpu_set = True @@ -1118,7 +1179,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): extended_text = yaml.safe_dump(extended, default_flow_style=True, width=256) db_flavor["extended"] = extended_text # look if flavor exist - temp_flavor_dict = {'disk': db_flavor.get('disk', 1), + temp_flavor_dict = {'disk': db_flavor.get('disk', 0), 'ram': db_flavor.get('ram'), 'vcpus': db_flavor.get('vcpus'), 'extended': db_flavor.get('extended') @@ -1187,14 +1248,13 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): if mgmt_access: db_vnf["mgmt_access"] = yaml.safe_dump(mgmt_access, default_flow_style=True, width=256) - - db_vnfs.append(db_vnf) db_tables=[ {"vnfs": db_vnfs}, {"nets": db_nets}, {"images": db_images}, {"flavors": db_flavors}, + {"ip_profiles": db_ip_profiles}, {"vms": db_vms}, {"interfaces": db_interfaces}, ] @@ -1260,7 +1320,7 @@ def new_vnf(mydb, tenant_id, vnf_descriptor): myflavorDict["description"] = VNFCitem["description"] myflavorDict["ram"] = vnfc.get("ram", 0) myflavorDict["vcpus"] = vnfc.get("vcpus", 0) - myflavorDict["disk"] = vnfc.get("disk", 1) + myflavorDict["disk"] = vnfc.get("disk", 0) myflavorDict["extended"] = {} devices = vnfc.get("devices") @@ -1396,7 +1456,7 @@ def new_vnf_v02(mydb, tenant_id, vnf_descriptor): myflavorDict["description"] = VNFCitem["description"] myflavorDict["ram"] = vnfc.get("ram", 0) myflavorDict["vcpus"] = vnfc.get("vcpus", 0) - myflavorDict["disk"] = vnfc.get("disk", 1) + myflavorDict["disk"] = vnfc.get("disk", 0) myflavorDict["extended"] = {} devices = vnfc.get("devices") @@ -1583,26 +1643,33 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None): continue #flavor not used, must be deleted #delelte at VIM - c = mydb.get_rows(FROM='datacenters_flavors', WHERE={'flavor_id':flavor}) + c = mydb.get_rows(FROM='datacenters_flavors', WHERE={'flavor_id': flavor}) for flavor_vim in c: - if flavor_vim["datacenter_vim_id"] not in vims: # TODO change to datacenter_tenant_id + if not flavor_vim['created']: # skip this flavor because not created by openmano continue - if flavor_vim['created']=='false': #skip this flavor because not created by openmano + # look for vim + myvim = None + for vim in vims.values(): + if vim["config"]["datacenter_tenant_id"] == flavor_vim["datacenter_vim_id"]: + myvim = vim + break + if not myvim: continue - myvim=vims[ flavor_vim["datacenter_id"] ] try: myvim.delete_flavor(flavor_vim["vim_id"]) - except vimconn.vimconnNotFoundException as e: - logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"], flavor_vim["datacenter_id"] ) + except vimconn.vimconnNotFoundException: + logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"], + flavor_vim["datacenter_vim_id"] ) 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_id"], type(e).__name__, str(e)) - undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"], flavor_vim["datacenter_id"] )) - #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors + flavor_vim["vim_id"], flavor_vim["datacenter_vim_id"], type(e).__name__, str(e)) + undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"], + flavor_vim["datacenter_vim_id"])) + # delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors mydb.delete_row_by_id('flavors', flavor) except db_base_Exception as e: logger.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor, str(e)) - undeletedItems.append("flavor %s" % flavor) + undeletedItems.append("flavor {}".format(flavor)) for image in imageList: @@ -2098,7 +2165,7 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): :param mydb: :param tenant_id: :param nsd_descriptor: - :return: The list of cretated NSD ids + :return: The list of created NSD ids """ try: mynsd = nsd_catalog.nsd() @@ -2110,6 +2177,11 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): db_sce_nets = [] db_sce_vnfs = [] db_sce_interfaces = [] + db_sce_vnffgs = [] + db_sce_rsps = [] + db_sce_rsp_hops = [] + db_sce_classifiers = [] + db_sce_classifier_matches = [] db_ip_profiles = [] db_ip_profiles_index = 0 uuid_list = [] @@ -2117,7 +2189,7 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): for nsd_yang in mynsd.nsd_catalog.nsd.itervalues(): nsd = nsd_yang.get() - # table sceanrios + # table scenarios scenario_uuid = str(uuid4()) uuid_list.append(scenario_uuid) nsd_uuid_list.append(scenario_uuid) @@ -2241,26 +2313,155 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor): 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": #TODO + "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(): + sce_vnffg_uuid = str(uuid4()) + uuid_list.append(sce_vnffg_uuid) + db_sce_vnffg = { + "uuid": sce_vnffg_uuid, + "name": get_str(vnffg, "name", 255), + "scenario_id": scenario_uuid, + "vendor": get_str(vnffg, "vendor", 255), + "description": get_str(vld, "description", 255), + } + 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) + db_sce_rsp = { + "uuid": sce_rsp_uuid, + "name": get_str(rsp, "name", 255), + "sce_vnffg_id": sce_vnffg_uuid, + "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 = int(iface['member-vnf-index-ref']) + if_order = int(iface['order']) + # check correct parameters + if vnf_index not in vnf_index2vnf_uuid: + raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'rsp[{}]':'vnfd-connection-point" + "-ref':'member-vnf-index-ref':'{}'. Reference to a non-existing index at " + "'nsd':'constituent-vnfd'".format( + str(nsd["id"]), str(rsp["id"]), str(iface["member-vnf-index-ref"])), + HTTP_Bad_Request) + + existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid',), + 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[{}]':'rsp[{}]':'vnfd-connection-point" + "-ref':'vnfd-connection-point-ref':'{}'. Reference to a non-existing " + "connection-point name at VNFD '{}'".format( + str(nsd["id"]), str(rsp["id"]), str(iface["vnfd-connection-point-ref"]), + str(iface.get("vnfd-id-ref"))[:255]), + HTTP_Bad_Request) + interface_uuid = existing_ifaces[0]["uuid"] + sce_rsp_hop_uuid = str(uuid4()) + uuid_list.append(sce_rsp_hop_uuid) + db_sce_rsp_hop = { + "uuid": sce_rsp_hop_uuid, + "if_order": if_order, + "interface_id": interface_uuid, + "sce_vnf_id": vnf_index2scevnf_uuid[vnf_index], + "sce_rsp_id": sce_rsp_uuid, + } + 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) + + # source VNF + vnf_index = int(classifier['member-vnf-index-ref']) + if vnf_index not in vnf_index2vnf_uuid: + raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'classifier[{}]':'vnfd-connection-point" + "-ref':'member-vnf-index-ref':'{}'. Reference to a non-existing index at " + "'nsd':'constituent-vnfd'".format( + str(nsd["id"]), str(classifier["id"]), str(classifier["member-vnf-index-ref"])), + HTTP_Bad_Request) + existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid',), + FROM="interfaces as i join vms on i.vm_id=vms.uuid", + WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index], + 'external_name': get_str(classifier, "vnfd-connection-point-ref", + 255)}) + if not existing_ifaces: + raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'rsp[{}]':'vnfd-connection-point" + "-ref':'vnfd-connection-point-ref':'{}'. Reference to a non-existing " + "connection-point name at VNFD '{}'".format( + str(nsd["id"]), str(rsp["id"]), str(iface["vnfd-connection-point-ref"]), + str(iface.get("vnfd-id-ref"))[:255]), + HTTP_Bad_Request) + interface_uuid = existing_ifaces[0]["uuid"] + + db_sce_classifier = { + "uuid": sce_classifier_uuid, + "name": get_str(classifier, "name", 255), + "sce_vnffg_id": sce_vnffg_uuid, + "sce_vnf_id": vnf_index2scevnf_uuid[vnf_index], + "interface_id": interface_uuid, + } + rsp_id = get_str(classifier, "rsp-id-ref", 255) + rsp = next((item for item in db_sce_rsps if item["id"] == rsp_id), None) + 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) + db_sce_classifier_match = { + "uuid": sce_classifier_match_uuid, + "ip_proto": get_str(match, "ip-proto", 2), + "source_ip": get_str(match, "source-ip-address", 16), + "destination_ip": get_str(match, "destination-ip-address", 16), + "source_port": get_str(match, "source-port", 5), + "destination_port": get_str(match, "destination-port", 5), + "sce_classifier_id": sce_classifier_uuid, + } + db_sce_classifier_matches.append(db_sce_classifier_match) + # TODO: vnf/cp keys + + # remove unneeded id's in sce_rsps + for rsp in db_sce_rsps: + rsp.pop('id') + db_tables = [ {"scenarios": db_scenarios}, {"sce_nets": db_sce_nets}, {"ip_profiles": db_ip_profiles}, {"sce_vnfs": db_sce_vnfs}, {"sce_interfaces": db_sce_interfaces}, + {"sce_vnffgs": db_sce_vnffgs}, + {"sce_rsps": db_sce_rsps}, + {"sce_rsp_hops": db_sce_rsp_hops}, + {"sce_classifiers": db_sce_classifiers}, + {"sce_classifier_matches": db_sce_classifier_matches}, ] - logger.debug("create_vnf Deployment done vnfDict: %s", + logger.debug("new_nsd_v3 done: %s", yaml.safe_dump(db_tables, indent=4, default_flow_style=False) ) mydb.new_rows(db_tables, uuid_list) return nsd_uuid_list @@ -2685,7 +2886,6 @@ def create_instance(mydb, tenant_id, instance_dict): myvim_threads_id[default_datacenter_id], _ = get_vim_thread(mydb, tenant_id, default_datacenter_id) tenant = mydb.get_rows_by_id('nfvo_tenants', tenant_id) # myvim_tenant = myvim['tenant_id'] - rollbackList=[] # print "Checking that the scenario exists and getting the scenario dictionary" @@ -2699,6 +2899,10 @@ def create_instance(mydb, tenant_id, instance_dict): db_instance_vnfs = [] db_instance_vms = [] db_instance_interfaces = [] + db_instance_sfis = [] + db_instance_sfs = [] + db_instance_classifications = [] + db_instance_sfps = [] db_ip_profiles = [] db_vim_actions = [] uuid_list = [] @@ -2782,15 +2986,11 @@ def create_instance(mydb, tenant_id, instance_dict): # 0.1 parse cloud-config parameters cloud_config = unify_cloud_config(instance_dict.get("cloud-config"), scenarioDict.get("cloud-config")) - # We add the RO key to cloud_config - if tenant[0].get('RO_pub_key'): - RO_key = {"key-pairs": [tenant[0]['RO_pub_key']]} - cloud_config = unify_cloud_config(cloud_config, RO_key) # 0.2 merge instance information into scenario # 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 net_name, net_instance_desc in instance_dict.get("networks", {}).iteritems(): for scenario_net in scenarioDict['nets']: if net_name == scenario_net["name"]: if 'ip-profile' in net_instance_desc: @@ -2811,13 +3011,13 @@ def create_instance(mydb, tenant_id, instance_dict): scenario_net['ip_profile'] = ipprofile_db else: update(scenario_net['ip_profile'], ipprofile_db) - for interface in net_instance_desc.get('interfaces', () ): + for interface in net_instance_desc.get('interfaces', ()): if 'ip_address' in interface: for vnf in scenarioDict['vnfs']: if interface['vnf'] == vnf['name']: for vnf_interface in vnf['interfaces']: if interface['vnf_interface'] == vnf_interface['external_name']: - vnf_interface['ip_address']=interface['ip_address'] + vnf_interface['ip_address'] = interface['ip_address'] # logger.debug(">>>>>>>> Merged dictionary") # logger.debug("Creating instance scenario-dict MERGED:\n%s", @@ -3012,6 +3212,9 @@ def create_instance(mydb, tenant_id, instance_dict): # myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict) sce_vnf_list = sorted(scenarioDict['vnfs'], key=lambda k: k['name']) for sce_vnf in sce_vnf_list: + ssh_access = None + if sce_vnf.get('mgmt_access'): + ssh_access = sce_vnf['mgmt_access'].get('config-access', {}).get('ssh-access') vnf_availability_zones = [] for vm in sce_vnf['vms']: vm_av = vm.get('availability_zone') @@ -3088,50 +3291,53 @@ def create_instance(mydb, tenant_id, instance_dict): db_vm_ifaces = [] for iface in vm['interfaces']: netDict = {} - if iface['type']=="data": + if iface['type'] == "data": netDict['type'] = iface['model'] - elif "model" in iface and iface["model"]!=None: - netDict['model']=iface['model'] + elif "model" in iface and iface["model"] != None: + netDict['model'] = iface['model'] # TODO in future, remove this because mac_address will not be set, and the type of PV,VF # is obtained from iterface table model # discover type of interface looking at flavor - for numa in flavor_dict.get('extended',{}).get('numas',[]): - for flavor_iface in numa.get('interfaces',[]): + for numa in flavor_dict.get('extended', {}).get('numas', []): + for flavor_iface in numa.get('interfaces', []): if flavor_iface.get('name') == iface['internal_name']: if flavor_iface['dedicated'] == 'yes': - netDict['type']="PF" #passthrough + netDict['type'] = "PF" # passthrough elif flavor_iface['dedicated'] == 'no': - netDict['type']="VF" #siov + netDict['type'] = "VF" # siov elif flavor_iface['dedicated'] == 'yes:sriov': - netDict['type']="VFnotShared" #sriov but only one sriov on the PF + netDict['type'] = "VFnotShared" # sriov but only one sriov on the PF netDict["mac_address"] = flavor_iface.get("mac_address") - break; + break netDict["use"]=iface['type'] - if netDict["use"]=="data" and not netDict.get("type"): - #print "netDict", netDict - #print "iface", iface - e_text = "Cannot determine the interface type PF or VF of VNF '%s' VM '%s' iface '%s'" %(sce_vnf['name'], vm['name'], iface['internal_name']) - if flavor_dict.get('extended')==None: + if netDict["use"] == "data" and not netDict.get("type"): + # print "netDict", netDict + # print "iface", iface + e_text = "Cannot determine the interface type PF or VF of VNF '{}' VM '{}' iface '{}'".fromat( + sce_vnf['name'], vm['name'], iface['internal_name']) + if flavor_dict.get('extended') == None: raise NfvoException(e_text + "After database migration some information is not available. \ Try to delete and create the scenarios and VNFs again", HTTP_Conflict) else: raise NfvoException(e_text, HTTP_Internal_Server_Error) - if netDict["use"]=="mgmt" or netDict["use"]=="bridge": + if netDict["use"] == "mgmt" or netDict["use"] == "bridge": netDict["type"]="virtual" - if "vpci" in iface and iface["vpci"] is not None: + if iface.get("vpci"): netDict['vpci'] = iface['vpci'] - if "mac" in iface and iface["mac"] is not None: + if iface.get("mac"): netDict['mac_address'] = iface['mac'] - if "port-security" in iface and iface["port-security"] is not None: + if iface.get("ip_address"): + netDict['ip_address'] = iface['ip_address'] + if iface.get("port-security") is not None: netDict['port_security'] = iface['port-security'] - if "floating-ip" in iface and iface["floating-ip"] is not None: + if iface.get("floating-ip") is not None: netDict['floating_ip'] = iface['floating-ip'] netDict['name'] = iface['internal_name'] if iface['net_id'] is None: for vnf_iface in sce_vnf["interfaces"]: # print iface # print vnf_iface - if vnf_iface['interface_id']==iface['uuid']: + if vnf_iface['interface_id'] == iface['uuid']: netDict['net_id'] = "TASK-{}".format(net2task_id['scenario'][ vnf_iface['sce_net_id'] ][datacenter_id]) instance_net_id = sce_net2instance[ vnf_iface['sce_net_id'] ][datacenter_id] task_depends_on.append(net2task_id['scenario'][ vnf_iface['sce_net_id'] ][datacenter_id]) @@ -3152,6 +3358,7 @@ def create_instance(mydb, tenant_id, instance_dict): # 'vim_interface_id': , 'type': 'external' if iface['external_name'] is not None else 'internal', 'ip_address': iface.get('ip_address'), + 'mac_address': iface.get('mac'), 'floating_ip': int(iface.get('floating-ip', False)), 'port_security': int(iface.get('port-security', True)) } @@ -3161,10 +3368,15 @@ def create_instance(mydb, tenant_id, instance_dict): # print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False) # print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False) # print ">>>>>>>>>>>>>>>>>>>>>>>>>>>" + + # We add the RO key to cloud_config if vnf will need ssh access + cloud_config_vm = cloud_config + 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("boot_data"): - cloud_config_vm = unify_cloud_config(vm["boot_data"], cloud_config) - else: - cloud_config_vm = cloud_config + cloud_config_vm = unify_cloud_config(vm["boot_data"], cloud_config_vm) + if myVMDict.get('availability_zone'): av_index = vnf_availability_zones.index(myVMDict['availability_zone']) else: @@ -3180,8 +3392,8 @@ def create_instance(mydb, tenant_id, instance_dict): for net in myVMDict['networks']: if "vim_id" in net: for iface in vm['interfaces']: - if net["name"]==iface["internal_name"]: - iface["vim_id"]=net["vim_id"] + if net["name"] == iface["internal_name"]: + iface["vim_id"] = net["vim_id"] break vm_uuid = str(uuid4()) uuid_list.append(vm_uuid) @@ -3231,6 +3443,157 @@ def create_instance(mydb, tenant_id, instance_dict): task_index += 1 db_vim_actions.append(db_vim_action) + task_depends_on = [] + for vnffg in scenarioDict['vnffgs']: + for rsp in vnffg['rsps']: + sfs_created = [] + for cp in rsp['connection_points']: + count = mydb.get_rows( + SELECT=('vms.count'), + FROM="vms join interfaces on vms.uuid=interfaces.vm_id join sce_rsp_hops as h on interfaces.uuid=h.interface_id", + WHERE={'h.uuid': cp['uuid']})[0]['count'] + instance_vnf = next((item for item in db_instance_vnfs if item['sce_vnf_id'] == cp['sce_vnf_id']), None) + instance_vms = [item for item in db_instance_vms if item['instance_vnf_id'] == instance_vnf['uuid']] + dependencies = [] + for instance_vm in instance_vms: + action = next((item for item in db_vim_actions if item['item_id'] == instance_vm['uuid']), None) + if action: + dependencies.append(action['task_index']) + # TODO: throw exception if count != len(instance_vms) + # TODO: and action shouldn't ever be None + sfis_created = [] + for i in range(count): + # create sfis + sfi_uuid = str(uuid4()) + uuid_list.append(sfi_uuid) + db_sfi = { + "uuid": sfi_uuid, + "instance_scenario_id": instance_uuid, + 'sce_rsp_hop_id': cp['uuid'], + 'datacenter_id': datacenter_id, + 'datacenter_tenant_id': myvim_thread_id, + "vim_sfi_id": None, # vim thread will populate + } + db_instance_sfis.append(db_sfi) + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": myvim_thread_id, + "action": "CREATE", + "status": "SCHEDULED", + "item": "instance_sfis", + "item_id": sfi_uuid, + "extra": yaml.safe_dump({"params": "", "depends_on": [dependencies[i]]}, + default_flow_style=True, width=256) + } + sfis_created.append(task_index) + task_index += 1 + db_vim_actions.append(db_vim_action) + # create sfs + sf_uuid = str(uuid4()) + uuid_list.append(sf_uuid) + db_sf = { + "uuid": sf_uuid, + "instance_scenario_id": instance_uuid, + 'sce_rsp_hop_id': cp['uuid'], + 'datacenter_id': datacenter_id, + 'datacenter_tenant_id': myvim_thread_id, + "vim_sf_id": None, # vim thread will populate + } + db_instance_sfs.append(db_sf) + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": myvim_thread_id, + "action": "CREATE", + "status": "SCHEDULED", + "item": "instance_sfs", + "item_id": sf_uuid, + "extra": yaml.safe_dump({"params": "", "depends_on": sfis_created}, + default_flow_style=True, width=256) + } + sfs_created.append(task_index) + task_index += 1 + db_vim_actions.append(db_vim_action) + classifier = rsp['classifier'] + + # TODO the following ~13 lines can be reused for the sfi case + count = mydb.get_rows( + SELECT=('vms.count'), + FROM="vms join interfaces on vms.uuid=interfaces.vm_id join sce_classifiers as c on interfaces.uuid=c.interface_id", + WHERE={'c.uuid': classifier['uuid']})[0]['count'] + instance_vnf = next((item for item in db_instance_vnfs if item['sce_vnf_id'] == classifier['sce_vnf_id']), None) + instance_vms = [item for item in db_instance_vms if item['instance_vnf_id'] == instance_vnf['uuid']] + dependencies = [] + for instance_vm in instance_vms: + action = next((item for item in db_vim_actions if item['item_id'] == instance_vm['uuid']), None) + if action: + dependencies.append(action['task_index']) + # TODO: throw exception if count != len(instance_vms) + # TODO: and action shouldn't ever be None + classifications_created = [] + for i in range(count): + for match in classifier['matches']: + # create classifications + classification_uuid = str(uuid4()) + uuid_list.append(classification_uuid) + db_classification = { + "uuid": classification_uuid, + "instance_scenario_id": instance_uuid, + 'sce_classifier_match_id': match['uuid'], + 'datacenter_id': datacenter_id, + 'datacenter_tenant_id': myvim_thread_id, + "vim_classification_id": None, # vim thread will populate + } + db_instance_classifications.append(db_classification) + classification_params = { + "ip_proto": match["ip_proto"], + "source_ip": match["source_ip"], + "destination_ip": match["destination_ip"], + "source_port": match["source_port"], + "destination_port": match["destination_port"] + } + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": myvim_thread_id, + "action": "CREATE", + "status": "SCHEDULED", + "item": "instance_classifications", + "item_id": classification_uuid, + "extra": yaml.safe_dump({"params": classification_params, "depends_on": [dependencies[i]]}, + default_flow_style=True, width=256) + } + classifications_created.append(task_index) + task_index += 1 + db_vim_actions.append(db_vim_action) + + # create sfps + sfp_uuid = str(uuid4()) + uuid_list.append(sfp_uuid) + db_sfp = { + "uuid": sfp_uuid, + "instance_scenario_id": instance_uuid, + 'sce_rsp_id': rsp['uuid'], + 'datacenter_id': datacenter_id, + 'datacenter_tenant_id': myvim_thread_id, + "vim_sfp_id": None, # vim thread will populate + } + db_instance_sfps.append(db_sfp) + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": myvim_thread_id, + "action": "CREATE", + "status": "SCHEDULED", + "item": "instance_sfps", + "item_id": sfp_uuid, + "extra": yaml.safe_dump({"params": "", "depends_on": sfs_created + classifications_created}, + default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) + scenarioDict["datacenter2tenant"] = myvim_threads_id db_instance_action["number_tasks"] = task_index @@ -3244,6 +3607,10 @@ def create_instance(mydb, tenant_id, instance_dict): {"instance_vms": db_instance_vms}, {"instance_interfaces": db_instance_interfaces}, {"instance_actions": db_instance_action}, + {"instance_sfis": db_instance_sfis}, + {"instance_sfs": db_instance_sfs}, + {"instance_classifications": db_instance_classifications}, + {"instance_sfps": db_instance_sfps}, {"vim_actions": db_vim_actions} ] @@ -3275,7 +3642,6 @@ def delete_instance(mydb, tenant_id, instance_id): # print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False) tenant_id = instanceDict["tenant_id"] # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id" - # 1. Delete from Database message = mydb.delete_instance_scenario(instance_id, tenant_id) @@ -3384,6 +3750,156 @@ def delete_instance(mydb, tenant_id, instance_id): task_index += 1 db_vim_actions.append(db_vim_action) + # 2.3 deleting VNFFGs + + for sfp in instanceDict.get('sfps', ()): + vimthread_affected[sfp["datacenter_tenant_id"]] = None + datacenter_key = (sfp["datacenter_id"], sfp["datacenter_tenant_id"]) + if datacenter_key not in myvims: + try: + _,myvim_thread = get_vim_thread(mydb, tenant_id, sfp["datacenter_id"], sfp["datacenter_tenant_id"]) + except NfvoException as e: + logger.error(str(e)) + myvim_thread = None + myvim_threads[datacenter_key] = myvim_thread + vims = get_vim(mydb, tenant_id, datacenter_id=sfp["datacenter_id"], + datacenter_tenant_id=sfp["datacenter_tenant_id"]) + if len(vims) == 0: + logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sfp["datacenter_id"], sfp["datacenter_tenant_id"])) + myvims[datacenter_key] = None + else: + myvims[datacenter_key] = vims.values()[0] + myvim = myvims[datacenter_key] + myvim_thread = myvim_threads[datacenter_key] + + if not myvim: + error_msg += "\n vim_sfp_id={} cannot be deleted because datacenter={} not found".format(sfp['vim_sfp_id'], sfp["datacenter_id"]) + continue + extra = {"params": (sfp['vim_sfp_id'])} + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": sfp["datacenter_tenant_id"], + "action": "DELETE", + "status": "SCHEDULED", + "item": "instance_sfps", + "item_id": sfp["uuid"], + "extra": yaml.safe_dump(extra, default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) + + for sf in instanceDict.get('sfs', ()): + vimthread_affected[sf["datacenter_tenant_id"]] = None + datacenter_key = (sf["datacenter_id"], sf["datacenter_tenant_id"]) + if datacenter_key not in myvims: + try: + _,myvim_thread = get_vim_thread(mydb, tenant_id, sf["datacenter_id"], sf["datacenter_tenant_id"]) + except NfvoException as e: + logger.error(str(e)) + myvim_thread = None + myvim_threads[datacenter_key] = myvim_thread + vims = get_vim(mydb, tenant_id, datacenter_id=sf["datacenter_id"], + datacenter_tenant_id=sf["datacenter_tenant_id"]) + if len(vims) == 0: + logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sf["datacenter_id"], sf["datacenter_tenant_id"])) + myvims[datacenter_key] = None + else: + myvims[datacenter_key] = vims.values()[0] + myvim = myvims[datacenter_key] + myvim_thread = myvim_threads[datacenter_key] + + if not myvim: + error_msg += "\n vim_sf_id={} cannot be deleted because datacenter={} not found".format(sf['vim_sf_id'], sf["datacenter_id"]) + continue + extra = {"params": (sf['vim_sf_id'])} + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": sf["datacenter_tenant_id"], + "action": "DELETE", + "status": "SCHEDULED", + "item": "instance_sfs", + "item_id": sf["uuid"], + "extra": yaml.safe_dump(extra, default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) + + for sfi in instanceDict.get('sfis', ()): + vimthread_affected[sfi["datacenter_tenant_id"]] = None + datacenter_key = (sfi["datacenter_id"], sfi["datacenter_tenant_id"]) + if datacenter_key not in myvims: + try: + _,myvim_thread = get_vim_thread(mydb, tenant_id, sfi["datacenter_id"], sfi["datacenter_tenant_id"]) + except NfvoException as e: + logger.error(str(e)) + myvim_thread = None + myvim_threads[datacenter_key] = myvim_thread + vims = get_vim(mydb, tenant_id, datacenter_id=sfi["datacenter_id"], + datacenter_tenant_id=sfi["datacenter_tenant_id"]) + if len(vims) == 0: + logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sfi["datacenter_id"], sfi["datacenter_tenant_id"])) + myvims[datacenter_key] = None + else: + myvims[datacenter_key] = vims.values()[0] + myvim = myvims[datacenter_key] + myvim_thread = myvim_threads[datacenter_key] + + if not myvim: + error_msg += "\n vim_sfi_id={} cannot be deleted because datacenter={} not found".format(sfi['vim_sfi_id'], sfi["datacenter_id"]) + continue + extra = {"params": (sfi['vim_sfi_id'])} + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": sfi["datacenter_tenant_id"], + "action": "DELETE", + "status": "SCHEDULED", + "item": "instance_sfis", + "item_id": sfi["uuid"], + "extra": yaml.safe_dump(extra, default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) + + for classification in instanceDict['classifications']: + vimthread_affected[classification["datacenter_tenant_id"]] = None + datacenter_key = (classification["datacenter_id"], classification["datacenter_tenant_id"]) + if datacenter_key not in myvims: + try: + _,myvim_thread = get_vim_thread(mydb, tenant_id, classification["datacenter_id"], classification["datacenter_tenant_id"]) + except NfvoException as e: + logger.error(str(e)) + myvim_thread = None + myvim_threads[datacenter_key] = myvim_thread + vims = get_vim(mydb, tenant_id, datacenter_id=classification["datacenter_id"], + datacenter_tenant_id=classification["datacenter_tenant_id"]) + if len(vims) == 0: + logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(classification["datacenter_id"], classification["datacenter_tenant_id"])) + myvims[datacenter_key] = None + else: + myvims[datacenter_key] = vims.values()[0] + myvim = myvims[datacenter_key] + myvim_thread = myvim_threads[datacenter_key] + + if not myvim: + error_msg += "\n vim_classification_id={} cannot be deleted because datacenter={} not found".format(classification['vim_classification_id'], classification["datacenter_id"]) + continue + extra = {"params": (classification['vim_classification_id'])} + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": classification["datacenter_tenant_id"], + "action": "DELETE", + "status": "SCHEDULED", + "item": "instance_classifications", + "item_id": classification["uuid"], + "extra": yaml.safe_dump(extra, default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) + db_instance_action["number_tasks"] = task_index db_tables = [ {"instance_actions": db_instance_action}, @@ -3752,7 +4268,7 @@ def new_datacenter(mydb, datacenter_descriptor): except (IOError, ImportError): # if module_info and module_info[0]: # file.close(module_info[0]) - raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type, module), HTTP_Bad_Request) + raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}.py' not installed".format(datacenter_type, module), HTTP_Bad_Request) datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True, confidential_data=True) return datacenter_id @@ -4339,29 +4855,35 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor): #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'): + #obtain datacenter_tenant_id + datacenter_tenant_id = mydb.get_rows(SELECT=('uuid',), + FROM='datacenter_tenants', + WHERE={'datacenter_id': datacenter})[0]['uuid'] try: sdn_network = {} sdn_network['vlan'] = net_vlan sdn_network['type'] = net_type sdn_network['name'] = net_name + sdn_network['region'] = datacenter_tenant_id ovim_content = ovim.new_network(sdn_network) except ovimException as e: - self.logger.error("ovimException creating SDN network={} ".format( + logger.error("ovimException creating SDN network={} ".format( sdn_network) + str(e), exc_info=True) raise NfvoException("ovimException creating SDN network={} ".format(sdn_network) + str(e), HTTP_Internal_Server_Error) # Save entry in in dabase mano_db in table instance_nets to stablish a dictionary vim_net_id <->sdn_net_id # use instance_scenario_id=None to distinguish from real instaces of nets - correspondence = {'instance_scenario_id': None, 'sdn_net_id': ovim_content, 'vim_net_id': content} - #obtain datacenter_tenant_id - correspondence['datacenter_tenant_id'] = mydb.get_rows(SELECT=('uuid',), FROM='datacenter_tenants', WHERE={'datacenter_id': datacenter})[0]['uuid'] - + correspondence = {'instance_scenario_id': None, + 'sdn_net_id': ovim_content, + 'vim_net_id': content, + 'datacenter_tenant_id': datacenter_tenant_id + } try: mydb.new_row('instance_nets', correspondence, add_uuid=True) except db_base_Exception as e: - raise NfvoException("Error saving correspondence for VIM/SDN dataplane networks{}: ".format(correspondence) + - str(e), HTTP_Internal_Server_Error) + raise NfvoException("Error saving correspondence for VIM/SDN dataplane networks{}: {}".format( + correspondence, e), HTTP_Internal_Server_Error) elif item=="tenants": tenant = descriptor["tenant"] content = myvim.new_tenant(tenant["name"], tenant.get("description"))