viernes, 4 de julio de 2008

VMware Server Backup



If you are running a virtual machine you can back it up using the script I use that does:
-Stop de virtual machine
-rsync the virtual machine directories
-start the VM (up to here the mahine has been stoped something like 5 minutes (if it is not a huge VM)
-tar the rsync directories
-rsync the backup file to a remote server (optional)
-encrypt the backup file + uploaded to a remote FTP + get an email reporting about the result of the process
-delete old backup files in order to save space on the disks

All this wonderfull features are posible thanks to Gerald Anderson (Left Bain/Hardaur) who initiated all this on an article

The initial script didn't had the encription+ftp+email features so I worked on the code taking pieces of codes from other script

So thank you guys for initiating your job and thank you to have made my script possible.

Here is the script I came up to:


#! /bin/bash
##
## vmsbackup.sh
## Copyright 2008 Gerald D. Anderson
## Licensed under GPL v3, see including LICENSE file.
##
## Version 1.0
## Original: http://www.twobaldgeeks.com/blog/index.php/2007/08/06/vmware-how-do-i-love-thee-let-me-count-the-ways/
##
## ** This is the culmination of work by a number of people, for more information see the above URL. As of 4/13/2008 the
## Project will be hosted a google code with a google group for discussion. Please refer to the following URLs:
##
## Google Code project: http://code.google.com/p/vmsbackup/
## Google Group: http://groups.google.com/group/vmsbackup
##
## Customise these settings:
## -------------------------
## "BACKUP_DEST" where you want the backups to go
## "VMWARE_CMD" the location of vmware-cmd
## "DEBUG" true if you want to see verbose output, else false
## "DAYS_TO_KEEP_TAR" how long before the script removes an old archive
## "BACKUP_ACTIVE_ONLY=true" prevent inactive VMs from being included
## "MODE=suspend" will suspend the VM before backup or
## "MODE=stop" will stop it all together (untested)
## "EXEMPTION_ARRAY" will exclude VMs in any of the specified directories
## "REMOTE_ARCHIVES" if true, will rsync your tar files to a remote host.
## "CLEAN_REMOTE_ARCHIVES" if true, will run rsync with the --delete parameter
## deleting any archive files on remote host that don't exist on this host.
## "REMOTE_ARCHIVE_URL" the remote path parameter for rsync.
##
## Any Virtual Machines in the VMware Server inventory may now be backed up
## by this script however the script WILL fail if you have any spaces in the
## canonical path to the VM. It's now going to be far easier to change your
## directory paths than it is to try and change the way this script handles
## arrays. You can now change your paths and then setup a symlink to the vmx
## file and directory so that VMware server is oblivious to the changed path.
##
## Eg. For a VM located in /mnt/data/Virtual Machines/OS XYZ/OS XYZ.vmx you
## can fix it by changing it to /mnt/data/Virtual_Machines/OS_XYZ/OS_XYZ.vmx
## and then running the following commands to create the symlinks:
## #ln -s /mnt/data/Virtual_Machines /mnt/data/Virtual\ Machines
## #ln -s /mnt/data/Virtual_Machines/OS_XYZ /mnt/data/Virtual\ Machines/OS\ XYZ
## #ln -s /mnt/data/Virtual_Machines/OS_XYZ/OS_XYZ.vmx /mnt/data/Virtual\ Machines/OS\ XYZ/OS\ XYZ.vmx
## (This is also untested ;p)
##
## Warning: It's now possible to have duplicate backup directories for VMs
## with the same directory names. This will result in backups being
## overwritten. This is an outstanding bug yet to be fixed most likely by
## changing the directory naming method.
##
## Thanks to Gerald Anderson (aka Left Bain/Hardaur) for the initial hard work!
##

BACKUP_DEST=/home/backups/destination
VMWARE_CMD=/usr/bin/vmware-cmd
DEBUG=true
DAYS_TO_KEEP_TAR=6
BACKUP_ACTIVE_ONLY=true
MODE=suspend
REMOTE_ARCHIVES=false
CLEAN_REMOTE_ARCHIVES=false
REMOTE_ARCHIVE_URL=rsync.mydomain.com::backup/vmback


#Variables added in order to encryipt the backup, load it to a FTP server and get a report by email.
#This new code encrypt the backup file obtained from the original script, upload it to the FTP server and get
#a report of the whole trhought email
GPG="/usr/bin/gpg" #Where is your Gnupg program?
TAR="/bin/tar" #Where is your tar program?
MAILC="/usr/bin/mail" #Where is your Mail program?
NCFTP="/usr/bin/ncftpput" #Where is your NCFTP program?
MTO="yourmail@here.com" #What is your email?

MSUB="Backup $(hostname) report" #Write you email Subject
GPGU="myGnuPGkeyID" #What is your GnuGP ID for your key?


FTPD="VMbackup/" #What is your FTP directory to put your files?
FTPH="ftp.myftpserver.com" #What is your FTP server
FTPU="myusername tolog to theserver" #What is your FTP username
FTPP="thepasswordtologtotheftpserver" #What is your FTP password?

TMPD="$BACKUP_DEST/archives" #Where is the files to encrypt and upload?


## Include any VMs in this array that you do NOT want backed up. Use
## the directory name. For example: If your vm is in a directory called
## web0 then put 'web0' in the list. Separate with spaces.
EXEMPTION_ARRAY=( )


###########################################################################
## DO NOT EDIT BELOW
###########################################################################

##
## Create the backup directories if they do not exist
##
function doCheckDirectories
{
## if BACKUP_DEST does not exist, create it
if [ ! -d $BACKUP_DEST ]; then

if [ "$DEBUG" = "true" ]; then
echo $BACKUP_DEST does not exist, creating.
fi

mkdir $BACKUP_DEST
fi

## if the archives directory does not exist, create it
if [ ! -d $BACKUP_DEST/archives ]; then

if [ "$DEBUG" = "true" ]; then
echo $BACKUP_DEST/archives does not exist, creating.
fi

mkdir $BACKUP_DEST/archives
fi

## if the directories directory does not exist, create it
if [ ! -d $BACKUP_DEST/directories ]; then

if [ "$DEBUG" = "true" ]; then
echo $BACKUP_DEST/directories does not exist, creating.
fi

mkdir $BACKUP_DEST/directories

fi
}

##
## If this VM is in our exempt array, set VM_EXEMPT to skip entirely.
##
function doCheckExempt
{
# iterate throught the array, if we get a match, set
# VM_EXEMPT to true
for check_vm in ${EXEMPTION_ARRAY[@]}; do

if [ "$check_vm" = "$directoryName" ]; then

if [ "$DEBUG" = "true" ]; then
echo $vm is on the exception list, skipping.
fi

VM_EXEMPT=true
fi
done
}

##
## Set the displayName from the vmx file
##
function setDisplayName
{
# get the line from the file
displayLine=`grep displayName "$1"`

# get the quoted name from it
quotedName=${displayLine#*=}

# and get rid of the quotes and spaces
displayName=${quotedName//[\" ]/} #" <- for syntax highlighting

if [ "$DEBUG" = "true" ]; then
echo $vm displayName is $displayName
fi
}

##
## Set the directoryName from the path
##
function setDirectoryName
{
# remove traling / and filename
directoryPath=${vm%/*}

# remove the begining of the path
directoryName=${directoryPath##*/}

if [ "$DEBUG" = "true" ]; then
echo $vm directoryName is $directoryName
fi
}

##
## suspend a VM if its running, skip it if not
##
function suspendVM
{
# get the current VM state
vmstate=`$VMWARE_CMD -q "$vm" getstate`

if [ "$DEBUG" = "true" ]; then
echo $displayName state is currently: $vmstate
fi

# if its running, suspend it, otherwise, move on.
if [ "$vmstate" = "on" ]; then

if [ "$DEBUG" = "true" ]; then
echo suspending $displayName - MODE=$MODE . . .
fi

# make sure it actually suspends
if [ `$VMWARE_CMD -q "$vm" $MODE hard` == 1 ]; then

# track if it was running, so I can restart or not
VM_WAS_RUNNING=true

if [ "$DEBUG" = "true" ]; then
echo $displayName Suspended at `date '+%F %T'`
fi

return
else
echo $vm DID NOT SUSPEND!! Exiting Program.
exit 0
fi
else
if [ "$DEBUG" = "true" ]; then
echo $displayName was not originally active, no need to restart
fi
fi
}

##
## backup the VM
##
function doBackup
{
# synchronise (update) all data to the directories tree
if [ "$DEBUG" = "true" ]; then
echo Backing up $displayName to $BACKUP_DEST/directories/$directoryName
rsync -vax --progress --numeric-ids --delete "$directoryPath" "$BACKUP_DEST/directories/$directoryName"
else
rsync -ax --numeric-ids --delete "$directoryPath" "$BACKUP_DEST/directories/$directoryName"
fi
}

##
## Resume the VM if it was running in the first place
##
function resumeVM
{
if [ "$VM_WAS_RUNNING" = "true" ]; then
if [ "$DEBUG" = "true" ]; then
echo Resuming $displayName at `date '+%F %T'`
fi

if [ `$VMWARE_CMD -q "$vm" start` == 1 ]; then

if [ "$DEBUG" = "true" ]; then
echo $displayName restarted
fi
else
echo $vm FAILED TO RESUME!! NOT Exiting Program.
#exit 0
fi

else
if [ "$DEBUG" = "true" ]; then
echo $displayName wasnt running in the first place, not resuming.
fi
fi
}

##
## tgz up the directory for a more compressed and mobile backup.
##
function doTar
{

fileName=backup_$displayName'_'`/bin/date +%d-%m-%Y_%H-%M-%S`.tgz

if [ "$DEBUG" = "true" ]; then
echo taring up $displayName to $fileName
$TAR -cvPpszf "$BACKUP_DEST/archives/$fileName" "$BACKUP_DEST/directories/$directoryName"
else
$TAR -cpPszf "$BACKUP_DEST/archives/$fileName" "$BACKUP_DEST/directories/$directoryName"
fi

}

##
## Clean up any tars that are older than DAYS_TO_KEEP_TAR
##
function doCleanTar
{
if [ "$DEBUG" = "true" ]; then
echo Cleaning up tars older than $DAYS_TO_KEEP_TAR
find "$BACKUP_DEST/archives" -name "backup_$displayName*.tgz" -ctime +$DAYS_TO_KEEP_TAR -exec rm -vf {} \;
else
find "$BACKUP_DEST/archives" -name "backup_$displayName*.tgz" -ctime +$DAYS_TO_KEEP_TAR -exec rm -vf {} \;
fi
}

##
## Copy my archives to a remote host via rsync
##
function doRemoteArchives
{
if [ "$DEBUG" = "true" ]; then
echo Copying archives to remote location.
if [ "$CLEAN_REMOTE_ARCHIVES" = "true" ]; then
rsync -vaxz --progress --stats --numeric-ids --delete "$BACKUP_DEST/archives/" "$REMOTE_ARCHIVE_URL"
else
rsync -vaxz --progress --stats --numeric-ids "$BACKUP_DEST/archives/" "$REMOTE_ARCHIVE_URL"
fi
else
if [ "$CLEAN_REMOTE_ARCHIVES" = "true" ]; then
rsync -axz --numeric-ids --delete "$BACKUP_DEST/archives/" "$REMOTE_ARCHIVE_URL"
else
rsync -axz --numeric-ids "$BACKUP_DEST/archives/" "$REMOTE_ARCHIVE_URL"
fi
fi
}

##
## Main Loop, iterate through the VMs and handle them apprpriately
##

# make sure we have the appropriate directories for backups
doCheckDirectories

#for vm_noncanon in $(vmware-cmd -l); do
$VMWARE_CMD -l | while read file; do

#This one line below is necessary to treat vm_noncanon as one string instead of multiple
vm_noncanon=$file

#Get the canonical path to the Virtual Machine (remove any symlinks)
vm=`readlink -f "$vm_noncanon"`

# reset variables for this VM
VM_WAS_RUNNING=false
VM_EXEMPT=false

if [ "$DEBUG" = "true" ]; then
echo ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
echo Current VM is $vm
fi

# get my display and directory names, for use in tar name, etc.
setDisplayName "$vm"
setDirectoryName "$vm"

# check to see if current vm should be exempted
doCheckExempt

# only back up if it is not on the exempt list
if [ "$VM_EXEMPT" = "false" ]; then

# suspend my VM if its running
suspendVM

if [ "$BACKUP_ACTIVE_ONLY" = "false" ] || [ "$VM_WAS_RUNNING" = "true" ]; then
# actually do the directory backup
doBackup

# resume the VM if it was running to begin with
resumeVM


##########################
####New code added########
##########################

if [ ! -x $TAR ]; then
echo "$TAR command not found, contact $ADMIN_INFO"
exit 1
fi

if [ ! -x $NCFTP ]; then
echo "$NCFTP command not found, contact $ADMIN_INFO"
exit 1
fi

if [ ! -x $GPG ] ; then
echo "$GPG command not found, contact $ADMIN_INFO"
exit 1
fi

# tar it up
doTar


##########################
####New code added########
##########################
OUT="$TMPD/$fileName"
FOUT="$OUT.gpg"
MFILE="/tmp/ftpout.$$.txt"
MESS=""

if [ $? -ne 0 ];
then
MESS="$TAR failed to create backup. Nothing uploaded to remote FTP $FTPH server"
else
# Encrypt the .tar.gz file before upload
$GPG -e -r $GPGU -o $FOUT $OUT
$NCFTP -m -u "$FTPU" -p "$FTPP" "$FTPH" "$FTPD" "$FOUT"
OSTAT="$?"
case $OSTAT in
0) MESS="Success.";;
1) MESS="Could not connect to remote host $FTPH.";;
2) MESS="Could not connect to remote host $FTPH - timed out.";;
3) MESS="Transfer failed.";;
4) MESS="Transfer failed - timed out.";;
5) MESS="Directory change failed.";;
6) MESS="Directory change failed - timed out.";;
7) MESS="Malformed URL.";;
8) MESS="Usage error. May be your version of ncftpput ($NCFTP) is old";;
9) MESS="Error in login configuration file.";;
10)MESS="Library initialization failed.";;
11) MESS="Session initialization failed.";;
*) MESS="Unknown error, contact admin $ADMIN_INFO";;
esac
fi

>$MFILE
echo "Backup status for $(hostname) as on $(date):" >>$MFILE
echo "" >>$MFILE
echo "Backup File : $FOUT" >>$MFILE
echo "Backup ftp server : $FTPH" >>$MFILE
echo "Backup status message : $MESS" >>$MFILE
echo "" >>$MFILE
echo "-- Automatically generated by $(basename $0)" >>$MFILE

# send an email to admin
$MAILC -s "$MSUB" $MTO <$MFILE # remove the files: you can comment the bellow lines with '#' at your convenience [ -f $MFILE ] && rm -f $MFILE || : #[ -f $FOUT ] && rm -f $FOUT || : #[ -f $OUT ] && rm -f $OUT || : # and finally, clean up my old tars doCleanTar fi fi done if [ "$REMOTE_ARCHIVES" = "true" ]; then doRemoteArchives fi

No hay comentarios: