How to start a VM on boot, and shutdown on VM stop?

Solution 1:

You could set up an Init.d/Systemd script like this one:

#! /bin/sh
# /etc/init.d/vbox

#Edit these variables! VMUSER=VMAdmin VMNAME="cdb62186-7c30-4c25-a0b0-e4a32cfb0504" BASEFOLDER=/home/VMAdmin/path/to/backups/

case "$1" in
    start)
        echo "Starting VirtualBox VM..."
        sudo -H -u $VMUSER VBoxManage startvm "$VMNAME" --type headless
        ;;
    reset)
        echo "Resetting VirtualBox VM..."
        sudo -H -u $VMUSER VBoxManage controlvm "$VMNAME" reset
        ;;
    stop)
        echo "Saving state of Virtualbox VM..."
        sudo -H -u $VMUSER VBoxManage controlvm "$VMNAME" savestate
        ;;
    shutdown)
        echo "Shutting down Virtualbox VM..."
        sudo -H -u $VMUSER VBoxManage controlvm "$VMNAME" acpipowerbutton
        ;;
    status)
        sudo -H -u $VMUSER VBoxManage list vms -l | grep -e ^"$VMNAME": -e ^State | sed s/\ \ //g | cut -d: -f2-
        ;;
    backup)
        echo ""
        sudo -H -u $VMUSER VBoxManage controlvm "$VMNAME" acpipowerbutton

        echo "Waiting for VM "$VMNAME" to poweroff..."
        until $(sudo -H -u $VMUSER VBoxManage showvminfo --machinereadable "$VMNAME" | grep -q ^VMState=.poweroff.)
        do
          sleep 1
        done

        FILENAME=$(date +"%Y_%m_%d-%T")
        echo "Backing up Virtualbox VM to '$BASEFOLDER$FILENAME'..."
        sudo -H -u $VMUSER VBoxManage clonevm "$VMNAME" --options keepallmacs --name $FILENAME --basefolder $BASEFOLDER

        echo "Restarting VirtualBox VM..."
        sudo -H -u $VMUSER VBoxManage startvm "$VMNAME" --type headless
        echo ""
        ;;
    *)
        echo "Usage: sudo service vbox {start|stop|status|shutdown|reset|backup}"
        exit 1
        ;; esac

exit 0

Please note that I got that script from here: https://superuser.com/questions/789653/init-d-control-script-for-virtualbox-vm

Please verify the commands within prior to installing the script, then test each functionality. You will need to place it in the /etc/init.d directory, and run chmod +x on it to make it run. Then go through and test the functionality of it. Once satisfied, run:

sudo update-rc.d vbox defaults 99 01

This will set it to start with the system. The original post has some steps for cron jobs, as an FYI. If anyone knows of a more up to date method of doing this, please feel free to edit this post, or post another answer.

Solution 2:

I would go with a combination of cron job and usage of vboxmanage via bash scripts.

I'd have a bash script which would start up the virtual machines and fire up a cron job for checking the status of the machines.

The script should look something like:

#!/bin/bash

vboxmanage startvm "Server App VM name"
vboxmanage startvm "Windows XP VM name"
crontab ~/check_vms_and_shutdown_job.txt

Let's say we save it as start_vms_and_cronjob.sh. Remember to chmod +x it, so it can be actually executed.

You might wonder about the check_vms_and_shutdown_job.txt file. It's a text file containing information about a job that should be run at certain intervals. In this example we placed it in the user's home folder and it should read:

*/5 * * * * ~/check_vms_and_shutdown.sh

This file should have a new line at the end of the line (press enter before saving ;) ) What this file does is that it describes a cron job which is run every 5 minutes and it executes a bash script.

Now what is this check_vms_and_shutdown.sh script you might ask? Well, here's the whole point. It should say:

#!/bin/bash

if vboxmanage list runningvms | grep "Windows XP VM name"
then
    echo "Windows XP still running."
else
    echo "Windows XP shut down. Shutting down the rest."
    vboxmanage controlvm "Server App VM name" savestate
    crontab -r 
    shutdown -h now
fi

Now what it does, that it will check if there is the XP virtual machine running. If it's not, it will then order the server app virtual machine to save it's state. After that the cronjob will be removed and the system shut down. Remember to chmod +x and here we also placed the file in user's home folder.

