This patch modifies the libvirt-guests init script to enable parallel shiutdown on guest machines and gets rid of error messages if the client is unable connect to the URI specified in the config file. --- Simultaneous shutdown of machines may speed up the shutdown process as the shutdown sequence of guests often consists of timeouts and storage un-intensive tasks. Simultaneous resume of machines was already supported, although not documented well enough. This patch also checks if connection to the URI can be done, and prints a error message if it's not the case. This get's rid of unrelevant and repeated error messages if the URI is unreachable. The last improvement is while using managed-save. Transient domains are excluded from the save sequence to get rid of error messages and a list of domains that are left behind is printed. Please tell me your suggestions how to improve this, as I'm not a bash "native speaker". tools/libvirt-guests.init.sh | 214 ++++++++++++++++++++++++++++++++++++++---- tools/libvirt-guests.sysconf | 10 ++- 2 files changed, 204 insertions(+), 20 deletions(-) diff --git a/tools/libvirt-guests.init.sh b/tools/libvirt-guests.init.sh index 367177e..c858747 100644 --- a/tools/libvirt-guests.init.sh +++ b/tools/libvirt-guests.init.sh @@ -78,8 +78,25 @@ run_virsh_c() { ( export LC_ALL=C; run_virsh "$@" ) } +test_connect() +{ + uri=$1 + + run_virsh "$uri" connect 2>/dev/null + if [ $? -ne 0 ]; then + eval_gettext "Can't connect to \$uri. Skipping." + echo + return 1 + fi +} + +# "persistent" argument options: +# yes: list only persistent guests +# no: list only transient guests +# all: list both persistent and transient guests list_guests() { uri=$1 + persistent=$2 list=$(run_virsh_c "$uri" list) if [ $? -ne 0 ]; then @@ -89,12 +106,19 @@ list_guests() { uuids= for id in $(echo "$list" | awk 'NR > 2 {print $1}'); do - uuid=$(run_virsh_c "$uri" dominfo "$id" | awk '/^UUID:/{print $2}') - if [ -z "$uuid" ]; then + dominfo=$(run_virsh_c "$uri" dominfo "$id") + uuid=$(echo "$dominfo" | awk '/^UUID:/{print $2}') + dompersist=$(echo "$dominfo" | awk '/^Persistent:/{print $2}') + + if [ -z "$uuid" ] || [ -z "$dompersist" ]; then RETVAL=1 return 1 fi - uuids="$uuids $uuid" + + if [ "$persistent" == "$dompersist" ] || + [ "$persistent" == "all" ]; then + uuids="$uuids $uuid" + fi done echo $uuids @@ -162,6 +186,8 @@ start() { continue fi + test_connect "$uri" || continue + eval_gettext "Resuming guests on \$uri URI..."; echo for guest in $list; do name=$(guest_name "$uri" "$guest") @@ -241,6 +267,102 @@ shutdown_guest() fi } +shutdown_guest_async() +{ + uri=$1 + guest=$2 + + name=$(guest_name "$uri" "$guest") + label=$(eval_gettext "Starting shutdown on guest: \$name") + echo $label + retval run_virsh "$uri" shutdown "$guest" >/dev/null || return +} + +set_add() +{ + item=$1 + items=$2 + + echo "$items $item" +} + +set_remove() +{ + item=$1 + items=$2 + + newitems= + for nit in $items; do + if [ "$nit" != "$domain" ]; then + newitems="$newitems $nit" + fi + done + + echo "$newitems" +} + +set_count() +{ + items=$1 + + count="0" + for item in $items; do + count=$((count+1)) + done + + echo $count +} + +set_head() +{ + items=$1 + + for item in $items; do + echo $item + return 0 + done +} + +remove_shutdown_domains() +{ + uri=$1 + domains=$2 + + newlist= + for dom in $domains; do + guest_is_on "$uri" "$dom" 2>&1 > /dev/null || return + if "$guest_running"; then + newlist="$newlist $dom" + fi + done + + echo "$newlist" +} + +notify_shutdown_domains() +{ + uri=$1 + all=$2 + running=$3 + + for dom in $all; do + found=false + for run in $running; do + if [ $dom = $run ]; then + found=true + break + fi + done + + if ! "$found"; then + name=$(guest_name "$uri" "$dom") + eval_gettext "Shutdown of guest \$name complete." + echo + fi + done +} + + stop() { # last stop was not followed by start [ -f "$LISTFILE" ] && return 0 @@ -260,14 +382,12 @@ stop() { set -f for uri in $URIS; do set +f - eval_gettext "Running guests on \$uri URI: " - if [ "x$uri" = xdefault ] && [ ! -x "$libvirtd" ]; then - gettext "libvirtd not installed; skipping this URI."; echo - continue - fi + test_connect "$uri" || continue + + eval_gettext "Running guests on \$uri URI: " - list=$(list_guests "$uri") + list=$(list_guests "$uri" "all") if [ $? -eq 0 ]; then empty=true for uuid in $list; do @@ -275,13 +395,45 @@ stop() { printf %s "$(guest_name "$uri" "$uuid")" empty=false done + if "$empty"; then - gettext "no running guests."; echo + gettext "no running guests." + fi + echo + fi + + if "$suspending"; then + transient=$(list_guests "$uri" "no") + if [ $? -eq 0 ]; then + empty=true + for uuid in $transient; do + if "$empty"; then + eval_gettext "Not suspending transient domains on URI: \$uri: " + empty=false + else + printf ", " + fi + printf %s "$(guest_name "$uri" "$uuid")" + done + # reload domain list to contain only persistent domains + list=$(list_guests "$uri" "yes") + if [ $? -ne 0 ]; then + eval_gettext "Failed to list persistent domains on \$uri" + echo + RETVAL=1 + return + fi else + gettext "Failed to list transient domains" echo - echo "$uri" "$list" >>"$LISTFILE" + RETVAL=1 + return fi fi + + if [ -n "$list" ]; then + echo "$uri" "$list" >>"$LISTFILE" + fi done set +f @@ -292,13 +444,39 @@ 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 + on_shutdown= + timeout=$SHUTDOWN_TIMEOUT + while [ $(set_count "$on_shutdown") -gt "0" ] || + [ $(set_count "$list") -gt "0" ]; do + while [ $(set_count "$on_shutdown") -lt "$PARALLEL_SHUTDOWN" ] && + [ $(set_count "$list") -gt "0" ]; do + domain=$(set_head "$list") + shutdown_guest_async "$uri" "$domain" + on_shutdown=$(set_add "$domain" "$on_shutdown"); + list=$(set_remove "$domain" "$list"); + done + sleep 1 + timeout=$((timeout - 1)) + if [ $timeout -le 0 ]; then + eval_gettext "Timeout expired while shutting down domains"; echo + RETVAL=1 + return + fi + on_shutdown_old=$on_shutdown + on_shutdown=$(remove_shutdown_domains "$uri" "$on_shutdown" || return) + notify_shutdown_domains "$uri" "$on_shutdown_old" "$on_shutdown" + done + 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 9b8b64f..e16af4f 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,7 +24,12 @@ # value suitable for your guests. #ON_SHUTDOWN=suspend -# number of seconds we're willing to wait for a guest to shut down +# If set to non-zero, shutdown will suspend domains concurently. Number of domains +# 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. #SHUTDOWN_TIMEOUT=0 # If non-zero, try to bypass the file system cache when saving and -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list