vbox-headless: init script for multiple VMs

Discussions related to using VirtualBox on Linux hosts.
Post Reply
nte
Posts: 1
Joined: 25. Sep 2010, 01:08
Primary OS: Ubuntu other
VBox Version: PUEL
Guest OSses: Windows 2000

vbox-headless: init script for multiple VMs

Post by nte »

Hello, I needed an init script to load multiple VMs on boot. Since I could not find an adequate one, here is my solution.

This is a very rough version, I basically hacked it all together in one pass. Use at your own risk -- caveat emptor.

Features
  • configure VirtualBox user
  • run all registered VMs for user or
  • specify list of VMs to run
  • stopping VMs with controlvm savestate
  • uses standard mechanisms, that means
  • ignore already running/stopped VMs
  • manage with system tools, ie. update-rc.d
/etc/init.d/vbox-headless

Code: Select all

#! /bin/sh
### BEGIN INIT INFO
# Provides:          vbox-headless
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start VMs in headless mode.
# Description:       This script runs VMs for the default VirtualBox user in
#                    headless mode. Make sure all VMs are using different RDP
#                    ports.
### END INIT INFO

# Author: Nicolas Tessore <n.tessore@gmail.com>

####
# VirtualBox settings
####

# The user which owns the VMs
VBOX_USER=vbox

# The list of VMs to run. Leave empty to run all registered VMs.
VBOX_LIST=""

# VirtualBox executables
VBOX_MANAGE=/usr/bin/VBoxManage
VBOX_HEADLESS=/usr/bin/VBoxHeadless

####
# End VirtualBox settings
####

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="VirtualBox daemon"
NAME=vbox-headless
DAEMON=$VBOX_HEADLESS
DAEMON_ARGS=""
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions


vm_init_list()
{
	# get registered VMs
	LIST_VMS=`sudo -H -u $VBOX_USER $VBOX_MANAGE --nologo list vms | cut -d ' ' -f 1 | tr -d '"'`
	
	# check for list of VMs
	if [ -z "$VBOX_LIST" ]
	then
		# all registered VMs for user
		VBOX_LIST=$LIST_VMS
	else
		# check that VMs exist
		for VM in $VBOX_LIST
		do
			case $LIST_VMS in
			"$VM")
				continue
				;;
			*)
				log_failure_msg "ERROR: VM '$VM' is not registered!"
				exit 1
				;;
			esac
		done
	fi
}

# get uuid for vm
vm_get_uuid()
{
	vm=$1
	hwuuid=`sudo -H -u $VBOX_USER $VBOX_MANAGE --nologo showvminfo --machinereadable "$vm" | grep 'hardwareuuid='`
	echo $hwuuid | cut -d '=' -f 2 | tr -d '"'
}

# control running vm
vm_ctrl()
{
	sudo -H -u $VBOX_USER $VBOX_MANAGE --nologo controlvm $1 $2 > /dev/null 2>&1
}

#
# Function that starts the daemon/service
#
do_start()
{
	vm_init_list
	
	# Return
	#   0 if daemon has been started
	#   1 if daemon was already running
	#   2 if daemon could not be started
	RETVAL=0
	
	# Start all VMs
	for VM in $VBOX_LIST
	do
		VM_UUID=`vm_get_uuid $VM`
		VM_PIDFILE="$PIDFILE.$VM_UUID"
		VM_DAEMON="$DAEMON"
		VM_DAEMON_ARGS="$DAEMON_ARGS --startvm $VM_UUID"
		
		log_action_begin_msg "Starting VM '$VM'"
		
		# test for running VM
		USER=$VBOX_USER LOGNAME=$VBOX_USER start-stop-daemon \
			--start \
			--quiet \
			--pidfile $VM_PIDFILE \
			--startas $VM_DAEMON \
			--test \
			> /dev/null
		
		# VM already running
		if [ "$?" != 0 ]
		then
			# report VM is running
			log_warning_msg "VM '$VM' already running"
			[ "$RETVAL" = 0 ] && RETVAL=1
			continue
		fi
		
		# start VM
		USER=$VBOX_USER LOGNAME=$VBOX_USER start-stop-daemon \
			--start \
			--quiet \
			--pidfile $VM_PIDFILE \
			--make-pidfile \
			--background \
			--chuid $VBOX_USER \
			--startas $VM_DAEMON \
			-- $VM_DAEMON_ARGS
		
		log_action_end_msg "$?"
		
		# check if start failed
		if [ "$?" != 0 ]
		then
			# report error
			log_failure_msg "Error starting VM '$VM'"
			RETVAL=2
		fi
	done
	
	if [ "$RETVAL" -lt 2 ]
	then
		log_daemon_msg "VirtualBox daemon started successfully"
	else
		log_daemon_msg "VirtualBox daemon started with errors"
	fi
	
	return "$RETVAL"
}

