How to automatically start and shut down VirtualBox machines?

I need to run a software system that is intended to be installed as an appliance on a dedicated machine. In order to save energy, I plan to run the system on a VirtualBox VM instead.

The host is a standard Linux box with a SysV-Init system, the guest is a heavily modified Linux and I would prefer not to have to alter it further. VirtualBox is used in the OSE version.

I have already figured out how to start the VM when the host boots (Edit: this is done, as Nikhil mentioned below, through the command VBoxManager startvm), but how can I gracefully shut down the VM? Any script running on the host would need to wait until the guest has fully shut down.

Can anyone suggest how, for example, a service file doing this would have to look?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Have you tried acpipowerbutton from this command set?

VBoxManage controlvm        <uuid>|<name>
                            pause|resume|reset|poweroff|savestate|
                            acpipowerbutton|acpisleepbutton|

Edit after reading the comments:

You can use acpid or other acpi utilities to make it graceful. Also, can you provide more information about how do you shutdown the machine at the moment?

Plain shutdown wouldn’t wait for unfinished jobs, a time delay may be too long.

I assume you aren’t using a window manager so try this tool.

Just seen this daemon. You might find it useful.

Method 2

Rather than code this up yourself, consider using Vagrant, which is built to instantiate and control virtualbox instances. The documentation is excellent and I suggest that you check it out rather than attempting to roll your own.

The long and short of it is that you create a simple control file and then run vagrant up to start as many VirtualBox instances as you want. You can use vagrant ssh to log into the hosts and vagrant halt to shut the host down (without terminating). vagrant destroy will get rid of the instances.

It supports provisioning with puppet, Ansible or Chef and allows you to control most of the exposed VBox configuration settings.

Method 3

I have similar application as you, with one difference: I need to restart system and recover from snapshot.

What you are interested in is headless-mode.

I have a few of such services so I use following script:

VBox_StopRestoreStart.sh

#!/bin/bash
if [ -z "$1" ]; then
        echo "Usage: $0 VMNAME_or_UUID"
        exit 1
fi
set -x
VBoxManage controlvm  "$1" poweroff  #enforce turnoff
VBoxManage snapshot   "$1" restorecurrent   #retore state
VBoxManage showvminfo "$1" | grep State   #display state to ensure
VBoxHeadless -s       "$1"  #run in headless mode in background

how can I gracefully shut down the VM?

IF you want to turn off VM gracefully, you have two options, depending on your application:

  • Emulate “shut-down button” or “sleep button” and prepare VM to react on it (to close gracefully)
    • VBoxManage controlvm <uuid>|<VMname> acpipowerbutton
    • VBoxManage controlvm <uuid>|<VMname> acpisleepbutton
  • Save VM state in order to restore afterwards
    • VBoxManage controlvm <uuid>|<VMname> savestate

TIPS: You might find useful:

  • VBoxManage list vms – list of available vms
  • rdesktop IP-ADDR:3389 or rdesktop-vrdp IP-ADDR:3389 – when you would like a GUI (even remotely) when you run in headless mode : VBoxHeadless -s <uuid>|<VMname>
  • VBoxManage startvm – start with GUI for local debugging

Related VirtualBox manual’s chapter: Chapter 7. Remote virtual machines – Step by step: creating a virtual machine on a headless server

P.S. If you are interested in full featured already implemented solutions, OpenStack seems interesting choice.

Method 4

Looking at VirtualBox VM management documentation at http://www.virtualbox.org/manual/ch08.html

For listing the VMs, use the command VBoxManage list vms

For starting the VM, use the command VBoxManage startvm

http://www.virtualbox.org/manual/ch08.html#vboxmanage-controlvm

For controlling VM, use VBoxManage controlvm

The controlvm subcommand allows you to change the state of a virtual machine that is currently running. The following can be specified:

VBoxManage controlvm <vm> pause temporarily puts a virtual machine on hold, without changing its state for good. The VM window will be painted in gray to indicate that the VM is currently paused. (This is equivalent to selecting the “Pause” item in the “Machine” menu of the GUI.)

Use VBoxManage controlvm <vm> resume to undo a previous pause command. (This is equivalent to selecting the “Resume” item in the “Machine” menu of the GUI.)

VBoxManage controlvm <vm> reset has the same effect on a virtual machine as pressing the “Reset” button on a real computer: a cold reboot of the virtual machine, which will restart and boot the guest operating system again immediately. The state of the VM is not saved beforehand, and data may be lost. (This is equivalent to selecting the “Reset” item in the “Machine” menu of the GUI.)

VBoxManage controlvm <vm> poweroff has the same effect on a virtual machine as pulling the power cable on a real computer. Again, the state of the VM is not saved beforehand, and data may be lost. (This is equivalent to selecting the “Close” item in the “Machine” menu of the GUI or pressing the window’s close button, and then selecting “Power off the machine” in the dialog.)

After this, the VM’s state will be “Powered off”.

Method 5

For a systemd based system, you could try this.

Step #1: create a service file

[Unit]
Description=VBox Virtual Machine %i Service
Requires=systemd-modules-load.service
After=systemd-modules-load.service

[Service]
User=user
Group=vboxusers
ExecStart=/usr/bin/VBoxHeadless -s %i
ExecStop=/usr/bin/VBoxManage controlvm %i savestate

