buildbot-scripts/qemu.hook
2021-02-10 13:26:46 +01:00

179 lines
4.9 KiB
Python

#!/usr/bin/python3
"""
Creates an empemeral image and patches it
"""
# Script /etc/libvirt/hooks/qemu
# Don't forget to execute service libvirt-bin restart
# Also see https://www.libvirt.org/hooks.html
# This script make clean VM for each start using base image
import os
import subprocess
import sys
import tempfile
import xml.etree.ElementTree as et
from jinja2 import Environment, exceptions, FileSystemLoader
BACKINGSTORE_PATH = '/var/lib/libvirt/backingstore/'
IMAGES_PATH = '/var/lib/libvirt/images/'
EPHEMERAL_PATH = '/var/lib/libvirt/ephemeral/'
CLOUDINIT_PATH = '/mnt/nfsimages'
VENDOR_EXT = '.vendor'
USER_EXT = '.user'
CLOUDINIT_EXT = '.iso'
xml = None
def parse_xml():
"""
Parse XML provided in stdin
"""
global xml
if xml is None:
data = sys.stdin.read()
xml = et.fromstring(data)
return xml
def find_base(domain):
"""
Convert VM name into hostname (part before first _)
"""
return domain.split("_", 2)[0]
def prepare_files(domain, env_):
"""
Create the ephemeral images
"""
xml = parse_xml()
base = find_base(domain)
for disk in xml.iterfind("./devices/disk[@device='disk']/source"):
disk = disk.get('file')
if not os.path.exists(os.path.join(BACKINGSTORE_PATH,
base + '.qcow2')):
continue
if not disk.startswith(EPHEMERAL_PATH):
continue
cmd = ['/usr/bin/qemu-img',
'create', '-b',
os.path.join(BACKINGSTORE_PATH, base + '.qcow2'),
'-f', 'qcow2',
'-F', 'qcow2',
disk]
subprocess.call(cmd)
# resize
cmd = ['/usr/bin/qemu-img',
'resize', disk, "+10G"
]
subprocess.call(cmd)
try:
x = xml.find("./metadata/{http://buildbot.net/}auth")
username, password, master = (x.attrib["username"],
x.attrib["password"],
x.attrib["master"])
except Exception:
username = domain
password = domain
master = None
for cdrom in xml.iterfind("./devices/disk[@device='cdrom']/source"):
cdrom = cdrom.get('file')
if not cdrom.startswith(EPHEMERAL_PATH):
continue
# cloud init
if not os.path.exists(os.path.join(BACKINGSTORE_PATH,
base + USER_EXT)):
continue
hostname = os.uname()[1].replace('.', '_')
userdata = {
'guest': hostname,
'hostname': domain,
'buildbot_username': username,
'buildbot_password': password,
'buildbot_master': master
}
with tempfile.NamedTemporaryFile(mode='w+t') as temp_file:
# jinja user data
try:
temp_file.write(env_.get_template(domain + USER_EXT).
render(userdata))
except exceptions.TemplateNotFound:
temp_file.write(env_.get_template(base + USER_EXT).
render(userdata))
temp_file.flush()
# make ISO
cmd = ['/usr/bin/cloud-localds',
# '-V', os.path.join(CLOUDINIT_PATH,
# domain + VENDOR_EXT),
# '-H', HOSTNAME,
os.path.join(cdrom),
temp_file.name
]
subprocess.call(cmd)
def cleanup_files():
"""
Delete the ephemeral images
"""
xml = parse_xml()
for disk in xml.iterfind("./devices/disk[@device='disk']/source"):
disk = disk.get('file')
if disk.startswith(EPHEMERAL_PATH):
try:
os.remove(disk)
except FileNotFoundError:
pass
for cdrom in xml.iterfind("./devices/disk[@device='cdrom']/source"):
cdrom = cdrom.get('file')
if cdrom.startswith(EPHEMERAL_PATH):
try:
os.remove(cdrom)
except FileNotFoundError:
pass
def get_buildbot_password():
"""
Retrieve buildbot password for guest
"""
fname = '/etc/libvirt/buildbot.pwd'
with open(fname) as file_handle:
content = [line.rstrip('\n') for line in file_handle]
try:
return content[0]
except (TypeError, IndexError):
return "password"
if __name__ == "__main__":
try:
# pylint: disable=unbalanced-tuple-unpacking
VIR_DOMAIN, ACTION = sys.argv[1:3]
except IndexError:
sys.exit(1)
ENV = Environment(autoescape=False,
loader=FileSystemLoader(BACKINGSTORE_PATH),
trim_blocks=False)
if ACTION in ["prepare"]:
cleanup_files()
prepare_files(VIR_DOMAIN, ENV)
if ACTION in ["release"]:
cleanup_files()