#!/bin/bash
#
# Backup VM
#
if [ $# -ne 1 ]; then
echo "Usage for $0 : VM Name required as argument."
exit 1
fi
#
if [ $UID -eq 0 ]; then
echo "This script should NOT be run as root."
exit 1
fi
#
# Source config file
if [ ! -f ~/.vbconfig ]; then
echo "Config File ~/.vbconfig not found!"
echo "Run: set-folders to create .vbconfig"
exit 1
fi
. ~/.vbconfig
#
VB_VM_NAME=$1
#
# Configuration parameters
#
# Backup Type
# offline first takes the VM to savestate before backup
# online does a live backup
# offline is faster, safer but has slight downtime
# online is slower but keeps system live
#VB_VM_BACKUP_TYPE="online" # Or offline
VB_VM_BACKUP_TYPE="offline"
#
# Fix number of levels of Backup
# 2 Levels are minimal and sufficient
# 3 is Optimal but you can have as many as desired
VB_VM_MAX_LEVEL=3
#
# Indicate snapshot name prefix.
# Create multiple sets by changing LEVELNAME
LEVELNAME="Level"
#
VB_VM_BUSY_CHK="Y" # or N
#
# Begin Backup processing
#
VM_POWERED_ON=`VBoxManage list runningvms|grep -c '^"'${VB_VM_NAME}'"'`
if [ $VM_POWERED_ON -eq 0 ]; then
echo "Non-running VMs don't require snapshot for backups. Exiting."
exit
fi
#
# Check if VM is idle or busy
if [[ $VB_VM_BUSY_CHK == "Y" ]]; then
VM_STATE=`$VB_BIN_LOC/400-busy-chk-vm.bash $VB_VM_NAME`
if [[ $VM_STATE == "busy" ]]; then
echo "VM is busy. Not doing shapshot. Exiting."
exit 1
fi
fi
#
# Backup Day of Week, Date, Moth
# Day of Week (e.g. Sunday)
VB_VM_BK_DOW="Sunday"
# Date of the Month (e.g. 16th)
VB_VM_BK_DOM="16"
# Date and Month of the Year (e.g. 25th, November)
VB_VM_BK_DOY="25"
VB_VM_BK_MOY="11"
#
if [ $VB_VM_BK_DOM -eq $VB_VM_BK_DOY ]; then
echo "Warning:"
echo "Montly backup date is same as Yearly date"
echo "Avoid the same date to NOT skip one"
echo "Monthly backup each year"
fi
#
# Start with the smallest incremental backup
#
# For daily backups
VB_VM_BACKUP_LEVEL=$VB_VM_MAX_LEVEL
#
# For weekly backups (Sunday)
dayofweek=`date +"%A"`
if [[ $VB_VM_MAX_LEVEL -gt 1 ]]; then
if [[ $dayofweek == $VB_VM_BK_DOW ]]; then
let VB_VM_BACKUP_LEVEL=$VB_VM_MAX_LEVEL-1
fi
fi
#
# For monthly backups (16th day)
daynumber=`date +"%d"`
if [[ $VB_VM_MAX_LEVEL -gt 2 ]]; then
if [[ $daynumber == $VB_VM_BK_DOM ]]; then
let VB_VM_BACKUP_LEVEL=$VB_VM_MAX_LEVEL-2
fi
fi
# For yearly backups (Nov 25th)
# Annual will only kick in if we have VB_VM_MAX_LEVEL > 3
if [[ $VB_VM_MAX_LEVEL -gt 3 ]]; then
if [[ $daynumber == $VB_VM_BK_DOY ]]; then
monthnumber=`date +"%m"`
if [[ $monthnumber == $VB_VM_BK_MOY ]]; then
let VB_VM_BACKUP_LEVEL=$VB_VM_MAX_LEVEL-3
fi
fi
fi
# Check to make sure VB_VM_MAX_LEVEL is not set too low
# Alternatively remove higher level options (yearly)
if [ $VB_VM_BACKUP_LEVEL -lt 1 ]; then
echo "Config error. Inc Max Level"
exit 1
fi
#
# Check current Snapshot Level
# There should always be all level from 1 to VB_VM_MAX_LEVEL
CUR_SS=`VBoxManage snapshot "${VB_VM_NAME}" list --machinereadable \
| grep CurrentSnapshotName|cut -d"\"" -f2`
MAX_SS=${LEVELNAME}_${VB_VM_MAX_LEVEL}
if [[ $MAX_SS != $CUR_SS ]]; then
# Max Level does not exit in SS. This may be the 1st run, so reset
echo "Detecting 1st run ..."
VB_VM_BACKUP_LEVEL=1
else
echo "At Level $VB_VM_BACKUP_LEVEL / $VB_VM_MAX_LEVEL"
fi
#
# Save State
if [[ $VB_VM_BACKUP_TYPE == "offline" ]]; then
echo "Sending VM to savestate ..."
VBoxManage controlvm "${VB_VM_NAME}" savestate
fi
#
echo "Deleting (Merging) Old snapshots ..."
for i in $(eval echo "{${VB_VM_MAX_LEVEL}..${VB_VM_BACKUP_LEVEL}..-1}")
do
SS_NAME=${LEVELNAME}_${i}
# Ignore errors with delete on use the redirect to prevent display
#VBoxManage snapshot "${VB_VM_NAME}" delete $SS_NAME 2> /dev/null
SS_EXISTS=`VBoxManage snapshot "${VB_VM_NAME}" list|grep -c "Name: ${SS_NAME} "`
if [ $SS_EXISTS -gt 0 ]; then
echo "Deleting snapshot $SS_NAME ..."
VBoxManage snapshot "${VB_VM_NAME}" delete $SS_NAME
else
echo "Snapshot $SS_NAME to be deleted does not exist!"
fi
done
#
echo "Taking New snapshots ..."
for i in $(eval echo "{${VB_VM_BACKUP_LEVEL}..${VB_VM_MAX_LEVEL}}")
do
SS_NAME=${LEVELNAME}_${i}
echo "Taking snapshot $SS_NAME ..."
VBoxManage snapshot "${VB_VM_NAME}" take $SS_NAME --live
done
#
if [[ $VB_VM_BACKUP_TYPE == "offline" ]]; then
echo "Powering VM back on ..."
VBoxManage startvm "${VB_VM_NAME}" --type headless
fi
#
exit