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