#! /bin/sh ### BEGIN INIT INFO # Provides: vboxctl # Required-Start: $remote_fs $syslog $network vboxdrv # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start/Stop/Backup for VirtualBox VMs # Description: This script is designed as an ease of use VirtualBox # handler. Beside start and stop it gives you the ability to # backup VMs. Therefor the build in OVF export # function is used. ### END INIT INFO # Author: Philipp Micheel # # VBoxCtl provides ease of use start, stop and backup functionality for # VirtualBox virtual machines. # # Copyright (C) 2010 Philipp Micheel # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # # Changelog: # 10.07.2010 Implemented backup functionality # 13.07.2010 Revamped to be more generic # 31.07.2010 Implemented start/stop functionality (for use as init script) # 07.08.2010 Make it atleast fully work # Changed from clonehd to OVF export # 21.08.2010 Some minor fixes/changes # 15.11.2010 typo and wrong backup date format, old backups weren't always purged # # TODO: # - enhance backup (check on success, rotation etc.) # - make the script more silent or at least treat verbose=no # - kill VM (via pidfile) # # ATTENTION: # There is no support for snapshots! I never had a check on them. It probably # works since it's based on the OVF export. # # Installation: # copy to /etc/init.d # update-rc.d vboxctl defaults 80 # ### BEGIN CONFIG (Can be overwritten in /etc/default/vboxctl) USER="user1" # Machines to control (seperated by spaces) VMS="vm1 vm2" # Additional start parameters can be added here GUESTSTARTUPPARAMS="--vrdp off" # Shutdown method (Make sure your guests support acpi or change to savestate.) GUESTSHUTDOWN="acpipowerbutton" #GUESTSHUTDOWN="savestate" ## Backup # Where to store the backups: BACKUPDIR="/var/backup" # Compression makes no sense anymore; OVF export is used (vmdk is already # compressed) anyways --bzip or --use-compress-program=lbzip2 will do the job TARPARAMS="" TARSUFFIX=".tar" # FTP upload (leave FTPHOST empty to disable) FTPHOST="" FTPUSER="" FTPPASS="" ### END CONFIG # No need to edit anything below this line PATH=/sbin:/usr/sbin:/bin:/usr/bin NAME="vboxctl" DAEMON="/usr/bin/VBoxHeadless" DAEMON_ARGS="--startvm" CONTROL="/usr/bin/VBoxManage" PIDDIR="/var/run/VBoxHeadless/$USER" SCRIPTNAME="/etc/init.d/$NAME" SUCMD="su -- $USER -c" DATE=`date +%Y%m%d%H%M` [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Exit if VirtualBox is not installed [ -x "$DAEMON" ] && [ -x "$CONTROL" ] || exit 1 . /lib/init/vars.sh . /lib/lsb/init-functions # # Function that starts all the VMs # do_start() { #Make sure PIDDIR exists mkdir -p --mode=0771 "$PIDDIR" && chgrp vboxusers "$PIDDIR" #Start the given machines for VM in $@ ; do PIDFILE="$PIDDIR/$VM.pid" log_daemon_msg "Starting virtual machine" "$VM" #Machine already running? if [ `$SUCMD "$CONTROL -q list runningvms |grep -Fci '$VM'"` -eq 1 ] then log_warning_msg "Virtual machine $VM is already running" else #Make sure no old pidfile is present rm -f "$PIDFILE" #Let's go.. start-stop-daemon --start --quiet --background --make-pidfile \ --pidfile $PIDFILE --chuid $USER:vboxusers --startas $DAEMON -- \ $DAEMON_ARGS $VM $GUESTSTARTUPPARAMS && sleep 10 fi #The machine should be running now! [ `$SUCMD "$CONTROL -q list runningvms |grep -Fci '$VM'"` -eq 1 ] \ && log_end_msg 0 || log_end_msg 1 done } # # Function that stops the VMs # do_stop() { for VM in $@ ; do PIDFILE="$PIDDIR/$VM.pid" log_daemon_msg "Stopping virtual machine" "$VM" #Check if the machine is running if [ `$SUCMD "$CONTROL -q list runningvms |grep -Fci '$VM'"` -eq 1 ] then #Perform a clean guest shutdown and wait for it (max 90sec) $SUCMD "$CONTROL -q controlvm $VM $GUESTSHUTDOWN" > /dev/null 2>&1 TIMER=0 while [ `$SUCMD "$CONTROL -q list runningvms |grep -Fci '$VM'"` \ -eq 1 ] && [ $TIMER -lt 90 ] ; do sleep 3 TIMER=$((TIMER+3)) done #Force to shutdown if [ `$SUCMD "$CONTROL -q list runningvms |grep -Fci '$VM'"` -eq 1 ] then log_warning_msg "Virtual machine $VM is forced to shutdown" $SUCMD "$CONTROL -q controlvm $VM poweroff" > /dev/null 2>&1 sleep 5 fi #Get evil if [ `$SUCMD "$CONTROL -q list runningvms |grep -Fci '$VM'"` -eq 1 ] then log_warning_msg "Virtual machine $VM is going to be killed" start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE \ && sleep 5 \ || log_failure_msg "Virtual machine $VM could not be stopped" fi else log_warning_msg "Virtual machine $VM is not running" fi #Machine should be off now! [ `$SUCMD "$CONTROL -q list runningvms |grep -Fci '$VM'"` -eq 0 ] \ && log_end_msg 0 && rm -f $PIDFILE || log_end_msg 1 done } do_status() { for VM in $@ ; do STATE=`$SUCMD "VBoxManage -q showvminfo ${VM} --machinereadable" |grep VMState= | cut -d "=" -f2 | tr -d "\""` log_success_msg "Virtual machine $VM is $STATE" done } # # Function that backups all VMs # do_backup() { for VM in $@ ; do log_daemon_msg "Backing up virtual machine" "$VM" TARGETDIR="$BACKUPDIR/$DATE-$VM" TARGET="$TARGETDIR/$VM.ovf" FILE="$TARGETDIR$TARSUFFIX" mkdir -p --mode=0770 "$TARGETDIR" \ && chgrp vboxusers "$BACKUPDIR" \ && chgrp vboxusers "$TARGETDIR" cd $BACKUPDIR do_stop "$VM" #Export via VBoxManage if [ `$SUCMD "VBoxManage -q export $VM --output $TARGET" |grep -Fci 'Successfully exported'` -eq 1 ] then #Start the machine to minimize downtime do_start "$VM" tar --create --remove-files --file="$FILE" $TARPARAMS \ `basename $TARGETDIR` # Backups are for root only chown root:root $FILE && chmod 600 $FILE #Simple Rotation DELFILES="`date --date \"-5 days\" +%Y%m%d`*$VM$TARSUFFIX" rm -f "$BACKUPDIR/$DELFILES" # Check if FTP should be used if [ ! -z "$FTPHOST" ]; then /usr/bin/ftp -inv $FTPHOST << ENDFTP > /dev/null user $FTPUSER $FTPPASS lcd $BACKUPDIR put `basename $FILE` mdelete $DELFILES bye ENDFTP fi log_end_msg 0 else log_failure_msg "Virtual machine $VM export failed" log_end_msg 1 do_start "$VM" fi done } TASK="$1" #check if the VMs are specified as parameter [ $# -gt 1 ] && shift && VMS="$@" case "$TASK" in start) do_start "$VMS" ;; stop) do_stop "$VMS" ;; status) do_status "$VMS" ;; restart|force-reload) do_stop "$VMS" do_start "$VMS" ;; backup) do_backup "$VMS" ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload|backup} [vm1] [vm2] [..]" >&2 exit 3 ;; esac :