#!/bin/sh # # xendomains Start / stop domains automatically when domain 0 boots / shuts down. # # chkconfig: 345 99 00 # description: Start / stop Xen domains. # # This script offers fairly basic functionality. It should work on Redhat # but also on LSB-compliant SuSE releases and on Debian with the LSB package # installed. (LSB is the Linux Standard Base) # # Based on the example in the "Designing High Quality Integrated Linux # Applications HOWTO" by Avi Alkalay # # ### BEGIN INIT INFO # Provides: xendomains # Required-Start: $syslog $remote_fs xenstored xenconsoled # Should-Start: xend # Required-Stop: $syslog $remote_fs xenstored xenconsoled # Should-Stop: xend # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start/stop secondary xen domains # Description: Start / stop domains automatically when domain 0 # boots / shuts down. ### END INIT INFO . /etc/rc.d/init.d/functions CMD=xm $CMD list >/dev/null 2>/dev/null || CMD=xl $CMD list >/dev/null 2>/dev/null || exit 0 [ -e /proc/xen/privcmd ] || exit 0 if [ -r /etc/sysconfig/xendomains ]; then . /etc/sysconfig/xendomains else echo "/etc/sysconfig/xendomains does not exist" if [ "$1" = "stop" ]; then exit 0 else exit 6 fi fi ## # Returns 0 (success) if the given parameter names a directory, and that # directory is not empty. # contains_something() { if [ -d "$1" ] && [ `/bin/ls $1 | wc -l` -gt 0 ]; then return 0 else return 1 fi } # read name from xen config file rdname() { NM=$($CMD create --quiet --dryrun --defconfig "$1" | sed -n 's/^.*(name \(.*\))$/\1/p') } rdnames() { NAMES= if ! contains_something "$XENDOMAINS_AUTO"; then return fi for dom in $XENDOMAINS_AUTO/*; do rdname $dom if test -z $NAMES; then NAMES=$NM; else NAMES="$NAMES|$NM" fi done } parseln() { if [[ "$1" = "*(domain*" ]]; then name=;id= elif [[ "$1" = "*(name*" ]]; then name=$(echo $1 | sed -e 's/^.*(name \(.*\))$/\1/') elif [[ "$1" = "*(domid*" ]]; then id=$(echo $1 | sed -e 's/^.*(domid \(.*\))$/\1/') fi [ -n "$name" -a -n "$id" ] && return 0 || return 1 } is_running() { rdname $1 name=;id= $CMD list -l | grep '(\(domain\|domid\|name\)' | \ while read LN; do parseln "$LN" || continue [ $id = 0 ] && continue case $name in ($NM) return 0 ;; esac done return 1 } start() { if [ -f /var/lock/subsys/xendomains ]; then echo -e "xendomains already running (lockfile exists)" return fi saved_domains=" " if [ "$XENDOMAINS_RESTORE" = "true" ] && contains_something "$XENDOMAINS_SAVE"; then mkdir -p $(dirname "/var/lock/subsys/xendomains") touch /var/lock/subsys/xendomains echo -n "Restoring Xen domains:" saved_domains=`ls $XENDOMAINS_SAVE` for dom in $XENDOMAINS_SAVE/*; do if [ -f $dom ] ; then HEADER=`head -c 16 $dom | head -n 1 2> /dev/null` if [ $HEADER = "LinuxGuestRecord" ]; then echo -n " ${dom##*/}" XMR=`$CMD restore $dom 2>&1 1>/dev/null` #$CMD restore $dom if [ $? -ne 0 ]; then echo -e "\nAn error occurred while restoring domain ${dom##*/}:\n$XMR" echo -e '!' else # mv $dom ${dom%/*}/.${dom##*/} rm $dom fi fi fi done echo -e fi if contains_something "$XENDOMAINS_AUTO" ; then touch /var/lock/subsys/xendomains echo -n "Starting auto Xen domains:" # We expect config scripts for auto starting domains to be in # XENDOMAINS_AUTO - they could just be symlinks to files elsewhere # Create all domains with config files in XENDOMAINS_AUTO. # TODO: We should record which domain name belongs # so we have the option to selectively shut down / migrate later # If a domain statefile from $XENDOMAINS_SAVE matches a domain name # in $XENDOMAINS_AUTO, do not try to start that domain; if it didn't # restore correctly it requires administrative attention. for dom in $XENDOMAINS_AUTO/*; do echo -n " ${dom##*/}" shortdom=$(echo $dom | sed -n 's/^.*\/\(.*\)$/\1/p') echo $saved_domains | grep -w $shortdom > /dev/null if [ $? -eq 0 ] || is_running $dom; then echo -n "(skip)" else XMC=`$CMD create --quiet --defconfig $dom` if [ $? -ne 0 ]; then echo -e "\nAn error occurred while creating domain ${dom##*/}: $XMC\n" echo -e '!' else usleep $XENDOMAINS_CREATE_USLEEP fi fi done fi } all_zombies() { name=;id= $CMD list -l | grep '(\(domain\|domid\|name\)' | \ while read LN; do parseln "$LN" || continue if test $id = 0; then continue; fi if test "$state" != "-b---d" -a "$state" != "-----d"; then return 1; fi done return 0 } # Wait for max $XENDOMAINS_STOP_MAXWAIT for $CMD $1 to finish; # if it has not exited by that time kill it, so the init script will # succeed within a finite amount of time; if $2 is nonnull, it will # kill the command as well as soon as no domain (except for zombies) # are left (used for shutdown --all). Third parameter, if any, suppresses # output of dots per working state (formatting issues) watchdog_xencmd() { if test -z "$XENDOMAINS_STOP_MAXWAIT" -o "$XENDOMAINS_STOP_MAXWAIT" = "0"; then exit fi usleep 20000 for no in `seq 0 $XENDOMAINS_STOP_MAXWAIT`; do # exit if $CMD save/migrate/shutdown is finished PSAX=`ps axlw | grep "$CMD $1" | grep -v grep` if test -z "$PSAX"; then exit; fi if ! test -n "$3"; then echo -n '.'; fi sleep 1 # go to kill immediately if there's only zombies left if all_zombies && test -n "$2"; then break; fi done sleep 1 PSPID=$($PSAX | awk '{ print $3 }') # kill $CMD $1 kill $PSPID >/dev/null 2>&1 echo -e . } stop() { # Collect list of domains to shut down if test "$XENDOMAINS_AUTO_ONLY" = "true"; then rdnames fi echo -n "Shutting down Xen domains:" name=;id= $CMD list -l | grep '(\(domain\|domid\|name\)' | \ while read LN; do parseln "$LN" || continue if test $id = 0; then continue; fi echo -n " $name" if test "$XENDOMAINS_AUTO_ONLY" = "true"; then eval " case \"\$name\" in ($NAMES) # nothing ;; (*) echo -e '(skip)' continue ;; esac " fi # XENDOMAINS_SYSRQ chould be something like just "s" # or "s e i u" or even "s e s i u o" # for the latter, you should set XENDOMAINS_USLEEP to 1200000 or so if test -n "$XENDOMAINS_SYSRQ"; then for sysrq in $XENDOMAINS_SYSRQ; do echo -n "(SR-$sysrq)" XMR=`$CMD sysrq $id $sysrq 2>&1 1>/dev/null` if test $? -ne 0; then echo -e "\nAn error occurred while doing sysrq on domain:\n$XMR\n" echo -n '!' fi # usleep just ignores empty arg usleep $XENDOMAINS_USLEEP done fi if test "$state" = "-b---d" -o "$state" = "-----d"; then echo -n "(zomb)" continue fi if test -n "$XENDOMAINS_MIGRATE"; then echo -n "(migr)" watchdog_xencmd migrate & WDOG_PID=$! XMR=`$CMD migrate $id $XENDOMAINS_MIGRATE 2>&1 1>/dev/null` if test $? -ne 0; then echo -e "\nAn error occurred while migrating domain:\n$XMR\n" echo -e '!' kill $WDOG_PID >/dev/null 2>&1 else kill $WDOG_PID >/dev/null 2>&1 echo -e . usleep 1000 continue fi fi if test -n "$XENDOMAINS_SAVE"; then echo -n "(save)" watchdog_xencmd save & WDOG_PID=$! mkdir -p "$XENDOMAINS_SAVE" XMR=`$CMD save $id $XENDOMAINS_SAVE/$name 2>&1 1>/dev/null` if test $? -ne 0; then echo -e "\nAn error occurred while saving domain:\n$XMR\n" echo -e '!' kill $WDOG_PID >/dev/null 2>&1 else kill $WDOG_PID >/dev/null 2>&1 echo -e . usleep 1000 continue fi fi if test -n "$XENDOMAINS_SHUTDOWN"; then # XENDOMAINS_SHUTDOWN should be "--halt --wait" echo -n "(shut)" watchdog_xencmd shutdown & WDOG_PID=$! XMR=`$CMD shutdown $id $XENDOMAINS_SHUTDOWN 2>&1 1>/dev/null` if test $? -ne 0; then echo -e "\nAn error occurred while shutting down domain:\n$XMR\n" echo -e '!' fi kill $WDOG_PID >/dev/null 2>&1 fi done # NB. this shuts down ALL Xen domains (politely), not just the ones in # AUTODIR/* # This is because it's easier to do ;-) but arguably if this script is run # on system shutdown then it's also the right thing to do. if ! all_zombies && test -n "$XENDOMAINS_SHUTDOWN_ALL"; then # XENDOMAINS_SHUTDOWN_ALL should be "--all --halt --wait" echo -n " SHUTDOWN_ALL " watchdog_xencmd shutdown 1 false & WDOG_PID=$! XMR=`$CMD shutdown $XENDOMAINS_SHUTDOWN_ALL 2>&1 1>/dev/null` if test $? -ne 0; then echo -e "\nAn error occurred while shutting down all domains: $XMR\n" echo -e '!' fi kill $WDOG_PID >/dev/null 2>&1 fi # Unconditionally delete lock file rm -f /var/lock/subsys/xendomains } check_domain_up() { name=;id= $CMD list -l | grep '(\(domain\|domid\|name\)' | \ while read LN; do parseln "$LN" || continue if test $id = 0; then continue; fi case $name in ($1) return 0 ;; esac done return 1 } check_all_auto_domains_up() { if ! contains_something "$XENDOMAINS_AUTO"; then return 0 fi missing= for nm in $XENDOMAINS_AUTO/*; do rdname $nm found=0 if check_domain_up "$NM"; then echo -n " $name" else missing="$missing $NM" fi done if test -n "$missing"; then echo -n " MISS AUTO:$missing" return 1 fi return 0 } check_all_saved_domains_up() { if ! contains_something "$XENDOMAINS_SAVE"; then return 0 fi missing=`/bin/ls $XENDOMAINS_SAVE` echo -n " MISS SAVED: " $missing return 1 } RETVAL=0 # See how we were called. case "$1" in start) start ;; stop) stop ;; restart|reload) # This does NOT necessarily restart all running domains: instead it # stops all running domains and then boots all the domains specified in # AUTODIR. If other domains have been started manually then they will # not get restarted. stop start ;; status) if [ -f /var/lock/subsys/xendomains; then echo -n "Checking for xendomains:" check_all_auto_domains_up check_all_saved_domains_up fi ;; *) msg_usage "$0 {start|stop|restart|reload|status}" ;; esac exit $RETVAL