I have added my modified libvirt-guests script.
The changes I have made are:
1) Added ON_SHUTDOWN=migrate option
2) Added a RELOCATION_HOST variable
3) Added a migrate_guest() function
4) Modified the on stop function to add the migrate option
I hope the changes will be added to future libvirt releases.
Best regards,
Maurits van de Lande
#######################################################################
#!/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 or migrating active libvirt guests
# on shutdown and resuming the suspended guest 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=/etc
localstatedir=/var
libvirtd=/usr/sbin/libvirtd
# Source function library.
test ! -r "$sysconfdir"/rc.d/init.d/functions ||
. "$sysconfdir"/rc.d/init.d/functions
URIS=default
ON_BOOT=start
ON_SHUTDOWN=suspend
#ON_SHUTDOWN=migrate
SHUTDOWN_TIMEOUT=0
RELOCATION_HOST=relocation_server_name.domain.local
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() {
"$@"
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 "$@" </dev/null
}
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
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
RETVAL=1
return 1
fi
uuids="$uuids $uuid"
done
echo $uuids
}
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
guest_running=false
info=$(run_virsh_c $uri dominfo $uuid)
if [ $? -ne 0 ]; then
RETVAL=1
return 1
fi
id=$(echo "$info" | awk '/^Id:/{print $2}')
[ -n "$id" ] && [ "x$id" != x- ] &&
guest_running=true
return 0
}
started() {
touch "$VAR_SUBSYS_LIBVIRT_GUESTS"
}
start() {
[ -f "$LISTFILE" ] || { started; return 0; }
if [ "x$ON_BOOT" != xstart ]; then
echo $"libvirt-guests is configured not to start any guests on boot"
rm -f "$LISTFILE"
started
return 0
fi
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 guest_is_on $uri $guest; then
if $guest_running; then
echo $"already active"
else
retval run_virsh $uri start "$name" >/dev/null &&
\
echo $"done"
fi
fi
done
done <"$LISTFILE"
rm -f "$LISTFILE"
started
}
suspend_guest()
{
uri=$1
guest=$2
name=$(guest_name $uri $guest)
label=$"Suspending $name: "
echo -n "$label"
run_virsh $uri managedsave $guest >/dev/null &
virsh_pid=$!
while true; do
sleep 1
kill -0 $virsh_pid >/dev/null 2>&1 || 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"
}
shutdown_guest()
{
uri=$1
guest=$2
name=$(guest_name $uri $guest)
label=$"Shutting down $name: "
echo -n "$label"
retval run_virsh $uri shutdown $guest >/dev/null || return
timeout=$SHUTDOWN_TIMEOUT
while [ $timeout -gt 0 ]; do
sleep 1
timeout=$[timeout - 1]
guest_is_on $uri $guest || return
$guest_running || break
printf '\r%s%-12d ' "$label" $timeout
done
}
migrate_guest()
{
uri=$1
guest=$2
name=$(guest_name $uri $guest)
label=$"Migrating $name: to $RELOCATION_HOST"
echo -n "$label"
echo
retval run_virsh $uri migrate --live --verbose $guest
"qemu+ssh://$RELOCATION_HOST/system" || return
# if guest_is_on $uri $guest; then
# if $guest_running; then
# printf '\r%s%-12s\n' "$label" $"failed to
migrate"
# else
# printf '\r%s%-12s\n' "$label" $"done"
# fi
# fi
}
stop() {
# last stop was not followed by start
[ -f "$LISTFILE" ] && return 0
suspending=true
case "x$ON_SHUTDOWN" in
xshutdown )
suspending=false
if [ $SHUTDOWN_TIMEOUT -le 0 ]; then
echo $"Shutdown action requested but SHUTDOWN_TIMEOUT was not
set"
RETVAL=6
return
fi
;;
xmigrate )
suspending=false
;;
esac
# if [ "x$ON_SHUTDOWN" = xshutdown ]; then
# suspending=false
# if [ $SHUTDOWN_TIMEOUT -le 0 ]; then
# echo $"Shutdown action requested but SHUTDOWN_TIMEOUT was not set"
# RETVAL=6
# return
# fi
# fi
: >"$LISTFILE"
for uri in $URIS; do
echo -n $"Running guests on $uri URI: "
if [ "x$uri" = xdefault ] && [ ! -x "$libvirtd" ];
then
echo $"libvirtd not installed; skipping this URI."
continue
fi
list=$(list_guests $uri)
if [ $? -eq 0 ]; then
empty=true
for uuid in $list; do
$empty || printf ", "
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
if $suspending; then
echo $"Suspending guests on $uri URI..."
else
if [ "x$ON_SHUTDOWN" = xshutdown ]; then
echo $"Shutting down guests on $uri URI..."
else
echo $"Migrating guests on $uri URI... to $RELOCATION_HOST"
fi
fi
for guest in $list; do
if $suspending; then
suspend_guest $uri $guest
else
if [ "x$ON_SHUTDOWN" = xshutdown ]; then
shutdown_guest $uri $guest
else
migrate_guest $uri $guest
fi
fi
done
if [ "x$ON_SHUTDOWN" = xmigrate ]; then
#delete listfile after migration all VM's
rm -f $LISTFILE
fi
done <"$LISTFILE"
rm -f "$VAR_SUBSYS_LIBVIRT_GUESTS"
}
gueststatus() {
for uri in $URIS; do
echo "* $uri URI:"
retval run_virsh $uri list || echo
done
}
# 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
echo $"stopped, with saved guests"
RETVAL=3
else
if [ -f "$VAR_SUBSYS_LIBVIRT_GUESTS" ]; then
echo $"started"
else
echo $"stopped, with no saved guests"
fi
RETVAL=0
fi
}
# usage [val]
# Display usage string, then exit with VAL (defaults to 2).
usage() {
echo $"Usage: $0
{start|stop|status|restart|condrestart|try-restart|reload|force-reload|gueststatus|shutdown}"
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