Hi, I tuned my script to be more intelligent. It now detects save/restore conflict with Xen. Domain state file name is configurable. More robust save and restore. Option to start QEMU/KVM virtual machines if no restore file for the domain can be located, thus emulating libvirt autostart feature, which must be switched off at libvirt level.
-- Tuomas Jormola <t...@solitudo.net>
#!/bin/sh # # This script automatically saves running VMs # managed by libvirtd on stop and restores VMs on start # # (C) 2008 Tuomas Jormola <t...@solitudo.net> # ### BEGIN INIT INFO # Required-Start: $network $local_fs # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: save and restore libvirtd managed VMs ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin domain_state_file_name_pattern=%n enabled=false . /lib/lsb/init-functions if test -f /etc/default/libvirt-domain-state; then . /etc/default/libvirt-domain-state fi test "$enabled" = "true" || exit 0 xen_enabled=0 if test -f /etc/default/xendomains; then . /etc/default/xendomains if test -n "$XENDOMAINS_MIGRATE" || test "$XENDOMAINS_SAVE" = "true"; then xen_enabled=1 fi fi if test $xen_enabled -eq 1; then log_warning_msg "Automatic domain state save and restore implemented by Xen" exit 1 fi if test -z "$domain_state_file_directory"; then log_failure_msg "Domain save directory not defined" exit 1 fi if ! test -d "$domain_state_file_directory"; then log_failure_msg "Domain save directory not found: $domain_state_file_directory" exit 1 fi if test -z "$domain_state_file_name_pattern"; then log_failure_msg "Domain state file name pattern not defined" exit 1 fi if echo $domain_state_file_name_pattern | grep -q '/'; then log_failure_msg "Domain state file name pattern must not contain slashes" exit 1 fi if ! echo $domain_state_file_name_pattern | grep -q '%n'; then log_failure_msg "Domain state file name pattern must contain %n" exit 1 fi if test -z "$libvirt_hypervisor_uri"; then log_failure_msg "libvirt hypervisor connection URI not defined" exit 1 fi if test "$libvirt_hypervisor_uri" != "`virsh -q -c $libvirt_hypervisor_uri uri 2>/dev/null`"; then log_failure_msg "Failed to connect to libvirt hypervisor $libvirt_hypervisor_uri" exit 1 fi run_virsh() { virsh -q -c $libvirt_hypervisor_uri $* } # Print full path to domain state file for the domain. expand_domain_state_file() { test -n "$domain_name" || return domain_state_file_name=`echo $domain_state_file_name_pattern | sed "s/%n/$domain_name/g" 2>/dev/null` test -n "$domain_state_file_name" || return echo $domain_state_file_directory/$domain_state_file_name } check_domain_autostart() { virsh_output=`run_virsh dominfo $1 2>/dev/null` ret=$? if test $ret != 0; then return 2 fi echo $virsh_output | grep -q 'Autostart: disable' 2>/dev/null } # Restore a domain from state file if the domain is shut down # or start QEMU/KVM domain if enabled. restore_domain() { case "$domain_status" in "shut off") domain_state_file=`expand_domain_state_file` if test -f $domain_state_file; then if run_virsh restore $domain_state_file >/dev/null 2>&1; then if test "$delete_restored_domain_state_files" = "true"; then rm -f $domain_state_file fi log_action_msg "$domain_name restored" else log_failure_msg "Failed to restore $domain_name from $domain_state_file" fi elif test "$start_qemu_domains_without_state_file" = "true" && test -f /etc/libvirt/qemu/$domain_name.xml; then if run_virsh start $domain_name >/dev/null 2>&1; then log_action_msg "$domain_name started (QEMU/KVM domain with no restore file)" else log_failure_msg "Failed to start QEMU/KVM domain $domain_name" fi else log_warning_msg "Restore file not found for $domain_name" fi ;; "running") log_warning_msg "$domain_name already running"; return ;; *) log_warning_msg "Unknown status for domain $domain_name: $domain_status"; return ;; esac } # Save a domain to state file if domain is running and if libvirt # is not starting the domain save_domain() { if test "$domain_status" != "running"; then log_warning_msg "$domain_name is not running" return fi check_domain_autostart $domain_name ret=$? case "$ret" in 0) true ;; 1) log_warning_msg "libvirtd autostart enabled for $domain_name"; return ;; 2) log_failure_msg "Failed to get autostart status for $domain_name"; return ;; *) log_failure_msg "Unknown return code when checking autostart status for $domain_name"; return ;; esac domain_state_file=`expand_domain_state_file` if run_virsh save $domain_id $domain_state_file >/dev/null 2>&1; then log_action_msg "$domain_name saved" else log_failure_msg "Failed to save $domain_name as $domain_state_file" fi } print_domain_status() { log_action_msg "$domain_name: $domain_status" } # Generate list of all domains on the hypervisor and launch # the callback function for each domain. iterate_domains() { callback=$1 run_virsh list --all 2>/dev/null | grep -v ^Connecting | \ while read domain_id domain_name domain_status; do eval "$callback" done } case "$1" in start) log_action_begin_msg "Restoring virtual machines" iterate_domains restore_domain log_action_end_msg 0 ;; stop) log_action_begin_msg "Saving virtual machines" iterate_domains save_domain log_action_end_msg 0 ;; status) log_action_begin_msg "Checking status of virtual machines" iterate_domains print_domain_status log_action_end_msg 0 ;; *) N=/etc/init.d/libvirt-domain-state echo "Usage: $N {start|stop|status}" >&2 exit 1 ;; esac exit 0
# Provide support for storing virtual machine state on hypervisor host shutdown # and restore on hypervisor host start-up. In order to support this, please # note that you must configure each virtual machine so that the libvirt # autostart feature is disabled. Also if you're using Xen, the built-in # save/restore mechanism must be disabled. # Directory where to save virtual machine state files. This directory # needs to be created manually. Be sure that there's enough free disk # space available! You will need at least the combied amount of physical # memory and swap space allocated to all virtual machines plus some room # for overhead. For instance, if you are running two virtual machines # each configured to use 1GB of memory and 2GB of swap, you should # reserve more than 6GB of space in the file system holding this # directory. This setting is required. #domain_state_file_directory=/var/lib/libvirt/domain-state-files # File name pattern for state files where the virtual machine's state is saved. # The pattern must contain string "%n" which is replaced with the name of each # virtual machine. Default file name consists of just the virtual machine name, # i.e. the pattern is "%n". #domain_state_file_name_pattern=%n.state # libvirt URI of the hypervisor. # See http://libvirt.org/remote.html#Remote_URI_reference # This setting is required. #libvirt_hypervisor_uri=qemu:///system # Uncommenting this setting will destroy each virtual machine state file # after successful restore. Disabled by default, i.e. restore is performed # but state files are left intact. #delete_restored_domain_state_files=true # If this setting is enabled, during the hypervisor host machine start-up the # script will start each QEMU/KVM virtual machine that is found on the system # for which no state file can be found. Effectively this emulates the libvirt # auto-start feature, but in more smart manner. If state file is found, the # virtual machine will be restored, and if not, new instance of the virtual # machine is started. The net effect is that all QEMU/KVM machines will # automatically be running when the hypervisor has finished booting. #start_qemu_domains_without_state_file=true # Uncomment this to actually enable automatic saving and restoring # of the virtual machines. #enabled=true