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