#
# Function that stops the daemon/service
#
do_stop()
{
	vm_init_list
	
	# Return
	#   0 if daemon has been stopped
	#   1 if daemon was already stopped
	#   2 if daemon could not be stopped
	#   other if a failure occurred
	RETVAL=0
	
	for VM in $VBOX_LIST
	do
		VM_UUID=`vm_get_uuid $VM`
		VM_PIDFILE="$PIDFILE.$VM_UUID"
		
		log_action_begin_msg "Stopping VM '$VM'"
		
		# try savestate halt
		vm_ctrl $VM savestate
		
		# stop daemon
		USER=$VBOX_USER LOGNAME=$VBOX_USER start-stop-daemon \
			--stop \
			--quiet \
			--retry=TERM/30/KILL/5 \
			--pidfile $VM_PIDFILE
		
		case "$?" in
		0)
			log_action_end_msg 0
			;;
		1)
			log_warning_msg "VM '$VM' already stopped"
			[ "$RETVAL" = 0 ] && RETVAL=1
			;;
		2)
			log_action_end_msg 1
			log_failure_msg "ERROR: Could not stop VM '$VM'"
			RETVAL=2
			continue
			;;
		esac
		
		rm -f $VM_PIDFILE
	done
	
	if [ "$RETVAL" -lt 2 ]
	then
		log_daemon_msg "VirtualBox daemon stopped successfully"
	else
		log_daemon_msg "VirtualBox daemon stopped with errors"
	fi
	
	return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
	#
	# If the daemon can reload its configuration without
	# restarting (for example, when it is sent a SIGHUP),
	# then implement that here.
	#
	start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
	return 0
}

case "$1" in
  start)
	log_daemon_msg "Starting $DESC" "$NAME"
	do_start
	case "$?" in
		0|1) log_end_msg 0 ;;
		2) log_end_msg 1 ;;
	esac
	;;
  stop)
	log_daemon_msg "Stopping $DESC" "$NAME"
	do_stop
	case "$?" in
		0|1) log_end_msg 0 ;;
		2) log_end_msg 1 ;;
	esac
	;;
  status)
       status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
       ;;
  #reload|force-reload)
	#
	# If do_reload() is not implemented then leave this commented out
	# and leave 'force-reload' as an alias for 'restart'.
	#
	#log_daemon_msg "Reloading $DESC" "$NAME"
	#do_reload
	#log_end_msg $?
	#;;
  restart|force-reload)
	#
	# If the "reload" option is implemented then remove the
	# 'force-reload' alias
	#
	log_daemon_msg "Restarting $DESC" "$NAME"
	do_stop
	case "$?" in
	  0|1)
		do_start
		case "$?" in
			0) log_end_msg 0 ;;
			1) log_end_msg 1 ;; # Old process is still running
			*) log_end_msg 1 ;; # Failed to start
		esac
		;;
	  *)
	  	# Failed to stop
		log_end_msg 1
		;;
	esac
	;;
  *)
	#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
	echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
	exit 3
	;;
esac

:

mr.deek
Posts: 9
Joined: 22. Feb 2011, 05:03
Primary OS: Ubuntu other
VBox Version: OSE Debian
Guest OSses: ALL

Re: vbox-headless: init script for multiple VMs

Post by mr.deek »

Hello,

Did you know ...

You can start/manage/stop a VM without the pain of running vbox headless command itself?

Stick this in your startup:

