+ """
+ if not net.get("type"):
+ raise vimconn.VimConnException("Type is missing in the network details.")
+
+ if net["type"] == "virtual":
+ pass
+
+ # For VF
+ elif net["type"] == "VF" or net["type"] == "SR-IOV":
+ port_dict["binding:vnic_type"] = "direct"
+
+ # VIO specific Changes
+ if self.vim_type == "VIO":
+ # Need to create port with port_security_enabled = False and no-security-groups
+ port_dict["port_security_enabled"] = False
+ port_dict["provider_security_groups"] = []
+ port_dict["security_groups"] = []
+
+ else:
+ # For PT PCI-PASSTHROUGH
+ port_dict["binding:vnic_type"] = "direct-physical"
+
+ @staticmethod
+ def _set_fixed_ip(new_port: dict, net: dict) -> None:
+ """Set the "ip" parameter in net dictionary.
+
+ Args:
+ new_port (dict): New created port
+ net (dict): Network details
+
+ """
+ fixed_ips = new_port["port"].get("fixed_ips")
+
+ if fixed_ips:
+ net["ip"] = fixed_ips[0].get("ip_address")
+ else:
+ net["ip"] = None
+
+ @staticmethod
+ def _prepare_port_dict_mac_ip_addr(net: dict, port_dict: dict) -> None:
+ """Fill up the mac_address and fixed_ips in port_dict.
+
+ Args:
+ net (dict): Network details
+ port_dict (dict): Port details
+
+ """
+ if net.get("mac_address"):
+ port_dict["mac_address"] = net["mac_address"]
+
+ ip_dual_list = []
+ if ip_list := net.get("ip_address"):
+ if not isinstance(ip_list, list):
+ ip_list = [ip_list]
+ for ip in ip_list:
+ ip_dict = {"ip_address": ip}
+ ip_dual_list.append(ip_dict)
+ port_dict["fixed_ips"] = ip_dual_list
+ # TODO add "subnet_id": <subnet_id>
+
+ def _create_new_port(self, port_dict: dict, created_items: dict, net: dict) -> Dict:
+ """Create new port using neutron.
+
+ Args:
+ port_dict (dict): Port details
+ created_items (dict): All created items
+ net (dict): Network details
+
+ Returns:
+ new_port (dict): New created port
+
+ """
+ new_port = self.neutron.create_port({"port": port_dict})
+ created_items["port:" + str(new_port["port"]["id"])] = True
+ net["mac_address"] = new_port["port"]["mac_address"]
+ net["vim_id"] = new_port["port"]["id"]
+
+ return new_port
+
+ def _create_port(
+ self, net: dict, name: str, created_items: dict
+ ) -> Tuple[dict, dict]:
+ """Create port using net details.
+
+ Args:
+ net (dict): Network details
+ name (str): Name to be used as network name if net dict does not include name
+ created_items (dict): All created items
+
+ Returns:
+ new_port, port New created port, port dictionary
+
+ """
+
+ port_dict = {
+ "network_id": net["net_id"],
+ "name": net.get("name"),
+ "admin_state_up": True,
+ }
+
+ if not port_dict["name"]:
+ port_dict["name"] = name
+
+ self._prepare_port_dict_security_groups(net, port_dict)
+
+ self._prepare_port_dict_binding(net, port_dict)
+
+ vimconnector._prepare_port_dict_mac_ip_addr(net, port_dict)
+
+ new_port = self._create_new_port(port_dict, created_items, net)
+
+ vimconnector._set_fixed_ip(new_port, net)
+
+ port = {"port-id": new_port["port"]["id"]}
+
+ if float(self.nova.api_version.get_string()) >= 2.32:
+ port["tag"] = new_port["port"]["name"]
+
+ return new_port, port
+
+ def _prepare_network_for_vminstance(
+ self,
+ name: str,
+ net_list: list,
+ created_items: dict,
+ net_list_vim: list,
+ external_network: list,
+ no_secured_ports: list,
+ ) -> None:
+ """Create port and fill up net dictionary for new VM instance creation.
+
+ Args:
+ name (str): Name of network
+ net_list (list): List of networks
+ created_items (dict): All created items belongs to a VM
+ net_list_vim (list): List of ports
+ external_network (list): List of external-networks
+ no_secured_ports (list): Port security disabled ports
+ """
+
+ self._reload_connection()
+
+ for net in net_list:
+ # Skip non-connected iface
+ if not net.get("net_id"):
+ continue
+
+ new_port, port = self._create_port(net, name, created_items)
+
+ net_list_vim.append(port)
+
+ if net.get("floating_ip", False):
+ net["exit_on_floating_ip_error"] = True
+ external_network.append(net)
+
+ elif net["use"] == "mgmt" and self.config.get("use_floating_ip"):
+ net["exit_on_floating_ip_error"] = False
+ external_network.append(net)
+ net["floating_ip"] = self.config.get("use_floating_ip")
+
+ # If port security is disabled when the port has not yet been attached to the VM, then all vm traffic
+ # is dropped. As a workaround we wait until the VM is active and then disable the port-security
+ if net.get("port_security") is False and not self.config.get(
+ "no_port_security_extension"
+ ):
+ no_secured_ports.append(
+ (
+ new_port["port"]["id"],
+ net.get("port_security_disable_strategy"),
+ )
+ )
+
+ def _prepare_persistent_root_volumes(
+ self,
+ name: str,
+ vm_av_zone: list,
+ disk: dict,
+ base_disk_index: int,
+ block_device_mapping: dict,
+ existing_vim_volumes: list,
+ created_items: dict,
+ ) -> Optional[str]:
+ """Prepare persistent root volumes for new VM instance.
+
+ Args:
+ name (str): Name of VM instance
+ vm_av_zone (list): List of availability zones
+ disk (dict): Disk details
+ base_disk_index (int): Disk index
+ block_device_mapping (dict): Block device details
+ existing_vim_volumes (list): Existing disk details
+ created_items (dict): All created items belongs to VM
+
+ Returns:
+ boot_volume_id (str): ID of boot volume
+
+ """
+ # Disk may include only vim_volume_id or only vim_id."
+ # Use existing persistent root volume finding with volume_id or vim_id
+ key_id = "vim_volume_id" if "vim_volume_id" in disk.keys() else "vim_id"
+
+ if disk.get(key_id):
+ block_device_mapping["vd" + chr(base_disk_index)] = disk[key_id]
+ existing_vim_volumes.append({"id": disk[key_id]})
+
+ else:
+ # Create persistent root volume
+ volume = self.cinder.volumes.create(
+ size=disk["size"],
+ name=name + "vd" + chr(base_disk_index),
+ imageRef=disk["image_id"],
+ # Make sure volume is in the same AZ as the VM to be attached to
+ availability_zone=vm_av_zone,
+ )
+ boot_volume_id = volume.id
+ self.update_block_device_mapping(
+ volume=volume,
+ block_device_mapping=block_device_mapping,
+ base_disk_index=base_disk_index,
+ disk=disk,
+ created_items=created_items,
+ )
+
+ return boot_volume_id
+
+ @staticmethod
+ def update_block_device_mapping(
+ volume: object,
+ block_device_mapping: dict,
+ base_disk_index: int,
+ disk: dict,
+ created_items: dict,
+ ) -> None:
+ """Add volume information to block device mapping dict.
+ Args:
+ volume (object): Created volume object
+ block_device_mapping (dict): Block device details
+ base_disk_index (int): Disk index
+ disk (dict): Disk details
+ created_items (dict): All created items belongs to VM
+ """
+ if not volume:
+ raise vimconn.VimConnException("Volume is empty.")
+
+ if not hasattr(volume, "id"):
+ raise vimconn.VimConnException(
+ "Created volume is not valid, does not have id attribute."
+ )
+
+ volume_txt = "volume:" + str(volume.id)
+ if disk.get("keep"):
+ volume_txt += ":keep"
+ created_items[volume_txt] = True
+ block_device_mapping["vd" + chr(base_disk_index)] = volume.id
+
+ def new_shared_volumes(self, shared_volume_data) -> (str, str):
+ try:
+ volume = self.cinder.volumes.create(
+ size=shared_volume_data["size"],
+ name=shared_volume_data["name"],
+ volume_type="multiattach",
+ )
+ return (volume.name, volume.id)
+ except (ConnectionError, KeyError) as e:
+ self._format_exception(e)
+
+ def _prepare_shared_volumes(
+ self,
+ name: str,
+ disk: dict,
+ base_disk_index: int,
+ block_device_mapping: dict,
+ existing_vim_volumes: list,
+ created_items: dict,
+ ):
+ volumes = {volume.name: volume.id for volume in self.cinder.volumes.list()}
+ if volumes.get(disk["name"]):
+ sv_id = volumes[disk["name"]]
+ volume = self.cinder.volumes.get(sv_id)
+ self.update_block_device_mapping(
+ volume=volume,
+ block_device_mapping=block_device_mapping,
+ base_disk_index=base_disk_index,
+ disk=disk,
+ created_items=created_items,
+ )
+
+ def _prepare_non_root_persistent_volumes(
+ self,
+ name: str,
+ disk: dict,
+ vm_av_zone: list,
+ block_device_mapping: dict,
+ base_disk_index: int,
+ existing_vim_volumes: list,
+ created_items: dict,
+ ) -> None:
+ """Prepare persistent volumes for new VM instance.
+
+ Args:
+ name (str): Name of VM instance
+ disk (dict): Disk details
+ vm_av_zone (list): List of availability zones
+ block_device_mapping (dict): Block device details
+ base_disk_index (int): Disk index
+ existing_vim_volumes (list): Existing disk details
+ created_items (dict): All created items belongs to VM
+ """
+ # Non-root persistent volumes
+ # Disk may include only vim_volume_id or only vim_id."
+ key_id = "vim_volume_id" if "vim_volume_id" in disk.keys() else "vim_id"
+ if disk.get(key_id):
+ # Use existing persistent volume
+ block_device_mapping["vd" + chr(base_disk_index)] = disk[key_id]
+ existing_vim_volumes.append({"id": disk[key_id]})
+ else:
+ volume_name = f"{name}vd{chr(base_disk_index)}"
+ volume = self.cinder.volumes.create(
+ size=disk["size"],
+ name=volume_name,
+ # Make sure volume is in the same AZ as the VM to be attached to
+ availability_zone=vm_av_zone,
+ )
+ self.update_block_device_mapping(
+ volume=volume,
+ block_device_mapping=block_device_mapping,
+ base_disk_index=base_disk_index,
+ disk=disk,
+ created_items=created_items,
+ )
+
+ def _wait_for_created_volumes_availability(
+ self, elapsed_time: int, created_items: dict
+ ) -> Optional[int]:
+ """Wait till created volumes become available.
+
+ Args:
+ elapsed_time (int): Passed time while waiting
+ created_items (dict): All created items belongs to VM
+
+ Returns:
+ elapsed_time (int): Time spent while waiting
+
+ """
+ while elapsed_time < volume_timeout:
+ for created_item in created_items:
+ v, volume_id = (
+ created_item.split(":")[0],
+ created_item.split(":")[1],
+ )
+ if v == "volume":
+ volume = self.cinder.volumes.get(volume_id)
+ if (
+ volume.volume_type == "multiattach"
+ and volume.status == "in-use"
+ ):
+ return elapsed_time
+ elif volume.status != "available":