根据python-libvirt写的一个脚本,算比较全,包括虚拟机的开启,关闭,快照,克隆,以及虚拟机的系统参数(设备信息,镜像,CPU,磁盘,内存、网络等)
import libvirt
import os
from datetime import datetime
try:
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE, \
VIR_MIGRATE_UNSAFE, VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA
except:
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE
from lxml import etree
from xml.etree import ElementTree
import time
class Libvirt():
def __init__(self, authurl, domainname):
self.conn = libvirt.open(authurl)
self.dom = self.conn.lookupByName(domainname)
def get_xml_path(self, text, path = None, func = None):
"""
Return the content from the passed xml xpath, or return the result
of a passed function (receives xpathContext as its only arg)
"""
doc = None
ctx = None
result = None
html = etree.HTML(str(text), etree.HTMLParser())
if path and 'domain' in path:
path = './' + path
if path:
if '@' in path:
pass
else:
path = path + '/text()'
try:
result = html.xpath(path)
if len(result) > 0:
result = int(result[0])
except:
pass
if func:
result = func(html)
return result
def start(self):
self.dom.create()
def is_active(self):
r = self.dom.isActive()
return r
def status(self):
r = self.dom.state()[0]
return r
def shutdown(self):
self.dom.destroy()
def resume(self):
self.dom.resume()
def get_network(self,net):
netw = self.conn.networkLookupByName(net)
return netw
def get_net_device(self):
def get_mac_ipaddr(net, mac_host):
def fixed(ctx):
for net in ctx.xpath('/network/ip/dhcp/host'):
mac = net.xpath('@mac')[0]
host = net.xpath('@ip')[0]
if mac == mac_host:
return host
return None
return self.get_xml_path(net.XMLDesc(0), func=fixed)
def networks(ctx):
result = []
for net in ctx.xpath('.//domain/devices/interface'):
mac_host = net.xpath('mac/@address')[0]
nic_host = net.xpath('source/@network|source/@bridge|source/@dev')[0]
try:
net = self.get_network(nic_host)
ip = get_mac_ipaddr(net, mac_host)
except:
ip = None
result.append({'mac': mac_host, 'nic': nic_host, 'ip': ip})
return result
return self.get_xml_path(self.dom.XMLDesc(0), func=networks)
def get_disk_device(self):
def disks(ctx):
result = []
dev = None
volume = None
storage = None
src_fl = None
disk_format = None
for disk in ctx.xpath('.//domain/devices/disk'):
device = disk.xpath('@device')[0]
if device == 'disk':
try:
dev = disk.xpath('target/@dev')[0]
src_fl = disk.xpath('source/@file|source/@dev|source/@name|source/@volume')[0]
disk_format = disk.xpath('driver/@type')[0]
try:
vol = self.conn.storageVolLookupByPath(src_fl)
volume = vol.name()
stg = vol.storagePoolLookupByVolume()
storage = stg.name()
except:
volume = src_fl
except:
pass
finally:
result.append(
{'dev': dev, 'image': volume, 'storage': storage, 'path': src_fl, 'format': disk_format})
return result
return self.get_xml_path(self.dom.XMLDesc(0), func = disks)
def get_memory(self):
mem = self.get_xml_path(self.dom.XMLDesc(0), "/domain/currentmemory")
return int(mem) / 1024
def memory_usage(self):
self.dom.setMemoryStatsPeriod(10)
meminfo = self.dom.memoryStats()
print(meminfo)
free_mem = float(meminfo['unused'])
total_mem = float(meminfo['available'])
mem_usage = ((total_mem - free_mem) / total_mem) * 100
return mem_usage
def get_vcpu(self):
cur_vcpu = self.get_xml_path(self.dom.XMLDesc(0), "/domain/vcpu/@current")
if cur_vcpu:
vcpu = cur_vcpu
else:
vcpu = self.get_xml_path(self.dom.XMLDesc(0), "/domain/vcpu")
return vcpu
def cpu_usage(self):
cpu_usage = {}
if self.status() == 1:
nbcore = self.conn.getInfo()[2]
cpu_use_ago = self.dom.info()[4]
time.sleep(1)
cpu_use_now = self.dom.info()[4]
diff_usage = cpu_use_now - cpu_use_ago
cpu_usage['cpuuage'] = 100 * diff_usage / (1 * nbcore * 10 ** 9)
else:
cpu_usage['cpuusage'] = 0
return cpu_usage
def disk_use(self):
devices = []
dev_usrate = []
dev_usage = []
tree = ElementTree.fromstring(self.dom.XMLDesc(0))
for disk in tree.findall('devices/disk'):
if disk.get('device') == 'disk':
dev_file = None
dev_bus = None
network_disk = True
for elm in disk:
if elm.tag == 'source':
if elm.get('protocol'):
dev_file = elm.get('protocol')
network_disk = True
if elm.get('file'):
dev_file = elm.get('file')
if elm.get('dev'):
dev_file = elm.get('dev')
if elm.tag == 'target':
dev_bus = elm.get('dev')
if (dev_file and dev_bus) is not None:
if network_disk:
dev_file = dev_bus
devices.append([dev_file, dev_bus])
for dev in devices:
if self.status() == 1:
rd_use_ago = self.dom.blockStats(dev[0])[1]
wr_use_ago = self.dom.blockStats(dev[0])[3]
time.sleep(1)
rd_use_now = self.dom.blockStats(dev[0])[1]
wr_use_now = self.dom.blockStats(dev[0])[3]
rd_diff_usage = rd_use_now - rd_use_ago
wr_diff_usage = wr_use_now - wr_use_ago
else:
rd_diff_usage = 0
wr_diff_usage = 0
dev_usage.append(({'dev': dev[1], 'usage': round(self.dom.blockInfo(dev[0])[2]*100/self.dom.blockInfo(dev[0])[0], 2)}))
dev_usrate.append({'dev': dev[1], 'rd': rd_diff_usage, 'wr': wr_diff_usage})
return dev_usage, dev_usrate
def net_usrate(self):
devices = []
dev_usage = []
tree = ElementTree.fromstring(self.dom.XMLDesc(0))
if self.status() == 1:
tree = ElementTree.fromstring(self.dom.XMLDesc(0))
for target in tree.findall("devices/interface/target"):
devices.append(target.get("dev"))
for i, dev in enumerate(devices):
rx_use_ago = self.dom.interfaceStats(dev)[0]
tx_use_ago = self.dom.interfaceStats(dev)[4]
time.sleep(1)
rx_use_now = self.dom.interfaceStats(dev)[0]
tx_use_now = self.dom.interfaceStats(dev)[4]
rx_diff_usage = (rx_use_now - rx_use_ago) * 8
tx_diff_usage = (tx_use_now - tx_use_ago) * 8
dev_usage.append({'dev': i, 'rx': rx_diff_usage, 'tx': tx_diff_usage})
else:
for i, dev in enumerate(self.get_net_device()):
dev_usage.append({'dev': i, 'rx': 0, 'tx': 0})
return dev_usage
def create_snapshot(self, name):
xml = """<domainsnapshot>
<name>%s</name>
<state>shutoff</state>
<creationtime>%d</creationtime>""" % (name, time.time())
xml += self.dom.XMLDesc(VIR_DOMAIN_XML_SECURE)
xml += """<active>0</active>
</domainsnapshot>"""
self.dom.snapshotCreateXML(xml, 0)
def get_snapshot(self):
snapshots = []
snapshot_list = self.dom.snapshotListNames(0)
print(snapshot_list)
for snapshot in snapshot_list:
snap = self.dom.snapshotLookupByName(snapshot, 0)
snap_time_create = self.get_xml_path(snap.getXMLDesc(0), "/domainsnapshot/creationtime")
print(snap.getXMLDesc(0))
print(snap_time_create)
snapshots.append({'date': datetime.fromtimestamp(int(snap_time_create)), 'name': snapshot})
return snapshots
def snapshot_delete(self, snapshotname):
snap = self.dom.snapshotLookupByName(snapshotname, 0)
snap.delete(0)
def snapshot_revert(self, snapshotname):
snap = self.dom.snapshotLookupByName(snapshotname, 0)
self.dom.revertToSnapshot(snap, 0)
def clone_instance(self, clone_data):
#clone_data include name\disk\address\
clone_dev_path = []
xml = self.dom.XMLDesc(VIR_DOMAIN_XML_SECURE)
tree = ElementTree.fromstring(xml)
name = tree.find('name')
name.text = clone_data['name']
uuid = tree.find('uuid')
tree.remove(uuid)
for num, net in enumerate(tree.findall('devices/interface')):
elm = net.find('mac')
elm.set('address', clone_data['net-' + str(num)])
for disk in tree.findall('devices/disk'):
if disk.get('device') == 'disk':
elm = disk.find('target')
device_name = elm.get('dev')
if device_name:
target_file = clone_data['disk-' + device_name]
try:
meta_prealloc = clone_data['meta-' + device_name]
except:
meta_prealloc = False
elm.set('dev', device_name)
elm = disk.find('source')
source_file = elm.get('file')
if source_file:
clone_dev_path.append(source_file)
clone_path = os.path.join(os.path.dirname(source_file),
target_file)
elm.set('file', clone_path)
vol = self.get_volume_by_path(source_file)
vol_format = self.get_xml_path(vol.XMLDesc(0),
"/volume/target/format/@type")
if vol_format == 'qcow2' and meta_prealloc:
meta_prealloc = True
vol_clone_xml = """
<volume>
<name>%s</name>
<capacity>0</capacity>
<allocation>0</allocation>
<target>
<format type='%s'/>
</target>
</volume>""" % (target_file, vol_format)
stg = vol.storagePoolLookupByVolume()
stg.createXMLFrom(vol_clone_xml, vol, meta_prealloc)
self.dom.defineXML(ElementTree.tostring(tree))