Subject: Improved xendomains script
To: None <port-xen@NetBSD.org>
From: Johnny C. Lam <jlam@pkgsrc.org>
List: port-xen
Date: 10/17/2005 09:43:35
--9amGYk9869ThD9tj
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

I've greatly improved the initial "xendomains" script I had posted
two weeks ago.  The attached script now allows for per-domain hook
scripts that are run before a domain is created, and after a domain
is stopped.  Also, to prevent the xendomains rc.d script from hanging
during system shutdown, I've modified the "stop" action -- instead of
waiting for all the domains to stop, we now use a poll/timeout loop
to check that all the domains are stopped.

The reason I added the poll/timeout is because on my 3.0_BETA machine,
some guest domains seem to get stuck in the "s" (shutdown) state and
never seem to get removed from the xend's domain list, so an:

	xm shutdown --halt --wait --all

was waiting forever and never returning.  I'm told that this was fixed
in -current, so I guess some pullups to the netbsd-3 branch are missing.
If anyone knows any more information about this issue, please let me
know.

I personally use the hook scripts to bind and unbind cgd(4) devices
that are used by each domain.  It's possible to run cgdconfig directly
from the domain configuration file since it's just a Python script,
but then it's not possible to enter passphrases.  Running cgdconfig
via the xendomains script doesn't have this problem.

I've added a giant comment block at the top of the xendomains script
to describe the variables that may be set in /etc/rc.conf.  Some
version of this script will eventually become part of the pkgsrc
sysutils/xentools20 package, so if you have any suggested improvements
or fixes, I'd love to hear them.

	Cheers,

	-- Johnny Lam <jlam@pkgsrc.org>

--9amGYk9869ThD9tj
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=xendomains

#!/bin/sh
#
# $NetBSD$
#
# PROVIDE: xendomains
# REQUIRE: xend
# KEYWORD: shutdown
#
# xendomains		This required variable is a whitespace-separated
#			list of domains, e.g., xendomains="dom1 dom2 dom3".
#
# xendomains_config	This optional variable is a format string that
#			represents the path to the configuration file for
#			each domain.  "%s" is substituted with the name of
#			the domain.  The default is "/usr/pkg/etc/xen/%s".
#
# xendomains_prehook	This optional variable is a format string that
#			represents the command to run, if it exists, before
#			starting each domain.  "%s" is substituted with the
#			name of the domain.  The default is
#			"/usr/pkg/etc/xen/%s-pre".
#
# xendomains_posthook	This optional variable is a format string that
#			represents the command to run, if it exists, after
#			stopping each domain.  "%s" is substituted with the
#			name of the domain.  The default is
#			"/usr/pkg/etc/xen/%s-post".
#

. /etc/rc.subr

name="xendomains"
ctl_command="/usr/pkg/sbin/xm"
start_cmd="xendomains_start"
stop_cmd="xendomains_stop"
list_cmd="xendomains_list"
extra_commands="list"

xendomains_start()
{
	[ -n "$xendomains" ] || return

	echo "Starting xen domains."
	for domain in $xendomains; do
		case "$domain" in
		"")	continue ;;
		esac

		# Start off by running the pre-hook script if it's present.
		if [ -n "${xendomains_prehook}" ]; then
			cmdline=`printf "${xendomains_prehook}" $domain`
			cmd="${cmdline%% *}"
			if [ -x "$cmd" ]; then
				$cmdline || echo "Pre-hook \`\`$cmdline'' failed... skipping $domain."
				continue
			fi
		fi

		# Ask xend to create the domain.
		if [ -n "${xendomains_config}" ]; then
			file=`printf "${xendomains_config}" $domain`
			if [ -f "$file" ]; then
				${ctl_command} create "$file"
			fi
		fi
	done
}

xendomains_list() {
	# Output a whitespace-separated list of live guest domains.
	${ctl_command} list | awk '
		(FNR <= 2) { next }
		($5 !~ /s/) { s = s " " $1 }
		END { sub(" *", "", s); print s }'
}

xendomains_stop()
{
	# Determine an appropriate timeout waiting for all domains to
	# stop -- always wait at least 60s, and add 5s per active domain.
	#
	numdomains=$(xendomains_list | awk '{ print NF }')
	[ $numdomains -gt 0 ] || return
	timeout=$((60 + numdomains * 5))

	# Ask xend to stop every domain, and poll xend every 10s up to the
	# timeout period to check if all the domains are stopped.  We
	# consider a domain in the "s" (shutdown) state to be stopped.
	#
	echo "Stopping xen domains."
	${ctl_command} shutdown --halt --all
	while [ $timeout -gt 0 ]; do
		livedomains=$(xendomains_list)
		[ -n "$livedomains" ] || break
		timeout=$((timeout - 10))
		sleep 10
	done
	livedomains=$(xendomains_list)
	if [ -n "$livedomains" ]; then
		echo "Failed to stop: $livedomains"
	else
		echo "All domains stopped."
	fi

	# Finish off by running the post-hook script if it's present.
	for domain in $xendomains; do
		case "$domain" in
		"")	continue ;;
		esac
		if [ -n "${xendomains_posthook}" ]; then
			cmdline=`printf "${xendomains_posthook}" $domain`
			cmd="${cmdline%% *}"
			if [ -x "$cmd" ]; then
				$cmdline || echo "Post-hook \`\`$cmdline'' failed."
			fi
		fi
	done
}

load_rc_config $name

: ${xendomains_config="/usr/pkg/etc/xen/%s"}
: ${xendomains_prehook="/usr/pkg/etc/xen/%s-pre"}
: ${xendomains_posthook="/usr/pkg/etc/xen/%s-post"}

run_rc_command "$1"

--9amGYk9869ThD9tj--