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
161
162
163
164
165
166
167
168
169
170
171
172
|
#!/bin/sh
# Define and install a libvirt domain
# Copyright © 2013 Guilhem Moulin <guilhem@fripost.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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}
[ -d "$root/images" ] || mkdir "$root/images"
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
# --import \
# --disk path=/dev/sdc,bus=usb,perms=ro \
# 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
$0 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
|