[libvirt] [PATCH 4/4] libvirt-guests: Add parallel startup and shutdown of guests

2012-02-28 Thread Peter Krempa
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 |   10 +++-
 2 files changed, 141 insertions(+), 9 deletions(-)

diff --git a/tools/libvirt-guests.init.sh b/tools/libvirt-guests.init.sh
index 47914e3..dd933c7 100644
--- a/tools/libvirt-guests.init.sh
+++ b/tools/libvirt-guests.init.sh
@@ -273,6 +273,127 @@ 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 $#
+}
+
+# guest_first GUEST GUEST GUEST...
+# Returns the first guest in GUEST...
+guest_first()
+{
+echo $1
+}
+
+# guest_remove GUEST GUEST_LIST
+# Remove GUEST from GUEST_LIST
+guest_remove()
+{
+guest=$1
+guests=$2
+
+newguests=
+for dom in $guests; do
+if [ $dom != $guest ]; then
+newguests=$newguests $dom
+fi
+done
+
+echo $newguests
+}
+
+# check_domains_shutdown URI GUESTS
+# check if shutdown is complete on guests in GUESTS and returns only
+# guests that are still shutting down
+check_domains_shutdown()
+{
+uri=$1
+guests=$2
+
+guests_up=
+for guest in $guests; do
+guest_is_on $uri $dom 21  /dev/null || continue
+if $guest_running; then
+guests_up=$guests_up $guest
+fi
+done
+echo $guests_up
+}
+
+# print_domains_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_domains_shutdown()
+{
+uri=$1
+before=$2
+after=$3
+
+for guest in $before; do
+found=false
+for running in $after; do
+   if [ $guest = $running ]; then
+   found=true
+   break
+   fi
+done
+
+if ! $found; then
+name=$(guest_name $uri $guest)
+eval_gettext Shutdown of guest \$name complete.
+echo
+fi
+done
+}
+
+# shutdown_guests_parallel URI GUESTS
+# Shutdown guests GUESTS on machine URI in parallel
+shutdown_guests_parallel()
+{
+uri=$1
+guests=$2
+
+on_shutdown=
+timeout=$SHUTDOWN_TIMEOUT
+while [ -n $on_shutdown ] || [ -n $guests ]; do
+while [ -n $guests ] 
+  [ $(guest_count $on_shutdown) -lt $PARALLEL_SHUTDOWN ]; do
+guest=$(guest_first $guests)
+guests=$(guest_remove $guest $guests)
+shutdown_guest_async $uri $guest
+on_shutdown=$on_shutdown $guest
+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_prev=$on_shutdown
+on_shutdown=$(check_domains_shutdown $uri $on_shutdown)
+print_domains_shutdown $uri $on_shutdown_prev $on_shutdown
+done
+
+}
+
 # stop
 # Shutdown or save guests on the configured uris
 stop() {
@@ -357,13 +478,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 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
+# 

Re: [libvirt] [PATCH 4/4] libvirt-guests: Add parallel startup and shutdown of guests

2012-02-28 Thread Eric Blake
On 02/28/2012 11:00 AM, Peter Krempa wrote:
 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 |   10 +++-
  2 files changed, 141 insertions(+), 9 deletions(-)
 

Missing an initialization of PARALLEL_SHUTDOWN=0 alongside
SHUTDOWN_TIMEOUT=0 before sourcing the user's values.

 +
 +# check_domains_shutdown URI GUESTS
 +# check if shutdown is complete on guests in GUESTS and returns only
 +# guests that are still shutting down
 +check_domains_shutdown()
 +{
 +uri=$1
 +guests=$2
 +
 +guests_up=
 +for guest in $guests; do
 +guest_is_on $uri $dom 21  /dev/null || continue

You want '/dev/null 21' (order matters, when silencing a command and
using it just for its side effects).  But are we sure we want to
silently ignore a guest_is_on failure, or should we emit a message
stating that we are no longer able to track the shutdown status of that
guest?

 +print_domains_shutdown()
 +{
 +uri=$1
 +before=$2
 +after=$3
 +
 +for guest in $before; do
 +found=false
 +for running in $after; do
 +   if [ $guest = $running ]; then
 +   found=true
 +   break
 +   fi
 +done

slightly faster to do:

for guest in $before; do
found=false;
case  $after  in
* $guest *) found=true ;;
esac

But what you have is functionally correct.

 +
 +if ! $found; then
 +name=$(guest_name $uri $guest)
 +eval_gettext Shutdown of guest \$name complete.
 +echo
 +fi
 +done
 +}
 +
 +# shutdown_guests_parallel URI GUESTS
 +# Shutdown guests GUESTS on machine URI in parallel
 +shutdown_guests_parallel()
 +{
 +uri=$1
 +guests=$2
 +
 +on_shutdown=
 +timeout=$SHUTDOWN_TIMEOUT

If SHUTDOWN_TIMEOUT is the default of 0, then this function times out
right away; shouldn't that really mean that we have no maximum timeout,
and wait until everything has shut down?  I think you need another
variable, based on whether $timeout is 0 on entry, and skip the
$((timeout - 1)) calculation if that variable is true.

 +while [ -n $on_shutdown ] || [ -n $guests ]; do
 +while [ -n $guests ] 
 +  [ $(guest_count $on_shutdown) -lt $PARALLEL_SHUTDOWN ]; do
 +guest=$(guest_first $guests)
 +guests=$(guest_remove $guest $guests)

Faster to avoid these two sub-shells by doing:

set -- $guests
guest=$1
shift
guests=$*

and might even get rid of the need for some helper functions.  But what
you have is functionally correct.

 @@ -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

s/concurently/concurrently/

I think it's probably worth a v2 (or is it v3?) for just this patch.

-- 
Eric Blake   ebl...@redhat.com+1-919-301-3266
Libvirt virtualization library http://libvirt.org



signature.asc
Description: OpenPGP digital signature
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list