天天看點

KVM虛拟機快照研究(二)

使用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>

    </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'>

      </disks>

    </domainsnapshot>

另一個參數是标志位flags,Libvirt定義了一系列标志位控制建立快照的行為,每一位的作用可以通過檢視Libvirt官方文檔得知。Libvirt官方文檔隻有C語言的api文檔,Python api的用法基本跟C語言的一緻,是以不影響我們參考。标志位的取值及含義如下:

#Restore or alter metadata

VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE    =   1  

#With redefine, make snapshot current

VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT =   2  

#Make snapshot without remembering it

VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA =   4  

#Stop running guest after snapshot

VIR_DOMAIN_SNAPSHOT_CREATE_HALT =   8  

#disk snapshot, not system checkpoint

VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY   =   16 

#reuse any existing external files

VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT   =   32 

#use guest agent to quiesce all mounted file systems   within the domain

VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE =   64 

#atomically avoid partial changes

VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC  =   128

#create the snapshot while the guest is running

VIR_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/python

import libvirt

import sys

from 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>

      <disk   name='%s'>

    </domainsnapshot>""" % (diskfiles[0],diskfiles[1])

    with open('snapshot01.xml','w') as f:

        f.write(xml)

def createSnapshot(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()方法檢視合并任務是否已完成。

    dom = getDom('vm')

  dom.blockCommit('vda','/data/vm.snapshot02','/data/vm.snapshot03')

    dom.blockCommit('vdb','/data/data.snapshot02','/data/data.snapshot03')

繼續閱讀