[Install]
WantedBy=multi-user.target

Step #2: Enable the service file

$ sudo systemctl enable <a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5127333e29273c2234232738323411273c">[email protected]</a>_name.service

References

Method 6

How about to send the command via ssh from the host to the guest?

I am not sure if it works and if you can check the status of the machine afterwards or get something like an exit-status, but it should down clean atleast.

Method 7

My solution:
In this shellscript ‘root’ is the invoker, and ‘theuser’ is the owner of ‘thevm’

I know the vms have ended when the output of the command VBoxManage list runningvms returns an empty string.

...
start(){
    su -c "VBoxHeadless --startvm thevm" -s /bin/bash theuser &
    # maybe another vbox command
}

stop(){
    su -c "VBoxManage controlvm thevm acpipowerbutton" -s /bin/bash theuser
    # maybe another vbox command
    while [ "`su -c 'VBoxManage list runningvms' -s /bin/bash theuser`" != "" ]
    do
        echo waiting for VMs to shutdown
        sleep 3
    done
}
...

Method 8

To start vm:

VBoxManage startvm VMNAME --type headless

To stop vm:

VBoxManage controlvm VMNAME savestate

List all running vm’s:

VBoxManage list runningvms

Method 9

I have a virtual machine to control incoming faxes and other tasks that I perform a snapshot on nightly. To ensure that I can port the vm to another piece of hardware, I use a Linux cron job to turn-off the vm at 3a.m. using the acpipowerbutton, wait until the shutdown is complete, delete the previous week’s (7-days ago) snapshot, make a new snapshot, and power-up the vm to get ready for the day.

I have edited the script I use to make it generic from any vm. Of course, you can change the name of the script, but this is my current production candidate. This can be put in your /usr/local/bin. I used the .sh extension isn’t required, it is just a little insurance so I don’t accidentally kick-off the script and turn-off a vm that I didn’t want to. I have not put in a check to verify that a vm name was input, if the script is invoked without adding a vm name to the script, you will just get a few screens of error messages.

    #!/bin/bash
    # snaptake.sh - take a snapshot of vm in virtualbox
    # snapshot is named by the dow (Mon, Tue, ...) vm name must have no spaces.
    # Push the virtual power button to shut-off and wait so many minutes to complete
    # You need to have your vm configured to shutdown when the power button is pressed.
    # This method gives a much more controlled turn-off than the "pull-the-plug" methods.
    # A snapshot made with the vm not running, makes it easier to port to a different
    # computer.
    #
    # Syntax: snaptake.sh VBName
    #   where VBName is the name of the virtual machine.  There can be no spaces in the name.
    #
    # This script first attempts to turn-off the virtual machine with the acpipowerbutton method.  The
    # vm must have been configured to turn-off when the power button is pressed.  
    #Then, the oldest snapshot with the name for the day of week (Mon, Tue, Wed ... )
    # is deleted.  The name is derived from the date function.  Then a new snaphot 
    # is taken, using the same day of week. Finally the vm is restarted. 
    # 
    VBoxManage controlvm $1 acpipowerbutton 
    
    # Wait until vm has stopped running, waiting a few seconds between checks to keep cpu use down
    while [ `vboxmanage list runningvms | grep -c "$1"` -gt 0 ]
     do
      sleep 3
     done
    
    # Now delete last week's snapshot and make a new snapshot, using the 'dow' (Mon, Tue, Wed .... )
    vboxmanage --nologo snapshot $1 delete `date '+%a'` 2>/dev/null
    
    # This might be unnecessary, I haven't verified yet whether the wait is required
    # or not for delete to complete.
    while [ `ps -ax  | grep /VBoxManage | grep  $1 | grep -c delete` -gt 0 ]
     do
      sleep 3
     done

    # Take the new snapshot, give it the name of the day of week (Mon, Tue, ... )
    vboxmanage --nologo snapshot $1 take `date '+%a'` 2>/dev/null
    
    # wait a few more seconds, the snapshot goes fast
    while [ `ps -ax  | grep /VBoxManage | grep  $1 | grep -c take` -gt 0 ]
     do
      sleep 3
     done

    # Uncomment following line to start the vm, comment it to keep the vm off
    DISPLAY=:0 VBoxManage startvm "$1" --type gui 2>/dev/null

This solution comes from ideas on this website and others and trial and error to get things working for my configuration. This script is running on an Ubuntu 20.04. I believe the syntax and functions I have used will operate only on the exact virtual machine named and not similarly named vm’s.

Method 10

Maybe this will help as part of the solution.

VBoxManage list runningvms | tr -s '" {' '%{' | cut -d '%' -f3  | while read uuid; do
   VBoxManage controlvm $uuid savestate; 
done

Method 11

Why don’t you login to your guest and shutdown from there?

Unless you have a good reason for not installing sshd and accessing the VM really through VBox, I’d go for a script that just issues an ssh shutdown -h now. To be honest, I’d create a script for every machine that properly shuts it down and perform some checkups while at it.

Just pack an /etc/init.d/shutdown_vm script that call the other one from the host, the call will block until is ready. This process (as described) adds a linux dependency at the guest but removes the VBox dependency at the host.

Cutting to the chase: you don’t need to access VBox to shutdown a machine, if you have some means of accessing it (i.e. ssh) then the OS will always have some means for that (turning it on, is different of course)


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x