您的位置:首页

KVM虚拟机快照研究(二)

2018-04-10 10:18 169 查看
使用Python脚本操作快照

上一篇中介绍了KVM虚拟机各种快照的原理和命令行操作方法,由于磁盘外部快照最实用,所以本篇主要讲怎么利用Libvirt api操作磁盘外部快照。其中会涉及一些Libvirt api的基本用法,也会一起介绍。

操作环境

环境同上篇。Python与libvirt服务交互用的是libvirt模块;操作虚拟机的XML描述文件用的是xml.dom模块。

创建快照

我们要完成的功能是,给出一个虚拟机的名称,创建这个虚拟机的磁盘快照。首先建立与libvirt服务的连接,然后根据虚拟机名称获取该domain对象:
conn = libvirt.open("qemu:///system")dom = conn.lookupByName('vm')
domain对象的方法snapshotCreateXML()实现了通过一个XML描述文件创建快照的功能,该方法接收的参数是一个描述快照的XML字符串(不是文件)和标志位flags。快照的XML描述文件一般是下面这种格式:
<domainsnapshot> <name>snapshot01</name> <description>test api</description> <disks> <disk name='/path/diskname'> </disk> <disk name='/path/diskname'> </disk> </disks> </domainsnapshot>
可以看出,构建快照的XML描述文件需要首先获取到虚拟机的磁盘文件名,获取方法是读取并解析虚拟机的xml文件:
xml = dom.XMLDesc(0)doc = minidom.parseString(xml)disks = doc.getElementsByTagName('disk')for disk in disks: if disk.getAttribute('device') == 'disk': diskfile = disk.getElementsByTagName('source')[0].getAttribute('file') print diskfile
这段代码的输出结果是:
[root@localhost snapshot]# python test.py /data/vm.img/data/data.img
然后把磁盘文件的名字填到快照xml里,存放在文件snapshot01.xml中:
<domainsnapshot>
<name>snapshot01</name>
<description>test api</description>
<disks>
<disk name='/data/vm.img'>
</disk>
<disk name='/data/data.img'>
</disk>
</disks>
</domainsnapshot>
另一个参数是标志位flags,Libvirt定义了一系列标志位控制创建快照的行为,每一位的作用可以通过查看Libvirt官方文档得知。Libvirt官方文档只有C语言的api文档,Python api的用法基本跟C语言的一致,所以不影响我们参考。标志位的取值及含义如下:
#Restore or alter metadataVIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE = 1 #With redefine, make snapshot currentVIR_DOMAIN_SNAPSHOT_CREATE_CURRENT = 2 #Make snapshot without remembering itVIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA = 4 #Stop running guest after snapshotVIR_DOMAIN_SNAPSHOT_CREATE_HALT = 8 #disk snapshot, not system checkpointVIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY = 16 #reuse any existing external filesVIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT = 32 #use guest agent to quiesce all mounted file systems within the domainVIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE = 64 #atomically avoid partial changesVIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC = 128 #create the snapshot while the guest is runningVIR_DOMAIN_SNAPSHOT_CREATE_LIVE = 256
我们需要用到的标志有VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA,VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY和VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC,分别对应virsh snapshot-create-as命令的参数--disk-only,--no-metadata和--atmotic。多个标志位叠加是通过二进制按位或操作,换算成十进制下的操作就是相加,所以flags的值为4+16+128=148。
snapshotXML = open('snapshot01.xml','rb').read()dom.snapshotCreateXML(snapshotXML,flags=148)
脚本内容汇总如下:
#!/usr/bin/pythonimport libvirtimport sysfrom xml.dom import minidom def getDom(vm): try: conn = libvirt.open("qemu:///system") dom = conn.lookupByName(vm) return dom except Exception,e: print "Get domain object of vm %s failed: %s" % (vm,str(e)) sys.exit(1) def getDiskfile(vm): dom = getDom(vm) xml = dom.XMLDesc(0) doc = minidom.parseString(xml) disks = doc.getElementsByTagName('disk') diskfiles = [] for disk in disks: if disk.getAttribute('device') == 'disk': diskfile = disk.getElementsByTagName('source')[0].getAttribute('file') diskfiles.append(diskfile) return diskfiles def createXML(vm): diskfiles = getDiskfile(vm) xml = """<domainsnapshot> <name>snapshot01</name> <description>test api</description> <disks> <disk name='%s'> </disk> <disk name='%s'> </disk> </disks> </domainsnapshot>""" % (diskfiles[0],diskfiles[1]) with open('snapshot01.xml','w') as f: f.write(xml) def createSnapshot(vm): dom = getDom(vm) snapshotXML = open('snapshot01.xml','rb').read() dom.snapshotCreateXML(snapshotXML,flags=148) if __name__ == "__main__": createXML('vm') createSnapshot('vm')

合并快照文件

首先为虚拟机创建4个快照,现在磁盘文件形成了如下back chain(原理见上篇文章):base<-snapshot01<-snapshot02<-snapshot03<-snapshot04*
我们要通过api把snapshot03合并到snapshot02,用到的方法是blockCommit(),该方法有3个必须提供的参数disk,base和top,分别对应virsh blockcommit命令的参数--path,--base和--top。把命令virsh blockcommit --domain vm –path vda --base /data/vm.snapshot02 --top /data/vm.snapshot03翻译成Python代码就是:
dom.blockCommit('vda','/data/vm.snapshot02','/data/vm.snapshot03')
合并快照文件可能需要很长时间,但是blockCommit是异步的,执行完立即返回,如果我们想查看后台的这个合并任务,需要用blockJobInfo()方法查看合并任务是否已完成。脚本内容汇总如下:
#!/usr/bin/pythonimport libvirtimport sys def getDom(vm): try: conn = libvirt.open("qemu:///system") dom = conn.lookupByName(vm) return dom except Exception,e: print "Get domain object of vm %s failed: %s" % (vm,str(e)) sys.exit(1) if __name__ == "__main__": dom = getDom('vm') dom.blockCommit('vda','/data/vm.snapshot02','/data/vm.snapshot03') dom.blockCommit('vdb','/data/data.snapshot02','/data/data.snapshot03')
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  kvm 快照