On 10/21/2012 04:45 PM, Cole Robinson wrote: > 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@/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@"/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@/libvirt-guests.sh start > +ExecStop=@libexecdir@/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@"/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 > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list