def _get_domain_ips_and_macs( domain: libvirt.virDomain) -> Tuple[List[str], List[str]]: interfaces_sources = [ # getting all DHCP leases IPs libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE, # getting static IPs via ARP libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP, ] interfaces = {} for addresses_source in interfaces_sources: try: interfaces.update( **domain.interfaceAddresses(addresses_source)) except libvirt.libvirtError: log.exception( "Got an error while updating domain's network addresses") ips = [] macs = [] log.debug(f"Host {domain.name()} interfaces are {interfaces}") if interfaces: for (_, val) in interfaces.items(): if val["addrs"]: for addr in val["addrs"]: ips.append(addr["addr"]) macs.append(val["hwaddr"]) if ips: log.info("Host %s ips are %s", domain.name(), ips) if macs: log.info("Host %s macs are %s", domain.name(), macs) return ips, macs
def snapshot_domain(dom: libvirt.virDomain, tmpDir: str, disks: dict, wantedDisks: list): printNoNL("Creating temporary snapshot. ") xml_snapshot = ET.Element(SNAPSHOT_XML_ROOT) xml_disks = ET.SubElement(xml_snapshot, SNAPSHOT_XML_DISK_LIST) for disk in disks.values(): params = dict() params[SNAPSHOT_XML_DISK_NAME] = disk["name"] if disk["name"] in wantedDisks: xml_disk = ET.SubElement(xml_disks, SNAPSHOT_XML_DISK, **params) new_snapshot_path = tmpDir + '/' + disk["name"] + '.qcow2' #Make sure file has correct owner and permissions. f = open(new_snapshot_path, "w+") f.close() os.chmod(new_snapshot_path, 0o664) source_params = dict() source_params[SNAPSHOT_XML_SOURCE_FILE] = new_snapshot_path ET.SubElement(xml_disk, SNAPSHOT_XML_SOURCE, **source_params) else: params[SNAPSHOT_XML_DISK_SNAPSHOT] = "no" xml_disk = ET.SubElement(xml_disks, SNAPSHOT_XML_DISK, **params) xml_string = ET.tostring(xml_snapshot).decode('UTF-8') dom.snapshotCreateXML(xml_string, flags = libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA | libvirt. VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY | libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) print("Done.")
def revert_snapshot_for_disk(dom: libvirt.virDomain, disk:str): printNoNL(" Block committing " + disk + ".") dom.blockCommit(disk, None, None, flags=libvirt.VIR_DOMAIN_BLOCK_COMMIT_SHALLOW | libvirt.VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) while True: info = dom.blockJobInfo(disk) cur = info["cur"] end = info["end"] if cur >= end: break message = ('\r Block committing ' + disk + ': {:.2%}' + SPACE_PADDING).format(cur/end) printNoNL(message) printNoNL("\r Block committing " + disk + ": Finishing." + SPACE_PADDING) dom.blockJobAbort(disk, flags=libvirt.VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT) print("\r Block committing " + disk + ". Done." + SPACE_PADDING)
def storage_allocated_gb(domain: libvirt.virDomain): capacity = 0 for device in storage_devices(domain): capacity += domain.blockInfo(device)[0] return round( capacity / 1024**3, 2 ) # convert bytes to gb and round to 2 digits precision after the decimal point.
def mac_from_vm(vm: libvirt.virDomain = None) -> str: """ Parses the vm's XML to return just the mac address as a string """ doc = minidom.parseString(vm.XMLDesc()) interfaces = doc.getElementsByTagName('mac') return interfaces[0].getAttribute('address')
def storage_used_gb(domain: libvirt.virDomain): allocation = 0 for device in storage_devices(domain): allocation += domain.blockInfo(device)[1] return round( allocation / 1024**3, 2 ) # convert bytes to gb and round to 2 digits precision after the decimal point.
def backup_vm_def(dom: libvirt.virDomain, tar:tarfileProg.TarFile): printNoNL("Writing backup of vm definition. ") _, xmlFile_path = tempfile.mkstemp(suffix=".xml", prefix="backup_vm_def_") xmlFile = open(xmlFile_path, 'w') xmlFile.write(dom.XMLDesc()) xmlFile.close() tar.add(xmlFile_path, arcname=os.path.join(backup_name,"vm-def.xml")) os.remove(xmlFile_path) print("Done.")
def hostname(domain: libvirt.virDomain): try: with suppress_stderr(): hostname = domain.hostname() return hostname except libvirt.libvirtError: macs = [] ifaces = domain.interfaceAddresses( libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE) for (_, val) in ifaces.items(): if val["hwaddr"]: macs.append(val["hwaddr"]) conn = domain.connect() for network in conn.listAllNetworks( libvirt.VIR_CONNECT_LIST_NETWORKS_ACTIVE): for lease in network.DHCPLeases(): for mac in macs: if lease["mac"] == mac: return lease["hostname"]
def ip_addresses(domain: libvirt.virDomain): ips = [] ifaces = domain.interfaceAddresses( libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE) for (_, val) in ifaces.items(): if val["addrs"]: for ipaddr in val["addrs"]: if (ipaddr["type"] == libvirt.VIR_IP_ADDR_TYPE_IPV4 or ipaddr["type"] == libvirt.VIR_IP_ADDR_TYPE_IPV6): ips.append(ipaddr["addr"]) return ips
def domain_address(domain: libvirt.virDomain) -> str: interfaces = domain.interfaceAddresses( libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE) for iface in interfaces.values(): if isinstance(iface, dict) and 'addrs' in iface: for address in iface['addrs']: if 'addr' in address: return address['addr'] raise RuntimeError("No IP address found for the given domain")
def domain_vnc_server(domain: libvirt.virDomain) -> str: etree = ElementTree.fromstring(domain.XMLDesc()) vnc = etree.find('.//graphics[@type="vnc"]') if vnc is None: raise RuntimeError("No VNC connection found for the given domain") if 'socket' in vnc.keys(): return vnc.get('socket') elif {'listen', 'port'} <= set(vnc.keys()): return '::'.join((vnc.get('listen'), vnc.get('port'))) else: raise RuntimeError("No valid VNC connection found for the given domain")
def libvirt_screenshot(domain: libvirt.virDomain) -> BytesIO: """Takes a screenshot of the vnc connection of the guest. The resulting image file will be in Portable Pixmap format (PPM). """ def handler(_, buff, file_handler): file_handler.write(buff) string = BytesIO() stream = domain.connect().newStream(0) try: domain.screenshot(stream, 0, 0) stream.recvAll(handler, string) except Exception as error: stream.abort() raise RuntimeError("Unable to take screenshot") from error else: stream.finish() return string
def _status_code(self, domain:libvirt.virDomain): ''' 获取虚拟机的当前状态码 :param domain: 虚拟机实例 :return: success: state_code:int :raise VirtError() ''' try: info = domain.info() return info[0] except libvirt.libvirtError as e: raise VirtError(err=e)
def status_code(domain: libvirt.virDomain): """ 获取虚拟机的当前状态码 :param domain: 虚拟机实例 :return: success: state_code:int :raise VirtError() """ try: info = domain.info() return info[0] except libvirt.libvirtError as e: raise wrap_error(err=e)
def print_dom_ifaces(dom: libvirt.virDomain) -> None: ifaces = dom.interfaceAddresses( libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE) if ifaces is None: print("Failed to get domain interfaces") exit(0) print(" {0:10} {1:20} {2:12} {3}".format("Interface", "MAC address", "Protocol", "Address")) for (name, val) in ifaces.items(): if val['addrs']: for addr in val['addrs']: print(" {0:10} {1:19} {2:12} {3}/{4}".format( name, val['hwaddr'], IPTYPE[addr['type']], addr['addr'], addr['prefix'])) else: print(" {0:10} {1:19} {2:12} {3}".format(name, val['hwaddr'], "N/A", "N/A"))
def start_domain(self, domain: libvirt.virDomain): """ 开机启动一个虚拟机 :return: success: True failed: False :raise VirtError() """ if self.domain_is_running(domain): return True try: res = domain.create() if res == 0: return True return False except libvirt.libvirtError as e: raise wrap_error(err=e, msg=f'启动虚拟机失败,{str(e)}')
def shutdown_domain(self, domain: libvirt.virDomain): """ 关机 :return: success: True failed: False :raise VirtError() """ if not self.domain_is_running(domain): return True try: res = domain.shutdown() if res == 0: return True return False except libvirt.libvirtError as e: raise wrap_error(err=e, msg=f'关闭虚拟机失败, {str(e)}')
def power_off_domain(self, domain: libvirt.virDomain): """ 关闭电源 :return: success: True failed: False :raise VirtError() """ if not self.domain_is_running(domain): return True res = domain.destroy() try: if res == 0: return True return False except libvirt.libvirtError as e: raise wrap_error(err=e, msg=f'关闭虚拟机电源失败, {str(e)}')
def myDomainEventDeviceRemovalFailedCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, dev: str, opaque: _T) -> None: print("myDomainEventDeviceRemovalFailedCallback: Domain %s(%s) failed to remove device: %s" % ( dom.name(), dom.ID(), dev))
def myDomainEventJobCompletedCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, params: Dict[str, Any], opaque: _T) -> None: print("myDomainEventJobCompletedCallback: Domain %s(%s) %s" % ( dom.name(), dom.ID(), params))
def myDomainEventMigrationIteration(conn: libvirt.virConnect, dom: libvirt.virDomain, iteration: int, opaque: _T) -> None: print("myDomainEventMigrationIteration: Domain %s(%s) started migration iteration %d" % ( dom.name(), dom.ID(), iteration))
def myDomainEventDeviceAddedCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, dev: str, opaque: _T) -> None: print("myDomainEventDeviceAddedCallback: Domain %s(%s) device added: %s" % ( dom.name(), dom.ID(), dev))
def myDomainEventAgentLifecycleCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, state: int, reason: int, opaque: _T) -> None: print("myDomainEventAgentLifecycleCallback: Domain %s(%s) %s %s" % ( dom.name(), dom.ID(), AGENT_STATES[state], AGENT_REASONS[reason]))
def myDomainEventBlockJob2Callback(conn: libvirt.virConnect, dom: libvirt.virDomain, disk: str, type: int, status: int, opaque: _T) -> None: print("myDomainEventBlockJob2Callback: Domain %s(%s) %s on disk %s %s" % ( dom.name(), dom.ID(), BLOCK_JOB_TYPES[type], disk, BLOCK_JOB_STATUS[status]))
def myDomainEventMemoryFailureCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, recipient: int, action: int, flags: int, opaque: _T) -> None: print("myDomainEventMemoryFailureCallback: Domain %s(%s) memory failure recipient %d action %d flags %d" % ( dom.name(), dom.ID(), recipient, action, flags))
def myDomainEventMetadataChangeCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, mtype: int, nsuri: str, opaque: _T) -> None: print("myDomainEventMetadataChangeCallback: Domain %s(%s) changed metadata mtype=%d nsuri=%s" % ( dom.name(), dom.ID(), mtype, nsuri))
def __init__(self, libvirt_domain: libvirt.virDomain): self.libvirt_domain = libvirt_domain self.name = libvirt_domain.name() self.libvirt_snapshot = None
def myDomainEventBlockThresholdCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, dev: str, path: str, threshold: int, excess: int, opaque: _T) -> None: print("myDomainEventBlockThresholdCallback: Domain %s(%s) block device %s(%s) threshold %d exceeded by %d" % ( dom.name(), dom.ID(), dev, path, threshold, excess))
def myDomainEventBalloonChangeCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, actual: int, opaque: _T) -> None: print("myDomainEventBalloonChangeCallback: Domain %s(%s) %d" % ( dom.name(), dom.ID(), actual))
def myDomainEventPMSuspendDiskCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, reason: int, opaque: _T) -> None: print("myDomainEventPMSuspendDiskCallback: Domain %s(%s) system pmsuspend_disk" % ( dom.name(), dom.ID()))