vboxmanage startvm "VMNAME" --type headless

and

vboxmanage controlvm "VMNAME" poweroff

And all will be good.
larrykemp
Posts: 4
Joined: 28. Sep 2010, 22:51
Primary OS: Linux other
VBox Version: OSE other
Guest OSses: Cent OS, Windows

Re: vbox-headless: init script for multiple VMs

Post by larrykemp »

What about when you need to have them gracefully shutdown when the host system is going down for reboot or getting powered off?
mooninite
Posts: 16
Joined: 17. Jan 2008, 05:50
Primary OS: Fedora other
VBox Version: OSE Fedora
Guest OSses: RHEL, SuSE, SCO OpenServer, Windows XP

Re: vbox-headless: init script for multiple VMs

Post by mooninite »

You should have your scripts save state instead of powering off the VMs.

service vbox-guests start
# Starts all VMs in "Saved State" state.

service vbox-guests stop
# Calls "VBoxManage controlvm $VM savestate"
ofirk
Posts: 1
Joined: 10. Jul 2011, 16:44
Primary OS: Ubuntu other
VBox Version: PUEL
Guest OSses: XP,Ubuntu

Re: vbox-headless: init script for multiple VMs

Post by ofirk »

Sorry to bump this topic now, but I have searched the web for days trying to find a working init script for Ubuntu 10.10 (probably will work for 11.04 too), and couldn't find.

I bumped into this post but the script attached to this post didn't work. To keep the (very) long story short, I found a working init script which auto starts a Virtualbox VM at start (boot) and saves its states at shutdown (or reboot).
It can be found at http://www.glump.net/howto/virtualbox_as_a_service, however, since the link refers to an external website, which could be down regardless of this post, I am posting the main parts of that URL here.
Create the init.d Script
Now that you've got your virtual machine setup and configured and tested, you're ready to create and configure scripts in ”/etc/init.d/” to start and suspend the guest on demand.

First, if you look at ”/etc/init.d/vboxdrv”, the service manager script for the VirtualBox kernel driver, you'll see that it looks for a couple of options to tell it what to do with running virtual machines when vboxdrv stops. Create or edit the config file:

Code: Select all

sudo touch /etc/default/virtualbox
sudo nano /etc/default/virtualbox
/etc/default/virtualbox:

Code: Select all

SHUTDOWN_USERS="user1 user2" # space-delimited list of users who might have runnings vms
SHUTDOWN=savestate # if any are found, suspend them to disk
Now, the above settings only cover the system shutdown process, not startup. VirtualBox itself doesn't provide any mechanism for starting virtual machines automatically. To do that, create a new service manager script of your own.

Items that you need to fill in for yourself marked with ”!!”. In all the example files and commands below, find those items and fill them in with strings that make sense for your personal setup.

Code: Select all

sudo touch /etc/init.d/virtualbox-!!SHORTNAME #substitute your machine name here
sudo chmod +x /etc/init.d/virtualbox-!!SHORTNAME
sudo nano /etc/init.d/virtualbox-!!SHORTNAME
/etc/init.d/virtualbox-!!SHORTNAME:

Code: Select all

#! /bin/sh
### BEGIN INIT INFO
# Provides:          virtualbox-!!SHORTNAME
# Required-Start:    $local_fs $remote_fs vboxdrv vboxnet
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: !!LONGNAME virtual machine
# Description:       !!LONGNAME virtual machine hosted by VirtualBox
### END INIT INFO
 
# Author: Brendan Kidwell <brendan@glump.net>
#
# Based on /etc/init.d/skeleton from Ubuntu 8.04. Updated for Ubuntu 9.10.
# If you are using Ubuntu <9.10, you might need to change "Default-Stop"
# above to "S 0 1 6".
 
# Do NOT "set -e"
 
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/usr/sbin:/usr/bin:/sbin:/bin
DESC="!!LONGNAME virtual machine"
NAME=virtualbox-!!SHORTNAME
SCRIPTNAME=/etc/init.d/$NAME
 
MANAGE_CMD=VBoxManage
VM_OWNER=!!USERNAME
VM_NAME="!!LONGNAME" #This has to be the name exactly as it appears in your VirtualBox GUI control panel.
 
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
 
