averainy's Blog

averainy

14 Jun 2022

Backup Kvm Vms With Python Libvirt

we changed the vm platform from esxi to kvm a few months ago,so we need to writ e some scripts to backup vms automatically.
we only have a few vms,so we just need a simple script that can do the following operation:

  1. shutdown vm
  2. backup configure xml and images
  3. start vm
  4. send email when backup completely
    so we write the following script to do that:
#!/usr/bin/env python3
import sys
import os
import time
import shutil
import libvirt
from xml.dom import minidom
import logging
logging.basicConfig(
        level=logging.INFO,
        encoding='utf-8',
        format="%(asctime)s [%(levelname)s] %(message)s",
        handlers=[
            logging.FileHandler("~/backup_vm.log"),
            logging.StreamHandler(sys.stdout)
            ]
        )
root_backup_dir='~/mnt'
backup_list = ['vm_1','vm_2','vm_3']
max_retry_count=20
def backup_vm(dom,domName):
    logging.info("backup vm:{0} start".format(domName))
    back_path = os.path.join(root_backup_dir,domName+time.strftime("_%Y%m%d", time.localtime()))
    if not os.path.exists(back_path):
        os.mkdir(back_path)
    #backup xml
    raw_xml = dom.XMLDesc(0)
    with open(os.path.join(back_path,domName+'.xml'),'w+') as fp:
        fp.write(raw_xml)
    # backup vm disk
    xml = minidom.parseString(raw_xml)
    diskTypes = xml.getElementsByTagName('disk')
    for diskType in diskTypes:
        if diskType.getAttribute('device') != 'disk':
            continue
        sourceNode = diskType.getElementsByTagName('source')[0]
        src=sourceNode.getAttribute('file')
        shutil.copyfile(src,os.path.join(back_path,os.path.basename(src)))
    logging.info("backup vm:{0} end".format(domName))
def main():
    conn = libvirt.open("qemu:///system")
    for domName in backup_list:
        dom = conn.lookupByName(domName)
        if dom.isActive():
            dom.shutdown()
    time.sleep(60)
    retry_count=0
    while len(backup_list) != 0:
        for domName in backup_list:
            dom = conn.lookupByName(domName)
            if dom.isActive():
                dom.shutdown()
                time.sleep(5)
                if retry_count > max_retry_count:
                    backup_list.remove(domName)
                    logging.error('重试次数超过最大值。虚拟机:{0}备份失败'.format(domName))
                    break
                retry_count = retry_count +1
                continue
            backup_vm(dom,domName)
            dom.create()
            backup_list.remove(domName)
            retry_count=0
            break
    conn.close()
if __name__ == '__main__':
    try:
        main()
        from youjian import SendEmail
        send = SendEmail()
        user_list = ['[email protected]']
        sub = u"备份虚拟机成功"
        content = u"备份虚拟机成功"
        send.send_mail(user_list,sub,content)
    except Exception as e:
        logging.error(e)
        raise e