1

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:

bootvm@.service

[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.

3
  • Does running virsh shutdown domainname from the host do what you need? – ajgringo619 Mar 14 '20 at 2:29
  • 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. – Domenico Onorato Datteri Mar 14 '20 at 4:10
  • May be using the full path of virsh is more secure. – MUY Belgium Oct 22 '20 at 9:47
2

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

/etc/systemd/system/qemu@.service

[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.

3
  • This is useful only to get the machine shut down, if they can be shut down in - say - 30 seconds. But the systemd unit you posted will try to shut down the machine while the rest of the system is being shut down, and, after 30 seconds it will shut it down forcefully which is not what I want. I want that when a shutdown signal gets launched everything stays as it is, the VMs are shut down and: if successful then the system proceeds to shut down the rest of the system as usual, else -> another command. – Domenico Onorato Datteri Mar 15 '20 at 3:25
  • 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. – Stefan Skoglund Mar 15 '20 at 13:44
  • Hello Stefan, thanks for your comment. No I just use virt-manager and virsh – Domenico Onorato Datteri Mar 16 '20 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.