[libvirt] [PATCH] libvirt-guests: Enable parallel operations and improve error handling

Peter Krempa pkrempa at redhat.com
Mon Feb 20 13:32:26 UTC 2012


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




More information about the libvir-list mailing list