#!/usr/bin/env python3 import os import shutil import socket import subprocess import sys import tempfile import time import yaml def cloud_init_iso(iso, hostname, pubkey): tmp = tempfile.mkdtemp() with open(os.path.join(tmp, "meta-data"), "w") as f: f.write( f"""\ # Amazon EC2 style metadata local-hostname: {hostname} """ ) with open(os.path.join(tmp, "user-data"), "w") as f: f.write( f"""\ #cloud-config ssh_authorized_keys: - {pubkey} """ ) subprocess.check_call( [ "genisoimage", "-quiet", "-volid", "cidata", "-joliet", "-rock", "-output", iso, tmp, ] ) shutil.rmtree(tmp) def create_vm(vm, image, iso, memory=1024, cpus=1): subprocess.check_call( [ "virt-install", "--name", vm, "--memory", str(memory), "--vcpus", str(cpus), f"--disk=path={image},cache=none", f"--disk=path={iso},readonly=on", "--network=network=default", "--connect", "qemu:///system", "--cpu=host-passthrough", "--os-variant=debian9", "--import", "--graphics=spice", "--noautoconsole", "--quiet", ] ) def wait_for_ssh(hostname): ssh_port = 22 while True: time.sleep(5) try: conn = socket.create_connection((hostname, ssh_port), timeout=1) except Exception: continue conn.close() break def main(): config = yaml.safe_load(open(sys.argv[1])) base = config["base_image"] vm = config["name"] img = config["image_file"] size = config["image_size"] pubkey = config["public_key"] memory = config.get("memory", 1024) cpus = config.get("cpus", 1) memory = int(memory) cpus = int(cpus) pubkey = open(pubkey).read() iso = f"{vm}.iso" cloud_init_iso(iso, vm, pubkey) if os.path.exists(img): os.remove(img) shutil.copy(base, img) subprocess.check_call(["qemu-img", "resize", "-q", img, size]) create_vm(vm, img, iso, memory=memory, cpus=cpus) wait_for_ssh(vm) os.remove(iso) main()