diff options
Diffstat (limited to 'create-vm')
-rwxr-xr-x | create-vm | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/create-vm b/create-vm new file mode 100755 index 0000000..00242fc --- /dev/null +++ b/create-vm @@ -0,0 +1,148 @@ +#!/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 provision(vm, pubkey): + ssh_opts = [ + "ControlMaster=auto", + "ControlPersist=60s", + "StrictHostKeyChecking=accept-new", + "UserKnownHostsFile=/dev/null", + ] + + env = dict(os.environ) + env["ANSIBLE_SSH_ARGS"] = " ".join(f"-o{opt}" for opt in ssh_opts) + + vars_file = {"user_pub": pubkey} + + fd, filename = tempfile.mkstemp() + os.write(fd, yaml.safe_dump(vars_file).encode("UTF-8")) + os.close(fd) + + argv = [ + "ansible-playbook", + "-i", + "hosts", + "manager.yml", + f"-eansible_ssh_host={vm}", + f"-e@{filename}", + ] + subprocess.check_output(argv, env=env) + + os.remove(filename) + + +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().rstrip() + 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) + + +# provision(vm, pubkey) + + +main() |