aboutsummaryrefslogtreecommitdiffstats
path: root/virtualenv/virt
blob: 06b76425a0090b679f69e33ee3a564f858710153 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/bin/sh
#
# Define and install a libvirt domain
#
# Copyright 2013 Guilhem Moulin <guilhem@fripost.org>
#
# Licensed under the GNU GPL version 3 or higher.
#

set -ue
PATH=/usr/bin:/bin
root=$(dirname "$0")

usage() {
    cat >&2 <<-EOF
		Usage:
		  $0 install <libvirt domain> [<QEMU image>]
		      Install the given domain, using the given image (created if
		      necessary) as a disk.
		  $0 view <libvirt domain>
		      Open a connection to a running domain using the Spice protocol
	EOF
    exit 1
}

getXMLattr() {
    local id="$1" object="$2" attribute="$3" what="${4:-domain}"

    local cmd
    case "$what" in
        domain)  cmd=;;
        network) cmd=net;;
    esac

    virsh "${cmd:+$cmd-}dumpxml" "$id" \
    | xmlstarlet sel -t -m "/$what/$object" -n -v @"$attribute" \
    | sed '/^\s*$/d'
}
add_net_section() {
    local section="$1" xml="$2" net="${3:-$network}"
    virsh net-update "$net" add "$section" --xml "$xml" --live --config
}

doesExist() {
    virsh -r list --all --name | grep -qxF "$1"
}
isActive() {
    virsh -r list       --name | grep -qxF "$1"
}

install() {
    [ $# -eq 1 -o $# -eq 2 ] || usage
    local name=$1
    local disk=${2:-$root/images/${name}.qcow2}

    local darch
    case "${ARCH:=$(/bin/uname -m)}" in
        i386|i686) darch=i386;;
        x86_64)    darch=amd64;;
        *)         darch=$ARCH;;
    esac
    local version=$(sed -n '/^VERSION\s*=\s*/ {s///p;q}' $root/../preseed/Makefile)
    local cdrom="$root/../preseed/dist/$darch/debian-$version-$darch-netinst-preseeded.iso"

    if doesExist "$name"; then
        echo "Error: Domain $name already exists. If you want to replace the domain, run" >&2
        echo >&2
        isActive "$name" && echo "    virsh destroy  $name" >&2
        echo "    virsh undefine $name" >&2
        exit 1
    fi
    if ! [ -f "$cdrom" -a -r "$cdrom" ]; then
        cat >&2 <<- EOF
			Error: '$cdrom' does not exist or is not readable.
			To create the preseeded image, run

			    cd $root/../preseed
			    ARCH=$darch make iso-preseed
		EOF
        exit 1
    fi

    grep -q '^kvm\s' /proc/modules || echo 'WARN: KVM not available!' >&2

    if [ ! -f "$disk" ]; then
        local size=12G
        echo "Creating (sparse) $size disk image '$disk'" >&2
        qemu-img create -f "${disk##*.}" -o size="$size",preallocation=metadata "$disk"
    fi

    # TODO: the bus should be chosen at random among sata,ide,scsi,usb
    # TODO: test EFI: http://www.linux-kvm.org/page/OVMF
    local network=default ip mac
    virt-install -q \
        --name      "$name" \
        --arch      "$ARCH" \
        --ram       128 \
        --cdrom     "$cdrom" \
        --disk      "$disk",cache=writeback,bus=sata \
        --network   network="$network" \
        --graphics  spice

    # Attribute the next available IP. You may also want to add a domain
    # section, e.g., <domain name='libvirt.example.org'/>, and prepend
    # the DNS IP to /etc/resolv.conf.
    # Cf. http://libvirt.org/formatnetwork.html
    mac=$( getXMLattr $name devices/interface/mac address )
    ip=$( getXMLattr $network ip/dhcp/host ip network | sort -n | tail -1 )
    [ "$ip" ] || \
    ip=$( getXMLattr $network ip address network )
    ip=${ip%.*}.$(( 1 + ${ip##*.} ))
    add_net_section ip-dhcp-host "<host mac='$mac' name='$name' ip='$ip'/>"
    add_net_section dns-host     "<host ip='$ip'><hostname>$name</hostname></host>"

    cat >&2 <<- EOF
		Domain '$name' has been created, and has been given IP $ip.
		As you can see in

		    virsh list

		it should now be up and running. To open a graphical console, run

		    $0 view $name
	EOF
}

view(){
    [ $# -eq 1 ] || usage
    local domain="$1"

    if ! doesExist "$domain"; then
        cat >&2 <<- EOF
			Error: Domain $domain does not exist. To create it, run

			  ./virt install $domain
		EOF
        exit 1
    elif ! isActive "$domain"; then
        echo "Error: Domain $domain is not active" >&2
        exit 1
    fi

    local type=$(getXMLattr "$domain" devices/graphics type)
    local port=$(getXMLattr "$domain" devices/graphics port) || true

    if ! [ "$type" = spice -a "$port" ]; then
        echo "Error: Could not find a valid Spice server on domain '$domain'." >&2
        exit 1
    fi
    spicec -h 127.0.0.1 -p $port
}

[ $# -gt 0 ] || usage
command="$1"
shift;

case "$command" in
    install|view) $command "$@";;
    *) usage
esac