diff -r ed2b863f938f -r ebe549994431 kvmtool.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kvmtool.sh Sat Aug 08 01:20:27 2009 +0200 @@ -0,0 +1,201 @@ +#! /bin/bash +# $Id$ +# $URL$ +# status: in development +# 2008 Heiko Schlittermann + +# Should be written in Perl! + +# Structure of virtual machine directories +# $BASE (see below, hard coded into this script) +# | +# +-- +# | +--conf +# | | +--options +# | | +--id +# | +--var +# | | +--pid +# | | +--running_options +# | +-- +# | +-- .... +# | +-- +# | +# +-- +# | .... +# +-- + + +action="${1?}"; shift # mandatory +vm="$1" ; shift # optional + +# no user service able parts below + +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +unset ${!LC_*} LANG CDPATH + +ME=$(basename $0) +BASE=/kvm +KVM=$(command -v kvm) +NC=$(command -v nc) +FUSER=$(command -v fuser) +VNCVIEWER=$(command -v vncviewer) +TIMEOUT=30 + + +for f in "/etc/$ME.conf" ~/.$ME; do test -r "$f" && source "$f"; done + + +die() { echo $ME: "$@" >&2; exit 1; } +warn() { echo $ME: "$@" >&2; } +silently() { "$@" &>/dev/null; } + +debug() { echo "DEBUG: $@" >&2; } + +unique_ids() { + local dups=$(cat $BASE/*/conf/id 2>/dev/null | sort -n | uniq -c \ + | egrep -v '^[[:space:]]+1 ' | tr -s ' ' | cut -f2 -d:) + test "$dups" || return 0 + ERR="$dups" && return 1 +} + +convert_dirs() { + for dir in $BASE/*; do + test -d $dir/kvm || test -d $dir/conf || continue + local old=$dir/kvm + local new=$dir/conf + test -d $old && mv $old $new + test -f $new/cmdline && mv $new/cmdline $new/options + done +} + +monitor() { + local port=$1; shift + local command="$1"; shift + + # check, if the monitor is available, kill if somebody + # else is using it + local client=$(netstat -tn | egrep ":$port[[:space:]]+EST" | tr -s ' ' | cut -f4 -d' ') + test "${client%:*}" = 127.0.0.1 && fuser -k ${client#*:}/tcp + + local pid0 pid1 + ( + local a=$tmp/a.fifo; mkfifo $a + trap "rm -v $a" EXIT + exec 10<>$a + $NC localhost $port <&10 | { + read || exit # banner + while read -d' '; do test "$REPLY" = "(qemu)" && break; done + echo "$command" >&10 + while read -d' '; do test "$REPLY" = "(qemu)" && break; done + } + ) & pid0=$! + ( sleep $TIMEOUT; kill $pid0 ) & pid1=$! + wait $pid0 + silently kill $pid0 $pid1 +} + +### MAIN + +# sanity +test -x "$NC" || die "need nc (netcat)" +test -x "$KVM" || die "need kvm/qemu/kqemu" +test -x "$FUSER" || die "need fuser" +test -d "$BASE" || die "base dir $BASE does not exist" +test -d "$BASE/$vm" || die "vm $vm does not exist" + +unique_ids || die "duplicate ids (id: $ERR)" +convert_dirs + +trap 'test "$TMP" && rm -fr $TMP' EXIT + +for vm in ${vm:-$(echo $BASE/*)}; do + vm=$(basename $vm) + conf=$BASE/$vm/conf + var=$BASE/$vm/var + + tmp=$(mktemp -d) + TMP="$TMP $tmp" + + test -d $conf || continue + test -f $conf/id || { warn "need id file (vm: $vm)" && continue; } + test -f $conf/options || { warn "need options file (vm: $vm)" && continue; } + test -d $var || mkdir $var || exit 2 + + id=$(cat $conf/id) + port=$((4000 + id)) + pid=$(cat $var/pid 2>/dev/null) + + case "$action" in + + start) + echo "starting $vm" + options="$(grep -v '^#' $conf/options) \ + -pidfile var/pid \ + -name "$vm" \ + -vnc :$id \ + -monitor tcp:localhost:$port,server,nowait \ + $@" + options=$(echo "" $options) # shorten it + echo "$options" > $var/running_options + test -f $var/frozen && options="$options $(cat $var/frozen)" + + if silently fuser $var/pid; then + echo "running, pid: $pid, display :$id, monitor tcp:127.0.0.1:$port" + else + ( cd $BASE/$vm && $KVM $options -daemonize ) + pid=$(cat $var/pid 2>/dev/null) + test "$pid" || { warn "serious problem ($vm), no pid" && continue; } + echo "started, pid: $pid, display :$id, monitor tcp:127.0.0.1:$port" + fi + + test "$DISPLAY" && test "$VNCVIEWER" && test -t \ + && ( silently exec $VNCVIEWER :$id $var/frozen + } & + ;; + qemu) + echo "DO *NOT* USE \"quit\", use ^C for exiting!" + $NC localhost $port + ;; + + list) + echo "$vm:" $(silently fuser $var/pid \ + && echo "running (pid: $pid)" \ + || echo "not running") + ;; + + *) die "unknown command \"$action\"" + ;; + + esac + +done + +wait + +# vim:ts=4 sw=4 et: