mirror of https://github.com/lamw/ghettoVCB.git
Feature/Bug Fixes for ghettoVCB/ghettoVCB-restore + version control on github
This commit is contained in:
parent
19e0d4be55
commit
d20e3ebffd
1
README
1
README
|
@ -3,3 +3,4 @@ Website: http://www.virtuallyghetto.com/
|
|||
|
||||
ghettoVCB Documentation - http://communities.vmware.com/docs/DOC-8760
|
||||
ghettoVCB VMTN Group - http://communities.vmware.com/groups/ghettovcb
|
||||
ghettoVCB Restore Documentation - http://communities.vmware.com/docs/DOC-10595
|
||||
|
|
|
@ -0,0 +1,391 @@
|
|||
# Author: William Lam
|
||||
# 08/18/2009
|
||||
# http://www.virtuallyghetto.com/
|
||||
##################################################################
|
||||
|
||||
###### DO NOT EDIT PASS THIS LINE ######
|
||||
|
||||
LAST_MODIFIED_DATE=2011_11_19
|
||||
VERSION=1
|
||||
VERSION_STRING=${LAST_MODIFIED_DATE}_${VERSION}
|
||||
|
||||
printUsage() {
|
||||
echo "###############################################################################"
|
||||
echo "#"
|
||||
echo "# ghettoVCB-restore for ESX/ESXi 3.5, 4.x+ and 5.0"
|
||||
echo "# Author: William Lam"
|
||||
echo "# http://www.virtuallyghetto.com/"
|
||||
echo "# Documentation: http://communities.vmware.com/docs/DOC-8760"
|
||||
echo "# Created: 08/18/2009"
|
||||
echo "# Last modified: ${VERSION_STRING}"
|
||||
echo "#"
|
||||
echo "###############################################################################"
|
||||
echo
|
||||
echo "Usage: $0 -c [VM_BACKUP_UP_LIST] -l [LOG_FILE] -d [DRYRUN_DEBUG_INFO]"
|
||||
echo
|
||||
echo "OPTIONS:"
|
||||
echo " -c VM backup list"
|
||||
echo " -l File ot output logging"
|
||||
echo " -d Dryrun/Debug Info [1|2]"
|
||||
echo
|
||||
echo "(e.g.)"
|
||||
echo -e "\nOutput will go to stdout"
|
||||
echo -e "\t$0 -c vms_to_restore "
|
||||
echo -e "\nOutput will log to /tmp/ghettoVCB-restore.log"
|
||||
echo -e "\t$0 -c vms_to_restore -l /tmp/ghettoVCB-restore.log"
|
||||
echo -e "\nDryrun/Debug Info (dryrun only)"
|
||||
echo -e "\t$0 -c vms_to_restore -d 1"
|
||||
echo -e "\t$0 -c vms_to_restore -d 2"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
logger() {
|
||||
MSG=$1
|
||||
if [ "${LOG_TO_STDOUT}" -eq 1 ]; then
|
||||
echo -e "${MSG}"
|
||||
else
|
||||
echo -e "${MSG}" >> "${LOG_OUTPUT}"
|
||||
fi
|
||||
}
|
||||
|
||||
sanityCheck() {
|
||||
NUM_OF_ARGS=$1
|
||||
|
||||
if [[ ${NUM_OF_ARGS} -ne 2 ]] && [[ ${NUM_OF_ARGS} -ne 4 ]] && [[ ${NUM_OF_ARGS} -ne 6 ]]; then
|
||||
printUsage
|
||||
fi
|
||||
|
||||
#log to stdout or to logfile
|
||||
if [ -z "${LOG_OUTPUT}" ]; then
|
||||
LOG_TO_STDOUT=1
|
||||
REDIRECT=/dev/null
|
||||
else
|
||||
LOG_TO_STDOUT=0
|
||||
REDIRECT=${LOG_OUTPUT}
|
||||
echo "Logging output to \"${LOG_OUTPUT}\" ..."
|
||||
touch "${LOG_OUTPUT}"
|
||||
fi
|
||||
|
||||
if [[ "${DEVEL_MODE}" == "1" ]] && [[ "${DEVEL_MODE}" == "2" ]] && [[ "${DEVEL_MODE}" == "0" ]]; then
|
||||
DEVEL_MODE=0
|
||||
fi
|
||||
|
||||
if [ -f /usr/bin/vmware-vim-cmd ]; then
|
||||
VMWARE_CMD=/usr/bin/vmware-vim-cmd
|
||||
VMKFSTOOLS_CMD=/usr/sbin/vmkfstools
|
||||
elif [ -f /bin/vim-cmd ]; then
|
||||
VMWARE_CMD=/bin/vim-cmd
|
||||
VMKFSTOOLS_CMD=/sbin/vmkfstools
|
||||
else
|
||||
logger "ERROR: Unable to locate *vimsh*! You're not running ESX(i) 3.5+, 4.x, 5.x!"
|
||||
echo "ERROR: Unable to locate *vimsh*! You're not running ESX(i) 3.5+, 4.x, 5.x!"
|
||||
exit
|
||||
fi
|
||||
|
||||
ESX_VERSION=$(vmware -v | awk '{print $3}')
|
||||
if [ "${ESX_VERSION}" == "5.0.0" ]; then
|
||||
VER=5
|
||||
elif [[ "${ESX_VERSION}" == "4.0.0" ]] || [[ "${ESX_VERSION}" == "4.1.0" ]]; then
|
||||
VER=4
|
||||
else
|
||||
ESX_VERSION=$(vmware -v | awk '{print $4}')
|
||||
if [[ "${ESX_VERSION}" == "3.5.0" ]] || [[ "${ESX_VERSION}" == "3i" ]]; then
|
||||
VER=3
|
||||
else
|
||||
echo "You're not running ESX(i) 3.5, 4.x, 5.x!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! "`whoami`" == "root" ]; then
|
||||
logger "ERROR: This script needs to be executed by \"root\"!"
|
||||
echo "ERROR: This script needs to be executed by \"root\"!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#ensure input file exists
|
||||
if [ ! -f "${CONFIG_FILE}" ]; then
|
||||
logger "ERROR: \"${CONFIG_FILE}\" input file does not exists\n"
|
||||
echo -e "ERROR: \"${CONFIG_FILE}\" input file does not exists\n"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
startTimer() {
|
||||
START_TIME=$(date)
|
||||
S_TIME=$(date +%s)
|
||||
}
|
||||
|
||||
endTimer() {
|
||||
END_TIME=$(date)
|
||||
E_TIME=$(date +%s)
|
||||
logger "\nStart time: ${START_TIME}"
|
||||
logger "End time: ${END_TIME}"
|
||||
DURATION=$(echo $((E_TIME - S_TIME)))
|
||||
|
||||
#calculate overall completion time
|
||||
if [ ${DURATION} -le 60 ]; then
|
||||
logger "Duration : ${DURATION} Seconds"
|
||||
else
|
||||
logger "Duration : $(awk 'BEGIN{ printf "%.2f\n", '${DURATION}'/60}') Minutes\n"
|
||||
fi
|
||||
logger "\n---------------------------------------------------------------------------------------------------------------\n"
|
||||
echo
|
||||
}
|
||||
|
||||
ghettoVCBrestore() {
|
||||
VM_FILE=$1
|
||||
|
||||
startTimer
|
||||
|
||||
ORIG_IFS=${IFS}
|
||||
IFS='
|
||||
'
|
||||
for LINE in $(cat "${VM_FILE}" | sed '/^$/d' | sed -e '/^#/d' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//');
|
||||
do
|
||||
VM_TO_RESTORE=$(echo "${LINE}" | awk -F ';' '{print $1}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
|
||||
DATASTORE_TO_RESTORE_TO=$(echo "${LINE}" | awk -F ';' '{print $2}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
|
||||
RESTORE_DISK_FORMAT=$(echo "${LINE}" | awk -F ';' '{print $3}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
|
||||
|
||||
#figure the disk format to use
|
||||
if [ "${RESTORE_DISK_FORMAT}" -eq 1 ]; then
|
||||
FORMAT_STRING=zeroedthick
|
||||
elif [ "${RESTORE_DISK_FORMAT}" -eq 2 ]; then
|
||||
FORMAT_STRING=2gbsparse
|
||||
elif [ "${RESTORE_DISK_FORMAT}" -eq 3 ]; then
|
||||
FORMAT_STRING=thin
|
||||
elif [ "${RESTORE_DISK_FORMAT}" -eq 4 ]; then
|
||||
FORMAT_STRING=eagerzeroedthick
|
||||
fi
|
||||
|
||||
IS_DIR=0
|
||||
#supports DIR or .TGZ from ghettoVCB.sh ONLY!
|
||||
if [ -d "${VM_TO_RESTORE}" ]; then
|
||||
#figure out the contents of the directory (*.vmdk,*-flat.vmdk,*.vmx)
|
||||
VM_VMX=$(ls "${VM_TO_RESTORE}" | grep ".vmx")
|
||||
VM_VMDK_DESCRS=$(ls "${VM_TO_RESTORE}" | grep ".vmdk" | grep -v "\-flat.vmdk")
|
||||
VMDKS_FOUND=$(grep -iE '(scsi|ide)' "${VM_TO_RESTORE}/${VM_VMX}" | grep -i fileName | awk -F " " '{print $1}')
|
||||
VM_DISPLAY_NAME=$(grep -i "displayName" "${VM_TO_RESTORE}/${VM_VMX}" | awk -F '=' '{print $2}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
|
||||
VM_ORIG_FOLDER_NAME=$(echo "${VM_TO_RESTORE##*/}")
|
||||
VM_FOLDER_NAME=$(echo "${VM_ORIG_FOLDER_NAME}" | sed 's/-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]--[0-1]*//g')
|
||||
|
||||
#figure out the VMDK rename, esepcially important if original backup had VMDKs spread across multiple datastores
|
||||
#restoration will not support that since I can't assume the original system will be availabl with same ds/etc.
|
||||
#files will be restored to single VMFS volume without disrupting original backup
|
||||
|
||||
NUM_OF_VMDKS=0
|
||||
TMP_IFS=${IFS}
|
||||
IFS=${ORIG_IFS}
|
||||
for VMDK in ${VMDKS_FOUND};
|
||||
do
|
||||
#extract the SCSI ID and use it to check for valid vmdk disk
|
||||
SCSI_ID=$(echo ${VMDK%%.*})
|
||||
grep -i "${SCSI_ID}.present" "${VM_TO_RESTORE}/${VM_VMX}" | grep -i "true" > /dev/null 2>&1
|
||||
#if valid, then we use the vmdk file
|
||||
if [ $? -eq 0 ]; then
|
||||
grep -i "${SCSI_ID}.deviceType" "${VM_TO_RESTORE}/${VM_VMX}" | grep -i "scsi-hardDisk" > /dev/null 2>&1
|
||||
#if we find the device type is of scsi-disk, then proceed
|
||||
if [ $? -eq 0 ]; then
|
||||
DISK=$(grep -i ${SCSI_ID}.fileName "${VM_TO_RESTORE}/${VM_VMX}")
|
||||
else
|
||||
#if the deviceType is NULL for IDE which it is, thanks for the inconsistency VMware
|
||||
#we'll do one more level of verification by checking to see if an ext. of .vmdk exists
|
||||
#since we can not rely on the deviceType showing "ide-hardDisk"
|
||||
grep -i ${SCSI_ID}.fileName "${VM_TO_RESTORE}/${VM_VMX}" | grep -i ".vmdk" > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
DISK=$(grep -i ${SCSI_ID}.fileName "${VM_TO_RESTORE}/${VM_VMX}")
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ "${DISK}" != "" ]; then
|
||||
SCSI_CONTROLLER=$(echo ${DISK} | awk -F '=' '{print $1}')
|
||||
RENAME_DESTINATION_LINE_VMDK_DISK="${SCSI_CONTROLLER} = \"${VM_DISPLAY_NAME}-${NUM_OF_VMDKS}.vmdk\""
|
||||
if [ -z "${VMDK_LIST_TO_MODIFY}" ]; then
|
||||
VMDK_LIST_TO_MODIFY="${DISK},${RENAME_DESTINATION_LINE_VMDK_DISK}"
|
||||
else
|
||||
VMDK_LIST_TO_MODIFY="${VMDK_LIST_TO_MODIFY};${DISK},${RENAME_DESTINATION_LINE_VMDK_DISK}"
|
||||
fi
|
||||
DISK=''
|
||||
fi
|
||||
fi
|
||||
NUM_OF_VMDKS=$((NUM_OF_VMDKS+1))
|
||||
done
|
||||
IFS=${TMP_IFS}
|
||||
else
|
||||
logger "Support for .tgz not supported - \"${VM_TO_RESTORE}\" will not be backed up!"
|
||||
IS_TGZ=1
|
||||
fi
|
||||
|
||||
if [ ! "${IS_TGZ}" == "1" ]; then
|
||||
if [ "${DEVEL_MODE}" == "1" ]; then
|
||||
logger "\n################ DEBUG MODE ##############"
|
||||
logger "Virtual Machine: \"${VM_DISPLAY_NAME}\""
|
||||
logger "VM_VMX: \"${VM_VMX}\""
|
||||
logger "VM_ORG_FOLDER: \"${VM_ORIG_FOLDER_NAME}\""
|
||||
logger "VM_FOLDER_NAME: \"${VM_FOLDER_NAME}\""
|
||||
logger "VMDK_LIST_TO_MODIFY:"
|
||||
OLD_IFS="${IFS}"
|
||||
IFS=";"
|
||||
for i in ${VMDK_LIST_TO_MODIFY}
|
||||
do
|
||||
VMDK_1=$(echo $i | awk -F ',' '{print $1}')
|
||||
VMDK_2=$(echo $i | awk -F ',' '{print $2}')
|
||||
logger "${VMDK_1}"
|
||||
logger "${VMDK_2}"
|
||||
done
|
||||
unset IFS
|
||||
IFS="${OLD_IFS}"
|
||||
logger "##########################################\n"
|
||||
else
|
||||
#validates the datastore to restore is valid and available
|
||||
if [ ! -d "${DATASTORE_TO_RESTORE_TO}" ]; then
|
||||
logger "ERROR: Unable to verify datastore locateion: \"${DATASTORE_TO_RESTORE_TO}\"! Ensure this exists"
|
||||
#validates that all 4 required variables are defined before continuing
|
||||
elif [[ -z "${VM_VMX}" ]] && [[ -z "${VM_VMDK_DESCRS}" ]] && [[ -z "${VM_DISPLAY_NAME}" ]] && [[ -z "${VM_FOLDER_NAME}" ]]; then logger "ERROR: Unable to define all required variables: VM_VMX, VM_VMDK_DESCR and VM_DISPLAY_NAME!"
|
||||
#validates that a directory with the same VM does not already exists
|
||||
elif [ -d "${DATASTORE_TO_RESTORE_TO}/${VM_FOLDER_NAME}" ]; then
|
||||
logger "ERROR: Directory \"${DATASTORE_TO_RESTORE_TO}/${VM_FOLDER_NAME}\" looks like it already exists, please check contents and remove directory before trying to restore!"
|
||||
else
|
||||
logger "################## Restoring VM: $VM_DISPLAY_NAME #####################"
|
||||
if [ "${DEVEL_MODE}" == "2" ]; then
|
||||
logger "==========> DEBUG MODE LEVEL 2 ENABLED <=========="
|
||||
fi
|
||||
logger "Start time: $(date)"
|
||||
logger "Restoring VM from: \"${VM_TO_RESTORE}\""
|
||||
logger "Restoring VM to Datastore: \"${DATASTORE_TO_RESTORE_TO}\" using Disk Format: \"${FORMAT_STRING}\""
|
||||
|
||||
VM_RESTORE_DIR="${DATASTORE_TO_RESTORE_TO}/${VM_FOLDER_NAME}"
|
||||
|
||||
#create VM folder on datastore if it doesn't already exists
|
||||
logger "Creating VM directory: \"${VM_RESTORE_DIR}\" ..."
|
||||
if [ ! "${DEVEL_MODE}" == "2" ]; then
|
||||
mkdir -p "${VM_RESTORE_DIR}"
|
||||
fi
|
||||
|
||||
#copy .vmx file
|
||||
logger "Copying \"${VM_VMX}\" file ..."
|
||||
if [ ! "${DEVEL_MODE}" == "2" ]; then
|
||||
cp "${VM_TO_RESTORE}/${VM_VMX}" "${VM_RESTORE_DIR}/${VM_VMX}"
|
||||
fi
|
||||
|
||||
#loop through all VMDK(s) and vmkfstools copy to destination
|
||||
logger "Restoring VM's VMDK(s) ..."
|
||||
#MAX=${#ORIGINAL_VMX_VMDK_LINES[*]}
|
||||
OLD_IFS="${IFS}"
|
||||
IFS=";"
|
||||
for i in ${VMDK_LIST_TO_MODIFY}
|
||||
do
|
||||
#retrieve individual VMDKs
|
||||
SOURCE_LINE_VMDK=$(echo "${i}" | awk -F ',' '{print $1}' | awk -F '=' '{print $2}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
|
||||
DESTINATION_LINE_VMDK=$(echo "${i}" | awk -F ',' '{print $2}' | awk -F '=' '{print $2}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
|
||||
#retrieve individual VMDK lines in .vmx file to update
|
||||
ORIGINAL_VMX_LINE=$(echo "${i}" | awk -F ',' '{print $1}')
|
||||
MODIFIED_VMX_LINE=$(echo "${i}" | awk -F ',' '{print $2}')
|
||||
|
||||
#update restored VM to match VMDKs
|
||||
logger "Updating VMDK entry in \"${VM_VMX}\" file ..."
|
||||
if [ ! "${DEVEL_MODE}" == "2" ]; then
|
||||
sed -i "s#${ORIGINAL_VMX_LINE}#${MODIFIED_VMX_LINE}#g" "${VM_RESTORE_DIR}/${VM_VMX}"
|
||||
fi
|
||||
|
||||
echo "${SOURCE_LINE_VMDK}" | grep "/vmfs/volumes" > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
#SOURCE_VMDK="${SOURCE_LINE_VMDK}"
|
||||
DS_VMDK_PATH=$(echo "${SOURCE_LINE_VMDK}" | sed 's/\/vmfs\/volumes\///g')
|
||||
VMDK_DATASTORE=$(echo "${DS_VMDK_PATH%%/*}")
|
||||
VMDK_VM=$(echo "${DS_VMDK_PATH##*/}")
|
||||
SOURCE_VMDK="${VM_TO_RESTORE}/${VMDK_DATASTORE}/${VMDK_VM}"
|
||||
else
|
||||
SOURCE_VMDK="${VM_TO_RESTORE}/${SOURCE_LINE_VMDK}"
|
||||
fi
|
||||
DESTINATION_VMDK="${VM_RESTORE_DIR}/${DESTINATION_LINE_VMDK}"
|
||||
|
||||
if [ ! "${DEVEL_MODE}" == "2" ]; then
|
||||
ADAPTER_FORMAT=$(grep -i "ddb.adapterType" "${SOURCE_VMDK}" | awk -F "=" '{print $2}' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//;s/"//g')
|
||||
|
||||
if [ ${RESTORE_DISK_FORMAT} -eq 1 ]; then
|
||||
if [[ "${VER}" == "4" ]] || [[ "${VER}" == "5" ]]; then
|
||||
${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -a "${ADAPTER_FORMAT}" -d zeroedthick "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
|
||||
else
|
||||
${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -a "${ADAPTER_FORMAT}" "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
|
||||
fi
|
||||
elif [ ${RESTORE_DISK_FORMAT} -eq 2 ]; then
|
||||
${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -a "${ADAPTER_FORMAT}" -d 2gbsparse "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
|
||||
elif [ ${RESTORE_DISK_FORMAT} -eq 3 ]; then
|
||||
${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -a "${ADAPTER_FORMAT}" -d thin "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
|
||||
elif [ ${RESTORE_DISK_FORMAT} -eq 4 ]; then
|
||||
if [[ "${VER}" == "4" ]] || [[ "${VER}" == "5" ]]; then
|
||||
${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -a "${ADAPTER_FORMAT}" -d eagerzeroedthick "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
|
||||
else
|
||||
${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -a "${ADAPTER_FORMAT}" "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
logger "\nSOURCE: \"${SOURCE_VMDK}\""
|
||||
logger "\tORIGINAL_VMX_LINE: -->${ORIGINAL_VMX_LINE}<--"
|
||||
logger "DESTINATION: \"${DESTINATION_VMDK}\""
|
||||
logger "\tMODIFIED_VMX_LINE: -->${MODIFIED_VMX_LINE}<--"
|
||||
fi
|
||||
done
|
||||
unset IFS
|
||||
IFS="${OLD_IFS}"
|
||||
|
||||
#register VM on ESX(i) host
|
||||
logger "Registering $VM_DISPLAY_NAME ..."
|
||||
|
||||
if [ ! "${DEVEL_MODE}" == "2" ]; then
|
||||
${VMWARE_CMD} solo/registervm "${VM_RESTORE_DIR}/${VM_VMX}"
|
||||
fi
|
||||
|
||||
logger "End time: $(date)"
|
||||
logger "################## Completed restore for $VM_DISPLAY_NAME! #####################\n"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
VMDK_LIST_TO_MODIFY=''
|
||||
done
|
||||
unset IFS
|
||||
|
||||
endTimer
|
||||
}
|
||||
|
||||
####################
|
||||
# #
|
||||
# Start of Script #
|
||||
# #
|
||||
####################
|
||||
|
||||
IS_4I=0
|
||||
|
||||
if [ ! -f /bin/bash ]; then
|
||||
IS_4I=1
|
||||
fi
|
||||
|
||||
#read user input
|
||||
while getopts ":c:l:d:" ARGS; do
|
||||
case $ARGS in
|
||||
c) CONFIG_FILE="${OPTARG}"
|
||||
;;
|
||||
l)
|
||||
LOG_OUTPUT="${OPTARG}"
|
||||
;;
|
||||
d)
|
||||
DEVEL_MODE="${OPTARG}"
|
||||
;;
|
||||
:)
|
||||
echo "Option -${OPTARG} requires an argument."
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
#performs a check on the number of commandline arguments + verifies $2 is a valid file
|
||||
sanityCheck $#
|
||||
|
||||
ghettoVCBrestore ${CONFIG_FILE}
|
|
@ -0,0 +1,8 @@
|
|||
#"<DIRECTORY or .TGZ>;<DATASTORE_TO_RESTORE_TO>;<DISK_FORMAT_TO_RESTORE>"
|
||||
# DISK_FORMATS
|
||||
# 1 = zeroedthick
|
||||
# 2 = 2gbsparse
|
||||
# 3 = thin
|
||||
# 4 = eagerzeroedthick
|
||||
# e.g.
|
||||
# "/vmfs/volumes/dlgCore-NFS-bigboi.VM-Backups/WILLIAM_BACKUPS/STA202I/STA202I-2009-08-18--1;/vmfs/volumes/himalaya-local-SATA.RE4-GP:Storage;1"
|
|
@ -7,7 +7,6 @@ ITER_TO_WAIT_SHUTDOWN=4
|
|||
POWER_DOWN_TIMEOUT=5
|
||||
SNAPSHOT_TIMEOUT=15
|
||||
ENABLE_COMPRESSION=0
|
||||
ADAPTER_FORMAT=buslogic
|
||||
VM_SNAPSHOT_MEMORY=0
|
||||
VM_SNAPSHOT_QUIESCE=0
|
||||
VMDK_FILES_TO_BACKUP="VCAP.vmdk,VCAP_2.vmdk"
|
||||
|
|
|
@ -6,7 +6,6 @@ ENABLE_HARD_POWER_OFF=0
|
|||
ITER_TO_WAIT_SHUTDOWN=3
|
||||
POWER_DOWN_TIMEOUT=5
|
||||
ENABLE_COMPRESSION=0
|
||||
ADAPTER_FORMAT=buslogic
|
||||
VM_SNAPSHOT_MEMORY=0
|
||||
VM_SNAPSHOT_QUIESCE=0
|
||||
ENABLE_NON_PERSISTENT_NFS=0
|
||||
|
@ -20,5 +19,6 @@ EMAIL_LOG=0
|
|||
EMAIL_DEBUG=0
|
||||
EMAIL_SERVER=auroa.primp-industries.com
|
||||
EMAIL_SERVER_PORT=25
|
||||
EMAIL_DELAY_INTERVAL=1
|
||||
EMAIL_TO=auroa@primp-industries.com
|
||||
EMAIL_FROM=root@ghettoVCB
|
||||
|
|
69
ghettoVCB.sh
69
ghettoVCB.sh
|
@ -41,9 +41,6 @@ ENABLE_COMPRESSION=0
|
|||
####### NEW PARAMS #########
|
||||
############################
|
||||
|
||||
# Disk adapter type: buslogic, lsilogic or ide
|
||||
ADAPTER_FORMAT=buslogic
|
||||
|
||||
# Include VMs memory when taking snapshot
|
||||
VM_SNAPSHOT_MEMORY=0
|
||||
|
||||
|
@ -82,6 +79,9 @@ EMAIL_DEBUG=0
|
|||
# Email log 1=yes, 0=no
|
||||
EMAIL_LOG=0
|
||||
|
||||
# Email Delay Interval from NC (netcat) - default 1
|
||||
EMAIL_DELAY_INTERVAL=1
|
||||
|
||||
# Email SMTP server
|
||||
EMAIL_SERVER=auroa.primp-industries.com
|
||||
|
||||
|
@ -104,7 +104,7 @@ VMDK_FILES_TO_BACKUP="all"
|
|||
# default 15min timeout
|
||||
SNAPSHOT_TIMEOUT=15
|
||||
|
||||
LAST_MODIFIED_DATE=2011_06_28
|
||||
LAST_MODIFIED_DATE=2011_11_19
|
||||
VERSION=1
|
||||
VERSION_STRING=${LAST_MODIFIED_DATE}_${VERSION}
|
||||
|
||||
|
@ -117,6 +117,7 @@ printUsage() {
|
|||
echo "# ghettoVCB for ESX/ESXi 3.5, 4.x+ and 5.0"
|
||||
echo "# Author: William Lam"
|
||||
echo "# http://www.virtuallyghetto.com/"
|
||||
echo "# Documentation: http://communities.vmware.com/docs/DOC-8760"
|
||||
echo "# Created: 11/17/2008"
|
||||
echo "# Last modified: ${LAST_MODIFIED_DATE} Version ${VERSION}"
|
||||
echo "#"
|
||||
|
@ -227,18 +228,26 @@ sanityCheck() {
|
|||
fi
|
||||
|
||||
ESX_VERSION=$(vmware -v | awk '{print $3}')
|
||||
if [[ "${ESX_VERSION}" == "4.0.0" ]] || [[ "${ESX_VERSION}" == "4.1.0" ]] || [[ "${ESX_VERSION}" == "5.0.0" ]]; then
|
||||
if [[ "${ESX_VERSION}" == "5.0.0" ]]; then
|
||||
VER=5
|
||||
elif [[ "${ESX_VERSION}" == "4.0.0" ]] || [[ "${ESX_VERSION}" == "4.1.0" ]]; then
|
||||
VER=4
|
||||
else
|
||||
ESX_VERSION=$(vmware -v | awk '{print $4}')
|
||||
if [[ "${ESX_VERSION}" == "3.5.0" ]] || [[ "${ESX_VERSION}" == "3i" ]]; then
|
||||
VER=3
|
||||
else
|
||||
echo "You're not running ESX(i) 3.5+ or 4.x+!"
|
||||
echo "You're not running ESX(i) 3.5, 4.x, 5.x!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
NEW_VIMCMD_SNAPSHOT="no"
|
||||
${VMWARE_CMD} vmsvc/snapshot.remove | grep "snapshotId" > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
NEW_VIMCMD_SNAPSHOT="yes"
|
||||
fi
|
||||
|
||||
if [[ "${EMAIL_LOG}" -eq 1 ]] && [[ -f /usr/bin/nc ]] || [[ -f /bin/nc ]]; then
|
||||
if [ -f /usr/bin/nc ]; then
|
||||
NC_BIN=/usr/bin/nc
|
||||
|
@ -284,7 +293,6 @@ captureDefaultConfigurations() {
|
|||
DEFAULT_POWER_DOWN_TIMEOUT="${POWER_DOWN_TIMEOUT}"
|
||||
DEFAULT_SNAPSHOT_TIMEOUT="${SNAPSHOT_TIMEOUT}"
|
||||
DEFAULT_ENABLE_COMPRESSION="${ENABLE_COMPRESSION}"
|
||||
DEFAULT_ADAPTER_FORMAT="${ADAPTER_FORMAT}"
|
||||
DEFAULT_VM_SNAPSHOT_MEMORY="${VM_SNAPSHOT_MEMORY}"
|
||||
DEFAULT_VM_SNAPSHOT_QUIESCE="${VM_SNAPSHOT_QUIESCE}"
|
||||
DEFAULT_VMDK_FILES_TO_BACKUP="${VMDK_FILES_TO_BACKUP}"
|
||||
|
@ -302,7 +310,6 @@ useDefaultConfigurations() {
|
|||
POWER_DOWN_TIMEOUT="${DEFAULT_POWER_DOWN_TIMEOUT}"
|
||||
SNAPSHOT_TIMEOUT="${DEFAULT_SNAPSHOT_TIMEOUT}"
|
||||
ENABLE_COMPRESSION="${DEFAULT_ENABLE_COMPRESSION}"
|
||||
ADAPTER_FORMAT="${DEFAULT_ADAPTER_FORMAT}"
|
||||
VM_SNAPSHOT_MEMORY="${DEFAULT_VM_SNAPSHOT_MEMORY}"
|
||||
VM_SNAPSHOT_QUIESCE="${DEFAULT_VM_SNAPSHOT_QUIESCE}"
|
||||
VMDK_FILES_TO_BACKUP="all"
|
||||
|
@ -440,7 +447,6 @@ dumpVMConfigurations() {
|
|||
logger "info" "CONFIG - VM_BACKUP_ROTATION_COUNT = ${VM_BACKUP_ROTATION_COUNT}"
|
||||
logger "info" "CONFIG - VM_BACKUP_DIR_NAMING_CONVENTION = ${VM_BACKUP_DIR_NAMING_CONVENTION}"
|
||||
logger "info" "CONFIG - DISK_BACKUP_FORMAT = ${DISK_BACKUP_FORMAT}"
|
||||
logger "info" "CONFIG - ADAPTER_FORMAT = ${ADAPTER_FORMAT}"
|
||||
logger "info" "CONFIG - POWER_VM_DOWN_BEFORE_BACKUP = ${POWER_VM_DOWN_BEFORE_BACKUP}"
|
||||
logger "info" "CONFIG - ENABLE_HARD_POWER_OFF = ${ENABLE_HARD_POWER_OFF}"
|
||||
logger "info" "CONFIG - ITER_TO_WAIT_SHUTDOWN = ${ITER_TO_WAIT_SHUTDOWN}"
|
||||
|
@ -456,6 +462,7 @@ dumpVMConfigurations() {
|
|||
logger "info" "CONFIG - EMAIL_DEBUG = ${EMAIL_DEBUG}"
|
||||
logger "info" "CONFIG - EMAIL_SERVER = ${EMAIL_SERVER}"
|
||||
logger "info" "CONFIG - EMAIL_SERVER_PORT = ${EMAIL_SERVER_PORT}"
|
||||
logger "info" "CONFIG - EMAIL_DELAY_INTERVAL = ${EMAIL_DELAY_INTERVAL}"
|
||||
logger "info" "CONFIG - EMAIL_FROM = ${EMAIL_FROM}"
|
||||
logger "info" "CONFIG - EMAIL_TO = ${EMAIL_TO}"
|
||||
fi
|
||||
|
@ -863,7 +870,7 @@ ghettoVCB() {
|
|||
if [ $? -eq 1 ]; then
|
||||
FORMAT_OPTION="UNKNOWN"
|
||||
if [ "${DISK_BACKUP_FORMAT}" == "zeroedthick" ]; then
|
||||
if [ "${VER}" == "4" ]; then
|
||||
if [[ "${VER}" == "4" ]] || [[ "${VER}" == "5" ]] ; then
|
||||
FORMAT_OPTION="zeroedthick"
|
||||
else
|
||||
FORMAT_OPTION=""
|
||||
|
@ -873,7 +880,7 @@ ghettoVCB() {
|
|||
elif [ "${DISK_BACKUP_FORMAT}" == "thin" ]; then
|
||||
FORMAT_OPTION="thin"
|
||||
elif [ "${DISK_BACKUP_FORMAT}" == "eagerzeroedthick" ]; then
|
||||
if [ "${VER}" == "4" ]; then
|
||||
if [[ "${VER}" == "4" ]] || [[ "${VER}" == "5" ]] ; then
|
||||
FORMAT_OPTION="eagerzeroedthick"
|
||||
else
|
||||
FORMAT_OPTION=""
|
||||
|
@ -888,6 +895,8 @@ ghettoVCB() {
|
|||
tail -f "${VMDK_OUTPUT}" &
|
||||
TAIL_PID=$!
|
||||
|
||||
ADAPTER_FORMAT=$(grep -i "ddb.adapterType" "${SOURCE_VMDK}" | awk -F "=" '{print $2}' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//;s/"//g')
|
||||
|
||||
if [ -z "${FORMAT_OPTION}" ] ; then
|
||||
logger "debug" "${VMKFSTOOLS_CMD} -i \"${SOURCE_VMDK}\" -a \"${ADAPTER_FORMAT}\" \"${DESTINATION_VMDK}\""
|
||||
${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -a "${ADAPTER_FORMAT}" "${DESTINATION_VMDK}" > "${VMDK_OUTPUT}" 2>&1
|
||||
|
@ -919,7 +928,12 @@ ghettoVCB() {
|
|||
|
||||
#powered on VMs only w/snapshots
|
||||
if [[ ${SNAP_SUCCESS} -eq 1 ]] && [[ ! ${POWER_VM_DOWN_BEFORE_BACKUP} -eq 1 ]] && [[ "${ORGINAL_VM_POWER_STATE}" == "Powered on" ]] || [[ "${ORGINAL_VM_POWER_STATE}" == "Suspended" ]]; then
|
||||
${VMWARE_CMD} vmsvc/snapshot.remove ${VM_ID} > /dev/null 2>&1
|
||||
if [ "${NEW_VIMCMD_SNAPSHOT}" == "yes" ]; then
|
||||
SNAPSHOT_ID=$(${VMWARE_CMD} vmsvc/snapshot.get 16 | grep -E '(Snapshot Name|Snapshot Id)' | grep -A1 ${SNAPSHOT_NAME} | grep "Snapshot Id" | awk -F ":" '{print $2}' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
|
||||
${VMWARE_CMD} vmsvc/snapshot.remove ${VM_ID} ${SNAPSHOT_ID} > /dev/null 2>&1
|
||||
else
|
||||
${VMWARE_CMD} vmsvc/snapshot.remove ${VM_ID} > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
#do not continue until all snapshots have been committed
|
||||
logger "info" "Removing snapshot from ${VM_NAME} ..."
|
||||
|
@ -977,6 +991,22 @@ ghettoVCB() {
|
|||
logger "info" "WARN: ${VM_NAME} has some Independent VMDKs that can not be backed up!\n";
|
||||
[[ ${ENABLE_COMPRESSION} -eq 1 ]] && [[ $COMPRESSED_OK -eq 1 ]] || echo "WARN: ${VM_NAME} has some Independent VMDKs that can not be backed up" > ${VM_BACKUP_DIR}/STATUS.warn
|
||||
VMDK_FAILED=1
|
||||
#experimental
|
||||
#create symlink for the very last backup to support rsync functionality for additinal replication
|
||||
if [ "${RSYNC_LINK}" -eq 1 ]; then
|
||||
SYMLINK_DST=${VM_BACKUP_DIR}
|
||||
if [ ${ENABLE_COMPRESSION} -eq 1 ]; then
|
||||
SYMLINK_DST1="${RSYNC_LINK_DIR}.gz"
|
||||
else
|
||||
SYMLINK_DST1=${RSYNC_LINK_DIR}
|
||||
fi
|
||||
SYMLINK_SRC="$(echo "${SYMLINK_DST%*-*-*-*_*-*-*}")-symlink"
|
||||
logger "info" "Creating symlink \"${SYMLINK_SRC}\" to \"${SYMLINK_DST1}\""
|
||||
ln -sf "${SYMLINK_DST1}" "${SYMLINK_SRC}"
|
||||
fi
|
||||
|
||||
#storage info after backup
|
||||
storageInfo "after"
|
||||
else
|
||||
logger "info" "Successfully completed backup for ${VM_NAME}!\n"
|
||||
[[ ${ENABLE_COMPRESSION} -eq 1 ]] && [[ $COMPRESSED_OK -eq 1 ]] || echo "Successfully completed backup" > ${VM_BACKUP_DIR}/STATUS.ok
|
||||
|
@ -993,7 +1023,7 @@ ghettoVCB() {
|
|||
fi
|
||||
SYMLINK_SRC="$(echo "${SYMLINK_DST%*-*-*-*_*-*-*}")-symlink"
|
||||
logger "info" "Creating symlink \"${SYMLINK_SRC}\" to \"${SYMLINK_DST1}\""
|
||||
ln -s "${SYMLINK_DST1}" "${SYMLINK_SRC}"
|
||||
ln -sf "${SYMLINK_DST1}" "${SYMLINK_SRC}"
|
||||
fi
|
||||
|
||||
#storage info after backup
|
||||
|
@ -1073,6 +1103,15 @@ buildHeaders() {
|
|||
sendMail() {
|
||||
#close email message
|
||||
if [ "${EMAIL_LOG}" -eq 1 ]; then
|
||||
#validate firewall has email port open for ESXi 5
|
||||
if [ "${VER}" == "5" ]; then
|
||||
/sbin/esxcli network firewall ruleset rule list | grep "${EMAIL_SERVER_PORT}" > /dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
logger "info" "ERROR: Please enable firewall rule for email traffic on port ${EMAIL_SERVER_PORT}\n"
|
||||
logger "info" "Please refer to ghettoVCB documentation for ESXi 5 firewall configuration\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "${EMAIL_TO}" | grep "," > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
ORIG_IFS=${IFS}
|
||||
|
@ -1080,7 +1119,7 @@ sendMail() {
|
|||
for i in ${EMAIL_TO};
|
||||
do
|
||||
buildHeaders ${i}
|
||||
"${NC_BIN}" "${EMAIL_SERVER}" "${EMAIL_SERVER_PORT}" < "${EMAIL_LOG_CONTENT}" > /dev/null 2>&1
|
||||
"${NC_BIN}" -i "${EMAIL_DELAY_INTERVAL}" "${EMAIL_SERVER}" "${EMAIL_SERVER_PORT}" < "${EMAIL_LOG_CONTENT}" > /dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
logger "info" "ERROR: Failed to email log output to ${EMAIL_SERVER}:${EMAIL_SERVER_PORT} to ${EMAIL_TO}\n"
|
||||
fi
|
||||
|
@ -1088,7 +1127,7 @@ sendMail() {
|
|||
unset IFS
|
||||
else
|
||||
buildHeaders ${EMAIL_TO}
|
||||
"${NC_BIN}" "${EMAIL_SERVER}" "${EMAIL_SERVER_PORT}" < "${EMAIL_LOG_CONTENT}" > /dev/null 2>&1
|
||||
"${NC_BIN}" -i "${EMAIL_DELAY_INTERVAL}" "${EMAIL_SERVER}" "${EMAIL_SERVER_PORT}" < "${EMAIL_LOG_CONTENT}" > /dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
logger "info" "ERROR: Failed to email log output to ${EMAIL_SERVER}:${EMAIL_SERVER_PORT} to ${EMAIL_TO}\n"
|
||||
fi
|
||||
|
|
Loading…
Reference in New Issue