Permalink
Browse files

Feature/Bug Fixes for ghettoVCB/ghettoVCB-restore + version control o…

…n github
  • Loading branch information...
1 parent 19e0d4b commit d20e3ebffd1253e902cb884e661b4e69eee50633 lamw committed Nov 28, 2011
Showing with 455 additions and 17 deletions.
  1. +1 −0 README
  2. +391 −0 ghettoVCB-restore.sh
  3. +8 −0 ghettoVCB-restore_vm_restore_configuration_template
  4. +0 −1 ghettoVCB-vm_backup_configuration_template
  5. +1 −1 ghettoVCB.conf
  6. +54 −15 ghettoVCB.sh
View
@@ -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
View
@@ -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}
Oops, something went wrong.

0 comments on commit d20e3eb

Please sign in to comment.