+ Returns:
+ bool (True/False)
+ name (str) New name if it is a multiattach disk
+ """
+
+ if vdu_storage_requirements := virtual_storage_desc.get(
+ "vdu-storage-requirements", {}
+ ):
+ for item in vdu_storage_requirements:
+ if (
+ item.get("key") == "multiattach"
+ and item.get("value").lower() == "true"
+ ):
+ name = f"shared-{virtual_storage_desc['id']}-{vnfd_id}"
+ return name, True
+ return virtual_storage_desc["id"], False
+
+ @staticmethod
+ def _sort_vdu_interfaces(target_vdu: dict) -> None:
+ """Sort the interfaces according to position number.
+
+ Args:
+ target_vdu (dict): Details of VDU to be created
+
+ """
+ # If the position info is provided for all the interfaces, it will be sorted
+ # according to position number ascendingly.
+ sorted_interfaces = sorted(
+ target_vdu["interfaces"],
+ key=lambda x: (x.get("position") is None, x.get("position")),
+ )
+ target_vdu["interfaces"] = sorted_interfaces
+
+ @staticmethod
+ def _partially_locate_vdu_interfaces(target_vdu: dict) -> None:
+ """Only place the interfaces which has specific position.
+
+ Args:
+ target_vdu (dict): Details of VDU to be created
+
+ """
+ # If the position info is provided for some interfaces but not all of them, the interfaces
+ # which has specific position numbers will be placed and others' positions will not be taken care.
+ if any(
+ i.get("position") + 1
+ for i in target_vdu["interfaces"]
+ if i.get("position") is not None
+ ):
+ n = len(target_vdu["interfaces"])
+ sorted_interfaces = [-1] * n
+ k, m = 0, 0
+
+ while k < n:
+ if target_vdu["interfaces"][k].get("position") is not None:
+ if any(i.get("position") == 0 for i in target_vdu["interfaces"]):
+ idx = target_vdu["interfaces"][k]["position"] + 1
+ else:
+ idx = target_vdu["interfaces"][k]["position"]
+ sorted_interfaces[idx - 1] = target_vdu["interfaces"][k]
+ k += 1
+
+ while m < n:
+ if target_vdu["interfaces"][m].get("position") is None:
+ idy = sorted_interfaces.index(-1)
+ sorted_interfaces[idy] = target_vdu["interfaces"][m]
+ m += 1
+
+ target_vdu["interfaces"] = sorted_interfaces
+
+ @staticmethod
+ def _prepare_vdu_cloud_init(
+ target_vdu: dict, vdu2cloud_init: dict, db: object, fs: object
+ ) -> Dict:
+ """Fill cloud_config dict with cloud init details.
+
+ Args:
+ target_vdu (dict): Details of VDU to be created
+ vdu2cloud_init (dict): Cloud init dict
+ db (object): DB object
+ fs (object): FS object
+
+ Returns:
+ cloud_config (dict): Cloud config details of VDU
+
+ """
+ # cloud config
+ cloud_config = {}
+
+ if target_vdu.get("cloud-init"):
+ if target_vdu["cloud-init"] not in vdu2cloud_init:
+ vdu2cloud_init[target_vdu["cloud-init"]] = Ns._get_cloud_init(
+ db=db,
+ fs=fs,
+ location=target_vdu["cloud-init"],
+ )
+
+ cloud_content_ = vdu2cloud_init[target_vdu["cloud-init"]]
+ cloud_config["user-data"] = Ns._parse_jinja2(
+ cloud_init_content=cloud_content_,
+ params=target_vdu.get("additionalParams"),
+ context=target_vdu["cloud-init"],
+ )
+
+ if target_vdu.get("boot-data-drive"):
+ cloud_config["boot-data-drive"] = target_vdu.get("boot-data-drive")
+
+ return cloud_config
+
+ @staticmethod
+ def _check_vld_information_of_interfaces(
+ interface: dict, ns_preffix: str, vnf_preffix: str
+ ) -> Optional[str]:
+ """Prepare the net_text by the virtual link information for vnf and ns level.
+ Args:
+ interface (dict): Interface details
+ ns_preffix (str): Prefix of NS
+ vnf_preffix (str): Prefix of VNF
+
+ Returns:
+ net_text (str): information of net
+
+ """
+ net_text = ""
+ if interface.get("ns-vld-id"):
+ net_text = ns_preffix + ":vld." + interface["ns-vld-id"]
+ elif interface.get("vnf-vld-id"):
+ net_text = vnf_preffix + ":vld." + interface["vnf-vld-id"]
+
+ return net_text
+
+ @staticmethod
+ def _prepare_interface_port_security(interface: dict) -> None:
+ """
+
+ Args:
+ interface (dict): Interface details
+
+ """
+ if "port-security-enabled" in interface:
+ interface["port_security"] = interface.pop("port-security-enabled")
+
+ if "port-security-disable-strategy" in interface:
+ interface["port_security_disable_strategy"] = interface.pop(
+ "port-security-disable-strategy"
+ )
+
+ @staticmethod
+ def _create_net_item_of_interface(interface: dict, net_text: str) -> dict:
+ """Prepare net item including name, port security, floating ip etc.
+
+ Args:
+ interface (dict): Interface details
+ net_text (str): information of net
+
+ Returns:
+ net_item (dict): Dict including net details
+
+ """
+
+ net_item = {
+ x: v
+ for x, v in interface.items()
+ if x
+ in (
+ "name",
+ "vpci",
+ "port_security",
+ "port_security_disable_strategy",
+ "floating_ip",
+ )
+ }
+ net_item["net_id"] = "TASK-" + net_text
+ net_item["type"] = "virtual"
+
+ return net_item
+
+ @staticmethod
+ def _prepare_type_of_interface(
+ interface: dict, tasks_by_target_record_id: dict, net_text: str, net_item: dict
+ ) -> None:
+ """Fill the net item type by interface type such as SR-IOV, OM-MGMT, bridge etc.
+
+ Args:
+ interface (dict): Interface details
+ tasks_by_target_record_id (dict): Task details
+ net_text (str): information of net
+ net_item (dict): Dict including net details
+
+ """
+ # TODO mac_address: used for SR-IOV ifaces #TODO for other types
+ # TODO floating_ip: True/False (or it can be None)
+
+ if interface.get("type") in ("SR-IOV", "PCI-PASSTHROUGH"):
+ # Mark the net create task as type data
+ if deep_get(
+ tasks_by_target_record_id,
+ net_text,
+ "extra_dict",
+ "params",
+ "net_type",
+ ):
+ tasks_by_target_record_id[net_text]["extra_dict"]["params"][
+ "net_type"
+ ] = "data"
+
+ net_item["use"] = "data"
+ net_item["model"] = interface["type"]
+ net_item["type"] = interface["type"]
+
+ elif (
+ interface.get("type") == "OM-MGMT"
+ or interface.get("mgmt-interface")
+ or interface.get("mgmt-vnf")
+ ):
+ net_item["use"] = "mgmt"
+
+ else:
+ # If interface.get("type") in ("VIRTIO", "E1000", "PARAVIRT"):
+ net_item["use"] = "bridge"
+ net_item["model"] = interface.get("type")
+
+ @staticmethod
+ def _prepare_vdu_interfaces(
+ target_vdu: dict,
+ extra_dict: dict,
+ ns_preffix: str,
+ vnf_preffix: str,
+ logger: object,
+ tasks_by_target_record_id: dict,
+ net_list: list,
+ ) -> None:
+ """Prepare the net_item and add net_list, add mgmt interface to extra_dict.
+
+ Args:
+ target_vdu (dict): VDU to be created
+ extra_dict (dict): Dictionary to be filled
+ ns_preffix (str): NS prefix as string
+ vnf_preffix (str): VNF prefix as string
+ logger (object): Logger Object
+ tasks_by_target_record_id (dict): Task details
+ net_list (list): Net list of VDU
+ """
+ for iface_index, interface in enumerate(target_vdu["interfaces"]):
+ net_text = Ns._check_vld_information_of_interfaces(
+ interface, ns_preffix, vnf_preffix
+ )
+ if not net_text:
+ # Interface not connected to any vld
+ logger.error(
+ "Interface {} from vdu {} not connected to any vld".format(
+ iface_index, target_vdu["vdu-name"]
+ )
+ )
+ continue
+
+ extra_dict["depends_on"].append(net_text)
+
+ Ns._prepare_interface_port_security(interface)
+
+ net_item = Ns._create_net_item_of_interface(interface, net_text)
+
+ Ns._prepare_type_of_interface(
+ interface, tasks_by_target_record_id, net_text, net_item
+ )
+
+ if interface.get("ip-address"):
+ net_item["ip_address"] = interface["ip-address"]
+
+ if interface.get("mac-address"):
+ net_item["mac_address"] = interface["mac-address"]
+
+ net_list.append(net_item)
+
+ if interface.get("mgmt-vnf"):
+ extra_dict["mgmt_vnf_interface"] = iface_index
+ elif interface.get("mgmt-interface"):
+ extra_dict["mgmt_vdu_interface"] = iface_index
+
+ @staticmethod
+ def _prepare_vdu_ssh_keys(
+ target_vdu: dict, ro_nsr_public_key: dict, cloud_config: dict
+ ) -> None:
+ """Add ssh keys to cloud config.
+
+ Args:
+ target_vdu (dict): Details of VDU to be created
+ ro_nsr_public_key (dict): RO NSR public Key
+ cloud_config (dict): Cloud config details
+
+ """
+ ssh_keys = []