def _prepare_guest_kernel_and_ramdisk(config): """ Use PyGrub to extract the kernel and ramdisk from the given disk image. """ disk_image = config.getConfigItem(DomainConfig.DISK_IMAGE_PATH) # Use pygrub to extract the initrd and the kernel from the disk image. (status, output) = \ commands.getstatusoutput("%s -q %s" % (PYGRUB, disk_image)) if status != 0: raise VirtualizationException( "Error occurred while executing '%s' (status=%d). Output=%s" % (PYGRUB, status, output)) # Now analyze the output and extract the names of the new kernel and initrd # images from it. (pygrub_kernel_path, pygrub_initrd_path) = \ _extract_image_paths_from_pygrub_output(output) # Rename the extracted images to the names we are pointing to in the # configuration file. runtime_kernel_path = config.getConfigItem(DomainConfig.KERNEL_PATH) runtime_initrd_path = config.getConfigItem(DomainConfig.RAMDISK_PATH) try: os.rename(pygrub_kernel_path, runtime_kernel_path) os.rename(pygrub_initrd_path, runtime_initrd_path) except OSError: oe = sys.exc_info()[1] raise_with_tb( VirtualizationException( "Error occurred while renaming runtime image paths: %s" % str(oe)), sys.exc_info()[2])
def _connect_to_hypervisor(): """Connect to the hypervisor.""" # First, attempt to import libvirt. If we don't have that, we can't do # much else. try: import libvirt except ImportError as ie: raise VirtualizationException("Unable to locate libvirt: %s" % str(ie)) # Attempt to connect to the hypervisor. try: connection = libvirt.open(None) except Exception as e: raise VirtualizationException("Could not connect to hypervisor: %s" % str(e)) return connection
def start_domain(uuid): """ Boots the domain for the first time after installation is complete. """ # Load the configuration file for this UUID. domain = DomainDirectory() config = domain.load_config(uuid) # Connect to the hypervisor. connection = libvirt.open(None) # We will attempt to determine if the domain is configured to use a # bootloader. If not, we'll have to explicitly use the kernel and initrd # data provided in the config to start the domain. try: config.getConfigItem(DomainConfig.BOOTLOADER) except DomainConfigError: dce = sys.exc_info()[1] # No bootloader tag present. Use pygrub to extract the kernel from # the disk image if its Xen. For fully virt we dont have pygrub, it # directly emulates the BIOS loading the first sector of the boot disk. if connection.getType() == 'Xen': # This uses pygrub which comes only with xen _prepare_guest_kernel_and_ramdisk(config) # Now, we'll restart the instance, this time using the re-create XML. try: domain = connection.createLinux(config.toXML(), 0) except Exception: e = sys.exc_info()[1] raise_with_tb( VirtualizationException( "Error occurred while attempting to recreate domain %s: %s" % (uuid, str(e))), sys.exc_info()[2])
def _call_domain_control_routine(uuid, routine_name, *args): """ Call a function in a domain, optionally with a set of arguments. """ # If libvirt is not available, this is a no-op. if not libvirt: return # Lookup the domain by its UUID. (conn, domain) = _get_domain(uuid) # Get a reference to the domain's control routine. ctrl_func = None try: ctrl_func = getattr(domain, routine_name) except AttributeError: raise_with_tb( VirtualizationException("Unknown function: %s" % routine_name), sys.exc_info()[2]) result = 0 try: if sys.version_info[0] == 3: result = ctrl_func(*args) else: result = apply(ctrl_func, args) except TypeError: te = sys.exc_info()[1] raise_with_tb( VirtualizationException("Invalid arguments (%s) to %s: %s" % (str(args), routine_name, str(te))), sys.exc_info()[2]) except libvirt.libvirtError: le = sys.exc_info()[1] raise_with_tb( VirtualizationException("LibVirt Error %s: %s" % (routine_name, str(le))), sys.exc_info()[2]) # Handle the return code. Anything non-zero is an error. if result != 0: raise_with_tb( VirtualizationException( "Could not perform function '%s' on domain %s. Error: %s" % (routine_name, uuid, str(result))), sys.exc_info()[2])
def save_unknown_domain_configs(self, domain_uuids): """ This function saves the configuration for any domains whose UUIDs are passed in the domain_uuids list. If the UUID is already known, it is skipped. """ for uuid in domain_uuids: uuid = sstr(uuid) # If we already have a config for this uuid, skip it. Also, don't # try to figure out a config for a host UUID. if not is_host_uuid(uuid) and not self.is_known_config(uuid): # The UUID is a formatted string. Turn it back into a number, # since that's what libvirt wants. dehyphenized_uuid = dehyphenize_uuid(uuid) uuid_as_num = binascii.unhexlify(dehyphenized_uuid) # Lookup the domain by its uuid. try: domain = self.conn.lookupByUUID(uuid_as_num) except libvirt.libvirtError: lve = sys.exc_info()[1] raise VirtualizationException( "Failed to obtain handle to domain %s: %s" % (uuid, repr(lve))) # Now grab the XML description of the configuration. xml = domain.XMLDesc(0) # Write the xml out to a file so that we can load it into our # abstract DomainConfig object and manipulate it easily. cfg_file_path = self.__write_xml_file(uuid, xml) new_config = DomainConfig(self.__path, uuid) # Don't record the config this time if the domain is # installing; we don't want to restart the domain later and # make it re-install itself. if not new_config.isInstallerConfig(): # Now we'll reformat the configuration object so that it's # valid the next time this domain runs.. self.__fixup_config_for_restart(new_config) # The config is now prepared. Save it and move on to the # next uuid. new_config.save() else: # Remove the config file we just wrote. os.unlink(cfg_file_path)
def _get_domain(uuid): """ Lookup the domain by its UUID. If not found, raise an exception. """ conn = libvirt.open(None) domain = None hyphenized_uuid = hyphenize_uuid(uuid) try: domain = conn.lookupByUUIDString(hyphenized_uuid) except libvirt.libvirtError: lve = sys.exc_info()[1] raise_with_tb(VirtualizationException("Domain UUID '%s' not found: %s" % (hyphenized_uuid, str(lve))), sys.exc_info()[2]) return (conn, domain)
def _extract_image_paths_from_pygrub_output(output): """ Searches for the paths of the kernel and initrd files in the output of pygrub. If not found, a VirtualizationException is raised. Otherwise, the (kernel_path, initrd_path) tuple is returned. """ match = re.search("^linux \(kernel (\S+)\)\(ramdisk (\S+)\)", output, re.MULTILINE) if match is None or len(match.groups()) != 2: raise VirtualizationException( "Could not locate kernel and initrd in pygrub output: %s" % output) kernel_path = match.group(1) initrd_path = match.group(2) return (kernel_path, initrd_path)
def poll_state(uuid): """ Polls just the state of the guest with the provided UUID. This state is returned. """ conn = libvirt.openReadOnly(None) if not conn: raise VirtualizationException("Failed to open connection to hypervisor.") # Attempt to connect to the domain. Since there is technically no # "stopped" state, we will assume that if we cannot connect the domain is # not running. Unfortunately, we can't really determine if the domain # actually exists. domain = None try: domain = conn.lookupByUUIDString(hyphenize_uuid(uuid)) except libvirt.libvirtError: # Can't find domain. Return stopped state. return State(None) # Now that we have the domain, lookup the state. domain_info = domain.info() return State(VIRT_STATE_NAME_MAP[domain_info[0]])
def __init__(self): self.__path = CONFIG_DIR self.conn = libvirt.openReadOnly(None) if not self.conn: raise VirtualizationException( "Failed to open connection to hypervisor.")
def poll_hypervisor(): """ This function polls the hypervisor for information about the currently running set of domains. It returns a dictionary object that looks like the following: { uuid : { 'name' : '...', 'uuid' : '...', 'virt_type' : '...', 'memory_size' : '...', 'vcpus' : '...', 'state' : '...' }, ... } """ if not libvirt: return {} try: conn = libvirt.openReadOnly(None) except libvirt.libvirtError: # virConnectOpen() failed sys.stderr.write(rhncli.utf8_encode(_("Warning: Could not retrieve virtualization information!\n\t" + "libvirtd service needs to be running.\n"))) conn = None if not conn: # No connection to hypervisor made return {} domainIDs = conn.listDomainsID() state = {} for domainID in domainIDs: try: domain = conn.lookupByID(domainID) except libvirt.libvirtError: lve = sys.exc_info()[1] raise_with_tb(VirtualizationException("Failed to obtain handle to domain %d: %s" % (domainID, repr(lve)), sys.exc_info()[2])) uuid = binascii.hexlify(domain.UUID()) # SEE: http://libvirt.org/html/libvirt-libvirt.html#virDomainInfo # for more info. domain_info = domain.info() # Set the virtualization type. We can tell if the domain is fully virt # by checking the domain's OSType() attribute. virt_type = VirtualizationType.PARA if is_fully_virt(domain): virt_type = VirtualizationType.FULLY # we need to filter out the small per/minute KB changes # that occur inside a vm. To do this we divide by 1024 to # drop our precision down to megabytes with an int then # back up to KB memory = int(domain_info[2] / 1024); memory = memory * 1024; properties = { PropertyType.NAME : domain.name(), PropertyType.UUID : uuid, PropertyType.TYPE : virt_type, PropertyType.MEMORY : str(memory), # current memory PropertyType.VCPUS : domain_info[3], PropertyType.STATE : VIRT_STATE_NAME_MAP[domain_info[0]] } state[uuid] = properties if state: _log_debug("Polled state: %s" % repr(state)) return state