#!/bin/sh # # Define and install a libvirt domain # # Copyright 2013 Guilhem Moulin # # Licensed under the GNU GPL version 3 or higher. # set -ue root=$(dirname "$0") usage() { cat >&2 <<-EOF Usage: $0 install [] Install the given domain, using the given image (created if necessary) as a disk. $0 view Open a connection to a running domain using the Spice protocol EOF exit 1 } get_XML_attribute() { local domain="$1" object="$2" attribute="$3" /usr/bin/virsh dumpxml "$domain" \ | /usr/bin/xmlstarlet sel -t -m /domain/"$object" -v @"$attribute" } add_net_section() { local net="${3:-$network}" section="$1" xml="$2" /usr/bin/virsh net-update "$net" add "$section" --xml "$xml" --live --config } doesExist() { /usr/bin/virsh -r list --all --name | grep -qxF "$1" } isActive() { /usr/bin/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 version=$(sed -n 's/^VERSION\s*=\s*//p' $root/../preseed/Makefile) case "${ARCH:=$(/bin/uname -m)}" in i386|i686) darch=i386;; x86_64) darch=amd64;; *) darch=$ARCH;; esac 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 ! [ -r "$disk" -a -r "$disk" ]; then local size=12G echo "Creating (sparse) $size disk image '$disk'" >&2 /usr/bin/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 /usr/bin/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., , and prepend # the DNS IP to /etc/resolv.conf. # Cf. http://libvirt.org/formatnetwork.html local mac ip mac=$(get_XML_attribute "$name" devices/interface/mac address) ip=$( /usr/bin/virsh net-dumpxml $network \ | /usr/bin/xmlstarlet sel -t -m /network/ip/dhcp/host -n -v @ip \ | sed '/^\s*$/d' \ | sort -n \ | tail -1 ) [ "$ip" ] || \ ip=$( /usr/bin/virsh net-dumpxml $network \ | /usr/bin/xmlstarlet sel -t -m /network/ip -v @address ) ip=${ip%.*}.$(( 1 + ${ip##*.} )) add_net_section ip-dhcp-host "" add_net_section dns-host "$name" cat >&2 <<- EOF Domain '$name' has been created, and has been attributed the 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=$(get_XML_attribute "$domain" devices/graphics type) local port=$(get_XML_attribute "$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 /usr/bin/spicec -h 127.0.0.1 -p $port } [ $# -gt 0 ] || usage command="$1" shift; case "$command" in install|view) $command "$@";; *) usage esac