+ self._reload_connection()
+ port_dict = self.neutron.list_ports(device_id=vm_id)
+
+ for port in port_dict["ports"]:
+ interface = {}
+ interface["vim_info"] = self.serialize(port)
+ interface["mac_address"] = port.get("mac_address")
+ interface["vim_net_id"] = port["network_id"]
+ interface["vim_interface_id"] = port["id"]
+ # check if OS-EXT-SRV-ATTR:host is there,
+ # in case of non-admin credentials, it will be missing
+
+ if vm_vim.get("OS-EXT-SRV-ATTR:host"):
+ interface["compute_node"] = vm_vim["OS-EXT-SRV-ATTR:host"]
+
+ interface["pci"] = None
+
+ # check if binding:profile is there,
+ # in case of non-admin credentials, it will be missing
+ if port.get("binding:profile"):
+ if port["binding:profile"].get("pci_slot"):
+ # TODO: At the moment sr-iov pci addresses are converted to PF pci addresses by setting
+ # the slot to 0x00
+ # TODO: This is just a workaround valid for niantinc. Find a better way to do so
+ # CHANGE DDDD:BB:SS.F to DDDD:BB:00.(F%2) assuming there are 2 ports per nic
+ pci = port["binding:profile"]["pci_slot"]
+ # interface["pci"] = pci[:-4] + "00." + str(int(pci[-1]) % 2)
+ interface["pci"] = pci
+
+ interface["vlan"] = None
+
+ if port.get("binding:vif_details"):
+ interface["vlan"] = port["binding:vif_details"].get("vlan")
+
+ # Get vlan from network in case not present in port for those old openstacks and cases where
+ # it is needed vlan at PT
+ if not interface["vlan"]:
+ # if network is of type vlan and port is of type direct (sr-iov) then set vlan id
+ network = self.neutron.show_network(port["network_id"])
+
+ if (
+ network["network"].get("provider:network_type")
+ == "vlan"
+ ):
+ # and port.get("binding:vnic_type") in ("direct", "direct-physical"):
+ interface["vlan"] = network["network"].get(
+ "provider:segmentation_id"
+ )
+
+ ips = []
+ # look for floating ip address
+ try:
+ floating_ip_dict = self.neutron.list_floatingips(
+ port_id=port["id"]
+ )
+
+ if floating_ip_dict.get("floatingips"):
+ ips.append(
+ floating_ip_dict["floatingips"][0].get(
+ "floating_ip_address"
+ )
+ )
+ except Exception:
+ pass
+
+ for subnet in port["fixed_ips"]:
+ ips.append(subnet["ip_address"])
+
+ interface["ip_address"] = ";".join(ips)
+ vm["interfaces"].append(interface)
+ except Exception as e:
+ self.logger.error(
+ "Error getting vm interface information {}: {}".format(
+ type(e).__name__, e
+ ),
+ exc_info=True,
+ )
+ except vimconn.VimConnNotFoundException as e:
+ self.logger.error("Exception getting vm status: %s", str(e))
+ vm["status"] = "DELETED"
+ vm["error_msg"] = str(e)
+ except vimconn.VimConnException as e:
+ self.logger.error("Exception getting vm status: %s", str(e))
+ vm["status"] = "VIM_ERROR"
+ vm["error_msg"] = str(e)
+
+ vm_dict[vm_id] = vm
+
+ return vm_dict
+
+ def action_vminstance(self, vm_id, action_dict, created_items={}):
+ """Send and action over a VM instance from VIM
+ Returns None or the console dict if the action was successfully sent to the VIM
+ """
+ self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
+
+ try:
+ self._reload_connection()
+ server = self.nova.servers.find(id=vm_id)
+
+ if "start" in action_dict:
+ if action_dict["start"] == "rebuild":
+ server.rebuild()
+ else:
+ if server.status == "PAUSED":
+ server.unpause()
+ elif server.status == "SUSPENDED":
+ server.resume()
+ elif server.status == "SHUTOFF":
+ server.start()
+ else:
+ self.logger.debug(
+ "ERROR : Instance is not in SHUTOFF/PAUSE/SUSPEND state"
+ )
+ raise vimconn.VimConnException(
+ "Cannot 'start' instance while it is in active state",
+ http_code=vimconn.HTTP_Bad_Request,
+ )
+
+ elif "pause" in action_dict:
+ server.pause()
+ elif "resume" in action_dict:
+ server.resume()
+ elif "shutoff" in action_dict or "shutdown" in action_dict:
+ self.logger.debug("server status %s", server.status)
+ if server.status == "ACTIVE":
+ server.stop()
+ else:
+ self.logger.debug("ERROR: VM is not in Active state")
+ raise vimconn.VimConnException(
+ "VM is not in active state, stop operation is not allowed",
+ http_code=vimconn.HTTP_Bad_Request,
+ )
+ elif "forceOff" in action_dict:
+ server.stop() # TODO
+ elif "terminate" in action_dict:
+ server.delete()
+ elif "createImage" in action_dict:
+ server.create_image()
+ # "path":path_schema,
+ # "description":description_schema,
+ # "name":name_schema,
+ # "metadata":metadata_schema,
+ # "imageRef": id_schema,
+ # "disk": {"oneOf":[{"type": "null"}, {"type":"string"}] },
+ elif "rebuild" in action_dict:
+ server.rebuild(server.image["id"])
+ elif "reboot" in action_dict:
+ server.reboot() # reboot_type="SOFT"
+ elif "console" in action_dict:
+ console_type = action_dict["console"]
+
+ if console_type is None or console_type == "novnc":
+ console_dict = server.get_vnc_console("novnc")
+ elif console_type == "xvpvnc":
+ console_dict = server.get_vnc_console(console_type)
+ elif console_type == "rdp-html5":
+ console_dict = server.get_rdp_console(console_type)
+ elif console_type == "spice-html5":
+ console_dict = server.get_spice_console(console_type)
+ else:
+ raise vimconn.VimConnException(
+ "console type '{}' not allowed".format(console_type),
+ http_code=vimconn.HTTP_Bad_Request,
+ )
+
+ try:
+ console_url = console_dict["console"]["url"]
+ # parse console_url
+ protocol_index = console_url.find("//")
+ suffix_index = (
+ console_url[protocol_index + 2 :].find("/") + protocol_index + 2
+ )
+ port_index = (
+ console_url[protocol_index + 2 : suffix_index].find(":")
+ + protocol_index
+ + 2
+ )
+
+ if protocol_index < 0 or port_index < 0 or suffix_index < 0:
+ raise vimconn.VimConnException(
+ "Unexpected response from VIM " + str(console_dict)
+ )
+
+ console_dict2 = {
+ "protocol": console_url[0:protocol_index],
+ "server": console_url[protocol_index + 2 : port_index],
+ "port": int(console_url[port_index + 1 : suffix_index]),
+ "suffix": console_url[suffix_index + 1 :],
+ }
+
+ return console_dict2
+ except Exception:
+ raise vimconn.VimConnException(
+ "Unexpected response from VIM " + str(console_dict)
+ )
+
+ return None
+ except (
+ ksExceptions.ClientException,
+ nvExceptions.ClientException,
+ nvExceptions.NotFound,
+ ConnectionError,
+ ) as e:
+ self._format_exception(e)
+ # TODO insert exception vimconn.HTTP_Unauthorized
+
+ # ###### VIO Specific Changes #########
+ def _generate_vlanID(self):
+ """
+ Method to get unused vlanID
+ Args:
+ None
+ Returns:
+ vlanID
+ """
+ # Get used VLAN IDs
+ usedVlanIDs = []
+ networks = self.get_network_list()
+
+ for net in networks:
+ if net.get("provider:segmentation_id"):
+ usedVlanIDs.append(net.get("provider:segmentation_id"))
+
+ used_vlanIDs = set(usedVlanIDs)
+
+ # find unused VLAN ID
+ for vlanID_range in self.config.get("dataplane_net_vlan_range"):
+ try:
+ start_vlanid, end_vlanid = map(
+ int, vlanID_range.replace(" ", "").split("-")
+ )
+
+ for vlanID in range(start_vlanid, end_vlanid + 1):
+ if vlanID not in used_vlanIDs:
+ return vlanID
+ except Exception as exp:
+ raise vimconn.VimConnException(
+ "Exception {} occurred while generating VLAN ID.".format(exp)
+ )
+ else:
+ raise vimconn.VimConnConflictException(
+ "Unable to create the SRIOV VLAN network. All given Vlan IDs {} are in use.".format(
+ self.config.get("dataplane_net_vlan_range")
+ )
+ )
+
+ def _generate_multisegment_vlanID(self):
+ """
+ Method to get unused vlanID
+ Args:
+ None
+ Returns:
+ vlanID
+ """
+ # Get used VLAN IDs
+ usedVlanIDs = []
+ networks = self.get_network_list()
+ for net in networks:
+ if net.get("provider:network_type") == "vlan" and net.get(
+ "provider:segmentation_id"
+ ):
+ usedVlanIDs.append(net.get("provider:segmentation_id"))
+ elif net.get("segments"):
+ for segment in net.get("segments"):
+ if segment.get("provider:network_type") == "vlan" and segment.get(
+ "provider:segmentation_id"
+ ):
+ usedVlanIDs.append(segment.get("provider:segmentation_id"))
+
+ used_vlanIDs = set(usedVlanIDs)
+
+ # find unused VLAN ID
+ for vlanID_range in self.config.get("multisegment_vlan_range"):
+ try:
+ start_vlanid, end_vlanid = map(
+ int, vlanID_range.replace(" ", "").split("-")
+ )
+
+ for vlanID in range(start_vlanid, end_vlanid + 1):
+ if vlanID not in used_vlanIDs:
+ return vlanID
+ except Exception as exp:
+ raise vimconn.VimConnException(
+ "Exception {} occurred while generating VLAN ID.".format(exp)
+ )
+ else:
+ raise vimconn.VimConnConflictException(
+ "Unable to create the VLAN segment. All VLAN IDs {} are in use.".format(
+ self.config.get("multisegment_vlan_range")
+ )
+ )
+
+ def _validate_vlan_ranges(self, input_vlan_range, text_vlan_range):
+ """
+ Method to validate user given vlanID ranges
+ Args: None
+ Returns: None
+ """
+ for vlanID_range in input_vlan_range:
+ vlan_range = vlanID_range.replace(" ", "")
+ # validate format
+ vlanID_pattern = r"(\d)*-(\d)*$"
+ match_obj = re.match(vlanID_pattern, vlan_range)
+ if not match_obj:
+ raise vimconn.VimConnConflictException(
+ "Invalid VLAN range for {}: {}.You must provide "
+ "'{}' in format [start_ID - end_ID].".format(
+ text_vlan_range, vlanID_range, text_vlan_range
+ )
+ )
+
+ start_vlanid, end_vlanid = map(int, vlan_range.split("-"))
+ if start_vlanid <= 0:
+ raise vimconn.VimConnConflictException(
+ "Invalid VLAN range for {}: {}. Start ID can not be zero. For VLAN "
+ "networks valid IDs are 1 to 4094 ".format(
+ text_vlan_range, vlanID_range
+ )
+ )
+
+ if end_vlanid > 4094:
+ raise vimconn.VimConnConflictException(
+ "Invalid VLAN range for {}: {}. End VLAN ID can not be "
+ "greater than 4094. For VLAN networks valid IDs are 1 to 4094 ".format(
+ text_vlan_range, vlanID_range
+ )
+ )
+
+ if start_vlanid > end_vlanid:
+ raise vimconn.VimConnConflictException(
+ "Invalid VLAN range for {}: {}. You must provide '{}'"
+ " in format start_ID - end_ID and start_ID < end_ID ".format(
+ text_vlan_range, vlanID_range, text_vlan_range
+ )
+ )
+
+ def get_hosts_info(self):
+ """Get the information of deployed hosts
+ Returns the hosts content"""
+ if self.debug:
+ print("osconnector: Getting Host info from VIM")