From 6c3642e9bc7c46c8a0a74cf7c5e97c7cd46d9a24 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Tue, 28 Feb 2012 16:09:42 +0100 Subject: [PATCH] libvirt-guests: Add parallel startup and shutdown of guests With this patch, it's possible to shut down guests in parallel. Parallel startup was possible before, but this functionality was not documented properly. To enable parallel startup set the START_DELAY to 0. Parallel shutdown has a configurable parameter PARALLEL_SHUTDOWN that defines the number of machines being shut down in parallel. Enabling this feature changes the semantics of SHUTDOWN_TIMEOUT parameter that is applied as a cumulative timeout to shutdown all guests on a URI. --- tools/libvirt-guests.init.sh | 140 +++++++++++++++++++++++++++++++---- tools/libvirt-guests.sysconf | 15 +++- 2 files changed, 139 insertions(+), 16 deletions(-) diff --git a/tools/libvirt-guests.init.sh b/tools/libvirt-guests.init.sh index c867eceea6..aafb4d48d0 100644 --- a/tools/libvirt-guests.init.sh +++ b/tools/libvirt-guests.init.sh @@ -41,7 +41,8 @@ export TEXTDOMAIN="@PACKAGE@" TEXTDOMAINDIR="@localedir@" URIS=default ON_BOOT=start ON_SHUTDOWN=suspend -SHUTDOWN_TIMEOUT=0 +SHUTDOWN_TIMEOUT=300 +PARALLEL_SHUTDOWN=0 START_DELAY=0 BYPASS_CACHE=0 @@ -255,12 +256,18 @@ shutdown_guest() printf %s "$label" retval run_virsh "$uri" shutdown "$guest" >/dev/null || return timeout=$SHUTDOWN_TIMEOUT - while [ "$timeout" -gt 0 ]; do + check_timeout=false + if [ $timeout -gt 0 ]; then + check_timeout=true + fi + while ! $check_timeout || [ "$timeout" -gt 0 ]; do sleep 1 - timeout=$((timeout - 1)) guest_is_on "$uri" "$guest" || return "$guest_running" || break - printf '\r%s%-12d ' "$label" "$timeout" + if $check_timeout; then + timeout=$((timeout - 1)) + printf '\r%s%-12d ' "$label" "$timeout" + fi done if guest_is_on "$uri" "$guest"; then @@ -273,6 +280,108 @@ shutdown_guest() fi } +# shutdown_guest_async URI GUEST +# Start a ACPI shutdown of GUEST on URI. This function returns after the command +# was issued to libvirt to allow parallel shutdown. +shutdown_guest_async() +{ + uri=$1 + guest=$2 + + name=$(guest_name "$uri" "$guest") + eval_gettext "Starting shutdown on guest: \$name" + echo + retval run_virsh "$uri" shutdown "$guest" > /dev/null +} + +# guest_count GUEST_LIST +# Returns number of guests in GUEST_LIST +guest_count() +{ + set -- $1 + echo $# +} + +# check_guests_shutdown URI GUESTS +# check if shutdown is complete on guests in "GUESTS" and returns only +# guests that are still shutting down +check_guests_shutdown() +{ + uri=$1 + guests=$2 + + guests_up= + for guest in $guests; do + if ! guest_is_on "$uri" "$guest" >/dev/null 2>&1; then + eval_gettext "Failed to determine state of guest: \$guest. Not tracking it anymore." + echo + continue + fi + if "$guest_running"; then + guests_up="$guests_up $guest" + fi + done + echo "$guests_up" +} + +# print_guests_shutdown URI BEFORE AFTER +# Checks for differences in the lists BEFORE and AFTER and prints +# a shutdown complete notice for guests that have finished +print_guests_shutdown() +{ + uri=$1 + before=$2 + after=$3 + + for guest in $before; do + case " $after " in + *" $guest "*) continue;; + esac + + name=$(guest_name "$uri" "$guest") + eval_gettext "Shutdown of guest \$name complete." + echo + done +} + +# shutdown_guests_parallel URI GUESTS +# Shutdown guests GUESTS on machine URI in parallel +shutdown_guests_parallel() +{ + uri=$1 + guests=$2 + + on_shutdown= + check_timeout=false + timeout=$SHUTDOWN_TIMEOUT + if [ $timeout -gt 0 ]; then + check_timeout=true + fi + while [ -n "$on_shutdown" ] || [ -n "$guests" ]; do + while [ -n "$guests" ] && + [ $(guest_count "$on_shutdown") -lt "$PARALLEL_SHUTDOWN" ]; do + set -- $guests + guest=$1 + shift + guests=$* + shutdown_guest_async "$uri" "$guest" + on_shutdown="$on_shutdown $guest" + done + sleep 1 + if $check_timeout; then + timeout=$(($timeout - 1)) + if [ $timeout -le 0 ]; then + eval_gettext "Timeout expired while shutting down domains"; echo + RETVAL=1 + return + fi + fi + on_shutdown_prev=$on_shutdown + on_shutdown=$(check_guests_shutdown "$uri" "$on_shutdown") + print_guests_shutdown "$uri" "$on_shutdown_prev" "$on_shutdown" + done +} + # stop # Shutdown or save guests on the configured uris stop() { @@ -282,8 +391,8 @@ stop() { suspending=true if [ "x$ON_SHUTDOWN" = xshutdown ]; then suspending=false - if [ $SHUTDOWN_TIMEOUT -le 0 ]; then - gettext "Shutdown action requested but SHUTDOWN_TIMEOUT was not set" + if [ $SHUTDOWN_TIMEOUT -lt 0 ]; then + gettext "SHUTDOWN_TIMEOUT must be equal or greater than 0" echo RETVAL=6 return @@ -359,13 +468,18 @@ stop() { eval_gettext "Shutting down guests on \$uri URI..."; echo fi - for guest in $list; do - if "$suspending"; then - suspend_guest "$uri" "$guest" - else - shutdown_guest "$uri" "$guest" - fi - done + if [ "$PARALLEL_SHUTDOWN" -gt 1 ] && + ! "$suspending"; then + shutdown_guests_parallel "$uri" "$list" + else + for guest in $list; do + if "$suspending"; then + suspend_guest "$uri" "$guest" + else + shutdown_guest "$uri" "$guest" + fi + done + fi done <"$LISTFILE" rm -f "$VAR_SUBSYS_LIBVIRT_GUESTS" diff --git a/tools/libvirt-guests.sysconf b/tools/libvirt-guests.sysconf index 9b8b64fb24..d1f20510c0 100644 --- a/tools/libvirt-guests.sysconf +++ b/tools/libvirt-guests.sysconf @@ -10,7 +10,8 @@ # libvirtd #ON_BOOT=start -# number of seconds to wait between each guest start +# Number of seconds to wait between each guest start. Set to 0 to allow +# parallel startup. #START_DELAY=0 # action taken on host shutdown @@ -23,8 +24,16 @@ # value suitable for your guests. #ON_SHUTDOWN=suspend -# number of seconds we're willing to wait for a guest to shut down -#SHUTDOWN_TIMEOUT=0 +# If set to non-zero, shutdown will suspend guests concurrently. Number of +# guests on shutdown at any time will not exceed number set in this variable. +#PARALLEL_SHUTDOWN=0 + +# Number of seconds we're willing to wait for a guest to shut down. If parallel +# shutdown is enabled, this timeout applies as a timeout for shutting down all +# guests on a single URI defined in the variable URIS. If this is 0, then there +# is no time out (use with caution, as guests might not respond to a shutdown +# request). The default value is 300 seconds (5 minutes). +#SHUTDOWN_TIMEOUT=300 # If non-zero, try to bypass the file system cache when saving and # restoring guests, even though this may give slower operation for -- GitLab