+ additional_params, vdu_params = self._format_additional_params(
+ ns_request, vnf_index, vdu_id=vdu["id"], descriptor=vnfd
+ )
+
+ try:
+ vdu_virtual_storage_descriptors = utils.filter_in_list(
+ vnfd.get("virtual-storage-desc", []),
+ lambda stg_desc: stg_desc["id"] in vdu["virtual-storage-desc"],
+ )
+ except Exception:
+ vdu_virtual_storage_descriptors = []
+ vdur = {
+ "vdu-id-ref": vdu["id"],
+ # TODO "name": "" Name of the VDU in the VIM
+ "ip-address": None, # mgmt-interface filled by LCM
+ # "vim-id", "flavor-id", "image-id", "management-ip" # filled by LCM
+ "internal-connection-point": [],
+ "interfaces": [],
+ "additionalParams": additional_params,
+ "vdu-name": vdu["name"],
+ "virtual-storages": vdu_virtual_storage_descriptors,
+ }
+ if vdu_params and vdu_params.get("config-units"):
+ vdur["config-units"] = vdu_params["config-units"]
+ if deep_get(vdu, ("supplemental-boot-data", "boot-data-drive")):
+ vdur["boot-data-drive"] = vdu["supplemental-boot-data"][
+ "boot-data-drive"
+ ]
+ if vdu.get("pdu-type"):
+ vdur["pdu-type"] = vdu["pdu-type"]
+ vdur["name"] = vdu["pdu-type"]
+ # TODO volumes: name, volume-id
+ for icp in vdu.get("int-cpd", ()):
+ vdu_icp = {
+ "id": icp["id"],
+ "connection-point-id": icp["id"],
+ "name": icp.get("id"),
+ }
+
+ vdur["internal-connection-point"].append(vdu_icp)
+
+ for iface in icp.get("virtual-network-interface-requirement", ()):
+ # Name, mac-address and interface position is taken from VNFD
+ # and included into VNFR. By this way RO can process this information
+ # while creating the VDU.
+ iface_fields = ("name", "mac-address", "position", "ip-address")
+ vdu_iface = {
+ x: iface[x] for x in iface_fields if iface.get(x) is not None
+ }
+
+ vdu_iface["internal-connection-point-ref"] = vdu_icp["id"]
+ if "port-security-enabled" in icp:
+ vdu_iface["port-security-enabled"] = icp[
+ "port-security-enabled"
+ ]
+
+ if "port-security-disable-strategy" in icp:
+ vdu_iface["port-security-disable-strategy"] = icp[
+ "port-security-disable-strategy"
+ ]
+
+ for ext_cp in vnfd.get("ext-cpd", ()):
+ if not ext_cp.get("int-cpd"):
+ continue
+ if ext_cp["int-cpd"].get("vdu-id") != vdu["id"]:
+ continue
+ if icp["id"] == ext_cp["int-cpd"].get("cpd"):
+ vdu_iface["external-connection-point-ref"] = ext_cp.get(
+ "id"
+ )
+
+ if "port-security-enabled" in ext_cp:
+ vdu_iface["port-security-enabled"] = ext_cp[
+ "port-security-enabled"
+ ]
+
+ if "port-security-disable-strategy" in ext_cp:
+ vdu_iface["port-security-disable-strategy"] = ext_cp[
+ "port-security-disable-strategy"
+ ]
+
+ break
+
+ if (
+ vnfd_mgmt_cp
+ and vdu_iface.get("external-connection-point-ref")
+ == vnfd_mgmt_cp
+ ):
+ vdu_iface["mgmt-vnf"] = True
+ vdu_iface["mgmt-interface"] = True
+
+ for ecp in vdu_mgmt_cp:
+ if vdu_iface.get("external-connection-point-ref") == ecp:
+ vdu_iface["mgmt-interface"] = True
+
+ if iface.get("virtual-interface"):
+ vdu_iface.update(deepcopy(iface["virtual-interface"]))
+
+ # look for network where this interface is connected
+ iface_ext_cp = vdu_iface.get("external-connection-point-ref")
+ if iface_ext_cp:
+ # TODO: Change for multiple df support
+ for df in get_iterable(nsd.get("df")):
+ for vnf_profile in get_iterable(df.get("vnf-profile")):
+ for vlc_index, vlc in enumerate(
+ get_iterable(
+ vnf_profile.get("virtual-link-connectivity")
+ )
+ ):
+ for cpd in get_iterable(
+ vlc.get("constituent-cpd-id")
+ ):
+ if (
+ cpd.get("constituent-cpd-id")
+ == iface_ext_cp
+ ) and vnf_profile.get("id") == vnf_index:
+ vdu_iface["ns-vld-id"] = vlc.get(
+ "virtual-link-profile-id"
+ )
+ # if iface type is SRIOV or PASSTHROUGH, set pci-interfaces flag to True
+ if vdu_iface.get("type") in (
+ "SR-IOV",
+ "PCI-PASSTHROUGH",
+ ):
+ nsr_descriptor["vld"][vlc_index][
+ "pci-interfaces"
+ ] = True
+ break
+ elif vdu_iface.get("internal-connection-point-ref"):
+ vdu_iface["vnf-vld-id"] = icp.get("int-virtual-link-desc")
+ # TODO: store fixed IP address in the record (if it exists in the ICP)
+ # if iface type is SRIOV or PASSTHROUGH, set pci-interfaces flag to True
+ if vdu_iface.get("type") in ("SR-IOV", "PCI-PASSTHROUGH"):
+ ivld_index = utils.find_index_in_list(
+ vnfd.get("int-virtual-link-desc", ()),
+ lambda ivld: ivld["id"]
+ == icp.get("int-virtual-link-desc"),
+ )
+ vnfr_descriptor["vld"][ivld_index]["pci-interfaces"] = True
+
+ vdur["interfaces"].append(vdu_iface)
+
+ if vdu.get("sw-image-desc"):
+ sw_image = utils.find_in_list(
+ vnfd.get("sw-image-desc", ()),
+ lambda image: image["id"] == vdu.get("sw-image-desc"),
+ )
+ nsr_sw_image_data = utils.find_in_list(
+ nsr_descriptor["image"],
+ lambda nsr_image: (nsr_image.get("image") == sw_image.get("image")),
+ )
+ vdur["ns-image-id"] = nsr_sw_image_data["id"]
+
+ if vdu.get("alternative-sw-image-desc"):
+ alt_image_ids = []
+ for alt_image_id in vdu.get("alternative-sw-image-desc", ()):
+ sw_image = utils.find_in_list(
+ vnfd.get("sw-image-desc", ()),
+ lambda image: image["id"] == alt_image_id,
+ )
+ nsr_sw_image_data = utils.find_in_list(
+ nsr_descriptor["image"],
+ lambda nsr_image: (
+ nsr_image.get("image") == sw_image.get("image")
+ ),
+ )
+ alt_image_ids.append(nsr_sw_image_data["id"])
+ vdur["alt-image-ids"] = alt_image_ids
+
+ revision = revision if revision is not None else 1
+ flavor_data_name = (
+ vdu["id"][:56] + "-" + vnf_index + "-" + str(revision) + "-flv"
+ )
+ nsr_flavor_desc = utils.find_in_list(
+ nsr_descriptor["flavor"],
+ lambda flavor: flavor["name"] == flavor_data_name,
+ )
+
+ if nsr_flavor_desc:
+ vdur["ns-flavor-id"] = nsr_flavor_desc["id"]
+
+ # Adding Shared Volume information to vdur
+ if vdur.get("virtual-storages"):
+ nsr_sv = []
+ for vsd in vdur["virtual-storages"]:
+ if vsd.get("vdu-storage-requirements"):
+ if (
+ vsd["vdu-storage-requirements"][0].get("key")
+ == "multiattach"
+ and vsd["vdu-storage-requirements"][0].get("value")
+ == "True"
+ ):
+ nsr_sv.append(vsd["id"])
+ if nsr_sv:
+ vdur["shared-volumes-id"] = nsr_sv
+
+ # Adding Affinity groups information to vdur
+ try:
+ vdu_profile_affinity_group = utils.find_in_list(
+ vnfd.get("df")[0]["vdu-profile"],
+ lambda a_vdu: a_vdu["id"] == vdu["id"],
+ )
+ except Exception:
+ vdu_profile_affinity_group = None
+
+ if vdu_profile_affinity_group:
+ affinity_group_ids = []
+ for affinity_group in vdu_profile_affinity_group.get(
+ "affinity-or-anti-affinity-group", ()
+ ):
+ vdu_affinity_group = utils.find_in_list(
+ vdu_profile_affinity_group.get(
+ "affinity-or-anti-affinity-group", ()
+ ),
+ lambda ag_fp: ag_fp["id"] == affinity_group["id"],
+ )
+ nsr_affinity_group = utils.find_in_list(
+ nsr_descriptor["affinity-or-anti-affinity-group"],
+ lambda nsr_ag: (
+ nsr_ag.get("ag-id") == vdu_affinity_group.get("id")
+ and nsr_ag.get("member-vnf-index")
+ == vnfr_descriptor.get("member-vnf-index-ref")
+ ),
+ )
+ # Update Affinity Group VIM name if VDU instantiation parameter is present
+ if vnf_params and vnf_params.get("affinity-or-anti-affinity-group"):
+ vnf_params_affinity_group = utils.find_in_list(
+ vnf_params["affinity-or-anti-affinity-group"],
+ lambda vnfp_ag: (
+ vnfp_ag.get("id") == vdu_affinity_group.get("id")
+ ),
+ )
+ if vnf_params_affinity_group.get("vim-affinity-group-id"):
+ nsr_affinity_group[
+ "vim-affinity-group-id"
+ ] = vnf_params_affinity_group["vim-affinity-group-id"]
+ affinity_group_ids.append(nsr_affinity_group["id"])
+ vdur["affinity-or-anti-affinity-group-id"] = affinity_group_ids
+
+ if vdu_instantiation_level:
+ count = vdu_instantiation_level.get("number-of-instances")
+ else:
+ count = 1
+
+ for index in range(0, count):
+ vdur = deepcopy(vdur)
+ for iface in vdur["interfaces"]:
+ if iface.get("ip-address") and index != 0:
+ iface["ip-address"] = increment_ip_mac(iface["ip-address"])
+ if iface.get("mac-address") and index != 0:
+ iface["mac-address"] = increment_ip_mac(iface["mac-address"])
+
+ vdur["_id"] = str(uuid4())
+ vdur["id"] = vdur["_id"]
+ vdur["count-index"] = index
+ vnfr_descriptor["vdur"].append(vdur)
+ return vnfr_descriptor
+
+ def vca_status_refresh(self, session, ns_instance_content, filter_q):
+ """
+ vcaStatus in ns_instance_content maybe stale, check if it is stale and create lcm op
+ to refresh vca status by sending message to LCM when it is stale. Ignore otherwise.
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param ns_instance_content: ns instance content
+ :param filter_q: dict: query parameter containing vcaStatus-refresh as true or false
+ :return: None
+ """
+ time_now, time_delta = (
+ time(),
+ time() - ns_instance_content["_admin"]["modified"],
+ )
+ force_refresh = (
+ isinstance(filter_q, dict) and filter_q.get("vcaStatusRefresh") == "true"
+ )
+ threshold_reached = time_delta > 120
+ if force_refresh or threshold_reached:
+ operation, _id = "vca_status_refresh", ns_instance_content["_id"]
+ ns_instance_content["_admin"]["modified"] = time_now
+ self.db.set_one(self.topic, {"_id": _id}, ns_instance_content)
+ nslcmop_desc = NsLcmOpTopic._create_nslcmop(_id, operation, None)
+ self.format_on_new(
+ nslcmop_desc, session["project_id"], make_public=session["public"]
+ )
+ nslcmop_desc["_admin"].pop("nsState")
+ self.msg.write("ns", operation, nslcmop_desc)
+ return
+
+ def show(self, session, _id, filter_q=None, api_req=False):
+ """
+ Get complete information on an ns instance.
+ :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+ :param _id: string, ns instance id
+ :param filter_q: dict: query parameter containing vcaStatusRefresh as true or false
+ :param api_req: True if this call is serving an external API request. False if serving internal request.
+ :return: dictionary, raise exception if not found.
+ """
+ ns_instance_content = super().show(session, _id, api_req)
+ self.vca_status_refresh(session, ns_instance_content, filter_q)
+ return ns_instance_content