# Load the VERBOSE setting and other rcS variables
[ -f /etc/default/rcS ] && . /etc/default/rcS
 
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
 
#
# Function that starts the daemon/service
#
do_start()
{
	# Return
	#   0 if daemon has been started
	#   1 if daemon was already running
	#   2 if daemon could not be started
 
	sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME"|grep "^State:\s*running" >/dev/null && {
	    echo "$VM_NAME" is already running.
	    return 1
	}
 
	sudo -H -u $VM_OWNER $MANAGE_CMD startvm "$VM_NAME" -type vrdp >/dev/null || {
	    echo Failed to start "$VM_NAME".
	    return 2
	}
 
	echo "$VM_NAME" started or resumed.
	return 0
}
 
#
# Function that stops the daemon/service
#
do_stop()
{
	# Return
	#   0 if daemon has been stopped
	#   1 if daemon was already stopped
	#   2 if daemon could not be stopped
	#   other if a failure occurred
 
	sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME"|grep "^State:\s*running" >/dev/null || {
	    echo "$VM_NAME" is already stopped.
	    return 1
	}
 
	sudo -H -u $VM_OWNER $MANAGE_CMD controlvm "$VM_NAME" savestate || {
	    echo Failed to stop "$VM_NAME".
	    return 2
	}
 
	echo "$VM_NAME" suspended.
	return 0
}
 
#
# Display "State" field from showinfo action
#
do_status()
{
	sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME"|grep "^State:\s*.*$"
}
 
case "$1" in
  start)
	[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
	do_start
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
  stop)
	[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
	do_stop
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
  restart|force-reload)
	#
	# If the "reload" option is implemented then remove the
	# 'force-reload' alias
	#
	log_daemon_msg "Restarting $DESC" "$NAME"
	do_stop
	case "$?" in
	  0|1)
		do_start
		case "$?" in
			0) log_end_msg 0 ;;
			1) log_end_msg 1 ;; # Old process is still running
			*) log_end_msg 1 ;; # Failed to start
		esac
		;;
	  *)
	  	# Failed to stop
		log_end_msg 1
		;;
	esac
	;;
  status)
	do_status
	;;
  *)
	#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
	echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2
	exit 3
	;;
esac
Thanks to Trevor White who emailed me and suggested I add the -H option to the sudo commands when I said this script wasn't working correctly during boot time.

Test the init.d Script
Test the script's status, start, and start commands:

Code: Select all

/etc/init.d/virtualbox-!!SHORTNAME status # Is the VM running?
/etc/init.d/virtualbox-!!SHORTNAME start  # Start the VM
rdesktop localhost                        # Connect to the VM
/etc/inid.d/virtualbox-!!SHORTNAME stop   # Stop the VM
Install the init.d Script
Use the update-rc.d command to install the script.

Code: Select all

sudo update-rc.d virtualbox-!!SHORTNAME defaults
Now whenever you enter normal multiuser run mode (at boot time, for example) your VM will start, and when you exit multiuser mode (during shutdown, for example), your VM will be suspended to disk if it was running.
ikus060
Posts: 2
Joined: 10. Jul 2011, 17:56
Primary OS: Ubuntu other
VBox Version: OSE Debian
Guest OSses: Linux, Windows

Re: vbox-headless: init script for multiple VMs

Post by ikus060 »

To have Virtual machines startup and shutdown with an init script, I use vboxtool. It provide an init script easily configurable to startup vms in headless mode with vrde enabled.

Here the link : http://vboxtool.sourceforge.net/
zmerch
Posts: 4
Joined: 11. Jul 2011, 18:23
Primary OS: Ubuntu other
VBox Version: OSE Debian
Guest OSses: Win Server 2003

Re: vbox-headless: init script for multiple VMs

Post by zmerch »

I had a need to restart virtual servers gracefully, and this is what I came up with:

Code: Select all

