Example #1
0
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)
Example #2
0
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)