def readNsd(self): """ Reads and returns required information from nsd/vnfd """ url = f"https://{self.ip}:9999/osm/nsd/v1/ns_descriptors" while True: headers = { 'Content-Type': 'application/yaml', 'Accept': 'application/json', 'Authorization': f'Bearer {self.token}', } response = requests.get(url, headers=headers, verify=False) if (response.status_code != 401): osm_nsd_list = response.json() new_nsd = {} for osm_nsd in osm_nsd_list: new_nsd["nsd-id"] = osm_nsd["_id"] new_nsd["nsd-name"] = osm_nsd["id"] new_nsd["vnfd_list"] = [] new_nsd["flavor"] = { "memory-mb": 0, "vcpu-count": 0, "storage-gb": 0 } for osm_vnfd in osm_nsd['constituent-vnfd']: data = {"name": osm_vnfd["vnfd-id-ref"]} reg_vnfd = mongoUtils.find("vnfd", data) if not reg_vnfd: logger.warning("There is a vnfd missing from the \ NFVO repository") else: new_nsd["vnfd_list"].append(reg_vnfd["name"]) new_nsd["flavor"]["memory-mb"] +=\ reg_vnfd["flavor"]["memory-mb"] new_nsd["flavor"]["vcpu-count"] +=\ reg_vnfd["flavor"]["vcpu-count"] new_nsd["flavor"]["storage-gb"] +=\ reg_vnfd["flavor"]["storage-gb"] new_nsd["nfvo_id"] = self.nfvo_id new_nsd["_id"] = str(uuid.uuid4()) try: mongoUtils.add("nsd", new_nsd) except pymongo.errors.DuplicateKeyError: continue new_nsd = {} break else: self.getToken()
def get(self, uuid): """ Returns the available resources on platform, used by: `katana resource location <location>` """ location_id = uuid.lower() # Check if the location exists if not mongoUtils.find("location", {"id": location_id}): return f"Location {uuid} not found", 404 # Get VIMs filter_data = {"location": location_id} vims = get_vims(filter_data) # Get Functions functions = get_func(filter_data) resources = {"VIMs": vims, "Functions": functions} return dumps(resources), 200
def delete(self, uuid): """ Delete a specific vim. used by: `katana vim rm [uuid]` """ vim = mongoUtils.get("vim", uuid) if vim: if vim["tenants"]: return "Cannot delete vim {} - In use".format(uuid), 400 mongoUtils.delete("vim_obj", uuid) mongoUtils.delete("vim", uuid) # Update the location removing the VIM location = mongoUtils.find("location", {"id": vim["location"].lower()}) if location: location["vims"].remove(vim["id"]) mongoUtils.update("location", location["_id"], location) return "Deleted VIM {}".format(uuid), 200 else: # if uuid is not found, return error return "Error: No such vim: {}".format(uuid), 404
def delete_slice(slice_id, force=False): """ Deletes the given network slice """ # Update the slice status in mongo db slice_json = mongoUtils.get("slice", slice_id) slice_json["status"] = "Terminating" mongoUtils.update("slice", slice_json["_id"], slice_json) logger.info(f"{slice_json['_id']} Status: Terminating") # Check if slice monitoring has been enabled monitoring = os.getenv("KATANA_MONITORING", None) slice_monitoring = slice_json.get("slice_monitoring", None) mon_producer = None if monitoring: # Create the Kafka producer mon_producer = create_producer() mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": slice_id, "status": "terminating" }, }, ) # *** Step-1: Radio Slice Configuration *** if slice_json["conf_comp"]["ems"]: ems_messages = slice_json.get("ems_data", None) if ems_messages: for ems_id, ems_message in ems_messages.items(): # Find the EMS target_ems = mongoUtils.find("ems", {"id": ems_id}) if not target_ems or ems_id not in slice_json["conf_comp"][ "ems"]: # Error handling: There is no such EMS logger.error( "EMS {} not found - No configuration".format(ems_id)) continue target_ems_obj = pickle.loads( mongoUtils.find("ems_obj", {"id": ems_id})["obj"]) target_ems_obj.del_slice(ems_message) else: logger.info("There was not EMS configuration") # *** Step-2: WAN Slice *** wim_data = slice_json.get("wim_data", None) if wim_data: # Select WIM - Assume that there is only one registered wim_list = list(mongoUtils.index("wim")) if wim_list: target_wim = wim_list[0] target_wim_id = target_wim["id"] target_wim_obj = pickle.loads( mongoUtils.find("wim_obj", {"id": target_wim_id})["obj"]) target_wim_obj.del_slice(slice_id) try: del target_wim["slices"][slice_json["_id"]] except KeyError: logger.warning(f"Slice {slice_id} not in WIM {target_wim_id}") else: mongoUtils.update("wim", target_wim["_id"], target_wim) else: err = "Cannot find WIM - WAN Slice will not be deleted" logger.warning(err) slice_json["status"] = "Error" if monitoring: mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": slice_id, "status": "error" }, }, ) slice_json["error"] = slice_json.get("error", "") + err mongoUtils.update("slice", slice_json["_id"], slice_json) else: logger.info("There was no WIM configuration") # *** Step-3: Cloud *** vim_error_list = [] try: total_ns_list = slice_json["total_ns_list"] ns_inst_info = slice_json["ns_inst_info"] for ns in total_ns_list: # Check if the NS is shared. If it is, check if there is another running slice on this # sharing list if ns["shared_function"]: # Find the shared list shared_list = mongoUtils.get("sharing_lists", ns["shared_slice_key"]) # If there is another running slice, don't terminate the NS if len(shared_list["nest_list"]) > 1: continue if ns["nsd-id"] not in slice_json["conf_comp"]["nf"]: logger.error( f"{ns['nsd-id']} was not instantiated successfully") continue # Get the NFVO nfvo_id = ns["nfvo-id"] target_nfvo = mongoUtils.find("nfvo", {"id": ns["nfvo-id"]}) if not target_nfvo: logger.warning( "NFVO with id {} was not found - NSs won't terminate". format(nfvo_id)) vim_error_list += ns["vims"] continue target_nfvo_obj = pickle.loads( mongoUtils.find("nfvo_obj", {"id": ns["nfvo-id"]})["obj"]) # Stop the NS nfvo_inst_ns = ns_inst_info[ns["ns-id"]][ ns["placement_loc"]["location"]]["nfvo_inst_ns"] target_nfvo_obj.deleteNs(nfvo_inst_ns) while True: if target_nfvo_obj.checkNsLife(nfvo_inst_ns): break time.sleep(5) except KeyError as e: err = f"Error, not all NSs started or terminated correctly {e}" logger.warning(err) slice_json["status"] = "Error" if monitoring: mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": slice_id, "status": "error" }, }, ) slice_json["error"] = slice_json.get("error", "") + err mongoUtils.update("slice", slice_json["_id"], slice_json) vim_dict = slice_json.get("vim_list", {}) for vim, vim_info in vim_dict.items(): # Check if the VIM is shared with other slices. If yes, skip the deletion tenant_name = slice_id if vim_info["shared"]: shared_list = mongoUtils.get("sharing_lists", vim_info["shared_slice_list_key"]) tenant_name = vim_info["shared_slice_list_key"] vim_id = vim[:-2] # If there is another running slice, don't delete the VIM account if len(shared_list["nest_list"]) > 1: continue else: vim_id = vim try: # Delete the new tenants from the NFVO for nfvo, vim_account in vim_info["nfvo_vim_account"].items(): # Get the NFVO target_nfvo = mongoUtils.find("nfvo", {"id": nfvo}) target_nfvo_obj = pickle.loads( mongoUtils.find("nfvo_obj", {"id": nfvo})["obj"]) # Delete the VIM and update nfvo db target_nfvo_obj.deleteVim(vim_account) target_nfvo["tenants"][tenant_name].remove(vim_account) if len(target_nfvo["tenants"][tenant_name]) == 0: try: del target_nfvo["tenants"][tenant_name] except KeyError: logger.warning( f"Slice {tenant_name} not in NFO {nfvo}") else: mongoUtils.update("nfvo", target_nfvo["_id"], target_nfvo) # Delete the tenants from every vim if vim not in vim_error_list: # Get the VIM target_vim = mongoUtils.find("vim", {"id": vim_id}) if not target_vim: logger.warning( "VIM id {} was not found - Tenant won't be deleted". format(vim)) continue target_vim_obj = pickle.loads( mongoUtils.find("vim_obj", {"id": vim_id})["obj"]) if vim_info["shared"]: tenant_name = vim_info["shared_slice_list_key"] else: tenant_name = slice_json["_id"] target_vim_obj.delete_proj_user( target_vim["tenants"][tenant_name]) try: del target_vim["tenants"][tenant_name] except KeyError: logger.warning(f"Slice {slice_id} not in VIM {vim}") else: mongoUtils.update("vim", target_vim["_id"], target_vim) except KeyError as e: err = f"Error, not all tenants created or removed correctly {e}" logger.warning(err) slice_json["status"] = "Error" if monitoring: mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": slice_id, "status": "error" }, }, ) slice_json["error"] = slice_json.get("error", "") + err mongoUtils.update("slice", slice_json["_id"], slice_json) if "error" not in slice_json: mongoUtils.delete("slice", slice_json["_id"]) if monitoring: mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": slice_id, "status": "deleted" }, }, ) elif "error" in slice_json and force: mongoUtils.delete("slice", slice_json["_id"]) if monitoring: mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": slice_id, "status": "deleted" }, }, ) # Remove Slice from the tenants list on functions for func_id in slice_json["functions"]: ifunc = mongoUtils.get("func", func_id) try: ifunc["tenants"].remove(slice_json["_id"]) except (KeyError, ValueError): logger.warning(f"Slice {slice_id} not in function {func_id}") else: mongoUtils.update("func", func_id, ifunc) # Remove Slice dashboard if monitoring and slice_monitoring: # Use the Grafana API in order to delete the new dashboard for the new slice grafana_url = f"http://katana-grafana:3000/api/dashboards/uid/{slice_id}" headers = { "accept": "application/json", "content-type": "application/json" } grafana_user = os.getenv("GF_SECURITY_ADMIN_USER", "admin") grafana_passwd = os.getenv("GF_SECURITY_ADMIN_PASSWORD", "admin") r = requests.delete( url=grafana_url, headers=headers, auth=(grafana_user, grafana_passwd), ) logger.info(f"Deleted Grafana dashboard for slice {slice_id}") # Stop the threads monitoring NS status of the slice ns_inst_info = slice_json["ns_inst_info"] mon_producer.send(topic="nfv_mon", value={ "action": "delete", "ns_list": ns_inst_info }) # Check if the NSI has shared NSSIs and remove them try: for func_key, shared_list_key in slice_json["shared"]["core"].items(): # Remove the slice from the shared list try: shared_list = mongoUtils.get("sharing_lists", shared_list_key) func = mongoUtils.get("func", func_key) if len(shared_list["nest_list"]) > 1: # Remove the Slice from the list shared_list["nest_list"].remove(slice_id) mongoUtils.update("sharing_lists", shared_list_key, shared_list) func["shared"]["sharing_list"][shared_list_key].remove( slice_id) else: # Remove the the shared list mongoUtils.delete("sharing_lists", shared_list_key) del func["shared"]["sharing_list"][shared_list_key] mongoUtils.update("func", func_key, func) except ValueError as e: pass except KeyError as e: pass try: for func_key, shared_list_key in slice_json["shared"]["radio"].items(): # Remove the slice from the shared list try: shared_list = mongoUtils.get("sharing_lists", shared_list_key) func = mongoUtils.get("func", func_key) if len(shared_list["nest_list"]) > 1: # Remove the Slice from the list shared_list["nest_list"].remove(slice_id) mongoUtils.update("sharing_lists", shared_list_key, shared_list) func["shared"]["sharing_list"][shared_list_key].remove( slice_id) else: # Remove the the shared list mongoUtils.delete("sharing_lists", shared_list_key) del func["shared"]["sharing_list"][shared_list_key] mongoUtils.update("func", func_key, func) except ValueError as e: pass except KeyError as e: pass
def ns_details( ns_list, edge_loc, vim_dict, total_ns_list, shared_function=0, shared_slice_list_key=None, ): """ Get details for the NS that are part of the slice A) Find the nsd details for each NS B) Replace placement value with location C) Get the VIM for each NS """ pop_list = [] for ns in ns_list: try: if ns["placement_loc"] and not ns["placement"]: # Placement to Core already done - go to next NS continue else: # Placement to Edge - Is already done - Need to make another ns new_ns = copy.deepcopy(ns) except KeyError: # No placement at all new_ns = ns # 00) Check if the function is shared and if the ns is already instantiated new_ns["shared_function"] = shared_function new_ns["shared_slice_key"] = shared_slice_list_key # Search the nsd collection in Mongo for the nsd nsd = mongoUtils.find("nsd", {"nsd-id": new_ns["nsd-id"]}) if not nsd: # Bootstrap the NFVOs to check for NSDs that are not in mongo # If again is not found, check if NS is optional. # If it is just remove it, else error nfvo_obj_list = list(mongoUtils.find_all("nfvo_obj")) for infvo in nfvo_obj_list: nfvo = pickle.loads(infvo["obj"]) nfvo.bootstrapNfvo() nsd = mongoUtils.find("nsd", {"nsd-id": new_ns["nsd-id"]}) if not nsd and ns.get("optional", False): # The NS is optional - continue to next pop_list.append(ns) continue else: # Error handling: The ns is not optional and the nsd is not # on the NFVO - stop and return error_message = f"NSD {new_ns['nsd-id']} not found on any NFVO registered to SM" logger.error(error_message) return error_message, [] new_ns["nfvo-id"] = nsd["nfvo_id"] new_ns["nsd-info"] = nsd # B) ****** Replace placement value with location info ****** if type(new_ns["placement"]) is str: new_ns["placement_loc"] = {"location": new_ns["placement"]} else: new_ns["placement_loc"] = (lambda x: { "location": "Core" } if not x else { "location": edge_loc })(new_ns["placement"]) # C) ****** Get the VIM info ****** new_ns["vims"] = [] loc = new_ns["placement_loc"]["location"] get_vim = list(mongoUtils.find_all("vim", {"location": loc})) if not get_vim: if not new_ns.get("optional", False): # Error handling: There is no VIM at that location error_message = f"VIM not found in location {loc}" logger.error(error_message) return error_message, [] else: # The NS is optional - continue to next pop_list.append(ns) continue # TODO: Check the available resources and select vim # Temporary use the first element selected_vim = get_vim[0]["id"] if shared_function: selected_vim_id = selected_vim + "_s" else: selected_vim_id = selected_vim new_ns["vims"].append(selected_vim_id) try: vim_dict[selected_vim_id]["ns_list"].append(new_ns["ns-name"]) if new_ns["nfvo-id"] not in vim_dict[selected_vim_id]["nfvo_list"]: vim_dict[selected_vim_id]["nfvo_list"].append( new_ns["nfvo-id"]) except KeyError: vim_dict[selected_vim_id] = { "ns_list": [new_ns["ns-name"]], "nfvo_list": [new_ns["nfvo-id"]], "shared": shared_function, "shared_slice_list_key": shared_slice_list_key, } resources = vim_dict[selected_vim_id].get("resources", { "memory-mb": 0, "vcpu-count": 0, "storage-gb": 0, "instances": 0 }) for key in resources: resources[key] += nsd["flavor"][key] vim_dict[selected_vim_id]["resources"] = resources new_ns["placement_loc"]["vim"] = selected_vim_id # 0) Create an uuid for the ns new_ns["ns-id"] = str(uuid.uuid4()) total_ns_list.append(new_ns) del new_ns # Remove the ns that are optional and nsd was not found ns_list = [ns for ns in ns_list if ns not in pop_list] return 0, pop_list
def add_slice(nest_req): """ Creates the network slice """ # Recreate the NEST with None options where missiong nest = { "_id": nest_req["_id"], "status": "Init", "created_at": time.time(), # unix epoch "deployment_time": { "Placement_Time": None, "Provisioning_Time": None, "WAN_Deployment_Time": None, "NS_Deployment_Time": None, "Radio_Configuration_Time": None, "Slice_Deployment_Time": None, }, } mongoUtils.add("slice", nest) for nest_key in NEST_KEYS_OBJ: nest[nest_key] = nest_req.get(nest_key, None) for nest_key in NEST_KEYS_LIST: nest[nest_key] = nest_req.get(nest_key, []) # Check if slice monitoring has been enabled monitoring = os.getenv("KATANA_MONITORING", None) wim_monitoring = {} mon_producer = None if monitoring: # Create the Kafka producer mon_producer = create_producer() nest["slice_monitoring"] = {} # **** STEP-1: Placement **** nest["status"] = "Placement" if monitoring: mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": nest["_id"], "status": "placement" }, }, ) nest["conf_comp"] = {"nf": [], "ems": []} mongoUtils.update("slice", nest["_id"], nest) logger.info(f"{nest['_id']} Status: Placement") placement_start_time = time.time() # Initiate the lists vim_dict = {} total_ns_list = [] ems_messages = {} # Get Details for the Network Services # i) The NS part of the core slice inst_functions = {} for connection in nest["connections"]: for key in connection: # Check if the function has been instantiated from another connection if connection[key]["_id"] in inst_functions: connection[key] = inst_functions[connection[key]["_id"]] continue # Check if the function is shared with another slice # shared_check values: 0: No shared, 1: First shared, 2: Shared shared_check = 0 shared_slice_list_key = None try: shared_slice_list_key = nest["shared"][key][connection[key] ["_id"]] shared_slice_list = connection[key]["shared"]["sharing_list"][ shared_slice_list_key] if len(shared_slice_list) > 1: shared_check = 2 else: shared_check = 1 except KeyError: pass try: err, pop_list = ns_details( connection[key]["ns_list"], connection[key]["location"], vim_dict, total_ns_list, shared_check, shared_slice_list_key, ) if pop_list: connection[key]["ns_list"] = [ x for x in connection[key]["ns_list"] if x not in pop_list ] if err: nest["status"] = f"Failed - {err}" nest["ns_inst_info"] = {} nest["total_ns_list"] = [] mongoUtils.update("slice", nest["_id"], nest) return inst_functions[connection[key]["_id"]] = connection[key] except KeyError: continue # ii) The extra NS of the slice for location in nest["coverage"]: err, _ = ns_details(nest["ns_list"], location, vim_dict, total_ns_list) if err: nest["status"] = f"Failed - {err}" nest["ns_inst_info"] = {} nest["total_ns_list"] = [] mongoUtils.update("slice", nest["_id"], nest) return nest["vim_list"] = vim_dict nest["total_ns_list"] = total_ns_list nest["deployment_time"]["Placement_Time"] = format( time.time() - placement_start_time, ".4f") # **** STEP-2: Resource Provisioning **** nest["status"] = "Provisioning" if monitoring: mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": nest["_id"], "status": "provisioning" }, }, ) mongoUtils.update("slice", nest["_id"], nest) logger.info(f"{nest['_id']} Status: Provisioning") prov_start_time = time.time() # *** STEP-2a: Cloud *** # *** STEP-2a-i: Create the new tenant/project on the VIM *** for num, (vim, vim_info) in enumerate(vim_dict.items()): if vim_info["shared"]: vim_id = vim[:-2] else: vim_id = vim target_vim = mongoUtils.find("vim", {"id": vim_id}) target_vim_obj = pickle.loads( mongoUtils.find("vim_obj", {"id": vim_id})["obj"]) # Define project parameters if vim_info["shared"] == 1: name = "vim_{0}_katana_{1}_shared".format( num, vim_info["shared_slice_list_key"]) tenant_name = vim_info["shared_slice_list_key"] elif vim_info["shared"] == 0: name = "vim_{0}_katana_{1}".format(num, nest["_id"]) tenant_name = nest["_id"] else: # Find the shared list sharing_lists = mongoUtils.get("sharing_lists", vim_info["shared_slice_list_key"]) vim_dict[vim] = sharing_lists["vims"][target_vim["id"]] mongoUtils.update("slice", nest["_id"], nest) continue tenant_project_name = name tenant_project_description = name tenant_project_user = name tenant_project_password = "******" # If the vim is Openstack type, set quotas quotas = (vim_info["resources"] if target_vim["type"] == "openstack" or target_vim["type"] == "Openstack" else None) ids = target_vim_obj.create_slice_prerequisites( tenant_project_name, tenant_project_description, tenant_project_user, tenant_project_password, nest["_id"], quotas=quotas, ) # Register the tenant to the mongo db target_vim["tenants"][tenant_name] = name mongoUtils.update("vim", target_vim["_id"], target_vim) # STEP-2a-ii: Αdd the new VIM tenant to NFVO if target_vim["type"] == "openstack": # Update the config parameter for the tenant config_param = dict(security_groups=ids["secGroupName"]) elif target_vim["type"] == "opennebula": config_param = target_vim["config"] else: config_param = {} for nfvo_id in vim_info["nfvo_list"]: target_nfvo = mongoUtils.find("nfvo", {"id": nfvo_id}) target_nfvo_obj = pickle.loads( mongoUtils.find("nfvo_obj", {"id": nfvo_id})["obj"]) vim_id = target_nfvo_obj.addVim( tenant_project_name, target_vim["password"], target_vim["type"], target_vim["auth_url"], target_vim["username"], config_param, ) vim_info["nfvo_vim_account"] = vim_info.get("nfvo_vim_account", {}) vim_info["nfvo_vim_account"][nfvo_id] = vim_id # Register the tenant to the mongo db target_nfvo["tenants"][tenant_name] = target_nfvo["tenants"].get( nest["_id"], []) target_nfvo["tenants"][tenant_name].append(vim_id) mongoUtils.update("nfvo", target_nfvo["_id"], target_nfvo) if vim_info["shared"] == 1: sharing_lists = mongoUtils.get("sharing_lists", vim_info["shared_slice_list_key"]) sharing_lists["vims"] = sharing_lists.get("vims", {}) sharing_lists["vims"][target_vim["id"]] = vim_info mongoUtils.update("sharing_lists", vim_info["shared_slice_list_key"], sharing_lists) mongoUtils.update("slice", nest["_id"], nest) # *** STEP-2b: WAN *** if mongoUtils.count("wim") <= 0: logger.warning("There is no registered WIM") else: wan_start_time = time.time() # Crate the data for the WIM wim_data = { "_id": nest["_id"], "core_connections": [], "extra_ns": [], "slice_sla": {} } # i) Create the slice_sla data for the WIM wim_data["slice_sla"] = { "network_DL_throughput": nest["network_DL_throughput"], "network_UL_throughput": nest["network_UL_throughput"], "mtu": nest["mtu"], } # ii) Add the connections for connection in nest["connections"]: data = {} for key in connection: key_data = {} try: ns_l = connection[key]["ns_list"] except KeyError: pass else: key_data["ns"] = [] for ns in ns_l: if ns["placement_loc"] not in key_data["ns"]: key_data["ns"].append(ns["placement_loc"]) try: pnf_l = connection[key]["pnf_list"] except KeyError: pass else: key_data["pnf"] = pnf_l if key_data: data[key] = key_data if data: wim_data["core_connections"].append(data) # iii) Add the extra Network Services for ns in nest["ns_list"]: if ns["placement_loc"] not in wim_data["extra_ns"]: wim_data["extra_ns"].append(ns["placement_loc"]) # iV) Add the probes wim_data["probes"] = nest["probe_list"] # Select WIM - Assume that there is only one registered wim_list = list(mongoUtils.index("wim")) target_wim = wim_list[0] target_wim_id = target_wim["id"] target_wim_obj = pickle.loads( mongoUtils.find("wim_obj", {"id": target_wim_id})["obj"]) target_wim_obj.create_slice(wim_data) nest["wim_data"] = wim_data target_wim["slices"][nest["_id"]] = nest["_id"] mongoUtils.update("slice", nest["_id"], nest) mongoUtils.update("wim", target_wim["_id"], target_wim) # Add monitoring from WIM in nest try: wim_monitoring = target_wim["monitoring-url"] nest["slice_monitoring"]["WIM"] = wim_monitoring except KeyError: pass nest["deployment_time"]["WAN_Deployment_Time"] = format( time.time() - wan_start_time, ".4f") nest["deployment_time"]["Provisioning_Time"] = format( time.time() - prov_start_time, ".4f") # **** STEP-3: Slice Activation Phase**** nest["status"] = "Activation" if monitoring: mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": nest["_id"], "status": "activation" }, }, ) mongoUtils.update("slice", nest["_id"], nest) logger.info(f"{nest['_id']} Status: Activation") # *** STEP-3a: Cloud *** # Instantiate NS # Store info about instantiated NSs ns_inst_info = {} nest["deployment_time"]["NS_Deployment_Time"] = {} for ns in total_ns_list: ns["start_time"] = time.time() if ns["shared_function"] == 2: # The ns is already instantiated and there is no need to instantiate again # Find the sharing list shared_list = mongoUtils.get("sharing_lists", ns["shared_slice_key"]) ns_inst_info[ns["ns-id"]] = shared_list["ns_list"][ns["nsd-id"]] nest["conf_comp"]["nf"].append(ns["nsd-id"]) continue ns_inst_info[ns["ns-id"]] = {} target_nfvo = mongoUtils.find("nfvo", {"id": ns["nfvo-id"]}) target_nfvo_obj = pickle.loads( mongoUtils.find("nfvo_obj", {"id": ns["nfvo-id"]})["obj"]) selected_vim = ns["placement_loc"]["vim"] nfvo_vim_account = vim_dict[selected_vim]["nfvo_vim_account"][ ns["nfvo-id"]] nfvo_inst_ns = target_nfvo_obj.instantiateNs(ns["ns-name"], ns["nsd-id"], nfvo_vim_account) ns_inst_info[ns["ns-id"]][ns["placement_loc"]["location"]] = { "nfvo_inst_ns": nfvo_inst_ns, "nfvo-id": ns["nfvo-id"], "ns-name": ns["ns-name"], "slice_id": nest["_id"], "vim": selected_vim, } # Check if this the first slice of a sharing list if ns["shared_function"] == 1: shared_list = mongoUtils.get("sharing_lists", ns["shared_slice_key"]) ns_inst_info[ns["ns-id"]][ns["placement_loc"] ["location"]]["shared"] = True ns_inst_info[ns["ns-id"]][ns["placement_loc"]["location"]][ "sharing_list"] = ns["shared_slice_key"] shared_list["ns_list"][ns["nsd-id"]] = ns_inst_info[ns["ns-id"]] mongoUtils.update("sharing_lists", ns["shared_slice_key"], shared_list) nest["conf_comp"]["nf"].append(ns["nsd-id"]) time.sleep(4) time.sleep(2) # Get the nsr for each service and wait for the activation for ns in total_ns_list: target_nfvo = mongoUtils.find("nfvo", {"id": ns["nfvo-id"]}) target_nfvo_obj = pickle.loads( mongoUtils.find("nfvo_obj", {"id": ns["nfvo-id"]})["obj"]) site = ns["placement_loc"] nfvo_inst_ns_id = ns_inst_info[ns["ns-id"]][ site["location"]]["nfvo_inst_ns"] insr = target_nfvo_obj.getNsr(nfvo_inst_ns_id) while insr["operational-status"] != "running" or insr[ "config-status"] != "configured": if insr["operational-status"] == "failed": error_message = ( f"Network Service {ns['nsd-id']} failed to start on NFVO {ns['nfvo-id']}." ) logger.error(error_message) nest["ns_inst_info"] = ns_inst_info nest["status"] = f"Failed - {error_message}" mongoUtils.update("slice", nest["_id"], nest) return time.sleep(10) insr = target_nfvo_obj.getNsr(nfvo_inst_ns_id) nest["deployment_time"]["NS_Deployment_Time"][ns["ns-name"]] = format( time.time() - ns["start_time"], ".4f") # Get the IPs of the instantiated NS vnf_list = [] vnfr_id_list = target_nfvo_obj.getVnfrId(insr) for ivnfr_id in vnfr_id_list: vnfr = target_nfvo_obj.getVnfr(ivnfr_id) vnf_list.append(target_nfvo_obj.getIPs(vnfr)) ns_inst_info[ns["ns-id"]][site["location"]]["vnfr"] = vnf_list nest["ns_inst_info"] = ns_inst_info mongoUtils.update("slice", nest["_id"], nest) # If monitoring parameter is set, send the ns_list to nfv_mon module if monitoring and mon_producer: mon_producer.send(topic="nfv_mon", value={ "action": "create", "ns_list": ns_inst_info }) nest["slice_monitoring"]["nfv_ns_status_monitoring"] = True # *** STEP-3b: Radio Slice Configuration *** if mongoUtils.count("ems") <= 0: logger.warning("There is no registered EMS") else: # Add the management IPs for the NS sent ems in ems_messages: ems_radio_data = { "ue_DL_throughput": nest["ue_DL_throughput"], "ue_UL_throughput": nest["ue_UL_throughput"], "group_communication_support": nest["group_communication_support"], "number_of_terminals": nest["number_of_terminals"], "positional_support": nest["positional_support"], "radio_spectrum": nest["radio_spectrum"], "device_velocity": nest["device_velocity"], "terminal_density": nest["terminal_density"], } radio_start_time = time.time() iii = 0 for connection in nest["connections"]: iii += 1 data = {} ems_id_list = [] for key in connection: # Check if the connection is shared try: shared_slice_list_key = nest["shared"][key][connection[key] ["_id"]] shared_slice_list = connection[key]["shared"][ "sharing_list"][shared_slice_list_key] shared = True if len(shared_slice_list) > 1: shared_check = 2 else: shared_check = 1 except KeyError: shared_slice_list_key = None shared = False key_data = {} try: ems_id = connection[key]["ems-id"] except KeyError: continue else: if ems_id not in ems_id_list: ems_id_list.append(ems_id) try: ns_l = connection[key]["ns_list"] except KeyError: pass else: key_data["ns"] = [] for ns in ns_l: try: ns_info = ns_inst_info[ns["ns-id"]][ connection[key]["location"]] except KeyError: ns_info = ns_inst_info[ns["ns-id"]]["Core"] ns_data = { "name": ns["ns-name"], "location": ns["placement_loc"]["location"], "vnf_list": ns_info["vnfr"], } # Add the shared information for the ns, if any if shared: ns_data["shared"] = ns_inst_info[ns["ns-id"]][ connection[key]["location"]]["shared"] ns_data["sharing_list"] = ns_inst_info[ ns["ns-id"]][connection[key] ["location"]]["sharing_list"] else: ns_data["shared"] = False key_data["ns"].append(ns_data) try: key_data["pnf"] = connection[key]["pnf_list"] except KeyError: pass else: if shared: for ipnf in connection[key]["pnf_list"]: ipnf["shared"] = True ipnf["sharing_list"] = shared_slice_list_key if key_data: data[key] = key_data if data: data["slice_sla"] = ems_radio_data data["slice_id"] = nest["_id"] for ems_id in ems_id_list: messages = ems_messages.get(ems_id, []) messages.append(data) ems_messages[ems_id] = messages for ems_id, ems_message in ems_messages.items(): # Find the EMS target_ems = mongoUtils.find("ems", {"id": ems_id}) if not target_ems: # Error handling: There is no such EMS logger.error( "EMS {} not found - No configuration".format(ems_id)) continue target_ems_obj = pickle.loads( mongoUtils.find("ems_obj", {"id": ems_id})["obj"]) # Send the message for imessage in ems_message: target_ems_obj.conf_radio(imessage) nest["conf_comp"]["ems"].append(ems_id) nest["ems_data"] = ems_messages nest["deployment_time"]["Radio_Configuration_Time"] = format( time.time() - radio_start_time, ".4f") # *** STEP-4: Finalize *** # Create Grafana Dashboard for monitoring # Create the NS status panel if monitoring: # Open the Grafana Dashboard template monitoring_slice_id = "slice_" + nest["_id"].replace("-", "_") with open("/katana-grafana/templates/new_dashboard.json", mode="r") as dashboard_file: new_dashboard = json.load(dashboard_file) new_dashboard["dashboard"]["title"] = monitoring_slice_id new_dashboard["dashboard"]["uid"] = nest["_id"] # Add the dashboard panels # Add the NS Status panels expr = "ns_status" + '{slice_id="' + nest["_id"] + '"}' targets = [{ "expr": expr, "legendFormat": "", "interval": "", "format": "table", "instant": True }] infra_targets = {} for ns in ns_inst_info.values(): for key, value in ns.items(): # Check if the VIM supports infrastructure monitoring search_vim_id = value["vim"] if value.get("shared", False): search_vim_id = search_vim_id[:-2] selected_vim = mongoUtils.find("vim", {"id": search_vim_id}) try: vim_monitoring = selected_vim["type"] vim_monitoring_list = infra_targets.get(vim_monitoring, []) for ivnf in value["vnfr"]: vim_monitoring_list += ivnf["vm_list"] infra_targets[vim_monitoring] = vim_monitoring_list except KeyError: pass # Create the VM Monitoring panels PANELS = [ "vm_state", "vm_cpu_cpu_time", "vm_cpu_overall_cpu_usage", "vm_memory_actual", "vm_memory_available", "vm_memory_usage", "vm_disk_read_bytes", "vm_disk_write_bytes", "vm_disk_errors", ] with open("/katana-grafana/templates/new_vm_monitoring_panel.json", mode="r") as panel_file: vm_panel_template = json.load(panel_file) for i, panel in enumerate(PANELS): vm_panel = copy.deepcopy(vm_panel_template) vm_panel["title"] = panel vm_panel["gridPos"] = {"h": 8, "w": 12, "x": 13, "y": i * 9} vm_panel["id"] = 10 + i vm_targets = [] for vim_type, vm_list in infra_targets.items(): for vm in vm_list: expr = (vim_type + "_" + panel + '{project=~".*' + nest["_id"] + '",vm_name="' + vm + '"}') vm_targets.append({ "expr": expr, "interval": "", "legendFormat": "" }) vm_panel["targets"] = vm_targets new_dashboard["dashboard"]["panels"].append(vm_panel) # Read and fill the NS Status panel template with open("/katana-grafana/templates/new_ns_status_panel.json", mode="r") as panel_file: ns_panel = json.load(panel_file) ns_panel["targets"] = targets new_dashboard["dashboard"]["panels"].append(ns_panel) # Add the WIM Monitoring panel if wim_monitoring: # Read and fill the panel template with open("/katana-grafana/templates/new_wim_panel.json", mode="r") as panel_file: wim_panel = json.load(panel_file) wim_panel["targets"].append({ "expr": f"rate({monitoring_slice_id}_flows[1m])", "interval": "", "legendFormat": "", "refId": "A", }) new_dashboard["dashboard"]["panels"].append(wim_panel) mon_producer.send( "nfv_mon", value={ "action": "katana_mon", "slice_info": { "slice_id": nest["_id"], "status": "running" }, }, ) # Use the Grafana API in order to create the new dashboard for the new slice grafana_url = "http://katana-grafana:3000/api/dashboards/db" headers = { "accept": "application/json", "content-type": "application/json" } grafana_user = os.getenv("GF_SECURITY_ADMIN_USER", "admin") grafana_passwd = os.getenv("GF_SECURITY_ADMIN_PASSWORD", "admin") r = requests.post( url=grafana_url, headers=headers, auth=(grafana_user, grafana_passwd), data=json.dumps(new_dashboard), ) logger.info(f"Created new Grafana dashboard for slice {nest['_id']}") logger.info(f"{nest['_id']} Status: Running") nest["status"] = "Running" nest["deployment_time"]["Slice_Deployment_Time"] = format( time.time() - nest["created_at"], ".4f") mongoUtils.update("slice", nest["_id"], nest)
def delete_slice(slice_id, force=False): """ Deletes the given network slice """ # Update the slice status in mongo db slice_json = mongoUtils.get("slice", slice_id) slice_json["status"] = "Terminating" mongoUtils.update("slice", slice_json["_id"], slice_json) logger.info(f"{slice_json['_id']} Status: Terminating") # *** Step-1: Radio Slice Configuration *** if slice_json["conf_comp"]["ems"]: ems_messages = slice_json.get("ems_data", None) if ems_messages: for ems_id, ems_message in ems_messages.items(): # Find the EMS target_ems = mongoUtils.find("ems", {"id": ems_id}) if not target_ems or ems_id not in slice_json["conf_comp"]["ems"]: # Error handling: There is no such EMS logger.error("EMS {} not found - No configuration".format(ems_id)) continue target_ems_obj = pickle.loads(mongoUtils.find("ems_obj", {"id": ems_id})["obj"]) target_ems_obj.del_slice(ems_message) else: logger.info("There was not EMS configuration") # *** Step-2: WAN Slice *** wim_data = slice_json.get("wim_data", None) if wim_data: # Select WIM - Assume that there is only one registered wim_list = list(mongoUtils.index("wim")) if wim_list: target_wim = wim_list[0] target_wim_id = target_wim["id"] target_wim_obj = pickle.loads(mongoUtils.find("wim_obj", {"id": target_wim_id})["obj"]) target_wim_obj.del_slice(slice_id) try: del target_wim["slices"][slice_json["_id"]] except KeyError: logger.warning(f"Slice {slice_id} not in WIM {target_wim_id}") else: mongoUtils.update("wim", target_wim["_id"], target_wim) else: err = "Cannot find WIM - WAN Slice will not be deleted" logger.warning(err) slice_json["status"] = "Error" slice_json["error"] = slice_json.get("error", "") + err mongoUtils.update("slice", slice_json["_id"], slice_json) else: logger.info("There was no WIM configuration") # *** Step-3: Cloud *** vim_error_list = [] try: total_ns_list = slice_json["total_ns_list"] ns_inst_info = slice_json["ns_inst_info"] for ns in total_ns_list: if ns["nsd-id"] not in slice_json["conf_comp"]["nf"]: logger.error(f"{ns['nsd-id']} was not instantiated successfully") continue # Get the NFVO nfvo_id = ns["nfvo-id"] target_nfvo = mongoUtils.find("nfvo", {"id": ns["nfvo-id"]}) if not target_nfvo: logger.warning( "NFVO with id {} was not found - NSs won't terminate".format(nfvo_id) ) vim_error_list += ns["vims"] continue target_nfvo_obj = pickle.loads( mongoUtils.find("nfvo_obj", {"id": ns["nfvo-id"]})["obj"] ) # Stop the NS nfvo_inst_ns = ns_inst_info[ns["ns-id"]][ns["placement_loc"]["location"]][ "nfvo_inst_ns" ] target_nfvo_obj.deleteNs(nfvo_inst_ns) while True: if target_nfvo_obj.checkNsLife(nfvo_inst_ns): break time.sleep(5) except KeyError as e: err = f"Error, not all NSs started or terminated correctly {e}" logger.warning(err) slice_json["status"] = "Error" slice_json["error"] = slice_json.get("error", "") + err mongoUtils.update("slice", slice_json["_id"], slice_json) vim_dict = slice_json["vim_list"] for vim, vim_info in vim_dict.items(): try: # Delete the new tenants from the NFVO for nfvo, vim_account in vim_info["nfvo_vim_account"].items(): # Get the NFVO target_nfvo = mongoUtils.find("nfvo", {"id": nfvo}) target_nfvo_obj = pickle.loads(mongoUtils.find("nfvo_obj", {"id": nfvo})["obj"]) # Delete the VIM and update nfvo db target_nfvo_obj.deleteVim(vim_account) target_nfvo["tenants"][slice_json["_id"]].remove(vim_account) if len(target_nfvo["tenants"][slice_json["_id"]]) == 0: try: del target_nfvo["tenants"][slice_json["_id"]] except KeyError: logger.warning(f"Slice {slice_id} not in NFO {nfvo}") else: mongoUtils.update("nfvo", target_nfvo["_id"], target_nfvo) # Delete the tenants from every vim if vim not in vim_error_list: # Get the VIM target_vim = mongoUtils.find("vim", {"id": vim}) if not target_vim: logger.warning("VIM id {} was not found - Tenant won't be deleted".format(vim)) continue target_vim_obj = pickle.loads(mongoUtils.find("vim_obj", {"id": vim})["obj"]) target_vim_obj.delete_proj_user(target_vim["tenants"][slice_json["_id"]]) try: del target_vim["tenants"][slice_json["_id"]] except KeyError: logger.warning(f"Slice {slice_id} not in VIM {vim}") else: mongoUtils.update("vim", target_vim["_id"], target_vim) except KeyError as e: err = f"Error, not all tenants created or removed correctly {e}" logger.warning(err) slice_json["status"] = "Error" slice_json["error"] = slice_json.get("error", "") + err mongoUtils.update("slice", slice_json["_id"], slice_json) if "error" not in slice_json: mongoUtils.delete("slice", slice_json["_id"]) elif "error" in slice_json and force: mongoUtils.delete("slice", slice_json["_id"]) # Remove Slice from the tenants list on functions for func_id in slice_json["functions"]: ifunc = mongoUtils.get("func", func_id) try: ifunc["tenants"].remove(slice_json["_id"]) except (KeyError, ValueError): logger.warning(f"Slice {slice_id} not in function {func_id}") else: mongoUtils.update("func", func_id, ifunc)
def add_slice(nest_req): """ Creates the network slice """ # Recreate the NEST with None options where missiong nest = { "_id": nest_req["_id"], "status": "Init", "created_at": time.time(), # unix epoch "deployment_time": { "Placement_Time": None, "Provisioning_Time": None, "WAN_Deployment_Time": None, "NS_Deployment_Time": None, "Radio_Configuration_Time": None, "Slice_Deployment_Time": None, }, } mongoUtils.add("slice", nest) for nest_key in NEST_KEYS_OBJ: nest[nest_key] = nest_req.get(nest_key, None) for nest_key in NEST_KEYS_LIST: nest[nest_key] = nest_req.get(nest_key, []) # **** STEP-1: Placement **** nest["status"] = "Placement" nest["conf_comp"] = {"nf": [], "ems": []} mongoUtils.update("slice", nest["_id"], nest) logger.info(f"{nest['_id']} Status: Placement") placement_start_time = time.time() # Initiate the lists vim_dict = {} total_ns_list = [] ems_messages = {} # Get Details for the Network Services # i) The extra NS of the slice for location in nest["coverage"]: err, _ = ns_details(nest["ns_list"], location, vim_dict, total_ns_list) if err: delete_slice(nest) return del nest["ns_list"] nest["ns_list"] = copy.deepcopy(total_ns_list) # ii) The NS part of the core slice inst_functions = {} for connection in nest["connections"]: for key in connection: if connection[key]["_id"] in inst_functions: connection[key] = inst_functions[connection[key]["_id"]] continue try: err, pop_list = ns_details( connection[key]["ns_list"], connection[key]["location"], vim_dict, total_ns_list ) if pop_list: connection[key]["ns_list"] = [ x for x in connection[key]["ns_list"] if x not in pop_list ] if err: delete_slice(nest) return inst_functions[connection[key]["_id"]] = connection[key] except KeyError: continue nest["vim_list"] = vim_dict nest["total_ns_list"] = total_ns_list nest["deployment_time"]["Placement_Time"] = format(time.time() - placement_start_time, ".4f") # **** STEP-2: Resource Provisioning **** nest["status"] = "Provisioning" mongoUtils.update("slice", nest["_id"], nest) logger.info(f"{nest['_id']} Status: Provisioning") prov_start_time = time.time() # *** STEP-2a: Cloud *** # *** STEP-2a-i: Create the new tenant/project on the VIM *** for num, (vim, vim_info) in enumerate(vim_dict.items()): target_vim = mongoUtils.find("vim", {"id": vim}) target_vim_obj = pickle.loads(mongoUtils.find("vim_obj", {"id": vim})["obj"]) # Define project parameters tenant_project_name = "vim_{0}_katana_{1}".format(num, nest["_id"]) tenant_project_description = "vim_{0}_katana_{1}".format(num, nest["_id"]) tenant_project_user = "******".format(num, nest["_id"]) tenant_project_password = "******" # If the vim is Openstack type, set quotas quotas = ( vim_info["resources"] if target_vim["type"] == "openstack" or target_vim["type"] == "Openstack" else None ) ids = target_vim_obj.create_slice_prerequisites( tenant_project_name, tenant_project_description, tenant_project_user, tenant_project_password, nest["_id"], quotas=quotas, ) # Register the tenant to the mongo db target_vim["tenants"][nest["_id"]] = tenant_project_name mongoUtils.update("vim", target_vim["_id"], target_vim) # STEP-2a-ii: Αdd the new VIM tenant to NFVO if target_vim["type"] == "openstack": # Update the config parameter for the tenant config_param = dict(security_groups=ids["secGroupName"]) elif target_vim["type"] == "opennebula": config_param = target_vim["config"] else: config_param = {} for nfvo_id in vim_info["nfvo_list"]: target_nfvo = mongoUtils.find("nfvo", {"id": nfvo_id}) target_nfvo_obj = pickle.loads(mongoUtils.find("nfvo_obj", {"id": nfvo_id})["obj"]) vim_id = target_nfvo_obj.addVim( tenant_project_name, target_vim["password"], target_vim["type"], target_vim["auth_url"], target_vim["username"], config_param, ) vim_info["nfvo_vim_account"] = vim_info.get("nfvo_vim_account", {}) vim_info["nfvo_vim_account"][nfvo_id] = vim_id # Register the tenant to the mongo db target_nfvo["tenants"][nest["_id"]] = target_nfvo["tenants"].get(nest["_id"], []) target_nfvo["tenants"][nest["_id"]].append(vim_id) mongoUtils.update("nfvo", target_nfvo["_id"], target_nfvo) mongoUtils.update("slice", nest["_id"], nest) # *** STEP-2b: WAN *** if mongoUtils.count("wim") <= 0: logger.warning("There is no registered WIM") else: wan_start_time = time.time() # Crate the data for the WIM wim_data = {"_id": nest["_id"], "core_connections": [], "extra_ns": [], "slice_sla": {}} # i) Create the slice_sla data for the WIM wim_data["slice_sla"] = { "network_DL_throughput": nest["network_DL_throughput"], "network_UL_throughput": nest["network_UL_throughput"], "mtu": nest["mtu"], } # ii) Add the connections for connection in nest["connections"]: data = {} for key in connection: key_data = {} try: ns_l = connection[key]["ns_list"] except KeyError: pass else: key_data["ns"] = [] for ns in ns_l: if ns["placement_loc"] not in key_data["ns"]: key_data["ns"].append(ns["placement_loc"]) try: pnf_l = connection[key]["pnf_list"] except KeyError: pass else: key_data["pnf"] = pnf_l if key_data: data[key] = key_data if data: wim_data["core_connections"].append(data) # iii) Add the extra Network Services for ns in nest["ns_list"]: if ns["placement_loc"] not in wim_data["extra_ns"]: wim_data["extra_ns"].append(ns["placement_loc"]) # iV) Add the probes wim_data["probes"] = nest["probe_list"] # Select WIM - Assume that there is only one registered wim_list = list(mongoUtils.index("wim")) target_wim = wim_list[0] target_wim_id = target_wim["id"] target_wim_obj = pickle.loads(mongoUtils.find("wim_obj", {"id": target_wim_id})["obj"]) target_wim_obj.create_slice(wim_data) nest["wim_data"] = wim_data target_wim["slices"][nest["_id"]] = nest["_id"] mongoUtils.update("wim", target_wim["_id"], target_wim) nest["deployment_time"]["WAN_Deployment_Time"] = format(time.time() - wan_start_time, ".4f") nest["deployment_time"]["Provisioning_Time"] = format(time.time() - prov_start_time, ".4f") # **** STEP-3: Slice Activation Phase**** nest["status"] = "Activation" mongoUtils.update("slice", nest["_id"], nest) logger.info(f"{nest['_id']} Status: Activation") # *** STEP-3a: Cloud *** # Instantiate NS # Store info about instantiated NSs ns_inst_info = {} nest["deployment_time"]["NS_Deployment_Time"] = {} for ns in total_ns_list: ns["start_time"] = time.time() ns_inst_info[ns["ns-id"]] = {} target_nfvo = mongoUtils.find("nfvo", {"id": ns["nfvo-id"]}) target_nfvo_obj = pickle.loads(mongoUtils.find("nfvo_obj", {"id": ns["nfvo-id"]})["obj"]) selected_vim = ns["placement_loc"]["vim"] nfvo_vim_account = vim_dict[selected_vim]["nfvo_vim_account"][ns["nfvo-id"]] nfvo_inst_ns = target_nfvo_obj.instantiateNs(ns["ns-name"], ns["nsd-id"], nfvo_vim_account) ns_inst_info[ns["ns-id"]][ns["placement_loc"]["location"]] = {"nfvo_inst_ns": nfvo_inst_ns} nest["conf_comp"]["nf"].append(ns["nsd-id"]) time.sleep(4) time.sleep(2) # Get the nsr for each service and wait for the activation for ns in total_ns_list: target_nfvo = mongoUtils.find("nfvo", {"id": ns["nfvo-id"]}) target_nfvo_obj = pickle.loads(mongoUtils.find("nfvo_obj", {"id": ns["nfvo-id"]})["obj"]) site = ns["placement_loc"] nfvo_inst_ns_id = ns_inst_info[ns["ns-id"]][site["location"]]["nfvo_inst_ns"] insr = target_nfvo_obj.getNsr(nfvo_inst_ns_id) while insr["operational-status"] != "running" or insr["config-status"] != "configured": time.sleep(10) insr = target_nfvo_obj.getNsr(nfvo_inst_ns_id) nest["deployment_time"]["NS_Deployment_Time"][ns["ns-name"]] = format( time.time() - ns["start_time"], ".4f" ) # Get the IPs of the instantiated NS vnf_list = [] vnfr_id_list = target_nfvo_obj.getVnfrId(insr) for ivnfr_id in vnfr_id_list: vnfr = target_nfvo_obj.getVnfr(ivnfr_id) vnf_list.append(target_nfvo_obj.getIPs(vnfr)) ns_inst_info[ns["ns-id"]][site["location"]]["vnfr"] = vnf_list nest["ns_inst_info"] = ns_inst_info mongoUtils.update("slice", nest["_id"], nest) # *** STEP-3b: Radio Slice Configuration *** if mongoUtils.count("ems") <= 0: logger.warning("There is no registered EMS") else: # Add the management IPs for the NS sent ems in ems_messages: ems_radio_data = { "ue_DL_throughput": nest["ue_DL_throughput"], "ue_UL_throughput": nest["ue_UL_throughput"], "group_communication_support": nest["group_communication_support"], "number_of_terminals": nest["number_of_terminals"], "positional_support": nest["positional_support"], "radio_spectrum": nest["radio_spectrum"], "device_velocity": nest["device_velocity"], "terminal_density": nest["terminal_density"], } radio_start_time = time.time() for connection in nest["connections"]: data = {} ems_id_list = [] for key in connection: key_data = {} try: ems_id = connection[key]["ems-id"] except KeyError: continue else: if ems_id not in ems_id_list: ems_id_list.append(ems_id) try: ns_l = connection[key]["ns_list"] except KeyError: pass else: key_data["ns"] = [] for ns in ns_l: try: ns_info = ns_inst_info[ns["ns-id"]][connection[key]["location"]] except KeyError: ns_info = ns_inst_info[ns["ns-id"]]["Core"] ns_data = { "name": ns["ns-name"], "location": ns["placement_loc"]["location"], "vnf_list": ns_info["vnfr"], } key_data["ns"].append(ns_data) try: key_data["pnf"] = connection[key]["pnf_list"] except KeyError: pass if key_data: data[key] = key_data if data: data["slice_sla"] = ems_radio_data data["slice_id"] = nest["_id"] for ems_id in ems_id_list: messages = ems_messages.get(ems_id, []) messages.append(data) ems_messages[ems_id] = messages for ems_id, ems_message in ems_messages.items(): # Find the EMS target_ems = mongoUtils.find("ems", {"id": ems_id}) if not target_ems: # Error handling: There is no such EMS logger.error("EMS {} not found - No configuration".format(ems_id)) continue target_ems_obj = pickle.loads(mongoUtils.find("ems_obj", {"id": ems_id})["obj"]) # Send the message for imessage in ems_message: target_ems_obj.conf_radio(imessage) nest["conf_comp"]["ems"].append(ems_id) nest["ems_data"] = ems_messages nest["deployment_time"]["Radio_Configuration_Time"] = format( time.time() - radio_start_time, ".4f" ) # *** STEP-4: Finalize *** logger.info(f"{nest['_id']} Status: Running") nest["status"] = "Running" nest["deployment_time"]["Slice_Deployment_Time"] = format( time.time() - nest["created_at"], ".4f" ) mongoUtils.update("slice", nest["_id"], nest)
def nest_mapping(req): """ Function that maps nest to the underlying network functions """ # Store the gst in DB mongoUtils.add("gst", req) nest = {"_id": req["_id"]} # Recreate the nest req # Check if the base_slice_des_ref or the required fields are set base_slice_des_ref = req["base_slice_descriptor"].get("base_slice_des_ref", None) if not base_slice_des_ref: for req_key in REQ_FIELDS: if req_key not in req["base_slice_descriptor"]: logger.error("Required field base_slice_descriptor.{} is missing".format(req_key)) return ( "Error: Required field base_slice_descriptor.{} is missing".format(req_key), 400, ) for field in NEST_FIELDS: req[field] = req.get(field, None) # ****** STEP 1: Slice Descriptor ****** if not req["base_slice_descriptor"]: logger.error("No Base Slice Descriptor given - Exit") return "NEST Error: No Base Slice Descriptor given", 400 req_slice_des = req["base_slice_descriptor"] # *** Recreate the NEST *** for req_key in SLICE_DES_OBJ: req_slice_des[req_key] = req_slice_des.get(req_key, None) for req_key in SLICE_DES_LIST: req_slice_des[req_key] = req_slice_des.get(req_key, []) # *** Check if there are references for slice *** if req_slice_des["base_slice_des_ref"]: ref_slice = mongoUtils.find( "base_slice_des_ref", {"base_slice_des_id": req_slice_des["base_slice_des_ref"]} ) if ref_slice: for key, value in req_slice_des.items(): try: if value is None or value == []: req_slice_des[key] = ref_slice[key] except KeyError: continue else: logger.error( "slice_descriptor {} not found".format(req_slice_des["base_slice_des_ref"]) ) return "Error: referenced slice_descriptor not found", 400 # Create the shared value nest["shared"] = { "isolation": req_slice_des["isolation"], "simultaneous_nsi": req_slice_des["simultaneous_nsi"], } # Check that the location in coverage field is registered not_supp_loc = [] for location_id in req_slice_des["coverage"]: if not mongoUtils.find("location", {"id": location_id.lower()}): not_supp_loc.append(location_id) logger.warning(f"Location {location_id} is not registered") for location_id in not_supp_loc: req_slice_des["coverage"].remove(location_id) # *************************** Start the mapping *************************** # Currently supports: # 1) If delay_tolerance --> EMBB else --> URLLC # If EMBB --> EPC Placement=@Core. If URLLC --> EPC Placement=@Edge # 2) If network throughput > 100 Mbps --> Type=5G # ************************************************************************* functions_list = [] if req_slice_des["network_DL_throughput"]["guaranteed"] > 100000: gen = 5 else: gen = 4 # *** Calculate the type of the slice (sst) *** if req_slice_des["delay_tolerance"]: # EMBB nest["sst"] = 1 # Find the registered function for Core Function epc = mongoUtils.find("func", calc_find_data(gen, "core", 0)) if not epc: return "Error: Not available Core Network Functions", 400 # Check if the nest allows shareable functions, if the function is shareable if ( req_slice_des["isolation"] != 1 and req_slice_des["isolation"] != 3 and epc["shared"]["availability"] ): found_list_key = None max_len = epc["shared"].get("max_shared", 0) for grouped_nest_key, grouped_nest_list in epc["shared"]["sharing_list"].items(): if len(grouped_nest_list) < max_len or not max_len: found_list_key = grouped_nest_key grouped_nest_list.append(nest["_id"]) sharing_list = mongoUtils.get("sharing_lists", found_list_key) sharing_list["nest_list"].append(nest["_id"]) mongoUtils.update("sharing_lists", found_list_key, sharing_list) break if not found_list_key: found_list_key = str(uuid.uuid4()) epc["shared"]["sharing_list"][found_list_key] = [nest["_id"]] data = { "_id": found_list_key, "nest_list": [nest["_id"]], "ns_list": {}, } mongoUtils.add("sharing_lists", data) nest["shared"]["core"] = {epc["_id"]: found_list_key} connections = [] not_supp_loc = [] for location in req_slice_des["coverage"]: enb = mongoUtils.find("func", calc_find_data(gen, location.lower(), 1)) if not enb: not_supp_loc.append(location) else: # Check if the nest allows shareable functions, if the function is shareable if req_slice_des["isolation"] < 2 and enb["shared"]["availability"]: found_list_key = None max_len = enb["shared"].get("max_shared", 0) for grouped_nest_key, grouped_nest_list in enb["shared"][ "sharing_list" ].items(): if len(grouped_nest_list) < max_len or not max_len: found_list_key = grouped_nest_key grouped_nest_list.append(nest["_id"]) sharing_list = mongoUtils.get("sharing_lists", found_list_key) sharing_list["nest_list"].append(nest["_id"]) mongoUtils.update("sharing_lists", found_list_key, sharing_list) break if not found_list_key: found_list_key = str(uuid.uuid4()) enb["shared"]["sharing_list"][found_list_key] = [nest["_id"]] data = { "_id": found_list_key, "nest_list": [nest["_id"]], "ns_list": {}, } mongoUtils.add("sharing_lists", data) nest["shared"]["radio"] = nest["shared"].get("radio", {}) nest["shared"]["radio"][enb["_id"]] = found_list_key connections.append({"core": epc, "radio": enb}) enb["tenants"].append(nest["_id"]) mongoUtils.update("func", enb["_id"], enb) functions_list.append(enb["_id"]) if not epc or not connections: return "Error: Not available Network Functions", 400 epc["tenants"].append(nest["_id"]) mongoUtils.update("func", epc["_id"], epc) functions_list.append(epc["_id"]) for location in not_supp_loc: logger.warning(f"Location {location} not supported") req_slice_des["coverage"].remove(location) else: # URLLC nest["sst"] = 2 connections = [] not_supp_loc = [] for location in req_slice_des["coverage"]: epc = mongoUtils.find("func", calc_find_data(gen, location.lower(), 0)) enb = mongoUtils.find("func", calc_find_data(gen, location.lower(), 1)) if not epc or not enb: not_supp_loc.append(location) else: # Check if the nest allows shareable functions, if the function is shareable # For the Core function if ( req_slice_des["isolation"] != 1 and req_slice_des["isolation"] != 3 and epc["shared"]["availability"] ): found_list_key = None max_len = epc["shared"].get("max_shared", 0) for grouped_nest_key, grouped_nest_list in epc["shared"][ "sharing_list" ].items(): if len(grouped_nest_list) < max_len or not max_len: found_list_key = grouped_nest_key grouped_nest_list.append(nest["_id"]) sharing_list = mongoUtils.get("sharing_lists", found_list_key) sharing_list["nest_list"].append(nest["_id"]) mongoUtils.update("sharing_lists", found_list_key, sharing_list) break if not found_list_key: found_list_key = str(uuid.uuid4()) epc["shared"]["sharing_list"][found_list_key] = [nest["_id"]] data = { "_id": found_list_key, "nest_list": [nest["_id"]], "ns_list": {}, } mongoUtils.add("sharing_lists", data) nest["shared"]["core"] = nest["shared"].get("core", {}) nest["shared"]["core"][epc["_id"]] = found_list_key # For the RAN function if req_slice_des["isolation"] < 2 and enb["shared"]["availability"]: found_list_key = None max_len = enb["shared"].get("max_shared", 0) for grouped_nest_key, grouped_nest_list in enb["shared"][ "sharing_list" ].items(): if len(grouped_nest_list) < max_len or not max_len: found_list_key = grouped_nest_key grouped_nest_list.append(nest["_id"]) sharing_list = mongoUtils.get("sharing_lists", found_list_key) sharing_list["nest_list"].append(nest["_id"]) mongoUtils.update("sharing_lists", found_list_key, sharing_list) break if not found_list_key: found_list_key = str(uuid.uuid4()) enb["shared"]["sharing_list"][found_list_key] = [nest["_id"]] data = { "_id": found_list_key, "nest_list": [nest["_id"]], "ns_list": {}, } mongoUtils.add("sharing_lists", data) nest["shared"]["radio"] = nest["shared"].get("radio", {}) nest["shared"]["radio"][enb["_id"]] = found_list_key connections.append({"core": epc, "radio": enb}) epc["tenants"].append(nest["_id"]) enb["tenants"].append(nest["_id"]) mongoUtils.update("func", enb["_id"], enb) mongoUtils.update("func", epc["_id"], epc) functions_list.extend([epc["_id"], enb["_id"]]) if not connections: return "Error: Not available Network Functions", 400 for location in not_supp_loc: logger.warning(f"Location {location} not supported") req_slice_des["coverage"].remove(location) nest["connections"] = connections nest["functions"] = functions_list # Values to be copied to NEST KEYS_TO_BE_COPIED = ( "network_DL_throughput", "ue_DL_throughput", "network_UL_throughput", "ue_UL_throughput", "group_communication_support", "mtu", "number_of_terminals", "positional_support", "radio_spectrum", "device_velocity", "terminal_density", "coverage", ) for key in KEYS_TO_BE_COPIED: nest[key] = req_slice_des[key] # Add slice_name to NEST based on the base_slice_des id nest["slice_name"] = req_slice_des["base_slice_des_id"] # ****** STEP 2: Service Descriptor ****** if req["service_descriptor"]: req_service_des = req["service_descriptor"] # *** Recreate the NEST *** for req_key in SERVICE_DES_OBJ: req_service_des[req_key] = req_service_des.get(req_key, None) for req_key in SERVICE_DES_LIST: req_service_des[req_key] = req_service_des.get(req_key, []) # Create the NS field on Nest nest["ns_list"] = req_service_des["ns_list"] # # Replace Placement with location in each NS # for ns in nest["ns_list"]: # ns["placement"] = ( # lambda x: {"location": ["Core"]} if not x else # {"location": req_slice_des["coverage"]})(ns["placement"]) # ****** STEP 3: Test Descriptor ****** if req["test_descriptor"]: req_test_des = req["test_descriptor"] # *** Recreate the NEST *** for req_key in TEST_DES_OBJ: req_test_des[req_key] = req_test_des.get(req_key, None) for req_key in TEST_DES_LIST: req_test_des[req_key] = req_test_des.get(req_key, []) # Create the Probe field on Nest nest["probe_list"] = req_test_des["probe_list"] if ( not mongoUtils.find( "base_slice_des_ref", {"base_slice_des_id": req["base_slice_descriptor"]["base_slice_des_id"]}, ) and req["base_slice_descriptor"]["base_slice_des_id"] ): new_uuid = str(uuid.uuid4()) req["base_slice_descriptor"]["_id"] = new_uuid mongoUtils.add("base_slice_des_ref", req["base_slice_descriptor"]) return nest, 0
def ns_details(ns_list, edge_loc, vim_dict, total_ns_list): """ Get details for the NS that are part of the slice A) Find the nsd details for each NS B) Replace placement value with location C) Get the VIM for each NS """ pop_list = [] for ns in ns_list: try: if ns["placement_loc"] and not ns["placement"]: # Placement to Core already done - go to next NS continue else: # Placement to Edge - Is already done - Need to make another ns new_ns = copy.deepcopy(ns) except KeyError: # No placement at all new_ns = ns # A) ****** Get the NSD ****** # Search the nsd collection in Mongo for the nsd nsd = mongoUtils.find("nsd", { "nsd-id": new_ns["nsd-id"], "nfvo_id": new_ns["nfvo-id"] }) if not nsd: # Bootstrap the NFVO to check for NSDs that are not in mongo # If again is not found, check if NS is optional. # If it is just remove it, else error nfvo_obj_json = mongoUtils.find("nfvo_obj", {"id": new_ns["nfvo-id"]}) if not nfvo_obj_json: # Error handling: There is no OSM for that ns - # Stop and return logger.error("There is no NFVO with id {}".format( new_ns["nfvo-id"])) return 1, [] nfvo = pickle.loads(nfvo_obj_json["obj"]) nfvo.bootstrapNfvo() nsd = mongoUtils.find("nsd", { "nsd-id": new_ns["nsd-id"], "nfvo_id": new_ns["nfvo-id"] }) if not nsd and ns.get("optional", False): pop_list.append(ns) continue else: # Error handling: The ns is not optional and the nsd is not # on the NFVO - stop and return logger.error( f"NSD {new_ns['nsd-id']} not found on OSM {new_ns['nfvo-id']}" ) return 1, [] new_ns["nsd-info"] = nsd # B) ****** Replace placement value with location info ****** new_ns["placement_loc"] = (lambda x: { "location": "Core" } if not x else { "location": edge_loc })(new_ns["placement"]) # C) ****** Get the VIM info ****** new_ns["vims"] = [] loc = new_ns["placement_loc"]["location"] get_vim = list(mongoUtils.find_all("vim", {"location": loc})) if not get_vim: # Error handling: There is no VIM at that location logger.error(f"VIM not found in location {loc}") return 1, [] # TODO: Check the available resources and select vim # Temporary use the first element selected_vim = get_vim[0]["id"] new_ns["vims"].append(selected_vim) try: vim_dict[selected_vim]["ns_list"].append(new_ns["ns-name"]) if new_ns["nfvo-id"] not in vim_dict[selected_vim]["nfvo_list"]: vim_dict[selected_vim]["nfvo_list"].append(new_ns["nfvo-id"]) except KeyError: vim_dict[selected_vim] = { "ns_list": [new_ns["ns-name"]], "nfvo_list": [new_ns["nfvo-id"]], } resources = vim_dict[selected_vim].get("resources", { "memory-mb": 0, "vcpu-count": 0, "storage-gb": 0, "instances": 0 }) for key in resources: resources[key] += nsd["flavor"][key] vim_dict[selected_vim]["resources"] = resources new_ns["placement_loc"]["vim"] = selected_vim # 0) Create an uuid for the ns new_ns["ns-id"] = str(uuid.uuid4()) total_ns_list.append(new_ns) del new_ns # Remove the ns that are optional and nsd was not found ns_list = [ns for ns in ns_list if ns not in pop_list] return 0, pop_list
def nest_mapping(req): """ Function that maps nest to the underlying network functions """ # Store the gst in DB mongoUtils.add("gst", req) nest = {"_id": req["_id"]} # Recreate the nest req for field in NEST_FIELDS: req[field] = req.get(field, None) # ****** STEP 1: Slice Descriptor ****** if not req["base_slice_descriptor"]: logger.error("No Base Slice Descriptor given - Exit") return "NEST Error: No Base Slice Descriptor given", 400 req_slice_des = req["base_slice_descriptor"] # *** Recreate the NEST *** for req_key in SLICE_DES_OBJ: req_slice_des[req_key] = req_slice_des.get(req_key, None) for req_key in SLICE_DES_LIST: req_slice_des[req_key] = req_slice_des.get(req_key, []) # *** Check if there are references for slice *** if req_slice_des["base_slice_des_ref"]: ref_slice = mongoUtils.find( "base_slice_des_ref", {"base_slice_des_id": req_slice_des["base_slice_des_ref"]} ) if ref_slice: for key, value in req_slice_des.items(): try: if value is None: req_slice_des[key] = ref_slice[key] except KeyError: continue else: logger.error( "slice_descriptor {} not found".format(req_slice_des["base_slice_des_ref"]) ) return "Error: referenced slice_descriptor not found", 400 # *************************** Start the mapping *************************** # Currently supports: # 1) If delay_tolerance --> EMBB else --> URLLC # If EMBB --> EPC Placement=@Core. If URLLC --> EPC Placement=@Edge # 2) If network throughput > 100 Mbps --> Type=5G # ************************************************************************* functions_list = [] if req_slice_des["network_DL_throughput"]["guaranteed"] > 100000: gen = 5 else: gen = 4 # *** Calculate the type of the slice (sst) *** if req_slice_des["delay_tolerance"]: # EMBB nest["sst"] = 1 epc = mongoUtils.find("func", calc_find_data(gen, "Core", 0)) if not epc: return "Error: Not available Core Network Functions", 400 connections = [] not_supp_loc = [] for location in req_slice_des["coverage"]: enb = mongoUtils.find("func", calc_find_data(gen, location, 1)) if not enb: not_supp_loc.append(location) else: connections.append({"core": epc, "radio": enb}) enb["tenants"].append(nest["_id"]) mongoUtils.update("func", enb["_id"], enb) functions_list.append(enb["_id"]) if not epc or not connections: return "Error: Not available Network Functions", 400 epc["tenants"].append(nest["_id"]) mongoUtils.update("func", epc["_id"], epc) functions_list.append(epc["_id"]) for location in not_supp_loc: logger.warning(f"Location {location} not supported") req_slice_des["coverage"].remove(location) else: # URLLC nest["sst"] = 2 connections = [] not_supp_loc = [] for location in req_slice_des["coverage"]: epc = mongoUtils.find("func", calc_find_data(gen, location, 0)) enb = mongoUtils.find("func", calc_find_data(gen, location, 1)) if not epc or not enb: not_supp_loc.append(location) else: connections.append({"core": epc, "radio": enb}) epc["tenants"].append(nest["_id"]) enb["tenants"].append(nest["_id"]) mongoUtils.update("func", enb["_id"], enb) mongoUtils.update("func", epc["_id"], epc) functions_list.extend([epc["_id"], enb["_id"]]) if not connections: return "Error: Not available Network Functions", 400 for location in not_supp_loc: logger.warning(f"Location {location} not supported") req_slice_des["coverage"].remove(location) nest["connections"] = connections nest["functions"] = functions_list # Values to be copied to NEST KEYS_TO_BE_COPIED = ( "network_DL_throughput", "ue_DL_throughput", "network_UL_throughput", "ue_UL_throughput", "group_communication_support", "mtu", "number_of_terminals", "positional_support", "radio_spectrum", "device_velocity", "terminal_density", "coverage", ) for key in KEYS_TO_BE_COPIED: nest[key] = req_slice_des[key] # Create the shared value nest["shared"] = { "isolation": req_slice_des["isolation_level"], "simultaneous_nsi": req_slice_des["simultaneous_nsi"], } # ****** STEP 2: Service Descriptor ****** if req["service_descriptor"]: req_service_des = req["service_descriptor"] # *** Recreate the NEST *** for req_key in SERVICE_DES_OBJ: req_service_des[req_key] = req_service_des.get(req_key, None) for req_key in SERVICE_DES_LIST: req_service_des[req_key] = req_service_des.get(req_key, []) # Create the NS field on Nest nest["ns_list"] = req_service_des["ns_list"] # # Replace Placement with location in each NS # for ns in nest["ns_list"]: # ns["placement"] = ( # lambda x: {"location": ["Core"]} if not x else # {"location": req_slice_des["coverage"]})(ns["placement"]) # ****** STEP 3: Service Descriptor ****** if req["test_descriptor"]: req_test_des = req["test_descriptor"] # *** Recreate the NEST *** for req_key in TEST_DES_OBJ: req_test_des[req_key] = req_test_des.get(req_key, None) for req_key in TEST_DES_LIST: req_test_des[req_key] = req_test_des.get(req_key, []) # Create the Probe field on Nest nest["probe_list"] = req_test_des["probe_list"] if not mongoUtils.find( "base_slice_des_ref", {"base_slice_des_id": req["base_slice_descriptor"]["base_slice_des_id"]}, ): new_uuid = str(uuid.uuid4()) req["base_slice_descriptor"]["_id"] = new_uuid mongoUtils.add("base_slice_des_ref", req["base_slice_descriptor"]) return nest, 0
def post(self): """ Add a new vim. The request must provide the vim details. used by: `katana vim add -f [file]` """ new_uuid = str(uuid.uuid4()) request.json["_id"] = new_uuid request.json["created_at"] = time.time() # unix epoch request.json["tenants"] = {} # Check the required fields try: username = request.json["username"] password = request.json["password"] auth_url = request.json["auth_url"] project_name = request.json["admin_project_name"] location_id = request.json["location"].lower() request.json["location"] = location_id vim_id = request.json["id"] except KeyError: return f"Error: Required fields: {self.req_fields}", 400 # Check that the VIM location is registered location = mongoUtils.find("location", {"id": location_id}) if not location: return f"Location {location_id} is not registered. Please add the location first", 400 location["vims"].append(vim_id) # Type of OpenStack if request.json["type"] == "openstack": try: new_vim = openstackUtils.Openstack( uuid=new_uuid, auth_url=auth_url, project_name=project_name, username=username, password=password, ) if new_vim.auth_error: raise (AttributeError) except AttributeError: return "Error: VIM Error", 400 else: request.json["resources"] = new_vim.get_resources() thebytes = pickle.dumps(new_vim) obj_json = {"_id": new_uuid, "id": request.json["id"], "obj": Binary(thebytes)} try: vim_monitoring = request.json["infrastructure_monitoring"] except KeyError: pass else: with open("/targets/vim_targets.json", mode="r") as prom_file: prom = json.load(prom_file) prom.append({"targets": [vim_monitoring], "labels": {}}) with open("/targets/vim_targets.json", mode="w") as prom_file: json.dump(prom, prom_file) # Type of OpenNebula elif request.json["type"] == "opennebula": try: new_vim = opennebulaUtils.Opennebula( uuid=new_uuid, auth_url=auth_url, project_name=project_name, username=username, password=password, ) except AttributeError: return "Error: VIM Error", 400 else: request.json["resources"] = {"N/A": "N/A"} thebytes = pickle.dumps(new_vim) obj_json = {"_id": new_uuid, "id": request.json["id"], "obj": Binary(thebytes)} else: response = dumps({"error": "This type VIM is not supported"}) return response, 400 try: new_uuid = mongoUtils.add("vim", request.json) except pymongo.errors.DuplicateKeyError: return f"VIM with id {vim_id} already exists", 400 mongoUtils.add("vim_obj", obj_json) if location: mongoUtils.update("location", location["_id"], location) return new_uuid, 201