[libvirt] libvirt-guests - migrate/relocate on stop feature request

Hello I'm using KVM in a clustered environment. When a host server shuts down or reboots the VM's should migrate to another cluster node. Currently I'm using a custom script for a two node cluster. It would be very nice if this feature could be incorporated into the libvirt-guests script. Or if a host could be specified as a relocation host. Is there any chance for this feature to be added to the script? Sincerely, Maurits van de Lande

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

Hi,
I'm using KVM in a clustered environment. When a host server shuts down or reboots the VM's should migrate to another cluster node. Currently I'm using a custom script for a two node cluster. It would be very nice if this feature could be incorporated into the libvirt-guests script. Or if a host could be specified as a relocation host.
In general, this should better be managed by a higher-level management application that manages the whole cluster and migrate VMs to different hosts when their original host is about to shutdown. But I agree that for simple cases (such as yours two node cluster) this would be a pretty heavy weight solution. Thus I think having this feature in libvirt-guests makes sense.
Is there any chance for this feature to be added to the script?
I guess there is, especially after you sent the modified script :-) However, could you send your modifications as a patch? Ideally using git but if that's too much for you, even the output of diff -u unmodified-libvirt-guests modified-libvirt-guests would work much better than just the modified script. Jirka

Hello, <could you send your modifications as a patch? Ideally using git but if that's too much for you, even the output of < < diff -u unmodified-libvirt-guests modified-libvirt-guests < <would work much better than just the modified script. Oké, I haven't worked with git yet. Here is the diff output: --- libvirt-guests 2011-11-04 12:11:58.326115749 +0100 +++ libvirt-guests-modified 2011-11-04 12:17:55.032105427 +0100 @@ -9,8 +9,8 @@ # 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 +# 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 @@ -19,8 +19,9 @@ # 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 \ +# description: This is a script for suspending or relocation active \ +# libvirt guests on shutdown and resuming the suspended \ +# guests on next boot \ # See http://libvirt.org # @@ -35,7 +36,9 @@ URIS=default ON_BOOT=start ON_SHUTDOWN=suspend +#ON_SHUTDOWN=migrate SHUTDOWN_TIMEOUT=0 +RELOCATION_HOST=RelocationHostname.domain.local test -f "$sysconfdir"/sysconfig/libvirt-guests && . "$sysconfdir"/sysconfig/libvirt-guests @@ -208,14 +211,18 @@ $guest_running || break printf '\r%s%-12d ' "$label" $timeout done +} - if guest_is_on $uri $guest; then - if $guest_running; then - printf '\r%s%-12s\n' "$label" $"failed to shutdown in time" - else - printf '\r%s%-12s\n' "$label" $"done" - fi - fi +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 } stop() { @@ -223,14 +230,19 @@ [ -f "$LISTFILE" ] && return 0 suspending=true - 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 + 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 : >"$LISTFILE" for uri in $URIS; do @@ -262,16 +274,28 @@ if $suspending; then echo $"Suspending guests on $uri URI..." else - echo $"Shutting down guests on $uri URI..." + 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 - shutdown_guest $uri $guest + 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 migrating all VM's + rm -f $LISTFILE + fi done <"$LISTFILE" rm -f "$VAR_SUBSYS_LIBVIRT_GUESTS"
participants (2)
-
Jiri Denemark
-
Maurits van de Lande