#!/bin/sh -e
#
# Copyright (C) 2007-2009 Canonical, Ltd.
# Author: Jamie Strandboge <jamie@canonical.com>
# License: GPLv3
#
# Simple starter script for when virt-manager won't do.
#

ustconf="$HOME/.uqt-vm-tools.conf"
if [ -s "$ustconf" ]; then
    . "$ustconf"
else
    echo "Could not find '$ustconf'"
    exit 1
fi

. $UQT_VM_TOOLS/libvm.sh
abort_if_root

help() {
    cat << EOM
Usage:	vm-start [-v] [-w] [-s] <vm1> <vm2>
	vm-start [-v] [-w] [-s] -p PREFIX [-a ARCH]

 -v	Do not launch virt-viewer on started VMs
 -w	Wait for VMs to be SSH-available before exiting
 -s	Create new snapshot, overwriting any existing snapshots
EOM
}

start_machine() {
    machine="$1"
    if ! vm_exists $machine ; then
        echo "'$machine' does not exist" >&2
        return 1
    fi

    if vm_running $machine ; then
        echo "'$machine' is already running" >&2
        return 0
    fi

    disks=`get_disks $machine`
    if [ -z "$disks" ]; then
        echo "Could not find any disks for '$machine'. Skipping" >&2
        return
    fi

    if [ "$can_snapshot" = "no" ]; then
        for d in $disks ; do
            real=`readlink -f "$d"`
            dir=`dirname "$real"`
            bn=`basename "$real" .qcow2`
            pristine="$dir/$bn.pristine.qcow2"
            if [ ! -e "$real" ]; then
                echo -n "ERROR: '$real' does not exist. Aborting" >&2
                if [ -e "$pristine" ]; then
                    echo ". Try with '-s'" >&2
                else
                    echo "" >&2
                fi
                return 1
            fi
        done
    fi

    if [ "$can_snapshot" = "yes" ] && ! vm_can_snapshot "$machine" ; then
        echo "Not using snapshot for '$m'" >&2
        can_snapshot="no"
    fi

    if [ "$can_snapshot" = "yes" ]; then
        uuid=`virsh --connect ${vm_connect} domuuid "$machine" 2>/dev/null | head -1`
        if [ -z "$uuid" ]; then
            echo "ERROR: could not find uuid" >&2
            return 1
        fi

        # need to update the apparmor profile for the pristine disks
        update_apparmor="no"
        aa_profile="/etc/apparmor.d/libvirt/libvirt-$uuid"
        if `virsh --connect ${vm_connect} dominfo "$machine" 2>/dev/null | grep -q 'Security model: apparmor'` ; then
            update_apparmor="yes"
            if [ ! -e "$aa_profile" ]; then
                echo "INFO: Creating non-existent apparmor profile" >&2
                vah="/usr/lib/libvirt/virt-aa-helper"
                if [ ! -x "$vah" ]; then
                    vah="virt-aa-helper"
                fi
                # create it, then unload it
                virsh --connect ${vm_connect} dumpxml "$machine" 2>/dev/null | sudo $vah -c --uuid "libvirt-$uuid"
                virsh --connect ${vm_connect} dumpxml "$machine" 2>/dev/null | sudo $vah -R --uuid "libvirt-$uuid"
            fi
        fi

        for d in $disks ; do
            real=`readlink -f "$d"`
            dir=`dirname "$real"`
            bn=`basename "$real" .qcow2`
            pristine="$dir/$bn.pristine.qcow2"
            if [ ! -e "$pristine" ]; then
                echo "ERROR: '$pristine' does not exist. Aborting" >&2
                return 1
            fi
            if [ "$update_apparmor" = "yes" ] && [ -e "$aa_profile" ]; then
                if ! grep -q "$pristine" "$aa_profile" ; then
                    echo "INFO: Updating '$aa_profile' to have '$pristine rw,'" >&2
                    tmp=`mktemp`
                    sed "s<^}<  \"$pristine\" rw,<" "$aa_profile" > "$tmp"
                    echo "}" >> "$tmp"
                    sudo mv -f "$tmp" "$aa_profile"
                fi
            fi
            if [ -e "$real" ]; then
                echo "INFO: Removing old snapshot '$real'" >&2
                rm -f "$real"
            fi
            echo "INFO: snapshotting '$pristine' -> '$d'" >&2
            qemu-img create -F qcow2 -b "$pristine" -f qcow2 "$real" >/dev/null || {
                echo "ERROR: could not create snapshot" >&2
                return 1
            }
        done
    fi

    virsh --connect ${vm_connect} start "$machine" 1>&2 || return 1
    if [ -n "$opt_viewer" ]; then
        sleep 0.5
        cd /tmp
        nohup virt-viewer --wait -c ${vm_connect} "$machine" >/dev/null &
        cd - >/dev/null
    fi

    echo "Sleeping 15 seconds to give '$machine' a chance to start" >&2
    sleep 15
    return 0
}

arch=
prefix=
opt_viewer=1
opt_wait=
can_snapshot="no"
while getopts "hswva:p:" opt
do
    case "$opt" in
        a) arch="$OPTARG";;
        p) prefix="$OPTARG";;
        v) opt_viewer=;;
        w) opt_wait=1;;
        s) can_snapshot="yes";;
        ?|h) help
           exit 1
           ;;
    esac
done
shift $(($OPTIND - 1))

machines=
if [ -z "$prefix" ]; then
    if [ -z "$1" ]; then
        help
        exit 1
    fi

    for i in "$@" ; do
        machines="$machines $i"
    done
else
    archs=$vm_archs
    if [ ! -z "$arch" ]; then
        archs="$arch"
    fi

    for a in $archs ; do
        for m in `vm_get_machines_by_prefix "${prefix}" "$a"` ; do
            machines="$machines $m"
        done
    done
fi

# Start each machine
started=""
for m in $machines ; do
    start_machine "$m" && started="$started $m"
done

# Wait for them to come up
if [ -n "$opt_wait" ]; then
    for m in $started ; do
        vm_wait "$m"
    done
fi

exit 0