vboxserver@avotus-core:~$ cat /etc/init.d/virtuals 
#!/bin/sh -e
### BEGIN INIT INFO
# Provides:          virtualservers
# Required-Start:    networking
# Default-Start:     S
# Default-Stop:      0 6
### END INIT INFO
PATH="$PATH:/usr/X11R6/bin/:/usr/lib/virtualbox/"
# The Username:Group that will run VirtualBox
export USER="vboxuser"
#${RUNAS}
# The name that the Virtual Servers will have.
NAME1="Server1"
NAME2="SQLServer"
IP1="10.10.10.5"
IP2="10.10.10.6"
ADMIN="Administrator\%WindersAdminPasswd"

. /lib/lsb/init-functions
case "$1" in
start)
echo "Starting Server 1"
su ${USER} -c "/usr/bin/VBoxHeadless -s ${NAME1} > /dev/null &"
sleep 1
echo "Starting Server 2"
su ${USER} -c "/usr/bin/VBoxHeadless -s ${NAME2} > /dev/null &"
;;
stop)
echo "Stopping Servers -- waiting at least 20 seconds to make sure they've closed down."
su ${USER} -c "/usr/bin/net rpc SHUTDOWN -C Shutdown_Script -f -t 1 -I ${IP1} -U ${ADMIN}"
su ${USER} -c "/usr/bin/net rpc SHUTDOWN -C Shutdown_Script -f -t 1 -I ${IP2} -U ${ADMIN}"
sleep 20
;;
restart)
$0 stop
$0 start
;;
esac
exit 0
Yes, this is a very unsecure script as it has the Windows servers administrator password in plaintext, but I'm the only individual that has direct access to the host. Also, you have to install the Samba client (IIRC) to get the /usr/bin/net utility to send the correct shutdown signals to the windows guests.

Hope this helps,
Roger "Merch" Merchberger
AssureTek
Posts: 1
Joined: 16. Aug 2011, 09:48
Primary OS: Ubuntu other
VBox Version: OSE other
Guest OSses: Ubuntu WinXP

Re: vbox-headless: init script for multiple VMs

Post by AssureTek »

ofirk wrote: <Snip>
Install the init.d Script
Use the update-rc.d command to install the script.

Code: Select all

sudo update-rc.d virtualbox-!!SHORTNAME defaults
Now whenever you enter normal multiuser run mode (at boot time, for example) your VM will start, and when you exit multiuser mode (during shutdown, for example), your VM will be suspended to disk if it was running.
<snip>
[/quote]

I am using Ubuntu 11.04. When I used defaults for update-rc.d it makes the link S20 which is the same time as virtualbox-ose.
The problem was that my virtualbox is named virtualbox-Elastix. Which comes before. So the script was trying to start without the kernel modules being loaded.
I used update-rc.d virtualbox-Elastix defaults 98 02
That way it is started last on boot and stopped first on shutdown.

I should also not that I had to change the script from -type vrdp to -type headless.

This might be because I am using the OSE and installed extensions manually though.
levk
Posts: 33
Joined: 13. Apr 2011, 22:35
Primary OS: Ubuntu other
VBox Version: PUEL
Guest OSses: XP, Gentoo, Ubuntu*, CentOS, Scientific Linux

Re: vbox-headless: init script for multiple VMs

Post by levk »

Edit /etc/default/virtualbox-ose to specify powerdown event for guests on host shutdown. "poweroff" is hard power off, graceful shutdown is "acpibutton". You have to make sure the guest will actually power down on the event, most Windows will just ask you if you're really sure about that and wait there.

If you're having problems with your scripts starting your guests before the module is loaded, manually load the module; on Ubuntu you can put it in /etc/modules.

Last time I looked around for the autostarting tools, saw vboxtool, saw how it wasn't touched in 2 years and decided against it. These scripts are probably awesome and all, but what's wrong cron? It's literally one line of code in the crontab:

Code: Select all

@reboot for vm in $(grep -v "^#" /home/vbox/.autostart); do vboxmanage startvm $vm --type headless; done;
And the autostart file can even have comments in it:

Code: Select all

# List guests to start on boot, VM names or UUIDs work. No spaces in names.

# Empty lines and lines starting with '#' are ignored
# THERE ARE NO END OF LINE COMMENTS

# My awesome guest
guest1

# My second awesome guest
guest2
Post Reply