How to I gracefully shutdown my kvm virtual machines when shutting down the host?

7,591

Solution 1

Strange way for controlling VM. Good way -- use systemd for automatic start and stop VM. For example:

/etc/systemd/system/[email protected]

[Unit]
Description=QEMU virtual machine

[Service]
Environment="type=system-x86_64" "haltcmd=kill -INT $MAINPID"
EnvironmentFile=/etc/conf.d/qemu.d/%i
ExecStart=/usr/bin/qemu-${type} -name %i -nographic $args
ExecStop=/bin/sh -c ${haltcmd}
TimeoutStopSec=30
KillMode=none

[Install]
WantedBy=multi-user.target

... And, of course config(s) for run VM's:

/etc/conf.d/qemu.d/one

type="system-x86_64"

args="-enable-kvm -m 512 -hda /dev/vg0/vm1 -net nic,macaddr=DE:AD:BE:EF:E0:00 \
 -net tap,ifname=tap0 -serial telnet:localhost:7000,server,nowait,nodelay \
 -monitor telnet:localhost:7100,server,nowait,nodelay -vnc :0"

haltcmd="echo 'system_powerdown' | nc localhost 7100" # or netcat/ncat

# You can use other ways to shut down your VM correctly
#haltcmd="ssh powermanager@vm1 sudo poweroff"

...and another VM config:

/etc/conf.d/qemu.d/two

args="-enable-kvm -m 512 -hda /srv/kvm/vm2.img -net nic,macaddr=DE:AD:BE:EF:E0:01 \
 -net tap,ifname=tap1 -serial telnet:localhost:7001,server,nowait,nodelay \
 -monitor telnet:localhost:7101,server,nowait,nodelay -vnc :1"

haltcmd="echo 'system_powerdown' | nc localhost 7101"

Et cetera. Thanks ArchWiki contributors for this article.

Solution 2

The draft by the original post and @Oxyd's answer are useful when you need to control each Virtual Machines individually.

However if it's desired to shutdown/start all the VMs one could use the libvirt guests as mentioned on Libvirt docs.

  • Edit the file /etc/conf.d/libvirt-guests, or /etc/sysconfig/libvirt-guests for CentOS, then set ON_SHUTDOWN=shutdown and SHUTDOWN_TIMEOUT=0
  • I think one also needs to activate the libvirt-guests service, for example systemctl enable libvirt-guests and systemctl start libvirt-guests
Share:
7,591

Related videos on Youtube

Domenico Onorato Datteri
Author by

Domenico Onorato Datteri

Updated on September 18, 2022

Comments

  • Domenico Onorato Datteri
    Domenico Onorato Datteri over 1 year

    Bringing this question straight from here.

    I am running archlinux and I have a VM running often on it along with the system. Most of the time actually.

    My goal is to produce the following behaviour:

    • A shutdown / poweroff / reboot / halt signal is sent to the system
    • No action other then trying to shut down the virtual machines gracefully
    • If the VMs are shut down gracefully after X seconds, proceeds with shutting down the host system too.
    • If not, execute a different command

    Just give me a good idea on what to work on, because I don't even know from where to begin. I guess there is a call to the kernel that can be looked at.

    Let me know.


    My current code

    At the moment I am using these scripts to gracefully shutdown my kvm virtual machines, and it works! But only as long as my user launches a shutdown or a reboot using his shell. Any other case wouldn't work.

    These alias:

    alias sudocheck="/bin/bash /home/damiano/.script/sudocheck"
    alias sudo="sudocheck "
    

    Are triggering this function:

    #!/bin/bash
    
    # This script checks for what is being passed to sudo.
    # If the command passed is poweroff or reboot, it
    # launches a custom script instead, that also looks
    # fur currently running virtual machines and shuts them.
    
    sudocheck() {
        if [ $1 == "poweroff" ] || [ $1 == "reboot" ]; then
            eval "sudo /home/damiano/.script/graceful $@"
        else
            eval "sudo $@"
        fi
    }
    sudocheck $@
    

    That launches this script if needed:

    #!/bin/bash
    i=0
    e=0
    ## if virsh finds VMs running
    virsh -c qemu:///system list | awk '{ print $3}' | \
    if grep running > /dev/null ; then
        virsh -c qemu:///system list --all | grep running | awk '{print "-c qemu:///system shutdown "$2}' | \
    ## shuts them dow gracefully
        xargs -L1 virsh
    ## wait 30 seconds for them to go down
        until (( i >= 30 || e == 1 )) ; do
    ## check every second for their status
            virsh -c qemu:///system list --all | awk '{ print $3}' | \
            if grep -E '(running|shutdown)' > /dev/null ; then
    ## keep waiting if still running
                if (( i <= 30 )) ; then
                    sleep 1 && let i++ && echo $i
                else
                    e=1 && notify-send 'Shutdown has been canceled' 'Please check the status of your virtual machines: seems like even though a stop signal has been sent, some are still running.' --urgency=critical
                fi
            else
    ## if no machine is running anymore, original power command can be executed
                e=1 && eval $@
            fi
        done
    fi
    

    Systemd Unit

    I also made the following draft, to manage the execution of my VM:

    [email protected]

    [Unit]
    Description=This service manages the execution of the %i virtual machine
    Documentation=https://libvirt.org/manpages/virsh.html
    
    [Service]
    ExecStartPre=virsh -c qemu:///system
    ExecStart=virsh start %i
    ExecStop=virsh -c qemu:///system
    ExecStop=virsh shutdown %i 
    TimeoutStopSec=30
    KillMode=none
    
    [Install]
    WantedBy=multi-user.target
    

    But how can I tell the system to don't shut down the desktop environment, to stay as it is UNTIL the VM has been successfully shut down? Because if the system can't shut down the vm, I want to do it while still in my DE. I don't want the computer to begin stopping all the services and remain hung until it just forces the shut down.

    • ajgringo619
      ajgringo619 about 4 years
      Does running virsh shutdown domainname from the host do what you need?
    • Domenico Onorato Datteri
      Domenico Onorato Datteri about 4 years
      No, it just shuts down my virtual machine. I want to script a graceful shutdown for the entire system. So that all the vm's get shut down along with the host.
    • MUY Belgium
      MUY Belgium over 3 years
      May be using the full path of virsh is more secure.
  • Stefan Skoglund
    Stefan Skoglund about 4 years
    The virtual machine ? do you use something cfengine, puppet or chef to manage it ? Could you have something in policy which if something is true for the host propagates a shutdown action to the virtual machines ? In the case of cfengine : the hub can initiate a policy check with special variables set -> special variable set ? create a marker file and at end of policy shutdown the VM.
  • Domenico Onorato Datteri
    Domenico Onorato Datteri about 4 years
    Hello Stefan, thanks for your comment. No I just use virt-manager and virsh