For convenience and better usage on the purpose you might also want to run the virtualboxes headless and have their usage be done through remote display.

Now add the start_vms_and_cronjob.sh into your startup applications and you should be set.

So what we have here is:

  • When the system starts, the virtual machines are started by a shell script and a new cron job (running a shell script) is created from a cron job rule txt file.
  • In every 5 minutes the cron job runs the script which checks if the XP virtual machine is still running and if not it will save the other virtual machine, remove the cron job and shutdown the system.

Hope this helps you to configure just what you need.

Solution 3:

These are the steps to achieve the tasks outlined. The VM guest with the server application will be called "ServerApp", the Windows machine "WindowsXP" below. Replace these with their real names.

The method below involves creating a custom Xsession on the host machine. This has the advantage that we may strip down this session to only load applications we need for running our virtual machines (we likely won't need a full blown desktop for this). In addition, using the wait methods inbuilt to VirtualBox will not require any additional loops to be called for monitoring the VM states.

  1. Create a user for running the virtual machine.
  2. Install the guest additions to the guest
  3. Switch to fullscreen with Host + F while running the VM.
  4. Define a custom Lubuntu session on the host:

    • Create a file in /usr/share/xsessions and name it e.g. WindowsVM.desktop with following content:

      [Desktop Entry]
      Name=WindowsXP # or any other sensible name
      Comment=Custom Xsession running a VM 
      Exec=/etc/X11/Xsession
      
    • Make this file executable. This session will call ~/.xsession on login.

  5. Create the executable session startup script named ~/.xsession in above user's HOME:

    #! /bin/bash
    
    /usr/bin/lxsession -s Lubuntu LXDE &
    VBoxManage startvm "ServerApp" --type headless
    VBoxManage startvm "WindowsXP"
    VBoxManage guestproperty set RUNNING 1 --flags TRANSIENT
    VBoxManage guestproperty wait "WindowsXP" RUNNING
    VBoxManage controlvm "SeverApp" savestate
    dbus-send --system --print-reply --dest="org.freedesktop.ConsoleKit" /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Stop
    
  6. Choose the custom session in 4. on login.

The tricky bit is to get the guest property RUNNING (or any other name we choose) deleted from the virtual machine as it is not so transient as the specs suggest. Unfortunately it will survive a shutdown/poweroff of the virtual machine.

We therefore have to add the following command using VBoxcontrol.exe (installed with the guest additions) to the guest Windows at the end of its shutdown routine (or from a shutdown script we put there):

VBoxControl.exe guestproperty set RUNNING

This will then terminate the wait state to proceed with saving the "ServerAPP" then poweroff the host.

An alternative to this is starting a Windows application on the guest to wait for this application to terminate before we shutdown the machines and poweroff the host. Then we'd replace the two set guestproperty commands in the script by a line similar to this:

VBoxManage --nologo guestcontrol "WindowsXP" execute --image "C:\\full\\path\\to\\program.exe" --username <windowsuser> --password <password> --wait-exit --wait-stdout

See VirtualBox Manual for limitations, and for further details on how to set this up for a passwordless account in Windows.


Commands of script in step 5. explained:

  • /usr/bin/lxsession -s Lubuntu LXDE
    starts a Lubuntu session (replace with any other customized Xsession if applicable)

  • VBoxManage startvm "ServerApp --type headless"
    starts the virtual machine running the server App in headless mode (i.e. no display)

  • VBoxManage startvm "WindowsXP"
    starts the virtual machine running Windows (fullscreen or any other resolution as defined on last run)

  • VBoxManage guestproperty set "WindowsXP" RUNNING 1 --flags TRANSIENT
    sets a property RUNNING for the Windows machine that can be controlled from the guest OS

  • VBoxManage guestproperty wait "WindowsXP" RUNNING
    waits for the property RUNNING to be removed from the guest Windows

  • VBoxManage controlvm "SeverApp" savestate
    terminates the server App VM in savestate

  • dbus-send --system --print-reply --dest="org.freedesktop.ConsoleKit" \
    /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Stop
    terminates the Lubuntu host (poweroff state) without user interaction.