2021-03-24 22:05:34 +03:00
|
|
|
#!/usr/bin/python3
|
2021-03-24 23:27:57 +03:00
|
|
|
# Script by Александр Дрожевский from Rebrain
|
2021-03-24 22:05:34 +03:00
|
|
|
import time
|
|
|
|
import argparse
|
|
|
|
import libvirt
|
|
|
|
from lxml import etree
|
|
|
|
from lxml.builder import E
|
|
|
|
|
|
|
|
|
|
|
|
def parse_args():
|
|
|
|
parser = argparse.ArgumentParser(description='Create snapshot for libvirt machine')
|
|
|
|
parser.add_argument('--name', required=True, help='Machine name')
|
|
|
|
parser.add_argument('--device', required=True, help='Device path (like vda)')
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
|
|
def create_snapshot_node(disk_node):
|
|
|
|
device = disk_node.xpath('/domain/devices/disk/target/@dev')[0]
|
|
|
|
disk_path = disk_node.xpath('/domain/devices/disk/source/@file')[0]
|
|
|
|
|
|
|
|
now = int(time.time())
|
|
|
|
snap_path = disk_path.rsplit('.', 1)[0]
|
|
|
|
snap_path = f'{snap_path}-{now}.snap'
|
|
|
|
snap_name = snap_path.rsplit('/', 1)[1]
|
|
|
|
|
|
|
|
snap = E.domainsnapshot()
|
|
|
|
snap.append(E.name(snap_name))
|
|
|
|
|
|
|
|
disks = E.disks()
|
|
|
|
disk = E.disk(name=device)
|
|
|
|
disk.append(E.source(file=snap_path))
|
|
|
|
disks.append(disk)
|
|
|
|
|
|
|
|
snap.append(disks)
|
|
|
|
return snap
|
|
|
|
|
|
|
|
def get_disk_by_name(vm, name):
|
|
|
|
raw_xml = vm.XMLDesc(0)
|
|
|
|
xml = etree.XML(raw_xml)
|
|
|
|
disks = xml.xpath(f'/domain/devices/disk/target[@dev="{name}"]/..')
|
|
|
|
return disks[0]
|
|
|
|
|
|
|
|
def main():
|
|
|
|
args = parse_args()
|
|
|
|
session = libvirt.open('qemu:///system')
|
|
|
|
try:
|
|
|
|
vm = session.lookupByName(args.name)
|
|
|
|
except libvirt.libvirtError:
|
|
|
|
print(f'Machine with name {args.name} not found!')
|
|
|
|
session.close()
|
|
|
|
return
|
|
|
|
disk = get_disk_by_name(vm, args.device)
|
|
|
|
snapshot = create_snapshot_node(disk)
|
|
|
|
vm.snapshotCreateXML(etree.tostring(snapshot, encoding='unicode'),
|
|
|
|
libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY | libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC)
|
|
|
|
session.close()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|