Here’s a script that will loop through the virtual machines in VirtualBox and exports them.
Note: a new version of this script is available here.
Why not use snapshots?
I’ve seen scripts that will take a snapshot and then copy the ‘raw’ vm over to a backup disk. The advantages of such an approach are:
But there are drawbacks too:
Why export based backups?
The killer features for export based backups are obvious:
I’m running two vm’s on my server at home. All their users are local to my time zone and most of them sleep at night so I can afford a bit of downtime. Obviously if you run a bigger operation this may not be convenient. But then again you would probably be running Hyper-V or VMWare.
For each virtual machine this script will:
- save the state;
- export it to a predefined directory;
- restore the previous state;
- mail the results to a predefined address.
I suggest you combine the script with rsnapshot and rsnaptar for historical and off-site backups but that’s up to you.
Suggestions for improvements are welcome. If you take the script and find it useful please use the PayPal tip jar on the right side of the page or click some ads here :)
#!/bin/bash # This scripts loops through all the user's VirtualBox vm's, pauses them, # exports them and then restores the original state. # # VirtualBox's snapshot system is not stable enough for unmonitored use yet. # # Vorkbaard, 2012-02-01 # =============== Set your variables here =============== EXPORTDIR=/var/vmbackup MYMAILemail@example.com VBOXMANAGE="/usr/bin/VBoxManage -q" # ======================================================= # Generate a list of all vm's; use sed to remove the double quotes. # Note: better not use quotes or spaces in your vm name. If you do, # consider using the vms' ids instead of friendly names: # for VMNAME in $(vboxmanage list vms | cud -t " " -f 2) # Then you'd get the ids in your mail so you'd have to use vboxmanage # showvminfo $id or something to retrieve the vm's name. I never use # weird characters in my vm names anyway. for VMNAME in $(vboxmanage list vms | cut -d " " -f 1 | sed -e 's/^"//' -e 's/"$//') do ERR="nothing" SECONDS=0 # Delete old export.log file if it exists if [ -e export.log ]; then rm export.log; fi # Get the vm state VMSTATE=$(vboxmanage showvminfo $VMNAME --machinereadable | grep "VMState=" | cut -f 2 -d "=") echo "$VMNAME's state is: $VMSTATE." # If the VM's state is running or paused, save its state if [[ $VMSTATE == \"running\" || $VMSTATE == \"paused\" ]]; then echo "Saving state..." vboxmanage controlvm $VMNAME savestate if [ $? -ne 0 ]; then ERR="saving the state"; fi fi # Export the vm as appliance if [ "$ERR" == "nothing" ]; then echo "Exporting the VM..." vboxmanage export $VMNAME --output $EXPORTDIR/$VMNAME-new.ova &> export.log if [ $? -ne 0 ]; then ERR="exporting" else # Remove old backup and rename new one if [ -e $EXPORTDIR/$VMNAME.ova ]; then rm $EXPORTDIR/$VMNAME.ova; fi mv $EXPORTDIR/$VMNAME-new.ova $EXPORTDIR/$VMNAME.ova # Get file size FILESIZE=$(du -h $EXPORTDIR/$VMNAME.ova | cut -f 1) fi else echo "Not exporting because the VM's state couldn't be saved." &> export.log fi # Resume the VM to its previous state if that state was paused or running if [[ $VMSTATE == \"running\" || $VMSTATE == \"paused\" ]]; then echo "Resuming previous state..." vboxmanage startvm $VMNAME --type headless if [ $? -ne 0 ]; then ERR="resuming"; fi if [ $VMSTATE == \"paused\" ]; then vboxmanage controlvm $VMNAME pause if [ $? -ne 0 ]; then ERR="pausing"; fi fi fi # Calculate duration duration=$SECONDS duration="Operation took $(($duration / 60)) minutes, $(($duration % 60)) seconds." # Notify the admin if [ "$ERR" == "nothing" ]; then MAILBODY="Virtual Machine $VMNAME was exported succesfully!" MAILBODY="$MAILBODY"$'\n'"$duration" MAILBODY="$MAILBODY"$'\n'"Export filesize: $FILESIZE" MAILSUBJECT="VM $VMNAME succesfully backed up" else MAILBODY="There was an error $ERR VM $VMNAME." if [ "$ERR" == "exporting" ]; then MAILBODY=$(echo $MAILBODY && cat export.log) fi MAILSUBJECT="Error exporting VM $VMNAME" fi # Send the mail echo "$MAILBODY" | mail -s "$MAILSUBJECT" $MYMAIL # Clean up if [ -e export.log ]; then rm export.log; fi done
My HP ProLiant ML370 G4 exports a midsize Windows Server in about an hour. It exports a PfSense router installation in under three minutes. Your mileage may vary so best test the export time needed before taking the script in production.
The web interface you see here is phpVirtualBox, a very handy piece of software to have on your VirtualBox server. Learn how to set it up.