Now we started over this "project" - using almost the script that we used
authorHeiko <hs@schlittermann.de>
Thu, 15 Jul 2010 09:36:24 +0200
changeset 16 9504de208106
parent 15 3bed76a0fcd3
child 17 aa417316b86f
Now we started over this "project" - using almost the script that we used on our rooh-* servers.
Makefile
kvmtab.ex
kvmtool
kvmtool.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Thu Jul 15 09:36:24 2010 +0200
@@ -0,0 +1,25 @@
+DESTDIR = /
+
+prefix = /usr/local
+sbindir = ${prefix}/sbin
+etcdir = /etc
+
+.PHONY:		all clean install
+
+all:		kvmtool
+
+kvmtool:	kvmtool.sh
+		@sed -e 's|\[% VERSION %\]|'"`hg id -bit`"'|;' \
+		     -e 's|\[% BUILDINFO %\]|'"`hostname`:`pwd`"'|;' \
+			<$^ >$@
+		@chmod +x $@
+
+clean: 		; rm -f kvmtool
+
+install:	all
+		install -m 0755 -d ${DESTDIR}${sbindir}/
+		install -m 0555 kvmtool ${DESTDIR}${sbindir}/kvmtool
+		install -m 0755 -d ${DESTDIR}${etcdir}/
+		test -f ${DESTDIR}${etcdir}/kvmtab \
+		|| install -m 0644 kvmtab.ex ${DESTDIR}${etcdir}/kvmtab
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kvmtab.ex	Thu Jul 15 09:36:24 2010 +0200
@@ -0,0 +1,5 @@
+# this table is read by kvmtool (or vm-*)
+# do not forget to sync this table to the other hosts (*-{a,b})
+#
+# name  host    id      mac		  config file (builtin if empty)
+
--- a/kvmtool	Thu Jul 15 09:12:48 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +0,0 @@
-#! /usr/bin/perl
-# © 2009 Heiko Schlittermann
-
-# $opt_base/vm/{name}/
-#
-
-use strict;
-use warnings;
-use Getopt::Long qw(:config require_order);
-use Pod::Usage;
-use File::Basename;
-use Perl6::Slurp;
-use File::Path;
-use IO::File;
-use IO::Select;
-use POSIX qw(setsid);
-use feature qw(:5.10);
-use if $ENV{DEBUG} => qw(Smart::Comments);
-
-my $ME              = basename $0;
-my $opt_dev         = "/dev/kvm";
-my $opt_base        = "$ENV{HOME}/.$ME";
-my $opt_cmd_monitor = undef;
-my $opt_config      = undef;
-my $opt_import      = undef;
-
-my $KVM  = "kvm";
-my $KILL = 15;
-
-sub cmd_start(@);
-sub cmd_kill(@);
-sub cmd_list(@);
-sub cmd_monitor(@);
-sub _import(@);
-
-sub _base_dir($)            { "$opt_base/vm/$_[0]" }
-sub _running_config_file($) { "$opt_base/vm/$_[0]/running_config" }
-sub _user_config_file($)    { "$opt_base/vm/$_[0]/config" }
-sub _monitor_link($)        { "$opt_base/vm/$_[0]/monitor" }
-
-MAIN: {
-
-    GetOptions(
-        "h|help" => sub { pod2usage(-verbose => 1, -exit => 0) },
-        "man"    => sub { pod2usage(-verbose => 2, -exit => 0) },
-        "m|monitor"    => \$opt_cmd_monitor,
-        "c|config=s"   => \$opt_config,
-        "d|base-dir=s" => \$opt_base,
-        "i|import"     => \$opt_import,
-        "dev=s"        => \$opt_dev,
-    ) or pod2usage(-exit => 1);
-
-    -w $opt_dev or die "$ME: write access to $opt_dev: $!\n";
-
-    given (shift) {
-        when ("start") {
-            cmd_start(@ARGV);
-            cmd_monitor(@ARGV) if $opt_cmd_monitor;
-        }
-        when ("monitor") { cmd_monitor(@ARGV) }
-        when ("kill")    { cmd_kill(@ARGV) }
-	when ("list")	 { cmd_list(@ARGV) }
-        default          { pod2usage() };
-    }
-
-}
-
-sub cmd_start(@) {
-    my ($kvm, @kvm_opts) = @_;
-    pod2usage() if not defined $kvm;
-
-    -d _base_dir $kvm or mkpath _base_dir $kvm;
-
-    my $config = config->load_config_user($kvm,
-        defined $opt_config ? $opt_config : _user_config_file $kvm, @kvm_opts);
-
-    if (defined(my $pidfile = $config->get("-pidfile"))) {
-        -d dirname $pidfile
-          or die "$ME: directory for pidfile ($pidfile): $!\n";
-    }
-
-    $config->save_user_config(_user_config_file $kvm)
-      if defined $opt_config and defined $opt_import;
-
-    $config->save_running_config(_running_config_file $kvm, @kvm_opts);
-
-    defined(my $pid = open(VM, "-|")) or die "Can't fork: $!\n";
-
-    if ($pid == 0) {
-        setsid();
-        open(STDIN,  "</dev/null");
-        open(STDERR, ">&STDOUT")
-          or die "Can't redirect STDERR to STDOUT: $!\n";
-        exec $KVM "kvm-$kvm" => $config->get_all();
-        die "Can't exec: $!";
-    }
-
-    if (defined($_ = <VM>)) {
-        print $_;
-        if (/char device redirected to (\S+)$/) {
-            unlink(_monitor_link $kvm);
-            symlink($1, _monitor_link $kvm);
-            exit;
-        }
-
-        wait;
-        die "$ME: didn't start: (exit ", $? >> 8, ")\n";
-
-    }
-
-}
-
-sub cmd_monitor(@) {
-    my ($kvm, $cmd) = (shift, "@_");
-    pod2usage() if not defined $kvm;
-
-    my $monitor = _monitor_link $kvm;
-    my $pts     = readlink $monitor
-      or die "$ME: $monitor: $!\n";
-
-    my $i = new IO::File("<$pts") or die "$pts: $!\n";
-    my $o = new IO::File(">$pts") or die "$pts: $!\n";
-
-    $o->autoflush(1);
-
-    if (length $cmd) {
-        die "passing a command to monitor is not yet implemented\n";
-        $_ = "";
-        while (not /^\(qemu\) /) {
-            sysread($i, $_, 1, length);
-            $_ = "" if /\n$/;
-        }
-        syswrite($o, "$cmd\n");
-        $_ = "";
-        while (not /^\(qemu\) /m) {
-            sysread($i, $_, 1, length);
-        }
-        s/^.*?\r?\n//;
-        s/(\r?\n).*?$/$1/;
-        die "<$_>";
-        exit;
-    }
-
-    say("** to leave the monitor, just use the <ESC> key!");
-    my $termio = `stty -g`;
-    my $rows = (split " ", `stty size`)[0];
-    system("stty raw -echo");
-
-    eval {
-        my $row = 1;
-      INPUT:
-        while (my @ready = IO::Select->new($i, \*STDIN)->can_read(undef)) {
-            foreach my $fh (@ready) {
-                if ($fh == $i) {
-                    sysread($i, $_, 1) == 0
-                      and last INPUT;
-                    syswrite(STDOUT, $_);
-                    if (/\n/ and $row++ >= $rows) {
-                        syswrite(STDOUT, "more...");
-                        sysread(STDIN, $_, 1);
-                        $row = 1;
-                    }
-                }
-                elsif ($fh == \*STDIN) {
-                    (sysread(STDIN, $_, 1) == 0 or /\e/)
-                      and print("\r\n"), last INPUT;
-                    syswrite($o, $_);
-                    $row = 1;
-                }
-            }
-        }
-    };
-    system("stty $termio");
-}
-
-sub cmd_list(@) {
-    foreach my $dir (glob(_base_dir "*")) {
-	my $kvm = basename $dir;
-	print "$kvm: ";
-	my ($config, $pid);
-	eval {
-	    $config = config->load_running_config(_running_config_file $kvm);
-	    $pid = slurp $config->get("-pidfile"), { chomp => 1 };
-	};
-	if ($@ or !kill 0 => $pid) {
-	    print "not running";
-	    next;
-	}
-
-	print "running ($pid)";
-	    
-    } continue {
-	print "\n";
-    }
-}
-
-sub cmd_kill(@) {
-    my ($kvm) = @_;
-    pod2usage() if not defined $kvm;
-    my $config  = config->load_running_config(_running_config_file $kvm);
-    my $pidfile = $config->get("-pidfile");
-    my $pid     = slurp $pidfile, { chomp => 1 };
-
-    kill $KILL => $pid;
-    waitpid($pid, 0);
-    unlink $pidfile, _monitor_link $kvm, _running_config_file $kvm;
-
-}
-
-{
-
-    package config;
-    use strict;
-    use warnings;
-    use YAML::Syck;
-    use Perl6::Slurp;
-    use feature qw(:5.10);
-
-    use Data::Dumper;
-
-    my %data;
-
-    sub load_config_user {
-        my ($class, $kvm, $file, @extra_opts) = @_;
-        my $self = bless do { \my $x }
-          => $class;
-
-        my @config = slurp $file, { chomp => 1 };
-
-        $data{$self}{kvm} = $kvm;
-        push @config, "-name $kvm"   unless /^-name\b/    ~~ @config;
-        push @config, "-monitor pty" unless /^-monitor\b/ ~~ @config;
-        push @config, "-pidfile $opt_base/vm/$kvm/pid"
-          unless /^-pidfile\b/ ~~ @config;
-        $data{$self}{config} = \@config;
-        $data{$self}{extra}  = \@extra_opts;
-
-        return $self;
-    }
-
-    sub save_running_config {
-        my ($self, $file) = @_;
-        DumpFile($file, $data{$self});
-    }
-
-    sub save_user_config {
-        my ($self, $file) = @_;
-        my $fh = new IO::File ">$file" or die "$file: $!\n";
-        $fh->print(
-            join "\n",
-            "# kvm configuration file",
-            "# imported kvm config, you *may* edit this file",
-            @{ $data{$self}{config} }, undef
-        );
-    }
-
-    sub load_running_config {
-        my ($class, $file) = @_;
-        my $self = bless do { \my $x }
-          => $class;
-        $data{$self} = LoadFile($file);
-        return $self;
-    }
-
-    sub get {
-        my ($self, $key) = @_;
-        my @a = map { /^$key\s+(.*)/ ? $1 : () } @{ $data{$self}{config} };
-        return wantarray ? @a : $a[0];
-    }
-
-    sub get_all {
-        my ($self) = @_;
-        return +(map { split " ", $_, 2 } grep !/^\s*#/,
-            @{ $data{$self}{config} }), @{ $data{$self}{extra} };
-    }
-
-    sub DESTROY {
-        my $self = shift;
-        delete $data{$self};
-    }
-
-}
-
-__END__
-
-=head1 NAME
-
-kvmtool - tool to start and stop kvm w/o any X11
-
-=head1 SYNOPSIS
-
-    kvmtool [options] start <name> [kvm-options]
-    kvmtool [options] monitor <name>
-    kvmtool [options] kill <name>
-    kvmtool [options] list
-
-=head1 DESCRITPTION
-
-=head1 COMMANDS
-
-=head2 start
-
-The B<start> command starts the virtual machine. It looks for the
-startup config in the vm config space. For a new machine you may want to
-use the B<--config> option to specify (and optionally import) the
-new configuration.
-
-Options just used once (e.g. boot off a CDROM) may be passed too.
-
-=head2 monitor
-
-This opens a connection to the monitor of the specified VM.
-
-=head2 kill
-
-The B<kill> command kills the machine, using normal UNIX process
-manipulation tools.
-
-=head1 OPTIONS
-
-Some of the following options are of general nature (as B<--base-dir>), some
-other options are only useful in combination with some specific action
-(as B<--monitor>). You may pass as many useless options as you want ;-)
-
-=over
-
-=item B<-c>|B<--config> I<config>
-
-Use the specified configuration instead of the one once imported.
-(default: I<undef>)
-
-=item B<--dev>=I<device>
-
-Pathname of the KVM device. (default: F</dev/kvm>)
-
-=item B<-i>|B<--import> 
-
-Import the specified configuration. (default: I<undef>)
-
-=item B<-h>|B<--help>
-
-Show a short help page.
-
-=item B<-m>|B<--man>
-
-Show this manual page.
-
-=back
-
-=head1 AUTHOR
-
-    Heiko Schlittermann <hs@schlittermann.de>
-
-=cut
-
-# vim:sts=4 aw ai sm:
--- a/kvmtool.sh	Thu Jul 15 09:12:48 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,201 +0,0 @@
-#! /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)
-# |
-# +--<vm1>
-# |   +--conf
-# |   |     +--options
-# |   |     +--id
-# |   +--var
-# |   |     +--pid
-# |   |     +--running_options
-# |   +--<image1>
-# |   +-- ....
-# |   +--<imageN>
-# |
-# +--<vm2>             
-# | ....
-# +--<vmN>
-
-
-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 </dev/null & )
-
-        ;;
-    stop)   
-        {
-        echo "stopping (powerdown) $vm"
-        monitor $port "system_powerdown"
-        silently fuser $var/pid && $0 quit $vm
-        } &
-        ;;
-    quit) 
-        {
-        echo "quit $vm"
-        monitor $port "quit"
-        silently fuser $var/pid && $0 kill $vm
-        } &
-        ;;
-    kill)   
-        echo "killing $vm"
-        kill $pid 
-        ;;
-    freeze) 
-        {
-        echo "freezing $vm"
-        monitor $port "savevm HIBERNATED"
-        monitor $port "quit" 
-        echo "-loadvm HIBERNATED" >$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: