ESXiFTPbackup.sh |
Update - Problems with this method
There are two problems with using this script that you should be aware of...
I would instead recommend you look into using the vmkfstools + NFS option mentioned in this article. If for some reason you still think that FTP is your best choice, contact me and I'll let you know how you can mod this script to do what you want.
- This script assumes that the VMID of the guests start at 1 and increment from there, If I were to write this script over again, I would build an array of the VMIDs currently in use and work off of that array. This could easily be implemented, but I'm abandoning this script because of problem number 2.
- FTP can't handle thin provisioned disks correctly. IE - if you have a guest thin provisioned for 100GB but are only using 8GB, FTP will see the full 100GB and try to copy all 100GB. This will waste time and space on you backup destination. The problem is laid out in more detail here.
I would instead recommend you look into using the vmkfstools + NFS option mentioned in this article. If for some reason you still think that FTP is your best choice, contact me and I'll let you know how you can mod this script to do what you want.
#!/bin/sh
# Version 2.0
#===========================================================================
# FTPbackup.sh requires "ftpput" to be in /bin or /sbin
# http://RichSchreiber.com/uploads/4/4/3/0/4430201/ftpput
#===========================================================================
# Original Script: http://RichSchreiber.com/ftpbackupsh.html
#===========================================================================
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Please set the following variables
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BACKUPLOG='WHQ-ESXi-Test'
# The "BACKUPLOG" is the name that will be used to create a log file
# IE - 'WHQ-ESXi-Test' will make a log file "WHQ-ESXi-Test.log" in the "BACKUPDIR" of the FTP server
FTPHOST=192.168.161.102
FTPUSER=userftp
#FTPPASS='Password With Spaces'
# The "FTPPASS" variable can't contain any spaces, if your password has spaces, you will need to
# manually put the password in the two "putftp" statements below
BACKUPDIR='VMbackups'
# The "BACKUPDIR" variable should point from the FTP root to the folder where you want to create
# the backups. IE - FTProot/VMbackups
# Also, please note that FTPPUT that we use on ESXi is not a full FTP client and it can't create
# directories. You will need to create subdirectories in under $BACKUPDIR, on your FTP server
# for each backed up VM guest, and set permissions for your backup user.
# IE - The VMname is "WinXP-TestPC", you will need to create FTProot/VMbackups/WinXP-TestPC using
# the previous example for $BACKUPDIR
SHUTDOWNWAIT=15
# The "SHUTDOWNWAIT" variable is set in minutes. It is the max amount of time the script should
# wait for a VM guest to shutdown normally. When this wait period is reached, the script will
# issue a power off to the VM guest.
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# End Variable section
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Determine the total number of VM clients on this host
VMCOUNT=`vim-cmd /vmsvc/getallvms | grep -v "^Vmid" | grep "$SERVNAME" | awk '{ print $1 }'|tail -1`
VMID=1
# Begin Creating log file
mv -f /tmp/"$BACKUPLOG".log /tmp/"$BACKUPLOG".old
echo Begining FTP backup of VM guests on "$BACKUPLOG" at "$(date +%Y%m%d-%T)" > /tmp/"$BACKUPLOG".log
echo "-" >> /tmp/"$BACKUPLOG".log
vim-cmd /vmsvc/getallvms | grep -v "Name" | awk -F"[" '{ print $1 }' >> /tmp/"$BACKUPLOG".log
echo "-" >> /tmp/"$BACKUPLOG".log
echo "This will take a while ..." >> /tmp/"$BACKUPLOG".log
echo "-" >> /tmp/"$BACKUPLOG".log
exec >> /tmp/"$BACKUPLOG".log 2>&1
# Repeat for each VM client
while [ $VMID -le $VMCOUNT ]
do
#**************************************************************************************************
# Begin the backup process for each VM client
#**************************************************************************************************
VMNAME=`vim-cmd /vmsvc/getallvms | grep -i "^$VMID " | awk -F" {2,}" '{ print $2 }'`
# awk -F" {2,}" '{ print $2 }'
VMSTAT=`vim-cmd /vmsvc/power.getstate $VMID | grep Powered | awk '{ print $2 }'`
# vms can exist on multiple data stores so...
# grab the entire url line
# e.g.
# url /vmfs/volumes/4c372585-c5be3670-5b7e-001d091edb9f /vmfs/volumes/4c371e81-0c463360-dfe3-001d091edb9f
VMDATASTORES=`vim-cmd /vmsvc/get.datastores $VMID | grep url`
echo "$(date +%T) Datastores for $VMID"
echo "$(date +%T) $VMDATASTORES"
# vmname can be wildly different from vmdir so find vmdir
VMDIR=`vim-cmd /vmsvc/getallvms | grep -i "^$VMID " | awk -F"[]/]" '{ print $2 }' | sed 's/^[[:space:]]*\(.*\)[[:space:]]*$/\1/'`
# get the power status (is it on or off)
VMSTAT=`vim-cmd /vmsvc/power.getstate $VMID | grep Powered | awk '{ print $2 }'`
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Only backup VMs that were originally powered on
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if [ "$VMSTAT" = "on" ]; then
if [ "$VMSTAT" = "off" ]; then
echo "$(date +%T) Server $VMNAME with VMID $VMID is already powered off"
else
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Begin shutdown and wait for VM guest to be fully powered off
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
echo "$(date +%T) Powering off server $VMNAME with ID $VMID"
vim-cmd /vmsvc/power.shutdown $VMID
VMSTAT=on
echo "$(date +%T) Script will wait for $SHUTDOWNWAIT for guest shutdown"
SHUTDOWNCOUNT=0
VMFAIL="no"
echo "$(date +%T) Checking status (now $VMSTAT)"
while [ "$SHUTDOWNCOUNT" -le $SHUTDOWNWAIT ]; do
echo "$(date +%T) wait for $VMNAME to shutdown.. $SHUTDOWNCOUNT minutes"
sleep 60
SHUTDOWNCOUNT=`expr $SHUTDOWNCOUNT + 1`
VMSTAT=`vim-cmd /vmsvc/power.getstate $VMID | grep Powered | awk '{ print $2 }'`
if [ "$VMSTAT" = "off" ]; then
SHUTDOWNCOUNT=`expr $SHUTDOWNWAIT + 1`
echo "$(date +%T) Server $VMNAME with VMID $VMID has successfully shut down!"
else
if [ "$SHUTDOWNCOUNT" -ge $SHUTDOWNWAIT ]; then
echo "$(date +%T) $VMNAME failed to soft shutdown, Powering Off!"
vim-cmd /vmsvc/power.off $VMID
sleep 30
VMSTAT=`vim-cmd /vmsvc/power.getstate $VMID | grep Powered | awk '{ print $2 }'`
if [ "$VMSTAT" = "on" ]; then
VMFAIL='yes'
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "$(date +%T) FAIL- Server $VMNAME with VMID $VMID has failed to powered off, and might need attention!"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
else
echo "$(date +%T) Server $VMNAME with VMID $VMID has successfully shut down!"
fi
fi
fi
done
# ensure to start vm again when it was running:
VMSTAT=on
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Done with power off procedure
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fi
# working around ash bug regarding spaces in files
# echo Ok succesfully changed dir
for j in $VMDATASTORES
do
# vmlocation is the vmdatastore and vmdir
if [ "$j" != "url" ] ; then
VMLOCATE="$j/$VMDIR"
echo "$(date +%T) Location: $VMLOCATE"
echo "$(date +%T) change to vmware dir"
cd "$VMLOCATE" || exit 1
for i in ./*; do
FILE=`echo $i | sed s+\./++`
# Check for failed shutdown, VM guest might be in a funky state
if [ "$VMFAIL" = "no" ]; then
echo "$(date +%T) backup $VMLOCATE/$FILE to $BACKUPDIR/$VMNAME/$FILE on $FTPHOST"
#ftpput $FTPHOST $BACKUPDIR/$VMNAME/$FILE $VMLOCATE/$FILE -u $FTPUSER -p $FTPPASS
ftpput $FTPHOST $BACKUPDIR/$VMNAME/$FILE $VMLOCATE/$FILE -u $FTPUSER -p 'Password With Spaces'
fi
done
fi
done
if [ "$VMSTAT" = "on" ]; then
# vm was on when we started the backup, now start it again
vim-cmd /vmsvc/power.on $VMID
fi
else
echo "$(date +%T) Server $VMNAME with VMID $VMID was powered off - Skipping Backup"
fi
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# End of backup for powered on VMs
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#******************************************************************************************************
# Incriment to the next VMID
#******************************************************************************************************
VMID=`expr $VMID + 1`
done
#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
# Copy log file over to FTP server
#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
echo "$(date +%T) All Finished!"
#ftpput $FTPHOST $BACKUPDIR/$BACKUPLOG.log /tmp/$BACKUPLOG.log -u $FTPUSER -p $FTPPASS
ftpput $FTPHOST $BACKUPDIR/$BACKUPLOG.log /tmp/$BACKUPLOG.log -u $FTPUSER -p 'Password With Spaces'
#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$