[libvirt] [PATCH] Init script for suspending/resuming guests on shutdown/boot

Jiri Denemark jdenemar at redhat.com
Fri May 14 13:50:49 UTC 2010


Example output during shutdown:

Running guests on default URI: console, rhel6-1, rhel5-64
Running guests on lxc:/// URI: lxc-shell
Running guests on xen:/// URI: error: no hypervisor driver available for xen:///
error: failed to connect to the hypervisor
Running guests on vbox+tcp://orkuz/system URI: no running guests.
Suspending guests on default URI...
Suspending console: done
Suspending rhel6-1: done
Suspending rhel5-64: done
Suspending guests on lxc:/// URI...
Suspending lxc-shell: error: Failed to save domain 9cba8bfb-56f4-6589-2d12-8a58c886dd3b state
error: this function is not supported by the hypervisor: virDomainManagedSave

Note, the "Suspending $guest: " shows progress during the suspend phase
if domjobinfo gives meaningful output.

Example output during boot:

Resuming guests on default URI...
Resuming guest rhel6-1: done
Resuming guest rhel5-64: done
Resuming guest console: done
Resuming guests on lxc:/// URI...
Resuming guest lxc-shell: already active

Configuration used for generating the examples above:
URIS='default lxc:/// xen:/// vbox+tcp://orkuz/system'

The script uses /var/lib/libvirt/libvirt-guests files to note all active
guest it should try to resume on next boot. It's content looks like:

default 7f8b9d93-30e1-f0b9-47a7-cb408482654b 085b4c95-5da2-e8e1-712f-6ea6a4156af2 fb4d8360-5305-df3a-2da1-07d682891b8c
lxc:/// 9cba8bfb-56f4-6589-2d12-8a58c886dd3b
---
 daemon/Makefile.am            |   16 +++-
 daemon/libvirt-guests.init.in |  194 +++++++++++++++++++++++++++++++++++++++++
 daemon/libvirt-guests.sysconf |    3 +
 3 files changed, 209 insertions(+), 4 deletions(-)
 create mode 100644 daemon/libvirt-guests.init.in
 create mode 100644 daemon/libvirt-guests.sysconf

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index a82e9a9..ed469bf 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -29,6 +29,8 @@ EXTRA_DIST =						\
 	libvirtd.lxc.logrotate.in                       \
 	libvirtd.uml.logrotate.in                       \
 	test_libvirtd.aug                               \
+	libvirt-guests.init.in				\
+	libvirt-guests.sysconf				\
 	$(AVAHI_SOURCES)				\
 	$(DAEMON_SOURCES)
 
@@ -216,21 +218,27 @@ install-logrotate: $(LOGROTATE_CONFS)
 	$(INSTALL_DATA) libvirtd.uml.logrotate $(DESTDIR)$(sysconfdir)/logrotate.d/libvirtd.uml
 
 if LIBVIRT_INIT_SCRIPT_RED_HAT
-install-init: libvirtd.init
+install-init: libvirtd.init libvirt-guests.init
 	mkdir -p $(DESTDIR)$(sysconfdir)/rc.d/init.d
 	$(INSTALL_SCRIPT) libvirtd.init \
 	  $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirtd
+	$(INSTALL_SCRIPT) libvirt-guests.init \
+	  $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirt-guests
 	mkdir -p $(DESTDIR)$(sysconfdir)/sysconfig
 	$(INSTALL_SCRIPT) $(srcdir)/libvirtd.sysconf \
 	  $(DESTDIR)$(sysconfdir)/sysconfig/libvirtd
+	$(INSTALL_SCRIPT) $(srcdir)/libvirt-guests.sysconf \
+	  $(DESTDIR)$(sysconfdir)/sysconfig/libvirt-guests
 
 uninstall-init:
 	rm -f $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirtd \
-		$(DESTDIR)$(sysconfdir)/sysconfig/libvirtd
+		$(DESTDIR)$(sysconfdir)/sysconfig/libvirtd \
+		$(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirt-guests \
+		$(DESTDIR)$(sysconfdir)/sysconfig/libvirt-guests
 
-BUILT_SOURCES += libvirtd.init
+BUILT_SOURCES += libvirtd.init libvirt-guests.init
 
-libvirtd.init: libvirtd.init.in
+%.init: %.init.in
 	$(AM_V_GEN)sed					\
 	    -e s!\@localstatedir\@!@localstatedir@!g	\
 	    -e s!\@sbindir\@!@sbindir@!g		\
diff --git a/daemon/libvirt-guests.init.in b/daemon/libvirt-guests.init.in
new file mode 100644
index 0000000..e930115
--- /dev/null
+++ b/daemon/libvirt-guests.init.in
@@ -0,0 +1,194 @@
+#!/bin/sh
+
+# the following is the LSB init header see
+# http://www.linux-foundation.org/spec//booksets/LSB-Core-generic/LSB-Core-generic.html#INITSCRCOMCONV
+#
+### BEGIN INIT INFO
+# Provides: libvirt-guests
+# Required-Start: libvirtd
+# Required-Stop: libvirtd
+# Default-Start: 3 4 5
+# Short-Description: suspend/resume libvirt guests on shutdown/boot
+# Description: This is a script for suspending active libvirt guests
+#              on shutdown and resuming them on next boot
+#              See http://libvirt.org
+### END INIT INFO
+
+# the following is chkconfig init header
+#
+# libvirt-guests:   suspend/resume libvirt guests on shutdown/boot
+#
+# chkconfig: 345 98 02
+# description:  This is a script for suspending active libvirt guests
+#               on shutdown and resuming them on next boot
+#               See http://libvirt.org
+#
+
+sysconfdir=@sysconfdir@
+localstatedir=@localstatedir@
+
+# Source function library.
+. $sysconfdir/rc.d/init.d/functions
+
+URIS=default
+
+test -f $sysconfdir/sysconfig/libvirt-guests && . $sysconfdir/sysconfig/libvirt-guests
+
+LISTFILE=$localstatedir/lib/libvirt/libvirt-guests
+
+RETVAL=0
+
+retval() {
+    "$@"
+    if [ $? -ne 0 ]; then
+        RETVAL=1
+        return 1
+    else
+        return 0
+    fi
+}
+
+run_virsh() {
+    uri=$1
+    shift
+
+    if [ "x$uri" = xdefault ]; then
+        conn=
+    else
+        conn="-c $uri"
+    fi
+
+    virsh $conn "$@"
+}
+
+run_virsh_c() {
+    ( export LC_ALL=C; run_virsh "$@" )
+}
+
+list_guests() {
+    uri=$1
+
+    list=`run_virsh_c $uri list`
+    if [ $? -ne 0 ]; then
+        RETVAL=1
+        return 1
+    fi
+
+    for id in `echo "$list" | awk 'NR > 2 {print $1}'`; do
+        run_virsh_c $uri dominfo $id | awk '/^UUID:/{print $2}'
+    done
+}
+
+guest_name() {
+    uri=$1
+    uuid=$2
+
+    name=`run_virsh_c $uri dominfo $uuid 2>/dev/null | \
+          awk '/^Name:/{print $2}'`
+    [ -n "$name" ] || name=$uuid
+
+    echo "$name"
+}
+
+guest_is_on() {
+    uri=$1
+    uuid=$2
+
+    id=`run_virsh_c $uri dominfo $uuid 2>/dev/null | \
+        awk '/^Id:/{print $2}'`
+
+    [ -n "$id" ] && ! [ "x$id" = x- ]
+}
+
+start() {
+    while read uri list; do
+        configured=false
+        for confuri in $URIS; do
+            if [ $confuri = $uri ]; then
+                configured=true
+                break
+            fi
+        done
+        if ! $configured; then
+            echo $"Ignoring guests on $uri URI"
+            continue
+        fi
+
+        echo $"Resuming guests on $uri URI..."
+        for guest in $list; do
+            name=`guest_name $uri $guest`
+            echo -n $"Resuming guest $name: "
+            if retval guest_is_on $uri $guest; then
+                echo $"already active"
+            else
+                retval run_virsh $uri start "$name" >/dev/null && echo $"done"
+            fi
+        done
+    done <$LISTFILE
+
+    rm -f $LISTFILE
+}
+
+stop() {
+    >$LISTFILE
+    for uri in $URIS; do
+        echo -n $"Running guests on $uri URI: "
+        list=`list_guests $uri`
+        if [ $? -eq 0 ]; then
+            empty=true
+            for uuid in $list; do
+                $empty || echo -n ", "
+                echo -n `guest_name $uri $uuid`
+                empty=false
+            done
+            if $empty; then
+                echo $"no running guests."
+            else
+                echo
+                echo $uri $list >>$LISTFILE
+            fi
+        fi
+    done
+
+    while read uri list; do
+        echo $"Suspending guests on $uri URI..."
+        for guest in $list; do
+            name=`guest_name $uri $guest`
+            label=$"Suspending $name: "
+            echo -n "$label"
+            run_virsh $uri managedsave $guest >/dev/null &
+            virsh_pid=$!
+            while true; do
+                sleep .5
+                kill -0 $virsh_pid >&/dev/null || break
+                progress=`run_virsh_c $uri domjobinfo $guest 2>/dev/null | \
+                          awk '/^Data processed:/{print $3, $4}'`
+                if [ -n "$progress" ]; then
+                    printf '\r%s%12s ' "$label" "$progress"
+                else
+                    printf '\r%s%-12s ' "$label" "..."
+                fi
+            done
+            retval wait $virsh_pid && printf '\r%s%-12s\n' "$label" $"done"
+        done
+    done <$LISTFILE
+}
+
+gueststatus() {
+    for uri in $URIS; do
+        echo "* $uri URI:"
+        retval run_virsh $uri list || echo
+    done
+}
+
+# See how we were called.
+case "$1" in
+    start|stop|gueststatus)
+        $1
+        ;;
+    *)
+        echo $"Usage: $0 {start|stop|gueststatus}"
+        exit 3
+        ;;
+esac
+exit $RETVAL
diff --git a/daemon/libvirt-guests.sysconf b/daemon/libvirt-guests.sysconf
new file mode 100644
index 0000000..eb70ebf
--- /dev/null
+++ b/daemon/libvirt-guests.sysconf
@@ -0,0 +1,3 @@
+# specify URIs to check for running guests
+# example: URIS='default xen:/// vbox+tcp://host/system lxc:///'
+#URIS=default
-- 
1.7.1




More information about the libvir-list mailing list