VirtualBox

From TheBeard Science Project Wiki
Jump to: navigation, search

Startup Script

I created a file called /autostart-vms.list that contains the names of the VMs I want to start (one per line).

I then created this script called /custom-init.sh:

#!/bin/bash

vm_list=`cat /autostart-vms.list`
vm_user="username"
status_file="/home/$vm_user/vbox-status.log"

echo "VM START:" >$status_file

s=$IFS
IFS=`echo -en "\n\b"`
for x in $vm_list;do
        su -c "VBoxManage startvm \"$x\" --type headless &>>$status_file" $vm_user
done
IFS=$s

echo -e "\nVM LIST:\n$vm_list" >>$status_file

echo -e "\nRUNNING:" >>$status_file
su -c "VBoxManage list runningvms >>$status_file" $vm_user

Username needs to be some user other than root. This script creates a log file in the user's home directory ~/vbox-status.log that contains status info about the VM startup process on last boot. Make sure this script is started after all the VirtualBox services are started on bootup. Since the /etc/init.d/rc.local always starts last, I put the line at the bottom. Make sure custom-init.sh is executable.

sudo chmod 744 /custom-init.sh
su -c 'echo "/bin/bash /custom-init.sh &" >> /etc/init.d/rc.local'

Shutdown Script

When you shutdown your host server, it would be nice if it also gave the shutdown command to all your VMs. Here is a short script you can save in /etc/init.d:

#!/bin/bash

vm_user="username"
timeout=30

for vm in `su -c 'VBoxManage list runningvms' $vm_user|grep -o "\".*\""|sed 's/\"//g'`;do
        su -c "VBoxManage controlvm \"$vm\" acpipowerbutton" $vm_user
done

echo -n "Waiting for VMs to shutdown."
i=1
while (( $i <= $timeout ));do
        vm_count=`su -c 'VBoxManage list runningvms' $vm_user|wc -l`
        if (( $vm_count <= 0 ));then
                echo " All VMs were shutdown OK."
                break
        else
                echo -n "."
                let i++
                sleep 1
        fi
done

if (( $i == $timeout ));then
        echo " Some VMs did not shutdown!"
fi

Username must be something other than root. Timeout is how many seconds (roughtly) that it waits before it gives up on the remaining VMs and just shuts down the host server.

Once you have this script located in /etc/init.d (named "stop-vms" for example) you can create a symbolic link in the appropriate rc directories. Make sure this script is run before any of the VirtualBox services are stopped. For my server, I made it K64. Make sure stop-vms is executable.

sudo chmod 744 /etc/init.d/stop-vms
sudo ln -s /etc/init.d/stop-vms /etc/rc0.d/K64stop-vms
sudo ln -s /etc/init.d/stop-vms /etc/rc6.d/K64stop-vms

If you're using Systemd you need to do this differently.

You can put a script in the Systemd system-shutdown script folder. It is located in a different place on different Linux distributions:

  • Debian: /lib/systemd/system-shutdown
  • Other: /usr/lib/systemd/system-shutdown

I will continue assuming you are using Debian.

[ UNFINISHED SECTION ]

Create the file /lib/systemd/system-shutdown/wait-for-vms.sh:

Easier Command Line Management

The VBoxManage command is very powerful, but a bit difficult to remember the syntax in my opinion. I only use it occasionally, and I use it for simple things. I decided to simplify it.

I created a file called /scripts/vbox-commands.sh:

#!/bin/bash
#
# A handy shortcut script for controlling VirtualBox VMs.
#
# Recommended aliases:
#   alias vbm='VBoxManage'
#   alias vb='/scripts/vbox-commands.sh'
#   alias vbl='/scripts/vbox-commands.sh list'
#   alias vbll='/scripts/vbox-commands.sh listall'
#   alias vbla='/scripts/vbox-commands.sh listall'
#   alias vbls='/scripts/vbox-commands.sh start'
#   alias vblx='/scripts/vbox-commands.sh stop'
#   alias vblh='/scripts/vbox-commands.sh halt'

main() {
case $1 in
"list"|"listrunningvms")
        echo "Running VMs:"
        VBoxManage list runningvms
;;
"listall"|"listvms")
        echo "All VMs:"
        VBoxManage list vms
;;
"start"|"startvm")
        checkvm "$2"
        echo -n "Are you sure you want to start headless VM: \"$2\" [y/N]? ";read ans
        shopt -s nocaseglob
        if [[ "$ans" == y* ]];then
                shopt -u nocaseglob
                func_startvm "$2"
        else
                echo "Cancelled.";exit 0
        fi
;;
"stop"|"stopvm")
        checkvm "$2"
        echo -n "Are you sure you want to gracefully shutdown VM: \"$2\" [y/N]? ";read ans
        shopt -s nocaseglob
        if [[ "$ans" == y* ]];then
                shopt -u nocaseglob
                func_stopvm "$2"
        else
                echo "Cancelled.";exit 0
        fi
;;
"halt"|"hault"|"haltvm"|"haultvm")
        checkvm "$2"
        echo -n "Are you sure you want to abruptly poweroff VM: \"$2\" [y/N]? ";read ans
        shopt -s nocaseglob
        if [[ "$ans" == y* ]];then
                shopt -u nocaseglob
                func_haultvm "$2"
        else
                echo "Cancelled.";exit 0
        fi
;;
"-h"|"--help")
        echo "Usage: vbox-command.sh [-h|--help] list|listall|start|stop|halt VMNAME"
        exit 0
;;
*)
        echo "Error: No valid command given."
        echo "Usage: vbox-command.sh [-h|--help] list|listall|start|stop|halt VMNAME"
        exit 1
;;
esac
}

checkvm() {
if [ -z "`VBoxManage list vms|grep  \"$1\"`" ];then
        echo "Error: $1: No such VM."
        exit 1
fi
}

func_startvm() {
VBoxManage startvm "$1" --type headless
}

func_stopvm() {
VBoxManage controlvm "$1" acpipowerbutton && echo "ACPI signal sent."
}

func_haultvm() {
VBoxManage controlvm "$1" poweroff && echo "Power off."
}

main $@

I set the appropriate permissions:

sudo chmod 755 /scripts/vbox-commands.sh

And I added some aliases to my ~/.bashrc file:

# ALIASES
alias vbm='VBoxManage'
alias vb='/scripts/vbox-commands.sh'
alias vbl='/scripts/vbox-commands.sh list'
alias vbll='/scripts/vbox-commands.sh listall'
alias vbla='/scripts/vbox-commands.sh listall'
alias vbs='/scripts/vbox-commands.sh start'
alias vbx='/scripts/vbox-commands.sh stop'
alias vbh='/scripts/vbox-commands.sh halt'

I then reload my bashrc:

source ~/.bashrc

I should now be able to get the help dialog:

# Get help dialog:
vb -h

# Which prints:
#   Usage: vbox-command.sh [-h|--help] list|listall|start|stop|halt VMNAME

The aliases are just shortcuts to each of these options, which can be run like:

# To start VM (headless) with name "LDAPServer"
vbs LDAPServer

# Which is an alias for 'vb start LDAPServer', or 'VBoxManage startvm LDAPServer --type headless'
# Another difference is that using 'vb' or 'vbs' asks for a yes/no confirmation.

The vbm alias is just a nice shortcut for VBoxManage so you can still run some of the more complex commands. To get a full dialog of all VBoxManage parameters:

vbm|less

I'm very glad I made this, so I thought other people might enjoy it.