#!/bin/sh ### BEGIN INIT INFO # Provides: kvm-manage # Required-Start: kvm $local_fs $remote_fs $syslog $named $network $time # Required-Stop: $local_fs $remote_fs $syslog $named $network # Default-Start: 2 # Default-Stop: 0 1 6 # Short-Description: KVM-management init script # Description: This script does a controlled start and stop of kvm instances ### END INIT INFO # kvm-manage - v1.90 # # GPLv2: please have a look at the license text, which should have been # shipped with your distribution. # # written by Christian Roessner # # Script to manage kvm instances, if libvirt is not applicable # # Changes: # 2008-12-13: # - Introduces pgrep routine # - Implemeted restart() # - Some more friendly output for start() and stop() # - Fixes double-stop() in finish() # - Check for required helper tools # - Combine monitor feature with minicom, is available # 2008-12-14: # - Most parts have been rewritten to try to clean up the code # - no more need for the pidfile-paramter in the config files # - Clean difference between the kvm and the vdekvm pids # 2008-12-21: # - Detect, if a guest uses kvm or vdekvm-wrapper # 2008-12-22: # - Implemented a destroy() option and modified vdekvm-wrapper # detection. # - Stop guests that do not have KXX symlinks in rc. # 2008-12-23: # - Added RC_DIR and INST_DIR options. # - No more need to wrap run() around the (vde)kvm-commands. # 2008-12-30: (Thanks to Urs) # - Replaces the monitor option from pty to telnet # 2009-01-08: # - Bugfix: If there are no K* or S* files in RC_DIR, skip # 2009-01-24: # - sysvinit block included # 2010-06-14: # - Changing telnet to unix socket socat command # # Download: http://www.roessner-net.com/kvm-manage # How long to wait for starting the next guest TIME_TO_WAIT=40 # Path to kvm instance scripts INST_DIR="/etc/kvm/instances" # Where to store (S)tart and (K)ill symlinks? RC_DIR="/etc/kvm/rc" VAR_RUN_DIR="/var/run/kvm" LOG_CMD="/usr/bin/logger" AWK_CMD="/usr/bin/awk" SOCAT_CMD="/usr/bin/socat" LOG_OPTS="-i -t kvm-manage -p local0.info" ### Do not change things below ### get_kvm_pid() { ps -o pid=,args= -C kvm | grep -- "-name $1 " | $AWK_CMD '{ print $1; }' } get_vdekvm_pid() { ps -o pid=,args= -C vdekvm | grep -- "-name $1 " | $AWK_CMD '{ print $1; }' } get_pidline() { ps -o pid=,args= -C kvm | grep -- "-name $1 " } get_kvm_names() { found=0 for param in $(ps -o args= -C kvm); do if [ $found = 0 ]; then if [ "$param" = "-name" ]; then found=1 fi else list="$list $param" found=0 fi done echo $list } do_stop() { echo "Stopping VM: $1" pidline=$(get_pidline $1) if test -n "$pidline"; then var1=${pidline#*-monitor*} instance_sock=$(echo $var1 | cut -d " " -f 1 | cut -d "," -f1 | cut -d ":" -f2) $LOG_CMD $LOG_OPTS "Shutting down VM($1) on monitor $instance_sock" echo "system_powerdown" | $SOCAT_CMD - $instance_sock > /dev/null 2>&1 # Waiting for the guest to terminate for timer in $(seq 1 40); do pid=$(get_kvm_pid $1) if test -z "$pid"; then $LOG_CMD $LOG_OPTS -s "VM($1) shutdown complete" break fi sleep 5 done # Error! We kill the guest if [ $timer -eq 40 ]; then # Try to save a screendump echo "screendump /tmp/kvm-$pid.ppm" | $SOCAT_CMD - $instance_sock > /dev/null 2>&1 sleep 3 kill -TERM $pid > /dev/null 2>&1 $LOG_CMD $LOG_OPTS -s "VM($1) killed!" fi fi vdepid=$(get_vdekvm_pid $1) if test -n $vdepid; then kill -TERM $vdepid > /dev/null 2>&1 fi } destroy() { pid=$(get_kvm_pid $1) if test -n "$pid"; then kill -TERM $pid > /dev/null 2>&1 fi vdepid=$(get_vdekvm_pid $1) if test -n "$vdepid"; then kill -TERM $vdepid > /dev/null 2>&1 fi } error() { echo $1 exit 1 } # Check that all required components are available test -x $AWK_CMD || error "$AWK_CMD required!" test -x $LOG_CMD || error "$LOG_CMD required!" test -x $SOCAT_CMD || error "$SOCAT_CMD required!" # Create missing folders test -d $INST_DIR || mkdir -p $INST_DIR test -d $RC_DIR || mkdir -p $RC_DIR test -d $VAR_RUN_DIR || mkdir -p $VAR_RUN_DIR case "$1" in start) if test -z "$2"; then echo "Starting VMs in background" ( for service in $RC_DIR/S*; do test -r $service || continue base=$(basename $service) name=${base#*[SK][0-9][0-9]} if test -z "$(get_kvm_pid $name)"; then $LOG_CMD $LOG_OPTS "Starting VM($name)" . $service sleep $TIME_TO_WAIT fi done )& else name=$(basename $2) if test -n "$(get_kvm_pid $name)"; then error "Instance already running!" else echo "Starting VM: $name" if test -r $INST_DIR/$name; then . $INST_DIR/$name else error "$2 does not exist!" fi fi fi ;; stop) if test -z "$2"; then for service in $RC_DIR/K*; do test -r $service || continue base=$(basename $service) name=${base#*[SK][0-9][0-9]} do_stop $name done # Do we have any manual started guest running? still_running=$(get_kvm_names) for vm in $still_running; do do_stop $vm done else name=$(basename $2) do_stop $name fi ;; monitor) if test -z "$2"; then error "$0 monitor " else name=$(basename $2) pidline=$(get_pidline $2) if test -n "$pidline"; then var1=${pidline#*-monitor*} ip=$(echo $var1 | cut -d " " -f 1 | cut -d "," -f1 | cut -d ":" -f2) port=$(echo $var1 | cut -d " " -f 1 | cut -d "," -f1 | cut -d ":" -f3) echo "use telnet to monitor VM $name at: $ip:$port" fi fi ;; list) echo "Currently running VMs:" get_kvm_names ;; restart) if test -z "$2"; then $0 stop && $0 start else echo "Restarting VM: $2" $0 stop $2 && $0 start $2 fi ;; destroy) if test -z "$2"; then error "$0 destroy " else name=$(basename $2) echo "Destroying VM: $name" destroy $name fi ;; *) echo "$0 {start|stop|restart|destroy |monitor |list}" ;; esac exit 0 # vim: ts=2 sw=2 expandtab