X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_ro%2Fnfvo.py;h=2c6a5a3d90e5085dac80f43cac2eeb96bdb2fb3b;hb=a955020f8c8a74df3a4a97a4e2e2af5d44b46733;hp=d45a3c79865436d3f1238aa520489f91ab4f70fb;hpb=3e8e11a11215e19e41be646d9d4dcbe7f67b1ebd;p=osm%2FRO.git diff --git a/osm_ro/nfvo.py b/osm_ro/nfvo.py index d45a3c79..2c6a5a3d 100644 --- a/osm_ro/nfvo.py +++ b/osm_ro/nfvo.py @@ -38,6 +38,7 @@ import console_proxy_thread as cli import vimconn import logging import collections +from uuid import uuid4 from db_base import db_base_Exception import nfvo_db @@ -46,6 +47,12 @@ from time import time from lib_osm_openvim import ovim as ovim_module from lib_osm_openvim.ovim import ovimException +import osm_im.vnfd as vnfd_catalog +import osm_im.nsd as nsd_catalog + +from pyangbind.lib.serialise import pybindJSONDecoder +from itertools import chain + global global_config global vimconn_imported global logger @@ -334,7 +341,9 @@ def rollback(mydb, vims, rollback_list): if item["where"]=="vim": if item["vim_id"] not in vims: continue - vim=vims[ item["vim_id"] ] + if is_task_id(item["uuid"]): + continue + vim = vims[item["vim_id"]] try: if item["what"]=="image": vim.delete_image(item["uuid"]) @@ -392,12 +401,12 @@ def check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1): name_dict[ interface["name"] ] = "overlay" vnfc_interfaces[ vnfc["name"] ] = name_dict # check bood-data info - if "boot-data" in vnfc: - # check that user-data is incompatible with users and config-files - if (vnfc["boot-data"].get("users") or vnfc["boot-data"].get("config-files")) and vnfc["boot-data"].get("user-data"): - raise NfvoException( - "Error at vnf:VNFC:boot-data, fields 'users' and 'config-files' are not compatible with 'user-data'", - HTTP_Bad_Request) + # if "boot-data" in vnfc: + # # check that user-data is incompatible with users and config-files + # if (vnfc["boot-data"].get("users") or vnfc["boot-data"].get("config-files")) and vnfc["boot-data"].get("user-data"): + # raise NfvoException( + # "Error at vnf:VNFC:boot-data, fields 'users' and 'config-files' are not compatible with 'user-data'", + # HTTP_Bad_Request) #check if the info in external_connections matches with the one in the vnfcs name_list=[] @@ -481,7 +490,7 @@ def check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1): HTTP_Bad_Request) -def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error = None): +def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error=None): #look if image exist if only_create_at_vim: image_mano_id = image_dict['uuid'] @@ -628,11 +637,11 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ # continue #elif res_vim==0: - #Create the flavor in VIM - #Translate images at devices from MANO id to VIM id + # Create the flavor in VIM + # Translate images at devices from MANO id to VIM id disk_list = [] if 'extended' in flavor_dict and flavor_dict['extended']!=None and "devices" in flavor_dict['extended']: - #make a copy of original devices + # make a copy of original devices devices_original=[] for device in flavor_dict["extended"].get("devices",[]): @@ -643,7 +652,9 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ del device['image'] if 'image metadata' in device: del device['image metadata'] - dev_nb=0 + if 'image checksum' in device: + del device['image checksum'] + dev_nb = 0 for index in range(0,len(devices_original)) : device=devices_original[index] if "image" not in device and "image name" not in device: @@ -655,7 +666,7 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ image_dict['universal_name']=device.get('image name') image_dict['description']=flavor_dict['name']+str(dev_nb)+"-img" image_dict['location']=device.get('image') - #image_dict['new_location']=device.get('image location') + # image_dict['new_location']=device.get('image location') image_dict['checksum']=device.get('image checksum') image_metadata_dict = device.get('image metadata', None) image_metadata_str = None @@ -717,6 +728,370 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_ return flavor_vim_id if only_create_at_vim else flavor_mano_id +def get_str(obj, field, length): + """ + Obtain the str value, + :param obj: + :param length: + :return: + """ + value = obj.get(field) + if value is not None: + value = str(value)[:length] + return value + +def _lookfor_or_create_image(db_image, mydb, descriptor): + """ + fill image content at db_image dictionary. Check if the image with this image and checksum exist + :param db_image: dictionary to insert data + :param mydb: database connector + :param descriptor: yang descriptor + :return: uuid if the image exist at DB, or None if a new image must be created with the data filled at db_image + """ + + db_image["name"] = get_str(descriptor, "image", 255) + db_image["checksum"] = get_str(descriptor, "image-checksum", 32) + if not db_image["checksum"]: # Ensure that if empty string, None is stored + db_image["checksum"] = None + if db_image["name"].startswith("/"): + db_image["location"] = db_image["name"] + existing_images = mydb.get_rows(FROM="images", WHERE={'location': db_image["location"]}) + else: + db_image["universal_name"] = db_image["name"] + existing_images = mydb.get_rows(FROM="images", WHERE={'universal_name': db_image['universal_name'], + 'checksum': db_image['checksum']}) + if existing_images: + return existing_images[0]["uuid"] + else: + image_uuid = str(uuid4()) + db_image["uuid"] = image_uuid + return None + +def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): + """ + Parses an OSM IM vnfd_catalog and insert at DB + :param mydb: + :param tenant_id: + :param vnf_descriptor: + :return: The list of cretated vnf ids + """ + try: + myvnfd = vnfd_catalog.vnfd() + try: + pybindJSONDecoder.load_ietf_json(vnf_descriptor, None, None, obj=myvnfd) + except Exception as e: + raise NfvoException("Invalid yang descriptor format " + str(e), HTTP_Bad_Request) + db_vnfs = [] + db_nets = [] + db_vms = [] + db_vms_index = 0 + db_interfaces = [] + db_images = [] + db_flavors = [] + uuid_list = [] + vnfd_uuid_list = [] + for rift_vnfd in myvnfd.vnfd_catalog.vnfd.itervalues(): + vnfd = rift_vnfd.get() + + # table vnf + vnf_uuid = str(uuid4()) + uuid_list.append(vnf_uuid) + vnfd_uuid_list.append(vnf_uuid) + db_vnf = { + "uuid": vnf_uuid, + "osm_id": get_str(vnfd, "id", 255), + "name": get_str(vnfd, "name", 255), + "description": get_str(vnfd, "description", 255), + "tenant_id": tenant_id, + "vendor": get_str(vnfd, "vendor", 255), + "short_name": get_str(vnfd, "short-name", 255), + "descriptor": str(vnf_descriptor)[:60000] + } + + # table nets (internal-vld) + net_id2uuid = {} # for mapping interface with network + for vld in vnfd.get("internal-vld").itervalues(): + net_uuid = str(uuid4()) + uuid_list.append(net_uuid) + db_net = { + "name": get_str(vld, "name", 255), + "vnf_id": vnf_uuid, + "uuid": net_uuid, + "description": get_str(vld, "description", 255), + "type": "bridge", # TODO adjust depending on connection point type + } + net_id2uuid[vld.get("id")] = net_uuid + db_nets.append(db_net) + + # table vms (vdus) + vdu_id2uuid = {} + vdu_id2db_table_index = {} + for vdu in vnfd.get("vdu").itervalues(): + vm_uuid = str(uuid4()) + uuid_list.append(vm_uuid) + db_vm = { + "uuid": vm_uuid, + "osm_id": get_str(vdu, "id", 255), + "name": get_str(vdu, "name", 255), + "description": get_str(vdu, "description", 255), + "vnf_id": vnf_uuid, + } + vdu_id2uuid[db_vm["osm_id"]] = vm_uuid + vdu_id2db_table_index[db_vm["osm_id"]] = db_vms_index + if vdu.get("count"): + db_vm["count"] = int(vdu["count"]) + + # table image + image_present = False + if vdu.get("image"): + image_present = True + db_image = {} + image_uuid = _lookfor_or_create_image(db_image, mydb, vdu) + if not image_uuid: + image_uuid = db_image["uuid"] + db_images.append(db_image) + db_vm["image_id"] = image_uuid + + # volumes + devices = [] + if vdu.get("volumes"): + for volume_key in sorted(vdu["volumes"]): + volume = vdu["volumes"][volume_key] + if not image_present: + # Convert the first volume to vnfc.image + image_present = True + db_image = {} + image_uuid = _lookfor_or_create_image(db_image, mydb, volume) + if not image_uuid: + image_uuid = db_image["uuid"] + db_images.append(db_image) + db_vm["image_id"] = image_uuid + else: + # Add Openmano devices + device = {} + device["type"] = str(volume.get("device-type")) + if volume.get("size"): + device["size"] = int(volume["size"]) + if volume.get("image"): + device["image name"] = str(volume["image"]) + if volume.get("image-checksum"): + device["image checksum"] = str(volume["image-checksum"]) + devices.append(device) + + # table flavors + db_flavor = { + "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)), + } + # EPA TODO revise + extended = {} + numa = {} + if devices: + extended["devices"] = devices + if vdu.get("guest-epa"): # TODO or dedicated_int: + epa_vcpu_set = False + 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] + if numa_node.get("num-cores"): + numa["cores"] = numa_node["num-cores"] + epa_vcpu_set = True + if numa_node.get("paired-threads"): + if numa_node["paired-threads"].get("num-paired-threads"): + numa["paired-threads"] = numa_node["paired-threads"]["num-paired-threads"] + epa_vcpu_set = True + if len(numa_node["paired-threads"].get("paired-thread-ids")) > 0: + numa["paired-threads-id"] = [] + for pair in numa_node["paired-threads"]["paired-thread-ids"].itervalues: + numa["paired-threads-id"].append( + (str(pair["thread-a"]), str(pair["thread-b"])) + ) + if numa_node.get("num-threads"): + numa["threads"] = numa_node["num-threads"] + epa_vcpu_set = True + if numa_node.get("memory-mb"): + numa["memory"] = max(int(numa_node["memory-mb"] / 1024), 1) + if vdu["guest-epa"].get("mempage-size"): + if vdu["guest-epa"]["mempage-size"] != "SMALL": + numa["memory"] = max(int(db_flavor["ram"] / 1024), 1) + if vdu["guest-epa"].get("cpu-pinning-policy") and not epa_vcpu_set: + if vdu["guest-epa"]["cpu-pinning-policy"] == "DEDICATED": + if vdu["guest-epa"].get("cpu-thread-pinning-policy") and \ + vdu["guest-epa"]["cpu-thread-pinning-policy"] != "PREFER": + numa["cores"] = max(db_flavor["vcpus"], 1) + else: + numa["threads"] = max(db_flavor["vcpus"], 1) + if numa: + extended["numas"] = [numa] + if extended: + 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), + 'ram': db_flavor.get('ram'), + 'vcpus': db_flavor.get('vcpus'), + 'extended': db_flavor.get('extended') + } + existing_flavors = mydb.get_rows(FROM="flavors", WHERE=temp_flavor_dict) + if existing_flavors: + flavor_uuid = existing_flavors[0]["uuid"] + else: + flavor_uuid = str(uuid4()) + uuid_list.append(flavor_uuid) + db_flavor["uuid"] = flavor_uuid + db_flavors.append(db_flavor) + db_vm["flavor_id"] = flavor_uuid + + # cloud-init + boot_data = {} + if vdu.get("cloud-init"): + boot_data["user-data"] = vdu["cloud-init"] + elif vdu.get("cloud-init-file"): + # TODO Where this file content is present??? + # boot_data["user-data"] = rift_vnfd.files[vdu["cloud-init-file"]] + boot_data["user-data"] = str(vdu["cloud-init-file"]) + + if vdu.get("supplemental-boot-data"): + if vdu["supplemental-boot-data"].get('boot-data-drive'): + boot_data['boot-data-drive'] = True + if vdu["supplemental-boot-data"].get('config-file'): + om_cfgfile_list = list() + for custom_config_file in vdu["supplemental-boot-data"]['config-file'].itervalues(): + # TODO Where this file content is present??? + cfg_source = str(custom_config_file["source"]) + om_cfgfile_list.append({"dest": custom_config_file["dest"], + "content": cfg_source}) + boot_data['config-files'] = om_cfgfile_list + if boot_data: + db_vm["boot_data"] = boot_data + + db_vms.append(db_vm) + db_vms_index += 1 + + # table interfaces (internal/external interfaces) + cp_name2iface_uuid = {} + cp_name2vm_uuid = {} + # for iface in chain(vdu.get("internal-interface").itervalues(), vdu.get("external-interface").itervalues()): + for iface in vdu.get("interface").itervalues(): + iface_uuid = str(uuid4()) + uuid_list.append(iface_uuid) + db_interface = { + "uuid": iface_uuid, + "internal_name": get_str(iface, "name", 255), + "vm_id": vm_uuid, + } + if iface.get("virtual-interface").get("vpci"): + db_interface["vpci"] = get_str(iface.get("virtual-interface"), "vpci", 12) + + if iface.get("virtual-interface").get("bandwidth"): + bps = int(iface.get("virtual-interface").get("bandwidth")) + db_interface["bw"] = bps/1000 + + if iface.get("virtual-interface").get("type") == "OM-MGMT": + db_interface["type"] = "mgmt" + elif iface.get("virtual-interface").get("type") in ("VIRTIO", "E1000"): + db_interface["type"] = "bridge" + db_interface["model"] = get_str(iface.get("virtual-interface"), "type", 12) + elif iface.get("virtual-interface").get("type") in ("SR-IOV", "PCI-PASSTHROUGH"): + db_interface["type"] = "data" + db_interface["model"] = get_str(iface.get("virtual-interface"), "type", 12) + else: + raise ValueError("Interface type {} not supported".format(iface.get("virtual-interface").get("type"))) + + if iface.get("external-connection-point-ref"): + try: + 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_name2vm_uuid[db_interface["external_name"]] = vm_uuid + # TODO add port-security-enable + # if cp.get("port-security-enabled") == False: + # elif cp.get("port-security-enabled") == True: + except KeyError: + raise KeyError( + "Error wrong reference at vnfd['{vnf}'] vdu['{vdu}']:internal-interface['{iface}']:" + "vnfd-connection-point-ref '{cp}' is not present at connection-point".format( + vnf=vnfd["id"], vdu=vdu["id"], iface=iface["name"], + cp=iface.get("vnfd-connection-point-ref")) + ) + elif iface.get("internal-connection-point-ref"): + try: + 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")] + break + except KeyError: + raise KeyError( + "Error at vnfd['{vnf}'] vdu['{vdu}']:internal-interface['{iface}']:" + "vdu-internal-connection-point-ref '{cp}' is not referenced by any internal-vld".format( + vnf=vnfd["id"], vdu=vdu["id"], iface=iface["name"], + cp=iface.get("vdu-internal-connection-point-ref")) + ) + if iface.get("position") is not None: + db_interface["created_at"] = int(iface.get("position")) - 1000 + db_interfaces.append(db_interface) + + # VNF affinity and antiaffinity + for pg in vnfd.get("placement-groups").itervalues(): + pg_name = get_str(pg, "name", 255) + for vdu in pg.get("member-vdus").itervalues(): + vdu_id = get_str(vdu, "member-vdu-ref", 255) + if vdu_id not in vdu_id2db_table_index: + raise KeyError( + "Error at 'vnfd'['{vnf}']:'placement-groups'['{pg}']:'member-vdus':'{vdu}' references a non existing vdu".format( + vnf=vnfd["id"], pg=pg_name, vdu=vdu_id)) + 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"): + if vnfd["mgmt-interface"]["vdu-id"] not in vdu_id2uuid: + raise KeyError( + "Error at vnfd['{vnf}']:'mgmt-interface':'vdu-id':{vdu} reference a non existing vdu".format( + vnf=vnfd["id"], vdu=vnfd["mgmt-interface"]["vdu-id"])) + mgmt_access["vm_id"] = vdu_id2uuid[vnfd["mgmt-interface"]["vdu-id"]] + 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"]["cp"] not in cp_name2iface_uuid: + raise KeyError( + "Error at vnfd['{vnf}']:'mgmt-interface':'cp':{cp} reference a non existing connection-point". + format(vnf=vnfd["id"], cp=vnfd["mgmt-interface"]["cp"])) + mgmt_access["vm_id"] = cp_name2vm_uuid[vnfd["mgmt-interface"]["cp"]] + mgmt_access["interface_id"] = cp_name2iface_uuid[vnfd["mgmt-interface"]["cp"]] + 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 + 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}, + {"vms": db_vms}, + {"interfaces": db_interfaces}, + ] + + logger.debug("create_vnf Deployment done vnfDict: %s", + yaml.safe_dump(db_tables, indent=4, default_flow_style=False) ) + mydb.new_rows(db_tables, uuid_list) + return vnfd_uuid_list + except Exception as e: + logger.error("Exception {}".format(e)) + raise # NfvoException("Exception {}".format(e), HTTP_Bad_Request) + + def new_vnf(mydb, tenant_id, vnf_descriptor): global global_config @@ -757,6 +1132,7 @@ def new_vnf(mydb, tenant_id, vnf_descriptor): for vnfc in vnf_descriptor['vnf']['VNFC']: VNFCitem={} VNFCitem["name"] = vnfc['name'] + VNFCitem["availability_zone"] = vnfc.get('availability_zone') VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name)) #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"]) @@ -827,6 +1203,7 @@ def new_vnf(mydb, tenant_id, vnf_descriptor): #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id) VNFCDict[vnfc['name']]["image_id"] = image_id VNFCDict[vnfc['name']]["image_path"] = vnfc.get('VNFC image') + VNFCDict[vnfc['name']]["count"] = vnfc.get('count', 1) if vnfc.get("boot-data"): VNFCDict[vnfc['name']]["boot_data"] = yaml.safe_dump(vnfc["boot-data"], default_flow_style=True, width=256) @@ -962,6 +1339,7 @@ def new_vnf_v02(mydb, tenant_id, vnf_descriptor): #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id) VNFCDict[vnfc['name']]["image_id"] = image_id VNFCDict[vnfc['name']]["image_path"] = vnfc.get('VNFC image') + VNFCDict[vnfc['name']]["count"] = vnfc.get('count', 1) if vnfc.get("boot-data"): VNFCDict[vnfc['name']]["boot_data"] = yaml.safe_dump(vnfc["boot-data"], default_flow_style=True, width=256) @@ -996,14 +1374,15 @@ def get_vnf_id(mydb, tenant_id, vnf_id): where_or["public"] = True vnf = mydb.get_table_by_uuid_name('vnfs', vnf_id, "VNF", WHERE_OR=where_or, WHERE_AND_OR="AND") - vnf_id=vnf["uuid"] - filter_keys = ('uuid','name','description','public', "tenant_id", "created_at") + vnf_id = vnf["uuid"] + filter_keys = ('uuid', 'name', 'description', 'public', "tenant_id", "osm_id", "created_at") filtered_content = dict( (k,v) for k,v in vnf.iteritems() if k in filter_keys ) #change_keys_http2db(filtered_content, http2db_vnf, reverse=True) data={'vnf' : filtered_content} #GET VM content = mydb.get_rows(FROM='vnfs join vms on vnfs.uuid=vms.vnf_id', - SELECT=('vms.uuid as uuid','vms.name as name', 'vms.description as description', 'boot_data'), + SELECT=('vms.uuid as uuid', 'vms.osm_id as osm_id', 'vms.name as name', 'vms.description as description', + 'boot_data'), WHERE={'vnfs.uuid': vnf_id} ) if len(content)==0: raise NfvoException("vnf '{}' not found".format(vnf_id), HTTP_Not_Found) @@ -1602,6 +1981,173 @@ def new_scenario_v02(mydb, tenant_id, scenario_dict, version): return scenario_id +def new_nsd_v3(mydb, tenant_id, nsd_descriptor): + """ + Parses an OSM IM nsd_catalog and insert at DB + :param mydb: + :param tenant_id: + :param nsd_descriptor: + :return: The list of cretated NSD ids + """ + try: + mynsd = nsd_catalog.nsd() + try: + pybindJSONDecoder.load_ietf_json(nsd_descriptor, None, None, obj=mynsd) + except Exception as e: + raise NfvoException("Invalid yang descriptor format " + str(e), HTTP_Bad_Request) + db_scenarios = [] + db_sce_nets = [] + db_sce_vnfs = [] + db_sce_interfaces = [] + db_ip_profiles = [] + db_ip_profiles_index = 0 + uuid_list = [] + nsd_uuid_list = [] + for rift_nsd in mynsd.nsd_catalog.nsd.itervalues(): + nsd = rift_nsd.get() + + # table sceanrios + scenario_uuid = str(uuid4()) + uuid_list.append(scenario_uuid) + nsd_uuid_list.append(scenario_uuid) + db_scenario = { + "uuid": scenario_uuid, + "osm_id": get_str(nsd, "id", 255), + "name": get_str(nsd, "name", 255), + "description": get_str(nsd, "description", 255), + "tenant_id": tenant_id, + "vendor": get_str(nsd, "vendor", 255), + "short_name": get_str(nsd, "short-name", 255), + "descriptor": str(nsd_descriptor)[:60000], + } + db_scenarios.append(db_scenario) + + # table sce_vnfs (constituent-vnfd) + vnf_index2scevnf_uuid = {} + vnf_index2vnf_uuid = {} + for vnf in nsd.get("constituent-vnfd").itervalues(): + existing_vnf = mydb.get_rows(FROM="vnfs", WHERE={'osm_id': str(vnf["vnfd-id-ref"])[:255], + 'tenant_id': tenant_id}) + if not existing_vnf: + raise KeyError("Error at 'nsd[{}]':'constituent-vnfd':'vnfd-id-ref':'{}' references a " + "non existing VNFD in the catalog".format(str(nsd["id"]), + str(vnf["vnfd-id-ref"])[:255])) + sce_vnf_uuid = str(uuid4()) + uuid_list.append(sce_vnf_uuid) + db_sce_vnf = { + "uuid": sce_vnf_uuid, + "scenario_id": scenario_uuid, + "name": existing_vnf[0]["name"][:200] + "." + get_str(vnf, "member-vnf-index", 5), + "vnf_id": existing_vnf[0]["uuid"], + "member_vnf_index": int(vnf["member-vnf-index"]), + # TODO 'start-by-default': True + } + vnf_index2scevnf_uuid[int(vnf['member-vnf-index'])] = sce_vnf_uuid + vnf_index2vnf_uuid[int(vnf['member-vnf-index'])] = existing_vnf[0]["uuid"] + db_sce_vnfs.append(db_sce_vnf) + + # table ip_profiles (ip-profiles) + ip_profile_name2db_table_index = {} + for ip_profile in nsd.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 sce_nets (internal-vld) + for vld in nsd.get("vld").itervalues(): + sce_net_uuid = str(uuid4()) + uuid_list.append(sce_net_uuid) + db_sce_net = { + "uuid": sce_net_uuid, + "name": get_str(vld, "name", 255), + "scenario_id": scenario_uuid, + # "type": #TODO + "multipoint": not vld.get("type") == "ELINE", + # "external": #TODO + "description": get_str(vld, "description", 255), + } + # guess type of network + if vld.get("mgmt-network"): + db_sce_net["type"] = "bridge" + db_sce_net["external"] = True + elif vld.get("provider-network").get("overlay-type") == "VLAN": + db_sce_net["type"] = "data" + else: + db_sce_net["type"] = "bridge" + db_sce_nets.append(db_sce_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 KeyError("Error at 'nsd[{}]':'vld[{}]':'ip-profile-ref':'{}' references a non existing " + "'ip_profiles'".format( + str(nsd["id"]), str(vld["id"]), str(vld["ip-profile-ref"]))) + db_ip_profiles[ip_profile_name2db_table_index[ip_profile_name]]["sce_net_id"] = sce_net_uuid + + # table sce_interfaces (vld:vnfd-connection-point-ref) + for iface in vld.get("vnfd-connection-point-ref").itervalues(): + vnf_index = int(iface['member-vnf-index-ref']) + # check correct parameters + if vnf_index not in vnf_index2vnf_uuid: + raise KeyError("Error at 'nsd[{}]':'vld[{}]':'vnfd-connection-point-ref':'member-vnf-index-ref'" + ":'{}' references a non existing index at 'nsd':'constituent-vnfd'".format( + str(nsd["id"]), str(vld["id"]), str(iface["member-vnf-index-ref"]))) + + 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 KeyError("Error at 'nsd[{}]':'vld[{}]':'vnfd-connection-point-ref':'vnfd-connection-point" + "-ref':'{}' references a non existing interface at VNFD '{}'".format( + str(nsd["id"]), str(vld["id"]), str(iface["vnfd-connection-point-ref"]), + str(iface.get("vnfd-id-ref"))[:255])) + + interface_uuid = existing_ifaces[0]["uuid"] + sce_interface_uuid = str(uuid4()) + uuid_list.append(sce_net_uuid) + 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 + } + db_sce_interfaces.append(db_sce_interface) + + 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}, + ] + + logger.debug("create_vnf Deployment done vnfDict: %s", + yaml.safe_dump(db_tables, indent=4, default_flow_style=False) ) + mydb.new_rows(db_tables, uuid_list) + return nsd_uuid_list + except Exception as e: + logger.error("Exception {}".format(e)) + raise # NfvoException("Exception {}".format(e), HTTP_Bad_Request) + + def edit_scenario(mydb, tenant_id, scenario_id, data): data["uuid"] = scenario_id data["tenant_id"] = tenant_id @@ -1665,6 +2211,7 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc logger.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM") #For each vnf net, we create it and we add it to instanceNetlist. + for sce_vnf in scenarioDict['vnfs']: for net in sce_vnf['nets']: #print "Net name: %s. Description: %s" % (net["name"], net["description"]) @@ -1696,6 +2243,17 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict) i = 0 for sce_vnf in scenarioDict['vnfs']: + vnf_availability_zones = [] + for vm in sce_vnf['vms']: + vm_av = vm.get('availability_zone') + if vm_av and vm_av not in vnf_availability_zones: + vnf_availability_zones.append(vm_av) + + # check if there is enough availability zones available at vim level. + if myvims[datacenter_id].availability_zone and vnf_availability_zones: + if len(vnf_availability_zones) > len(myvims[datacenter_id].availability_zone): + raise NfvoException('No enough availability zones at VIM for this deployment', HTTP_Bad_Request) + for vm in sce_vnf['vms']: i += 1 myVMDict = {} @@ -1782,8 +2340,16 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc #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 ">>>>>>>>>>>>>>>>>>>>>>>>>>>" - vm_id = myvim.new_vminstance(myVMDict['name'],myVMDict['description'],myVMDict.get('start', None), - myVMDict['imageRef'],myVMDict['flavorRef'],myVMDict['networks']) + + if 'availability_zone' in myVMDict: + av_index = vnf_availability_zones.index(myVMDict['availability_zone']) + else: + av_index = None + + vm_id = myvim.new_vminstance(myVMDict['name'], myVMDict['description'], myVMDict.get('start', None), + myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'], + availability_zone_index=av_index, + availability_zone_list=vnf_availability_zones) #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id) vm['vim_id'] = vm_id rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id}) @@ -1813,10 +2379,10 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc def unify_cloud_config(cloud_config_preserve, cloud_config): - ''' join the cloud config information into cloud_config_preserve. + """ join the cloud config information into cloud_config_preserve. In case of conflict cloud_config_preserve preserves - None is admited - ''' + None is allowed + """ if not cloud_config_preserve and not cloud_config: return None @@ -1866,10 +2432,19 @@ def unify_cloud_config(cloud_config_preserve, cloud_config): new_cloud_config["boot-data-drive"] = cloud_config_preserve["boot-data-drive"] # user-data - if cloud_config and cloud_config.get("user-data") != None: - new_cloud_config["user-data"] = cloud_config["user-data"] - if cloud_config_preserve and cloud_config_preserve.get("user-data") != None: - new_cloud_config["user-data"] = cloud_config_preserve["user-data"] + new_cloud_config["user-data"] = [] + if cloud_config and cloud_config.get("user-data"): + if isinstance(cloud_config["user-data"], list): + new_cloud_config["user-data"] += cloud_config["user-data"] + else: + new_cloud_config["user-data"].append(cloud_config["user-data"]) + if cloud_config_preserve and cloud_config_preserve.get("user-data"): + if isinstance(cloud_config_preserve["user-data"], list): + new_cloud_config["user-data"] += cloud_config_preserve["user-data"] + else: + new_cloud_config["user-data"].append(cloud_config_preserve["user-data"]) + if not new_cloud_config["user-data"]: + del new_cloud_config["user-data"] # config files new_cloud_config["config-files"] = [] @@ -1923,6 +2498,7 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i except db_base_Exception as e: raise NfvoException("{} {}".format(type(e).__name__ , str(e)), e.http_code) + def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter): datacenter_id = None datacenter_name = None @@ -1978,14 +2554,30 @@ def create_instance(mydb, tenant_id, instance_dict): #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256))) #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256))) - scenarioDict['datacenter_id'] = default_datacenter_id + uuid_list = [] + instance_name = instance_dict["name"] + instance_uuid = str(uuid4()) + uuid_list.append(instance_uuid) + db_instance_scenario = { + "uuid": instance_uuid, + "name": instance_name, + "tenant_id": tenant_id, + "scenario_id": scenarioDict['uuid'], + "datacenter_id": default_datacenter_id, + # filled bellow 'datacenter_tenant_id' + "description": instance_dict.get("description"), + } + db_ip_profiles=[] + if scenarioDict.get("cloud-config"): + db_instance_scenario["cloud_config"] = yaml.safe_dump(scenarioDict["cloud-config"], + default_flow_style=True, width=256) + vnf_net2instance = {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id + sce_net2instance = {} auxNetDict = {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id auxNetDict['scenario'] = {} logger.debug("Creating instance from scenario-dict:\n%s", yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)) #TODO remove - instance_name = instance_dict["name"] - instance_description = instance_dict.get("description") try: # 0 check correct parameters for net_name, net_instance_desc in instance_dict.get("networks",{}).iteritems(): @@ -2069,12 +2661,12 @@ def create_instance(mydb, tenant_id, instance_dict): #logger.debug(">>>>>>>> Merged dictionary") 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" + db_instance_nets = [] for sce_net in scenarioDict['nets']: - sce_net["vim_id_sites"]={} - descriptor_net = instance_dict.get("networks",{}).get(sce_net["name"],{}) + descriptor_net = instance_dict.get("networks",{}).get(sce_net["name"],{}) net_name = descriptor_net.get("vim-network-name") + sce_net2instance[sce_net['uuid']] = {} auxNetDict['scenario'][sce_net['uuid']] = {} sites = descriptor_net.get("sites", [ {} ]) @@ -2089,27 +2681,32 @@ def create_instance(mydb, tenant_id, instance_dict): myvim_thread_id = myvim_threads_id[default_datacenter_id] net_type = sce_net['type'] lookfor_filter = {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True - if sce_net["external"]: - if not net_name: + + if not net_name: + if sce_net["external"]: net_name = sce_net["name"] - if "netmap-use" in site or "netmap-create" in site: - create_network = False - lookfor_network = False - if "netmap-use" in site: - lookfor_network = True - if utils.check_valid_uuid(site["netmap-use"]): - filter_text = "scenario id '%s'" % site["netmap-use"] - lookfor_filter["id"] = site["netmap-use"] - else: - filter_text = "scenario name '%s'" % site["netmap-use"] - lookfor_filter["name"] = site["netmap-use"] - if "netmap-create" in site: - create_network = True - net_vim_name = net_name - if site["netmap-create"]: - net_vim_name = site["netmap-create"] - - elif sce_net['vim_id'] != None: + else: + net_name = "{}.{}".format(instance_name, sce_net["name"]) + net_name = net_name[:255] # limit length + + if "netmap-use" in site or "netmap-create" in site: + create_network = False + lookfor_network = False + if "netmap-use" in site: + lookfor_network = True + if utils.check_valid_uuid(site["netmap-use"]): + filter_text = "scenario id '%s'" % site["netmap-use"] + lookfor_filter["id"] = site["netmap-use"] + else: + filter_text = "scenario name '%s'" % site["netmap-use"] + lookfor_filter["name"] = site["netmap-use"] + if "netmap-create" in site: + create_network = True + net_vim_name = net_name + if site["netmap-create"]: + net_vim_name = site["netmap-create"] + elif sce_net["external"]: + if sce_net['vim_id'] != None: #there is a netmap at datacenter_nets database #TODO REVISE!!!! create_network = False lookfor_network = True @@ -2124,13 +2721,12 @@ def create_instance(mydb, tenant_id, instance_dict): net_vim_name = sce_net["name"] filter_text = "scenario name '%s'" % sce_net["name"] else: - if not net_name: - net_name = "%s.%s" %(instance_name, sce_net["name"]) - net_name = net_name[:255] #limit length net_vim_name = net_name create_network = True lookfor_network = False + + if lookfor_network: vim_nets = vim.get_network_list(filter_dict=lookfor_filter) if len(vim_nets) > 1: @@ -2139,7 +2735,7 @@ def create_instance(mydb, tenant_id, instance_dict): if not create_network: raise NfvoException("No candidate VIM network found for " + filter_text, HTTP_Bad_Request ) else: - sce_net["vim_id_sites"][datacenter_id] = vim_nets[0]['id'] + vim_id = vim_nets[0]['id'] auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = vim_nets[0]['id'] create_network = False if create_network: @@ -2149,13 +2745,41 @@ def create_instance(mydb, tenant_id, instance_dict): instance_tasks[task_id] = task tasks_to_launch[myvim_thread_id].append(task) #network_id = vim.new_network(net_vim_name, net_type, sce_net.get('ip_profile',None)) - sce_net["vim_id_sites"][datacenter_id] = task_id + vim_id = task_id auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = task_id rollbackList.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id, 'uuid':task_id}) sce_net["created"] = True + # fill database content + net_uuid = str(uuid4()) + uuid_list.append(net_uuid) + sce_net2instance[sce_net['uuid']][datacenter_id] = net_uuid + db_net = { + "uuid": net_uuid, + 'vim_net_id': vim_id, + "instance_scenario_id": instance_uuid, + "sce_net_id": sce_net["uuid"], + "created": create_network, + 'datacenter_id': datacenter_id, + 'datacenter_tenant_id': myvim_thread_id, + 'status': 'BUILD' if create_network else "ACTIVE" + } + db_instance_nets.append(db_net) + if 'ip_profile' in sce_net: + db_ip_profile={ + 'instance_net_id': net_uuid, + 'ip_version': sce_net['ip_profile']['ip_version'], + 'subnet_address': sce_net['ip_profile']['subnet_address'], + 'gateway_address': sce_net['ip_profile']['gateway_address'], + 'dns_address': sce_net['ip_profile']['dns_address'], + 'dhcp_enabled': sce_net['ip_profile']['dhcp_enabled'], + 'dhcp_start_address': sce_net['ip_profile']['dhcp_start_address'], + 'dhcp_count': sce_net['ip_profile']['dhcp_count'], + } + db_ip_profiles.append(db_ip_profile) + # 2. Creating new nets (vnf internal nets) in the VIM" - #For each vnf net, we create it and we add it to instanceNetlist. + # For each vnf net, we create it and we add it to instanceNetlist. for sce_vnf in scenarioDict['vnfs']: for net in sce_vnf['nets']: if sce_vnf.get("datacenter"): @@ -2177,20 +2801,65 @@ def create_instance(mydb, tenant_id, instance_dict): instance_tasks[task_id] = task tasks_to_launch[myvim_thread_id].append(task) # network_id = vim.new_network(net_name, net_type, net.get('ip_profile',None)) - net['vim_id'] = task_id + vim_id = task_id + if sce_vnf['uuid'] not in vnf_net2instance: + vnf_net2instance[sce_vnf['uuid']] = {} + vnf_net2instance[sce_vnf['uuid']][net['uuid']] = task_id if sce_vnf['uuid'] not in auxNetDict: auxNetDict[sce_vnf['uuid']] = {} auxNetDict[sce_vnf['uuid']][net['uuid']] = task_id rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':task_id}) net["created"] = True - - #print "auxNetDict:" - #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False) + # fill database content + net_uuid = str(uuid4()) + uuid_list.append(net_uuid) + vnf_net2instance[sce_vnf['uuid']][net['uuid']] = net_uuid + db_net = { + "uuid": net_uuid, + 'vim_net_id': vim_id, + "instance_scenario_id": instance_uuid, + "net_id": net["uuid"], + "created": True, + 'datacenter_id': datacenter_id, + 'datacenter_tenant_id': myvim_thread_id, + } + db_instance_nets.append(db_net) + if 'ip_profile' in net: + db_ip_profile = { + 'instance_net_id': net_uuid, + 'ip_version': net['ip_profile']['ip_version'], + 'subnet_address': net['ip_profile']['subnet_address'], + 'gateway_address': net['ip_profile']['gateway_address'], + 'dns_address': net['ip_profile']['dns_address'], + 'dhcp_enabled': net['ip_profile']['dhcp_enabled'], + 'dhcp_start_address': net['ip_profile']['dhcp_start_address'], + 'dhcp_count': net['ip_profile']['dhcp_count'], + } + db_ip_profiles.append(db_ip_profile) + + #print "vnf_net2instance:" + #print yaml.safe_dump(vnf_net2instance, indent=4, default_flow_style=False) # 3. Creating new vm instances in the VIM + db_instance_vnfs = [] + db_instance_vms = [] + db_instance_interfaces = [] #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict) - for sce_vnf in scenarioDict['vnfs']: + sce_vnf_list = sorted(scenarioDict['vnfs'], key=lambda k: k['name']) + #for sce_vnf in scenarioDict['vnfs']: + for sce_vnf in sce_vnf_list: + vnf_availability_zones = [] + for vm in sce_vnf['vms']: + vm_av = vm.get('availability_zone') + if vm_av and vm_av not in vnf_availability_zones: + vnf_availability_zones.append(vm_av) + + # check if there is enough availability zones available at vim level. + if myvims[datacenter_id].availability_zone and vnf_availability_zones: + if len(vnf_availability_zones) > len(myvims[datacenter_id].availability_zone): + raise NfvoException('No enough availability zones at VIM for this deployment', HTTP_Bad_Request) + if sce_vnf.get("datacenter"): vim = myvims[ sce_vnf["datacenter"] ] myvim_thread_id = myvim_threads_id[ sce_vnf["datacenter"] ] @@ -2199,12 +2868,24 @@ def create_instance(mydb, tenant_id, instance_dict): vim = myvims[ default_datacenter_id ] myvim_thread_id = myvim_threads_id[ default_datacenter_id ] datacenter_id = default_datacenter_id - sce_vnf["datacenter_id"] = datacenter_id + sce_vnf["datacenter_id"] = datacenter_id i = 0 + + vnf_uuid = str(uuid4()) + uuid_list.append(vnf_uuid) + db_instance_vnf = { + 'uuid': vnf_uuid, + 'instance_scenario_id': instance_uuid, + 'vnf_id': sce_vnf['vnf_id'], + 'sce_vnf_id': sce_vnf['uuid'], + 'datacenter_id': datacenter_id, + 'datacenter_tenant_id': myvim_thread_id, + } + db_instance_vnfs.append(db_instance_vnf) + for vm in sce_vnf['vms']: - i += 1 myVMDict = {} - myVMDict['name'] = "{}.{}.{}".format(instance_name,sce_vnf['name'],chr(96+i)) + myVMDict['name'] = "{}.{}.{}".format(instance_name[:64], sce_vnf['name'][:64], vm["name"][:64]) myVMDict['description'] = myVMDict['name'][0:99] # if not startvms: # myVMDict['start'] = "no" @@ -2237,9 +2918,11 @@ def create_instance(mydb, tenant_id, instance_dict): vm['vim_flavor_id'] = flavor_id myVMDict['imageRef'] = vm['vim_image_id'] myVMDict['flavorRef'] = vm['vim_flavor_id'] + myVMDict['availability_zone'] = vm.get('availability_zone') myVMDict['networks'] = [] task_depends = {} #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true + db_vm_ifaces = [] for iface in vm['interfaces']: netDict = {} if iface['type']=="data": @@ -2286,48 +2969,114 @@ def create_instance(mydb, tenant_id, instance_dict): #print vnf_iface if vnf_iface['interface_id']==iface['uuid']: netDict['net_id'] = auxNetDict['scenario'][ vnf_iface['sce_net_id'] ][datacenter_id] + instance_net_id = sce_net2instance[ vnf_iface['sce_net_id'] ][datacenter_id] break else: netDict['net_id'] = auxNetDict[ sce_vnf['uuid'] ][ iface['net_id'] ] + instance_net_id = vnf_net2instance[ sce_vnf['uuid'] ][ iface['net_id'] ] if netDict.get('net_id') and is_task_id(netDict['net_id']): task_depends[netDict['net_id']] = instance_tasks[netDict['net_id']] #skip bridge ifaces not connected to any net #if 'net_id' not in netDict or netDict['net_id']==None: # continue myVMDict['networks'].append(netDict) - #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>" - #print myVMDict['name'] - #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 ">>>>>>>>>>>>>>>>>>>>>>>>>>>" + db_vm_iface={ + # "uuid" + # 'instance_vm_id': instance_vm_uuid, + "instance_net_id": instance_net_id, + 'interface_id': iface['uuid'], + # 'vim_interface_id': , + 'type': 'external' if iface['external_name'] is not None else 'internal', + 'ip_address': iface.get('ip_address'), + 'floating_ip': int(iface.get('floating-ip', False)), + 'port_security': int(iface.get('port-security', True)) + } + db_vm_ifaces.append(db_vm_iface) + # print ">>>>>>>>>>>>>>>>>>>>>>>>>>>" + # print myVMDict['name'] + # 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 ">>>>>>>>>>>>>>>>>>>>>>>>>>>" if vm.get("boot_data"): cloud_config_vm = unify_cloud_config(vm["boot_data"], cloud_config) else: cloud_config_vm = cloud_config - task = new_task("new-vm", (myVMDict['name'], myVMDict['description'], myVMDict.get('start', None), - myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'], - cloud_config_vm, myVMDict['disks']), depends=task_depends) - instance_tasks[task["id"]] = task - tasks_to_launch[myvim_thread_id].append(task) - vm_id = task["id"] - vm['vim_id'] = vm_id - rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id}) - #put interface uuid back to scenario[vnfs][vms[[interfaces] - 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"] - break + if myVMDict.get('availability_zone'): + av_index = vnf_availability_zones.index(myVMDict['availability_zone']) + else: + av_index = None + for vm_index in range(0, vm.get('count', 1)): + vm_index_name = "" + if vm.get('count', 1) > 1: + vm_index_name += "." + chr(97 + vm_index) + task = new_task("new-vm", (myVMDict['name']+vm_index_name, myVMDict['description'], + myVMDict.get('start', None), myVMDict['imageRef'], + myVMDict['flavorRef'], myVMDict['networks'], + cloud_config_vm, myVMDict['disks'], av_index, + vnf_availability_zones), depends=task_depends) + instance_tasks[task["id"]] = task + tasks_to_launch[myvim_thread_id].append(task) + vm_id = task["id"] + vm['vim_id'] = vm_id + rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id}) + # put interface uuid back to scenario[vnfs][vms[[interfaces] + 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"] + break + vm_uuid = str(uuid4()) + uuid_list.append(vm_uuid) + db_vm = { + "uuid": vm_uuid, + 'instance_vnf_id': vnf_uuid, + "vim_vm_id": vm_id, + "vm_id": vm["uuid"], + # "status": + } + db_instance_vms.append(db_vm) + for db_vm_iface in db_vm_ifaces: + iface_uuid = str(uuid4()) + uuid_list.append(iface_uuid) + db_vm_iface_instance = { + "uuid": iface_uuid, + "instance_vm_id": vm_uuid + } + db_vm_iface_instance.update(db_vm_iface) + if db_vm_iface_instance.get("ip_address"): # increment ip_address + ip = db_vm_iface_instance.get("ip_address") + i = ip.rfind(".") + if i > 0: + try: + i += 1 + ip = ip[i:] + str(int(ip[:i]) +1) + db_vm_iface_instance["ip_address"] = ip + except: + db_vm_iface_instance["ip_address"] = None + db_instance_interfaces.append(db_vm_iface_instance) + scenarioDict["datacenter2tenant"] = myvim_threads_id + + db_instance_scenario['datacenter_tenant_id'] = myvim_threads_id[default_datacenter_id] + db_instance_scenario['datacenter_id'] = default_datacenter_id + db_tables=[ + {"instance_scenarios": db_instance_scenario}, + {"instance_vnfs": db_instance_vnfs}, + {"instance_nets": db_instance_nets}, + {"ip_profiles": db_ip_profiles}, + {"instance_vms": db_instance_vms}, + {"instance_interfaces": db_instance_interfaces}, + ] + logger.debug("create_instance Deployment done scenarioDict: %s", - yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False) ) - instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_name, instance_description, scenarioDict) + yaml.safe_dump(db_tables, indent=4, default_flow_style=False) ) + mydb.new_rows(db_tables, uuid_list) for myvim_thread_id,task_list in tasks_to_launch.items(): for task in task_list: vim_threads["running"][myvim_thread_id].insert_task(task) - global_instance_tasks[instance_id] = instance_tasks + global_instance_tasks[instance_uuid] = instance_tasks # Update database with those ended instance_tasks # for task in instance_tasks.values(): # if task["status"] == "ok": @@ -2337,7 +3086,7 @@ def create_instance(mydb, tenant_id, instance_dict): # elif task["name"] == "new-net": # mydb.update_rows("instance_nets", UPDATE={"vim_net_id": task["result"]}, # WHERE={"vim_net_id": task["id"]}) - return mydb.get_instance_scenario(instance_id) + return mydb.get_instance_scenario(instance_uuid) except (NfvoException, vimconn.vimconnException,db_base_Exception) as e: message = rollback(mydb, myvims, rollbackList) if isinstance(e, db_base_Exception): @@ -2789,20 +3538,24 @@ def new_datacenter(mydb, datacenter_descriptor): def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor): - #obtain data, check that only one exist + # obtain data, check that only one exist datacenter = mydb.get_table_by_uuid_name('datacenters', datacenter_id_name) - #edit data + + # edit data datacenter_id = datacenter['uuid'] where={'uuid': datacenter['uuid']} + remove_port_mapping = False if "config" in datacenter_descriptor: - if datacenter_descriptor['config']!=None: + if datacenter_descriptor['config'] != None: try: new_config_dict = datacenter_descriptor["config"] #delete null fields to_delete=[] for k in new_config_dict: - if new_config_dict[k]==None: + if new_config_dict[k] == None: to_delete.append(k) + if k == 'sdn-controller': + remove_port_mapping = True config_text = datacenter.get("config") if not config_text: @@ -2814,7 +3567,16 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor): del config_dict[k] except Exception as e: raise NfvoException("Bad format at datacenter:config " + str(e), HTTP_Bad_Request) - datacenter_descriptor["config"]= yaml.safe_dump(config_dict,default_flow_style=True,width=256) if len(config_dict)>0 else None + if config_dict: + datacenter_descriptor["config"] = yaml.safe_dump(config_dict, default_flow_style=True, width=256) + else: + datacenter_descriptor["config"] = None + if remove_port_mapping: + try: + datacenter_sdn_port_mapping_delete(mydb, None, datacenter_id) + except ovimException as e: + logger.error("Error deleting datacenter-port-mapping " + str(e)) + mydb.update_rows('datacenters', datacenter_descriptor, where) return datacenter_id @@ -2823,6 +3585,10 @@ def delete_datacenter(mydb, datacenter): #get nfvo_tenant info datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter, 'datacenter') mydb.delete_row_by_id("datacenters", datacenter_dict['uuid']) + try: + datacenter_sdn_port_mapping_delete(mydb, None, datacenter_dict['uuid']) + except ovimException as e: + logger.error("Error deleting datacenter-port-mapping " + str(e)) return datacenter_dict['uuid'] + " " + datacenter_dict['name'] @@ -2936,7 +3702,7 @@ def edit_datacenter_to_tenant(mydb, nfvo_tenant, datacenter_id, vim_tenant_id=No def deassociate_datacenter_to_tenant(mydb, tenant_id, datacenter, vim_tenant_id=None): #get datacenter info - datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter) + datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter) #get nfvo_tenant info if not tenant_id or tenant_id=="any": @@ -3090,8 +3856,7 @@ def get_sdn_net_id(mydb, tenant_id, datacenter, network_id): datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter) network = myvim.get_network_list(filter_dict=filter_dict) except vimconn.vimconnException as e: - print "vim_action Not possible to get_%s_list from VIM: %s " % (item, str(e)) - raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code) + raise NfvoException("Not possible to get_sdn_net_id from VIM: {}".format(str(e)), e.http_code) # ensure the network is defined if len(network) == 0: