#!/bin/sh # # Create a new VM for liw. set -eu verbose() { echo "INFO: $@" } die() { echo "$@" 1>&2 exit 1 } get_ip() { python -c ' import sys, json leases = json.load(open(sys.argv[1])) for lease in leases: if lease["mac-address"] == sys.argv[2]: print lease["ip-address"] ' "$1" "$2" || true } xz_uncompressed_size() { xz --robot --verbose --list "$1" | awk '/^file/ { print $5 }' } raw_uncompressed_size() { stat -c %s "$1" } # Check parameters. if [ "$#" -lt 2 ] then die "Usage: $0 NAME BASE [virt-install-options]" fi verbose "Command line args OK" # Config variables. . "$HOME/.config/ansibleness/vm.conf" verbose "Loaded config file" # Command line parameters: name of VM and base image (no .img.xz suffix). name="$1" case "$2" in */*) basepath="$2" ;; *) basepath="$imagedir/base-$2.img.xz" ;; esac verbose "basepath=$basepath" shift 2 # Does the base image exist? if [ ! -e "$basepath" ] then echo "$basepath does not exist" 1>&2 exit 1 fi verbose "$basepath exists" # Is base image compressed? case "$basepath" in *.xz) xz=true ;; *) xz=false ;; esac # How large is the (uncompressed) image? In bytes. if $xz then size="$(xz_uncompressed_size "$basepath")" else size="$(raw_uncompressed_size "$basepath")" fi verbose "Image is $size bytes" # Create new LV. verbose "Creating LV /dev/$vg/$name" sudo lvcreate --name "$name" --size "${size}b" \ --zero y --wipesignatures n --activate y "$vg" lvpath="/dev/$vg/$name" verbose "lvpath=$lvpath" #sudo lvchange -ay "$lvpath" # Copy uncompressed image to LV. if $xz then verbose "Uncompressing and copying image to LV" unxz < "$basepath" | pv --size "$size" | sudo ionice -c3 tee "$lvpath" > /dev/null else verbose "Copying uncompressed imagew to LV" pv "$basepath" | sudo ionice -c3 tee "$lvpath" > /dev/null fi # Edit /etc/hostname verbose "Set hostname on new system to $name" mnt="$(mktemp -d)" for part in $(sudo kpartx -asv "$lvpath" | awk '/^add map / { print $3 }') do sudo mount "/dev/mapper/$part" "$mnt" if [ -e "$mnt/etc/hostname" ] then echo "$name" | sudo tee "$mnt/etc/hostname" fi sudo umount "$mnt" done sudo kpartx -dsv "$lvpath" # Create VM. verbose "Creating VM" virt-install --connect qemu:///system \ --quiet \ --name="$name" \ --memory=1024 \ --cpu=host-model-only \ --import \ --os-variant=debian9 \ --disk="path=$lvpath,cache=none" \ --network="$vmnetwork" \ --graphics=spice \ --noautoconsole \ "$@" # If we're using the virtual network "default", wait for the VM to get # a DHCP response and add it to /etc/hosts. We don't do it for other # types of network (e.g., bridge=br0), since we ... can't. if [ "$vmnetwork" = "network=default" ] then verbose "Waiting for VM to boot and get IP" # Get the MAC address. mac="$(virsh -c qemu:///system dumpxml "$name" | sed -n "/ /dev/null # Done. echo "Virtual machine $name ($ip) has been created and started." else echo "Virtual machine $name has been created and started, and may be ready soon." fi