kvmctl
changeset 4 1ab9431a52bc
parent 3 d8aba2189a27
equal deleted inserted replaced
3:d8aba2189a27 4:1ab9431a52bc
     1 #! /bin/bash
     1 #! /bin/bash
     2 # $Id$
     2 # $Id$
     3 # $URL$
     3 # $URL$
     4 # status: in development
     4 # status: in development
     5 # 2008 Heiko Schlittermann
     5 # 2008 Heiko Schlittermann
       
     6 
       
     7 # Should be written in Perl!
     6 
     8 
     7 # Structure of virtual machine directories
     9 # Structure of virtual machine directories
     8 # $BASE     (see below, hard coded into this script)
    10 # $BASE     (see below, hard coded into this script)
     9 # |
    11 # |
    10 # +--<vm1>
    12 # +--<vm1>
    21 # +--<vm2>             
    23 # +--<vm2>             
    22 # | ....
    24 # | ....
    23 # +--<vmN>
    25 # +--<vmN>
    24 
    26 
    25 
    27 
    26 action="${1?}"; shift
    28 action="${1?}"; shift           # mandatory
    27 vm="$1"       ;   shift
    29 vm="$1"       ; shift           # optional
    28 
    30 
    29 # no user service able parts below
    31 # no user service able parts below
    30 
    32 
    31 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    33 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    32 unset ${!LC_*} LANG CDPATH
    34 unset ${!LC_*} LANG CDPATH
    43 for f in "/etc/$ME.conf" ~/.$ME; do test -r "$f" && source "$f"; done
    45 for f in "/etc/$ME.conf" ~/.$ME; do test -r "$f" && source "$f"; done
    44 
    46 
    45 
    47 
    46 die()       { echo $ME: "$@" >&2; exit 1; }
    48 die()       { echo $ME: "$@" >&2; exit 1; }
    47 warn()      { echo $ME: "$@" >&2; }
    49 warn()      { echo $ME: "$@" >&2; }
    48 silent()    { "$@" &>/dev/null; }
    50 silently()  { "$@" &>/dev/null; }
    49 
    51 
       
    52 debug()     { echo "DEBUG: $@" >&2; }
    50 
    53 
    51 unique_ids() {
    54 unique_ids() {
    52     local dups=$(cat $BASE/*/conf/id 2>/dev/null | sort -n | uniq -c \
    55     local dups=$(cat $BASE/*/conf/id 2>/dev/null | sort -n | uniq -c \
    53         | egrep -v '^[[:space:]]+1 ' | tr -s ' ' | cut -f2 -d:)
    56         | egrep -v '^[[:space:]]+1 ' | tr -s ' ' | cut -f2 -d:)
    54     test "$dups" || return 0
    57     test "$dups" || return 0
    55     ERR="$dups"  && return 1
    58     ERR="$dups"  && return 1
    56 }
    59 }
       
    60 
    57 convert_dirs() {
    61 convert_dirs() {
    58     for dir in $BASE/*; do
    62     for dir in $BASE/*; do
    59         test -d $dir/kvm || test -d $dir/conf || continue
    63         test -d $dir/kvm || test -d $dir/conf || continue
    60         local old=$dir/kvm
    64         local old=$dir/kvm
    61         local new=$dir/conf
    65         local new=$dir/conf
    62         test -d $old && mv $old $new
    66         test -d $old && mv $old $new
    63         test -f $new/cmdline && mv $new/cmdline $new/options
    67         test -f $new/cmdline && mv $new/cmdline $new/options
    64     done
    68     done
       
    69 }
       
    70 
       
    71 monitor() {
       
    72     local port=$1;      shift
       
    73     local command="$1"; shift
       
    74 
       
    75     # check, if the monitor is available, kill if somebody
       
    76     # else is using it
       
    77     local client=$(netstat -tn | egrep ":$port[[:space:]]+EST" | tr -s ' ' | cut -f4 -d' ')
       
    78     test "${client%:*}" = 127.0.0.1 && fuser -k ${client#*:}/tcp
       
    79 
       
    80     local pid0 pid1
       
    81     (
       
    82         local a=$tmp/a.fifo; mkfifo $a
       
    83         trap "rm -v $a" EXIT
       
    84         exec 10<>$a
       
    85         $NC localhost $port <&10 | {
       
    86             read || exit       # banner
       
    87             while read -d' '; do test "$REPLY" = "(qemu)" && break; done
       
    88             echo "$command" >&10
       
    89             while read -d' '; do test "$REPLY" = "(qemu)" && break; done
       
    90         }
       
    91     ) &  pid0=$!
       
    92     ( sleep $TIMEOUT; kill $pid0 ) & pid1=$!
       
    93     wait $pid0
       
    94     silently kill $pid0 $pid1
    65 }
    95 }
    66 
    96 
    67 ### MAIN
    97 ### MAIN
    68 
    98 
    69 # sanity
    99 # sanity
   107         $@"
   137         $@"
   108         options=$(echo "" $options)        # shorten it
   138         options=$(echo "" $options)        # shorten it
   109         echo "$options" > $var/running_options
   139         echo "$options" > $var/running_options
   110         test -f $var/frozen && options="$options $(cat $var/frozen)"
   140         test -f $var/frozen && options="$options $(cat $var/frozen)"
   111 
   141 
   112         if silent fuser $var/pid; then
   142         if silently fuser $var/pid; then
   113             echo "running, pid: $pid, display :$id, monitor tcp:127.0.0.1:$port" 
   143             echo "running, pid: $pid, display :$id, monitor tcp:127.0.0.1:$port" 
   114         else
   144         else
   115             ( cd $BASE/$vm && $KVM $options -daemonize )
   145             ( cd $BASE/$vm && $KVM $options -daemonize )
   116             pid=$(cat $var/pid 2>/dev/null)
   146             pid=$(cat $var/pid 2>/dev/null)
   117             test "$pid" || { warn "serious problem ($vm), no pid" && continue; }
   147             test "$pid" || { warn "serious problem ($vm), no pid" && continue; }
   118             echo "started, pid: $pid, display :$id, monitor tcp:127.0.0.1:$port" 
   148             echo "started, pid: $pid, display :$id, monitor tcp:127.0.0.1:$port" 
   119         fi
   149         fi
   120 
   150 
   121         test "$DISPLAY" && test "$VNCVIEWER" && test -t \
   151         test "$DISPLAY" && test "$VNCVIEWER" && test -t \
   122         && ( silent exec $VNCVIEWER :$id </dev/null & )
   152         && ( silently exec $VNCVIEWER :$id </dev/null & )
   123 
   153 
   124         ;;
   154         ;;
   125     stop)   
   155     stop)   
   126         {
   156         {
   127         echo "stopping (powerdown) $vm"
   157         echo "stopping (powerdown) $vm"
   128         a=$tmp/a; b=$tmp/b; mkfifo $a $b
   158         monitor $port "system_powerdown"
   129         ( $NC localhost $port 0<>$a 1<>$b ) & pid0=$!
   159         silently fuser $var/pid && $0 quit $vm
   130         read <$b    # we should not send anything before we got the first line
       
   131         echo -e 'system_powerdown\n' >$a
       
   132         ( cat <$b & sleep $TIMEOUT; silent kill $! $pid0 ) & pid1=$!
       
   133         wait $pid0
       
   134         kill $pid1 2>/dev/null
       
   135         silent fuser $var/pid && $0 quit $vm
       
   136         } &
   160         } &
   137         ;;
   161         ;;
   138     quit) 
   162     quit) 
   139         {
   163         {
   140         echo "quit $vm"
   164         echo "quit $vm"
   141         a=$tmp/a; b=$tmp/b; mkfifo $a $b
   165         monitor $port "quit"
   142         ( $NC localhost $port 0<>$a 1<>$b ) & pid0=$!
   166         silently fuser $var/pid && $0 kill $vm
   143         read <$b
       
   144         echo -e 'quit\n' >$a
       
   145         ( cat <$b & sleep $TIMEOUT; silent kill $! $0 ) & pid1=$!
       
   146         wait $pid0
       
   147         kill $pid1 2>/dev/null
       
   148         silent fuser $var/pid && $0 kill $vm
       
   149         } &
   167         } &
   150         ;;
   168         ;;
   151     kill)   
   169     kill)   
   152         echo "killing $vm"
   170         echo "killing $vm"
   153         kill $pid 
   171         kill $pid 
   154         ;;
   172         ;;
   155     freeze) echo "freezing $vm"
   173     freeze) 
   156         fuser -k $port/tcp
   174         {
   157         echo -e "savevm HIBERNATE\nquit" | $NC localhost $port &
   175         echo "freezing $vm"
   158         echo "-loadvm HIBERNATE" >$var/frozen
   176         monitor $port "savevm HIBERNATED"
   159         ;;
   177         monitor $port "quit" 
   160     #status) echo "status $vm: "
   178         echo "-loadvm HIBERNATED" >$var/frozen
       
   179         } &
       
   180         ;;
   161     qemu)
   181     qemu)
   162         echo "DO *NOT* USE \"quit\", use ^C for exiting!"
   182         echo "DO *NOT* USE \"quit\", use ^C for exiting!"
   163         $NC localhost $port
   183         $NC localhost $port
   164         ;;
   184         ;;
   165 
   185 
   166     list)
   186     list)
   167         echo "$vm:" $(silent fuser $var/pid \
   187         echo "$vm:" $(silently fuser $var/pid \
   168             && echo "running (pid: $pid)" \
   188             && echo "running (pid: $pid)" \
   169             || echo "not running")
   189             || echo "not running")
   170         ;;
   190         ;;
   171 
   191 
   172     *)  die "unknown command \"$action\""
   192     *)  die "unknown command \"$action\""