-
Notifications
You must be signed in to change notification settings - Fork 0
/
backup.py
90 lines (69 loc) · 3.77 KB
/
backup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/bin/python2
import argparse
import datetime
import errno
import logging
import os
import stat
import sys
import time
from xml.etree import ElementTree
import libvirt # python2 linux only?! (no wheel for windows, could be built with swig?)
from config import ACCESS_KEY_ID, SECRET_ACCESS_KEY, PASSPHRASE, REGION_NAME, COMPRESSION_LEVEL
parser = argparse.ArgumentParser()
parser.add_argument('--blockpull',
help='Perform a blockpull prior to uploading, so that the resulting disk image is independent of prior snapshots.',
action='store_true')
parser.add_argument('--connection', help='Specify qemu:///system or qemu:///session', action='store')
args = parser.parse_args()
from glacier import Glacier
if __name__ == '__main__':
glacier = Glacier(access_key_id=ACCESS_KEY_ID, secret_access_key=SECRET_ACCESS_KEY, region_name=REGION_NAME)
try:
logging.debug("Connecting to libvirt")
virsh = libvirt.open(args.connection)
vault = glacier.create_vault()
for domain in virsh.listAllDomains(flags=libvirt.VIR_CONNECT_LIST_DOMAINS_ACTIVE):
logging.debug("Parsing XML for: %s" % domain.name())
domXML = domain.XMLDesc()
logging.debug(domXML)
tree = ElementTree.fromstring(domXML)
disks = tree.findall('./devices/disk[@type="file"]/source/[@file]')
if len(disks) == 0:
continue
snapshotXML = "<domainsnapshot><disks>"
for disk_file in [disk.attrib['file'] for disk in disks]:
is_block = stat.S_ISBLK(os.stat(disk_file).st_mode)
logging.debug("Disk: %s", disk_file)
if is_block or disk_file.startswith('/dev/'):
# TODO: support block devices? (LVM snapshot?)
logging.info('Skipping block device: %s', disk_file)
continue
snapshotXML += "<disk name='%s' snapshot='external'><driver name='qemu' type='qcow2'/></disk>" % disk_file
if args.blockpull:
# issue block pull on the read-only base image, making it independent of any previous snapshots
blockJob = domain.blockPull(disk_file)
while domain.blockJobInfo(disk_file):
time.sleep(30)
# TODO use returned jobInfo to wait more appropriately
snapshotXML += "</disks></domainsnapshot>"
logging.debug("Creating snapshot...")
# TODO: get guest agent working for fs quescing
snapshot = domain.snapshotCreateXML(snapshotXML,
flags=libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA | # makes restoring snapshot inconvienant, but no 'cleanup' required this way...
libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC
)
# disks are now the read-only bases for the newly created snapshot disk files.
logging.info("Snapshot created: %s" % snapshot.getName())
result = glacier.upload(disk_file, tag=domain.name(), passphrase=PASSPHRASE, compression_level=COMPRESSION_LEVEL)
if result is False:
logging.error("Upload of %s failed", disk_file)
else:
logging.info("Upload of %s completed successfully.")
logging.debug(result)
except Exception as e:
logging.critical(e)
sys.exit(errno.EAGAIN)
else:
logging.info("%s - No errors occurred during backup." % (datetime.datetime.utcnow()))