Most of this deals with moving the libvirt-guests.sh script which
does all the work to /usr/libexec, so it can be shared by both
systemd and traditional init. Previously systemd depended on
the script being in /etc/init.d
Required to fix
https://bugzilla.redhat.com/show_bug.cgi?id=789747
---
Ping on this too. I'd like to get this in before cutting 0.10.2 maint release.
Though this has a bit more going on so if anyone thinks it's risky I'm happy
to hold off.
Thanks,
Cole
v2:
Break out common functionality, move to /usr/libexec/libvirt-guests.sh
.gitignore | 1 +
libvirt.spec.in | 6 +-
po/POTFILES.in | 2 +-
tools/Makefile.am | 18 +-
tools/libvirt-guests.init.in | 27 ++
tools/libvirt-guests.init.sh | 597 ----------------------------------------
tools/libvirt-guests.service.in | 4 +-
tools/libvirt-guests.sh.in | 573 ++++++++++++++++++++++++++++++++++++++
8 files changed, 620 insertions(+), 608 deletions(-)
create mode 100644 tools/libvirt-guests.init.in
delete mode 100644 tools/libvirt-guests.init.sh
create mode 100644 tools/libvirt-guests.sh.in
diff --git a/.gitignore b/.gitignore
index 804eda4..1f1b26f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -177,6 +177,7 @@
/tools/*.[18]
/tools/libvirt-guests.init
/tools/libvirt-guests.service
+/tools/libvirt-guests.sh
/tools/virsh
/tools/virsh-*-edit.c
/tools/virt-*-validate
diff --git a/libvirt.spec.in b/libvirt.spec.in
index ebebfab..d701977 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1380,8 +1380,6 @@ rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/libvirtd.uml
mv $RPM_BUILD_ROOT%{_datadir}/doc/libvirt-%{version} \
$RPM_BUILD_ROOT%{_datadir}/doc/libvirt-docs-%{version}
-sed -i -e "s|$RPM_BUILD_ROOT||g"
$RPM_BUILD_ROOT%{_sysconfdir}/rc.d/init.d/libvirt-guests
-
%if %{with_dtrace}
%ifarch %{power64} s390x x86_64 ia64 alpha sparc64
mv $RPM_BUILD_ROOT%{_datadir}/systemtap/tapset/libvirt_probes.stp \
@@ -1600,10 +1598,13 @@ fi
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/nwfilter/
+%attr(0755, root, root) %{_libexecdir}/libvirt-guests.sh
%if %{with_systemd}
%{_unitdir}/libvirtd.service
+%{_unitdir}/libvirt-guests.service
%else
%{_sysconfdir}/rc.d/init.d/libvirtd
+%{_sysconfdir}/rc.d/init.d/libvirt-guests
%endif
%doc daemon/libvirtd.upstart
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
@@ -1865,7 +1866,6 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd
%{_datadir}/libvirt/cpu_map.xml
-%{_sysconfdir}/rc.d/init.d/libvirt-guests
%if %{with_systemd}
%{_unitdir}/libvirt-guests.service
%endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9768528..cbf5bc6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -190,7 +190,7 @@ src/xenapi/xenapi_utils.c
src/xenxs/xen_sxpr.c
src/xenxs/xen_xm.c
tools/console.c
-tools/libvirt-guests.init.sh
+tools/libvirt-guests.sh.in
tools/virsh.c
tools/virsh-domain-monitor.c
tools/virsh-domain.c
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 0d7822d..281f010 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -41,6 +41,7 @@ DISTCLEANFILES =
bin_SCRIPTS = virt-xml-validate virt-pki-validate
bin_PROGRAMS = virsh virt-host-validate
+libexec_SCRIPTS = libvirt-guests.sh
if HAVE_SANLOCK
sbin_SCRIPTS = virt-sanlock-cleanup
@@ -177,7 +178,7 @@ uninstall-sysconfig:
rm -f $(DESTDIR)$(sysconfdir)/sysconfig/libvirt-guests
rmdir $(DESTDIR)$(sysconfdir)/sysconfig ||:
-EXTRA_DIST += libvirt-guests.init.sh
+EXTRA_DIST += libvirt-guests.sh.in libvirt-guests.init.in
install-initscript: libvirt-guests.init
$(MKDIR_P) $(DESTDIR)$(sysconfdir)/rc.d/init.d
@@ -198,7 +199,7 @@ install-init:
uninstall-init:
endif # LIBVIRT_INIT_SCRIPT_RED_HAT
-libvirt-guests.init: libvirt-guests.init.sh $(top_builddir)/config.status
+libvirt-guests.sh: libvirt-guests.sh.in $(top_builddir)/config.status
$(AM_V_GEN)sed \
-e 's!\@PACKAGE\@!$(PACKAGE)!g' \
-e 's!\@bindir\@!$(bindir)!g' \
@@ -209,20 +210,26 @@ libvirt-guests.init: libvirt-guests.init.sh
$(top_builddir)/config.status
< $< > $@-t && \
chmod a+x $@-t && \
mv $@-t $@
+BUILT_SOURCES += libvirt-guests.sh
+libvirt-guests.init: libvirt-guests.init.in libvirt-guests.sh
+ $(AM_V_GEN)sed \
+ -e 's!\@libexecdir\@!$(libexecdir)!g' \
+ < $< > $@-t && \
+ chmod a+x $@-t && \
+ mv $@-t $@
EXTRA_DIST += libvirt-guests.service.in
-
SYSTEMD_UNIT_DIR = /lib/systemd/system
if LIBVIRT_INIT_SCRIPT_SYSTEMD
-install-systemd: libvirt-guests.service install-initscript install-sysconfig
+install-systemd: libvirt-guests.service install-sysconfig libvirt-guests.sh
$(MKDIR_P) $(DESTDIR)$(SYSTEMD_UNIT_DIR)
$(INSTALL_DATA) libvirt-guests.service \
$(DESTDIR)$(SYSTEMD_UNIT_DIR)/libvirt-guests.service
-uninstall-systemd: uninstall-initscript uninstall-sysconfig
+uninstall-systemd: uninstall-sysconfig
rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/libvirt-guests.service
rmdir $(DESTDIR)$(SYSTEMD_UNIT_DIR) ||:
@@ -241,6 +248,7 @@ libvirt-guests.service: libvirt-guests.service.in
$(top_builddir)/config.status
-e 's!\@localstatedir\@!$(localstatedir)!g' \
-e 's!\@sbindir\@!$(sbindir)!g' \
-e 's!\@sysconfdir\@!$(sysconfdir)!g' \
+ -e 's!\@libexecdir\@!$(libexecdir)!g' \
< $< > $@-t && \
chmod a+x $@-t && \
mv $@-t $@
diff --git a/tools/libvirt-guests.init.in b/tools/libvirt-guests.init.in
new file mode 100644
index 0000000..5f9a60e
--- /dev/null
+++ b/tools/libvirt-guests.init.in
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# the following is the LSB init header
+#
+### BEGIN INIT INFO
+# Provides: libvirt-guests
+# Required-Start: libvirtd
+# Required-Stop: libvirtd
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# 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 99 01
+# description: This is a script for suspending active libvirt guests \
+# on shutdown and resuming them on next boot \
+# See
http://libvirt.org
+#
+
+exec @libexecdir(a)/libvirt-guests.sh "$@"
diff --git a/tools/libvirt-guests.init.sh b/tools/libvirt-guests.init.sh
deleted file mode 100644
index 99ef331..0000000
--- a/tools/libvirt-guests.init.sh
+++ /dev/null
@@ -1,597 +0,0 @@
-#!/bin/sh
-
-# the following is the LSB init header
-#
-### BEGIN INIT INFO
-# Provides: libvirt-guests
-# Required-Start: libvirtd
-# Required-Stop: libvirtd
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# 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 99 01
-# 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@"
-libvirtd="@sbindir@"/libvirtd
-
-# Source function library.
-test ! -r "$sysconfdir"/rc.d/init.d/functions ||
- . "$sysconfdir"/rc.d/init.d/functions
-
-# Source gettext library.
-# Make sure this file is recognized as having translations: _("dummy")
-. "@bindir(a)"/gettext.sh
-
-export TEXTDOMAIN="@PACKAGE@" TEXTDOMAINDIR="@localedir@"
-
-URIS=default
-ON_BOOT=start
-ON_SHUTDOWN=suspend
-SHUTDOWN_TIMEOUT=300
-PARALLEL_SHUTDOWN=0
-START_DELAY=0
-BYPASS_CACHE=0
-
-test -f "$sysconfdir"/sysconfig/libvirt-guests &&
- . "$sysconfdir"/sysconfig/libvirt-guests
-
-LISTFILE="$localstatedir"/lib/libvirt/libvirt-guests
-VAR_SUBSYS_LIBVIRT_GUESTS="$localstatedir"/lock/subsys/libvirt-guests
-
-RETVAL=0
-
-# retval COMMAND ARGUMENTS...
-# run command with arguments and convert non-zero return value to 1 and set
-# the global return variable
-retval() {
- "$@"
- if [ $? -ne 0 ]; then
- RETVAL=1
- return 1
- else
- return 0
- fi
-}
-
-# run_virsh URI ARGUMENTS...
-# start virsh and let it execute ARGUMENTS on URI
-# If URI is "default" virsh is called without the "-c" argument
-# (using libvirt's default connection)
-run_virsh() {
- uri=$1
- shift
-
- if [ "x$uri" = xdefault ]; then
- virsh "$@" </dev/null
- else
- virsh -c "$uri" "$@" </dev/null
- fi
-}
-
-# run_virsh_c URI ARGUMENTS
-# Same as "run_virsh" but the "C" locale is used instead of
-# the system's locale.
-run_virsh_c() {
- ( export LC_ALL=C; run_virsh "$@" )
-}
-
-# test_connect URI
-# check if URI is reachable
-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
-}
-
-# list_guests URI PERSISTENT
-# List running guests on URI.
-# PERSISTENT argument options:
-# --persistent: list only persistent guests
-# --transient: list only transient guests
-# [none]: list both persistent and transient guests
-list_guests() {
- uri=$1
- persistent=$2
-
- list=$(run_virsh_c "$uri" list --uuid $persistent)
- if [ $? -ne 0 ]; then
- RETVAL=1
- return 1
- fi
-
- echo $list
-}
-
-# guest_name URI UUID
-# return name of guest UUID on URI
-guest_name() {
- uri=$1
- uuid=$2
-
- run_virsh "$uri" domname "$uuid" 2>/dev/null
-}
-
-# guest_is_on URI UUID
-# check if guest UUID on URI is running
-# Result is returned by variable "guest_running"
-guest_is_on() {
- uri=$1
- uuid=$2
-
- guest_running=false
- id=$(run_virsh "$uri" domid "$uuid")
- if [ $? -ne 0 ]; then
- RETVAL=1
- return 1
- fi
-
- [ -n "$id" ] && [ "x$id" != x- ] &&
guest_running=true
- return 0
-}
-
-# started
-# Create the startup lock file
-started() {
- touch "$VAR_SUBSYS_LIBVIRT_GUESTS"
-}
-
-# start
-# Start or resume the guests
-start() {
- [ -f "$LISTFILE" ] || { started; return 0; }
-
- if [ "x$ON_BOOT" != xstart ]; then
- gettext "libvirt-guests is configured not to start any guests on
boot"
- echo
- rm -f "$LISTFILE"
- started
- return 0
- fi
-
- isfirst=true
- bypass=
- test "x$BYPASS_CACHE" = x0 || bypass=--bypass-cache
- while read uri list; do
- configured=false
- set -f
- for confuri in $URIS; do
- set +f
- if [ "x$confuri" = "x$uri" ]; then
- configured=true
- break
- fi
- done
- set +f
- if ! "$configured"; then
- eval_gettext "Ignoring guests on \$uri URI"; echo
- continue
- fi
-
- test_connect "$uri" || continue
-
- eval_gettext "Resuming guests on \$uri URI..."; echo
- for guest in $list; do
- name=$(guest_name "$uri" "$guest")
- eval_gettext "Resuming guest \$name: "
- if guest_is_on "$uri" "$guest"; then
- if "$guest_running"; then
- gettext "already active"; echo
- else
- if "$isfirst"; then
- isfirst=false
- else
- sleep $START_DELAY
- fi
- retval run_virsh "$uri" start $bypass "$name" \
- >/dev/null && \
- gettext "done"; echo
- fi
- fi
- done
- done <"$LISTFILE"
-
- rm -f "$LISTFILE"
- started
-}
-
-# suspend_guest URI GUEST
-# Do a managed save on a GUEST on URI. This function returns after the guest
-# was saved.
-suspend_guest()
-{
- uri=$1
- guest=$2
-
- name=$(guest_name "$uri" "$guest")
- label=$(eval_gettext "Suspending \$name: ")
- bypass=
- slept=0
- test "x$BYPASS_CACHE" = x0 || bypass=--bypass-cache
- printf '%s...\n' "$label"
- run_virsh "$uri" managedsave $bypass "$guest" >/dev/null
&
- virsh_pid=$!
- while true; do
- sleep 1
- kill -0 "$virsh_pid" >/dev/null 2>&1 || break
-
- slept=$(($slept + 1))
- if [ $(($slept % 5)) -eq 0 ]; then
- progress=$(run_virsh_c "$uri" domjobinfo "$guest"
2>/dev/null | \
- awk '/^Data processed:/{print $3, $4}')
- if [ -n "$progress" ]; then
- printf '%s%s\n' "$label" "$progress"
- else
- printf '%s%s\n' "$label" "..."
- fi
- fi
- done
- retval wait "$virsh_pid" && printf '%s%s\n'
"$label" "$(gettext "done")"
-}
-
-# shutdown_guest URI GUEST
-# Start a ACPI shutdown of GUEST on URI. This function return after the quest
-# was successfully shutdown or the timeout defined by $SHUTDOWN_TIMEOUT expires.
-shutdown_guest()
-{
- 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 ||
return
- timeout=$SHUTDOWN_TIMEOUT
- check_timeout=false
- if [ $timeout -gt 0 ]; then
- check_timeout=true
- format=$(eval_gettext "Waiting for guest %s to shut down, %d seconds
left\n")
- else
- slept=0
- format=$(eval_gettext "Waiting for guest %s to shut down\n")
- fi
- while ! $check_timeout || [ "$timeout" -gt 0 ]; do
- sleep 1
- guest_is_on "$uri" "$guest" || return
- "$guest_running" || break
-
- if $check_timeout; then
- if [ $(($timeout % 5)) -eq 0 ]; then
- printf "$format" "$name" "$timeout"
- fi
- timeout=$(($timeout - 1))
- else
- slept=$(($slept + 1))
- if [ $(($slept % 5)) -eq 0 ]; then
- printf "$format" "$name"
- fi
- fi
- done
-
- if guest_is_on "$uri" "$guest"; then
- if "$guest_running"; then
- eval_gettext "Shutdown of guest \$name failed to complete in
time."
- else
- eval_gettext "Shutdown of guest \$name complete."
- fi
- 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 $#
-}
-
-# check_guests_shutdown URI GUESTS
-# check if shutdown is complete on guests in "GUESTS" and returns only
-# guests that are still shutting down
-check_guests_shutdown()
-{
- uri=$1
- guests=$2
-
- guests_up=
- for guest in $guests; do
- if ! guest_is_on "$uri" "$guest" >/dev/null 2>&1;
then
- eval_gettext "Failed to determine state of guest: \$guest. Not tracking
it anymore."
- echo
- continue
- fi
- if "$guest_running"; then
- guests_up="$guests_up $guest"
- fi
- done
- echo "$guests_up"
-}
-
-# print_guests_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_guests_shutdown()
-{
- uri=$1
- before=$2
- after=$3
-
- for guest in $before; do
- case " $after " in
- *" $guest "*) continue;;
- esac
-
- name=$(guest_name "$uri" "$guest")
- eval_gettext "Shutdown of guest \$name complete."
- echo
- done
-}
-
-# shutdown_guests_parallel URI GUESTS
-# Shutdown guests GUESTS on machine URI in parallel
-shutdown_guests_parallel()
-{
- uri=$1
- guests=$2
-
- on_shutdown=
- check_timeout=false
- timeout=$SHUTDOWN_TIMEOUT
- if [ $timeout -gt 0 ]; then
- check_timeout=true
- format=$(eval_gettext "Waiting for %d guests to shut down, %d seconds
left\n")
- else
- slept=0
- format=$(eval_gettext "Waiting for %d guests to shut down\n")
- fi
- while [ -n "$on_shutdown" ] || [ -n "$guests" ]; do
- while [ -n "$guests" ] &&
- [ $(guest_count "$on_shutdown") -lt
"$PARALLEL_SHUTDOWN" ]; do
- set -- $guests
- guest=$1
- shift
- guests=$*
- shutdown_guest_async "$uri" "$guest"
- on_shutdown="$on_shutdown $guest"
- done
- sleep 1
-
- set -- $guests
- guestcount=$#
- set -- $on_shutdown
- shutdowncount=$#
-
- if $check_timeout; then
- if [ $(($timeout % 5)) -eq 0 ]; then
- printf "$format" $(($guestcount + $shutdowncount))
"$timeout"
- fi
- timeout=$(($timeout - 1))
- if [ $timeout -le 0 ]; then
- eval_gettext "Timeout expired while shutting down domains";
echo
- RETVAL=1
- return
- fi
- else
- slept=$(($slept + 1))
- if [ $(($slept % 5)) -eq 0 ]; then
- printf "$format" $(($guestcount + $shutdowncount))
- fi
- fi
-
- on_shutdown_prev=$on_shutdown
- on_shutdown=$(check_guests_shutdown "$uri" "$on_shutdown")
- print_guests_shutdown "$uri" "$on_shutdown_prev"
"$on_shutdown"
- done
-}
-
-# stop
-# Shutdown or save guests on the configured uris
-stop() {
- # last stop was not followed by start
- [ -f "$LISTFILE" ] && return 0
-
- suspending=true
- if [ "x$ON_SHUTDOWN" = xshutdown ]; then
- suspending=false
- if [ $SHUTDOWN_TIMEOUT -lt 0 ]; then
- gettext "SHUTDOWN_TIMEOUT must be equal or greater than 0"
- echo
- RETVAL=6
- return
- fi
- fi
-
- : >"$LISTFILE"
- set -f
- for uri in $URIS; do
- set +f
-
- test_connect "$uri" || continue
-
- eval_gettext "Running guests on \$uri URI: "
-
- list=$(list_guests "$uri")
- if [ $? -eq 0 ]; then
- empty=true
- for uuid in $list; do
- "$empty" || printf ", "
- printf %s "$(guest_name "$uri" "$uuid")"
- empty=false
- done
-
- if "$empty"; then
- gettext "no running guests."
- fi
- echo
- fi
-
- if "$suspending"; then
- transient=$(list_guests "$uri" "--transient")
- if [ $? -eq 0 ]; then
- empty=true
- for uuid in $transient; do
- if "$empty"; then
- eval_gettext "Not suspending transient guests on URI:
\$uri: "
- empty=false
- else
- printf ", "
- fi
- printf %s "$(guest_name "$uri"
"$uuid")"
- done
- echo
- # reload domain list to contain only persistent guests
- list=$(list_guests "$uri" "--persistent")
- if [ $? -ne 0 ]; then
- eval_gettext "Failed to list persistent guests on \$uri"
- echo
- RETVAL=1
- set +f
- return
- fi
- else
- gettext "Failed to list transient guests"
- echo
- RETVAL=1
- set +f
- return
- fi
- fi
-
- if [ -n "$list" ]; then
- echo "$uri" "$list" >>"$LISTFILE"
- fi
- done
- set +f
-
- if [ -s "$LISTFILE" ]; then
- while read uri list; do
- if "$suspending"; then
- eval_gettext "Suspending guests on \$uri URI..."; echo
- else
- eval_gettext "Shutting down guests on \$uri URI..."; echo
- fi
-
- 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"
- else
- rm -f "$LISTFILE"
- fi
-
- rm -f "$VAR_SUBSYS_LIBVIRT_GUESTS"
-}
-
-# gueststatus
-# List status of guests
-gueststatus() {
- set -f
- for uri in $URIS; do
- set +f
- echo "* $uri URI:"
- retval run_virsh "$uri" list || echo
- done
- set +f
-}
-
-# rh_status
-# Display current status: whether saved state exists, and whether start
-# has been executed. We cannot use status() from the functions library,
-# since there is no external daemon process matching this init script.
-rh_status() {
- if [ -f "$LISTFILE" ]; then
- gettext "stopped, with saved guests"; echo
- RETVAL=3
- else
- if [ -f "$VAR_SUBSYS_LIBVIRT_GUESTS" ]; then
- gettext "started"; echo
- else
- gettext "stopped, with no saved guests"; echo
- fi
- RETVAL=0
- fi
-}
-
-# usage [val]
-# Display usage string, then exit with VAL (defaults to 2).
-usage() {
- program_name=$0
- eval_gettext "Usage: \$program_name {start|stop|status|restart|"\
-"condrestart|try-restart|reload|force-reload|gueststatus|shutdown}"; echo
- exit ${1-2}
-}
-
-# See how we were called.
-if test $# != 1; then
- usage
-fi
-case "$1" in
- --help)
- usage 0
- ;;
- start|stop|gueststatus)
- "$1"
- ;;
- restart)
- stop && start
- ;;
- condrestart|try-restart)
- [ -f "$VAR_SUBSYS_LIBVIRT_GUESTS" ] && stop && start
- ;;
- reload|force-reload)
- # Nothing to do; we reread configuration on each invocation
- ;;
- status)
- rh_status
- ;;
- shutdown)
- ON_SHUTDOWN=shutdown
- stop
- ;;
- *)
- usage
- ;;
-esac
-exit $RETVAL
diff --git a/tools/libvirt-guests.service.in b/tools/libvirt-guests.service.in
index 0f0c41c..d41bf2b 100644
--- a/tools/libvirt-guests.service.in
+++ b/tools/libvirt-guests.service.in
@@ -6,8 +6,8 @@ After=syslog.target network.target
EnvironmentFile=-/etc/sysconfig/libvirt-guests
# Hack just call traditional service until we factor
# out the code
-ExecStart=/etc/init.d/libvirt-guests start
-ExecStop=/etc/init.d/libvirt-guests stop
+ExecStart=@libexecdir(a)/libvirt-guests.sh start
+ExecStop=@libexecdir(a)/libvirt-guests.sh stop
Type=oneshot
RemainAfterExit=yes
StandardOutput=journal+console
diff --git a/tools/libvirt-guests.sh.in b/tools/libvirt-guests.sh.in
new file mode 100644
index 0000000..1c9c46b
--- /dev/null
+++ b/tools/libvirt-guests.sh.in
@@ -0,0 +1,573 @@
+#!/bin/sh
+
+sysconfdir="@sysconfdir@"
+localstatedir="@localstatedir@"
+libvirtd="@sbindir@"/libvirtd
+
+# Source function library.
+test ! -r "$sysconfdir"/rc.d/init.d/functions ||
+ . "$sysconfdir"/rc.d/init.d/functions
+
+# Source gettext library.
+# Make sure this file is recognized as having translations: _("dummy")
+. "@bindir(a)"/gettext.sh
+
+export TEXTDOMAIN="@PACKAGE@" TEXTDOMAINDIR="@localedir@"
+
+URIS=default
+ON_BOOT=start
+ON_SHUTDOWN=suspend
+SHUTDOWN_TIMEOUT=300
+PARALLEL_SHUTDOWN=0
+START_DELAY=0
+BYPASS_CACHE=0
+
+test -f "$sysconfdir"/sysconfig/libvirt-guests &&
+ . "$sysconfdir"/sysconfig/libvirt-guests
+
+LISTFILE="$localstatedir"/lib/libvirt/libvirt-guests
+VAR_SUBSYS_LIBVIRT_GUESTS="$localstatedir"/lock/subsys/libvirt-guests
+
+RETVAL=0
+
+# retval COMMAND ARGUMENTS...
+# run command with arguments and convert non-zero return value to 1 and set
+# the global return variable
+retval() {
+ "$@"
+ if [ $? -ne 0 ]; then
+ RETVAL=1
+ return 1
+ else
+ return 0
+ fi
+}
+
+# run_virsh URI ARGUMENTS...
+# start virsh and let it execute ARGUMENTS on URI
+# If URI is "default" virsh is called without the "-c" argument
+# (using libvirt's default connection)
+run_virsh() {
+ uri=$1
+ shift
+
+ if [ "x$uri" = xdefault ]; then
+ virsh "$@" </dev/null
+ else
+ virsh -c "$uri" "$@" </dev/null
+ fi
+}
+
+# run_virsh_c URI ARGUMENTS
+# Same as "run_virsh" but the "C" locale is used instead of
+# the system's locale.
+run_virsh_c() {
+ ( export LC_ALL=C; run_virsh "$@" )
+}
+
+# test_connect URI
+# check if URI is reachable
+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
+}
+
+# list_guests URI PERSISTENT
+# List running guests on URI.
+# PERSISTENT argument options:
+# --persistent: list only persistent guests
+# --transient: list only transient guests
+# [none]: list both persistent and transient guests
+list_guests() {
+ uri=$1
+ persistent=$2
+
+ list=$(run_virsh_c "$uri" list --uuid $persistent)
+ if [ $? -ne 0 ]; then
+ RETVAL=1
+ return 1
+ fi
+
+ echo $list
+}
+
+# guest_name URI UUID
+# return name of guest UUID on URI
+guest_name() {
+ uri=$1
+ uuid=$2
+
+ run_virsh "$uri" domname "$uuid" 2>/dev/null
+}
+
+# guest_is_on URI UUID
+# check if guest UUID on URI is running
+# Result is returned by variable "guest_running"
+guest_is_on() {
+ uri=$1
+ uuid=$2
+
+ guest_running=false
+ id=$(run_virsh "$uri" domid "$uuid")
+ if [ $? -ne 0 ]; then
+ RETVAL=1
+ return 1
+ fi
+
+ [ -n "$id" ] && [ "x$id" != x- ] &&
guest_running=true
+ return 0
+}
+
+# started
+# Create the startup lock file
+started() {
+ touch "$VAR_SUBSYS_LIBVIRT_GUESTS"
+}
+
+# start
+# Start or resume the guests
+start() {
+ [ -f "$LISTFILE" ] || { started; return 0; }
+
+ if [ "x$ON_BOOT" != xstart ]; then
+ gettext "libvirt-guests is configured not to start any guests on
boot"
+ echo
+ rm -f "$LISTFILE"
+ started
+ return 0
+ fi
+
+ isfirst=true
+ bypass=
+ test "x$BYPASS_CACHE" = x0 || bypass=--bypass-cache
+ while read uri list; do
+ configured=false
+ set -f
+ for confuri in $URIS; do
+ set +f
+ if [ "x$confuri" = "x$uri" ]; then
+ configured=true
+ break
+ fi
+ done
+ set +f
+ if ! "$configured"; then
+ eval_gettext "Ignoring guests on \$uri URI"; echo
+ continue
+ fi
+
+ test_connect "$uri" || continue
+
+ eval_gettext "Resuming guests on \$uri URI..."; echo
+ for guest in $list; do
+ name=$(guest_name "$uri" "$guest")
+ eval_gettext "Resuming guest \$name: "
+ if guest_is_on "$uri" "$guest"; then
+ if "$guest_running"; then
+ gettext "already active"; echo
+ else
+ if "$isfirst"; then
+ isfirst=false
+ else
+ sleep $START_DELAY
+ fi
+ retval run_virsh "$uri" start $bypass "$name" \
+ >/dev/null && \
+ gettext "done"; echo
+ fi
+ fi
+ done
+ done <"$LISTFILE"
+
+ rm -f "$LISTFILE"
+ started
+}
+
+# suspend_guest URI GUEST
+# Do a managed save on a GUEST on URI. This function returns after the guest
+# was saved.
+suspend_guest()
+{
+ uri=$1
+ guest=$2
+
+ name=$(guest_name "$uri" "$guest")
+ label=$(eval_gettext "Suspending \$name: ")
+ bypass=
+ slept=0
+ test "x$BYPASS_CACHE" = x0 || bypass=--bypass-cache
+ printf '%s...\n' "$label"
+ run_virsh "$uri" managedsave $bypass "$guest" >/dev/null
&
+ virsh_pid=$!
+ while true; do
+ sleep 1
+ kill -0 "$virsh_pid" >/dev/null 2>&1 || break
+
+ slept=$(($slept + 1))
+ if [ $(($slept % 5)) -eq 0 ]; then
+ progress=$(run_virsh_c "$uri" domjobinfo "$guest"
2>/dev/null | \
+ awk '/^Data processed:/{print $3, $4}')
+ if [ -n "$progress" ]; then
+ printf '%s%s\n' "$label" "$progress"
+ else
+ printf '%s%s\n' "$label" "..."
+ fi
+ fi
+ done
+ retval wait "$virsh_pid" && printf '%s%s\n'
"$label" "$(gettext "done")"
+}
+
+# shutdown_guest URI GUEST
+# Start a ACPI shutdown of GUEST on URI. This function return after the quest
+# was successfully shutdown or the timeout defined by $SHUTDOWN_TIMEOUT expires.
+shutdown_guest()
+{
+ 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 ||
return
+ timeout=$SHUTDOWN_TIMEOUT
+ check_timeout=false
+ if [ $timeout -gt 0 ]; then
+ check_timeout=true
+ format=$(eval_gettext "Waiting for guest %s to shut down, %d seconds
left\n")
+ else
+ slept=0
+ format=$(eval_gettext "Waiting for guest %s to shut down\n")
+ fi
+ while ! $check_timeout || [ "$timeout" -gt 0 ]; do
+ sleep 1
+ guest_is_on "$uri" "$guest" || return
+ "$guest_running" || break
+
+ if $check_timeout; then
+ if [ $(($timeout % 5)) -eq 0 ]; then
+ printf "$format" "$name" "$timeout"
+ fi
+ timeout=$(($timeout - 1))
+ else
+ slept=$(($slept + 1))
+ if [ $(($slept % 5)) -eq 0 ]; then
+ printf "$format" "$name"
+ fi
+ fi
+ done
+
+ if guest_is_on "$uri" "$guest"; then
+ if "$guest_running"; then
+ eval_gettext "Shutdown of guest \$name failed to complete in
time."
+ else
+ eval_gettext "Shutdown of guest \$name complete."
+ fi
+ 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 $#
+}
+
+# check_guests_shutdown URI GUESTS
+# check if shutdown is complete on guests in "GUESTS" and returns only
+# guests that are still shutting down
+check_guests_shutdown()
+{
+ uri=$1
+ guests=$2
+
+ guests_up=
+ for guest in $guests; do
+ if ! guest_is_on "$uri" "$guest" >/dev/null 2>&1;
then
+ eval_gettext "Failed to determine state of guest: \$guest. Not tracking
it anymore."
+ echo
+ continue
+ fi
+ if "$guest_running"; then
+ guests_up="$guests_up $guest"
+ fi
+ done
+ echo "$guests_up"
+}
+
+# print_guests_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_guests_shutdown()
+{
+ uri=$1
+ before=$2
+ after=$3
+
+ for guest in $before; do
+ case " $after " in
+ *" $guest "*) continue;;
+ esac
+
+ name=$(guest_name "$uri" "$guest")
+ eval_gettext "Shutdown of guest \$name complete."
+ echo
+ done
+}
+
+# shutdown_guests_parallel URI GUESTS
+# Shutdown guests GUESTS on machine URI in parallel
+shutdown_guests_parallel()
+{
+ uri=$1
+ guests=$2
+
+ on_shutdown=
+ check_timeout=false
+ timeout=$SHUTDOWN_TIMEOUT
+ if [ $timeout -gt 0 ]; then
+ check_timeout=true
+ format=$(eval_gettext "Waiting for %d guests to shut down, %d seconds
left\n")
+ else
+ slept=0
+ format=$(eval_gettext "Waiting for %d guests to shut down\n")
+ fi
+ while [ -n "$on_shutdown" ] || [ -n "$guests" ]; do
+ while [ -n "$guests" ] &&
+ [ $(guest_count "$on_shutdown") -lt
"$PARALLEL_SHUTDOWN" ]; do
+ set -- $guests
+ guest=$1
+ shift
+ guests=$*
+ shutdown_guest_async "$uri" "$guest"
+ on_shutdown="$on_shutdown $guest"
+ done
+ sleep 1
+
+ set -- $guests
+ guestcount=$#
+ set -- $on_shutdown
+ shutdowncount=$#
+
+ if $check_timeout; then
+ if [ $(($timeout % 5)) -eq 0 ]; then
+ printf "$format" $(($guestcount + $shutdowncount))
"$timeout"
+ fi
+ timeout=$(($timeout - 1))
+ if [ $timeout -le 0 ]; then
+ eval_gettext "Timeout expired while shutting down domains";
echo
+ RETVAL=1
+ return
+ fi
+ else
+ slept=$(($slept + 1))
+ if [ $(($slept % 5)) -eq 0 ]; then
+ printf "$format" $(($guestcount + $shutdowncount))
+ fi
+ fi
+
+ on_shutdown_prev=$on_shutdown
+ on_shutdown=$(check_guests_shutdown "$uri" "$on_shutdown")
+ print_guests_shutdown "$uri" "$on_shutdown_prev"
"$on_shutdown"
+ done
+}
+
+# stop
+# Shutdown or save guests on the configured uris
+stop() {
+ # last stop was not followed by start
+ [ -f "$LISTFILE" ] && return 0
+
+ suspending=true
+ if [ "x$ON_SHUTDOWN" = xshutdown ]; then
+ suspending=false
+ if [ $SHUTDOWN_TIMEOUT -lt 0 ]; then
+ gettext "SHUTDOWN_TIMEOUT must be equal or greater than 0"
+ echo
+ RETVAL=6
+ return
+ fi
+ fi
+
+ : >"$LISTFILE"
+ set -f
+ for uri in $URIS; do
+ set +f
+
+ test_connect "$uri" || continue
+
+ eval_gettext "Running guests on \$uri URI: "
+
+ list=$(list_guests "$uri")
+ if [ $? -eq 0 ]; then
+ empty=true
+ for uuid in $list; do
+ "$empty" || printf ", "
+ printf %s "$(guest_name "$uri" "$uuid")"
+ empty=false
+ done
+
+ if "$empty"; then
+ gettext "no running guests."
+ fi
+ echo
+ fi
+
+ if "$suspending"; then
+ transient=$(list_guests "$uri" "--transient")
+ if [ $? -eq 0 ]; then
+ empty=true
+ for uuid in $transient; do
+ if "$empty"; then
+ eval_gettext "Not suspending transient guests on URI:
\$uri: "
+ empty=false
+ else
+ printf ", "
+ fi
+ printf %s "$(guest_name "$uri"
"$uuid")"
+ done
+ echo
+ # reload domain list to contain only persistent guests
+ list=$(list_guests "$uri" "--persistent")
+ if [ $? -ne 0 ]; then
+ eval_gettext "Failed to list persistent guests on \$uri"
+ echo
+ RETVAL=1
+ set +f
+ return
+ fi
+ else
+ gettext "Failed to list transient guests"
+ echo
+ RETVAL=1
+ set +f
+ return
+ fi
+ fi
+
+ if [ -n "$list" ]; then
+ echo "$uri" "$list" >>"$LISTFILE"
+ fi
+ done
+ set +f
+
+ if [ -s "$LISTFILE" ]; then
+ while read uri list; do
+ if "$suspending"; then
+ eval_gettext "Suspending guests on \$uri URI..."; echo
+ else
+ eval_gettext "Shutting down guests on \$uri URI..."; echo
+ fi
+
+ 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"
+ else
+ rm -f "$LISTFILE"
+ fi
+
+ rm -f "$VAR_SUBSYS_LIBVIRT_GUESTS"
+}
+
+# gueststatus
+# List status of guests
+gueststatus() {
+ set -f
+ for uri in $URIS; do
+ set +f
+ echo "* $uri URI:"
+ retval run_virsh "$uri" list || echo
+ done
+ set +f
+}
+
+# rh_status
+# Display current status: whether saved state exists, and whether start
+# has been executed. We cannot use status() from the functions library,
+# since there is no external daemon process matching this init script.
+rh_status() {
+ if [ -f "$LISTFILE" ]; then
+ gettext "stopped, with saved guests"; echo
+ RETVAL=3
+ else
+ if [ -f "$VAR_SUBSYS_LIBVIRT_GUESTS" ]; then
+ gettext "started"; echo
+ else
+ gettext "stopped, with no saved guests"; echo
+ fi
+ RETVAL=0
+ fi
+}
+
+# usage [val]
+# Display usage string, then exit with VAL (defaults to 2).
+usage() {
+ program_name=$0
+ eval_gettext "Usage: \$program_name {start|stop|status|restart|"\
+"condrestart|try-restart|reload|force-reload|gueststatus|shutdown}"; echo
+ exit ${1-2}
+}
+
+# See how we were called.
+if test $# != 1; then
+ usage
+fi
+case "$1" in
+ --help)
+ usage 0
+ ;;
+ start|stop|gueststatus)
+ "$1"
+ ;;
+ restart)
+ stop && start
+ ;;
+ condrestart|try-restart)
+ [ -f "$VAR_SUBSYS_LIBVIRT_GUESTS" ] && stop && start
+ ;;
+ reload|force-reload)
+ # Nothing to do; we reread configuration on each invocation
+ ;;
+ status)
+ rh_status
+ ;;
+ shutdown)
+ ON_SHUTDOWN=shutdown
+ stop
+ ;;
+ *)
+ usage
+ ;;
+esac
+exit $RETVAL