#!/bin/sh # Define and install a libvirt domain # Copyright © 2013 Guilhem Moulin # # 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 . set -ue PATH=/usr/bin:/bin 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 } 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}.img} [ -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/../Makefile") local cdrom="$root/../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 # 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" \ --os-variant debianwheezy \ --arch "$ARCH" \ --virt-type kvm \ --cpu host \ --vcpu 2 \ --memory 512 \ --memballoon virtio \ --cdrom "$cdrom" \ --disk "$disk",size=12,format=raw,bus=virtio,cache=none,io=native \ --network network="$network",model=virtio \ --graphics spice,listen=none \ --rng "random,device=/dev/urandom,model=virtio" \ --noautoconsole # --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., , 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 "" add_net_section dns-host "$name" 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 virt-viewer --attach $name EOF } [ $# -gt 0 ] || usage command="$1" shift; case "$command" in install) $command "$@";; *) usage esac