Advertisement
Guest User

Untitled

a guest
Apr 4th, 2011
648
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.36 KB | None | 0 0
  1. # Author: William Lam
  2. # 08/18/2009
  3. # http://www.engineering.ucsb.edu/~duonglt/vmware/
  4. ##################################################################
  5.  
  6. ###### DO NOT EDIT PASS THIS LINE ######
  7.  
  8. LAST_MODIFIED="09/15/2010"
  9.  
  10. printUsage() {
  11. echo "###############################################################################"
  12. echo "#"
  13. echo "# ghettoVCB-restore for ESX/ESXi 3.5u2+ & 4.x+"
  14. echo "# Author: William Lam"
  15. echo "# http://www.engineering.ucsb.edu/~duonglt/vmware/"
  16. echo "# Created: 08/18/2009"
  17. echo "# Last modified: ${LAST_MODIFIED}"
  18. echo "#"
  19. echo "###############################################################################"
  20. echo
  21. echo "Usage: $0 -c [VM_BACKUP_UP_LIST] -l [LOG_FILE]"
  22. echo
  23. echo "OPTIONS:"
  24. echo " -c VM backup list"
  25. echo " -l File ot output logging"
  26. echo
  27. echo "(e.g.)"
  28. echo -e "\nOutput will go to stdout"
  29. echo -e "\t$0 -c vms_to_restore "
  30. echo -e "\nOutput will log to /tmp/ghettoVCB-restore.log"
  31. echo -e "\t$0 -c vms_to_restore -l /tmp/ghettoVCB-restore.log"
  32. echo
  33. exit 1
  34. }
  35.  
  36. logger() {
  37. MSG=$1
  38. if [ "${LOG_TO_STDOUT}" -eq 1 ]; then
  39. echo -e "${MSG}"
  40. else
  41. echo -e "${MSG}" >> "${LOG_OUTPUT}"
  42. fi
  43. }
  44.  
  45. sanityCheck() {
  46. NUM_OF_ARGS=$1
  47.  
  48. if [[ ${NUM_OF_ARGS} -ne 2 ]] && [[ ${NUM_OF_ARGS} -ne 4 ]] && [[ ${NUM_OF_ARGS} -ne 6 ]]; then
  49. printUsage
  50. fi
  51.  
  52. #log to stdout or to logfile
  53. if [ -z "${LOG_OUTPUT}" ]; then
  54. LOG_TO_STDOUT=1
  55. REDIRECT=/dev/null
  56. else
  57. LOG_TO_STDOUT=0
  58. REDIRECT=${LOG_OUTPUT}
  59. echo "Logging output to \"${LOG_OUTPUT}\" ..."
  60. touch "${LOG_OUTPUT}"
  61. fi
  62.  
  63. if [[ "${DEVEL_MODE}" == "1" ]] && [[ "${DEVEL_MODE}" == "2" ]] && [[ "${DEVEL_MODE}" == "0" ]]; then
  64. DEVEL_MODE=0
  65. fi
  66.  
  67. if [ -f /usr/bin/vmware-vim-cmd ]; then
  68. VMWARE_CMD=/usr/bin/vmware-vim-cmd
  69. VMKFSTOOLS_CMD=/usr/sbin/vmkfstools
  70. elif [ -f /bin/vim-cmd ]; then
  71. VMWARE_CMD=/bin/vim-cmd
  72. VMKFSTOOLS_CMD=/sbin/vmkfstools
  73. else
  74. logger "ERROR: Unable to locate *vimsh*! You're not running ESX(i) 3.5+ or 4.x+!"
  75. echo "ERROR: Unable to locate *vimsh*! You're not running ESX(i) 3.5+ or 4.x+!"
  76. exit
  77. fi
  78.  
  79. ESX_VERSION=$(vmware -v | awk '{print $3}')
  80. if [[ "${ESX_VERSION}" == "4.0.0" ]] || [[ "${ESX_VERSION}" == "4.1.0" ]]; then
  81. VER=4
  82. else
  83. ESX_VERSION=$(vmware -v | awk '{print $4}')
  84. if [[ "${ESX_VERSION}" == "3.5.0" ]] || [[ "${ESX_VERSION}" == "3i" ]]; then
  85. VER=3
  86. else
  87. logger "ERROR: You're not running ESX(i) 3.5+ or 4.x+!"
  88. exit
  89. fi
  90. fi
  91.  
  92. if [ ! "`whoami`" == "root" ]; then
  93. logger "ERROR: This script needs to be executed by \"root\"!"
  94. echo "ERROR: This script needs to be executed by \"root\"!"
  95. exit 1
  96. fi
  97.  
  98. #ensure input file exists
  99. if [ ! -f "${CONFIG_FILE}" ]; then
  100. logger "ERROR: \"${CONFIG_FILE}\" input file does not exists\n"
  101. echo -e "ERROR: \"${CONFIG_FILE}\" input file does not exists\n"
  102. exit 1
  103. fi
  104. }
  105.  
  106. startTimer() {
  107. START_TIME=$(date)
  108. S_TIME=$(date +%s)
  109. }
  110.  
  111. endTimer() {
  112. END_TIME=$(date)
  113. E_TIME=$(date +%s)
  114. logger "\nStart time: ${START_TIME}"
  115. logger "End time: ${END_TIME}"
  116. DURATION=$(echo $((E_TIME - S_TIME)))
  117.  
  118. #calculate overall completion time
  119. if [ ${DURATION} -le 60 ]; then
  120. logger "Duration : ${DURATION} Seconds"
  121. else
  122. logger "Duration : $(awk 'BEGIN{ printf "%.2f\n", '${DURATION}'/60}') Minutes\n"
  123. fi
  124. logger "\n---------------------------------------------------------------------------------------------------------------\n"
  125. echo
  126. }
  127.  
  128. ghettoVCBrestore() {
  129. VM_FILE=$1
  130.  
  131. startTimer
  132.  
  133. ORIG_IFS=${IFS}
  134. IFS='
  135. '
  136. for LINE in $(cat "${VM_FILE}" | sed '/^$/d' | sed -e '/^#/d' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//');
  137. do
  138. VM_TO_RESTORE=$(echo "${LINE}" | awk -F ';' '{print $1}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
  139. DATASTORE_TO_RESTORE_TO=$(echo "${LINE}" | awk -F ';' '{print $2}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
  140. RESTORE_DISK_FORMAT=$(echo "${LINE}" | awk -F ';' '{print $3}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
  141.  
  142. #figure the disk format to use
  143. if [ "${RESTORE_DISK_FORMAT}" -eq 1 ]; then
  144. FORMAT_STRING=zeroedthick
  145. elif [ "${RESTORE_DISK_FORMAT}" -eq 2 ]; then
  146. FORMAT_STRING=2gbsparse
  147. elif [ "${RESTORE_DISK_FORMAT}" -eq 3 ]; then
  148. FORMAT_STRING=thin
  149. elif [ "${RESTORE_DISK_FORMAT}" -eq 4 ]; then
  150. FORMAT_STRING=eagerzeroedthick
  151. fi
  152.  
  153. IS_DIR=0
  154. #supports DIR or .TGZ from ghettoVCB.sh ONLY!
  155. if [ -d "${VM_TO_RESTORE}" ]; then
  156. #figure out the contents of the directory (*.vmdk,*-flat.vmdk,*.vmx)
  157. VM_VMX=$(ls "${VM_TO_RESTORE}" | grep ".vmx")
  158. VM_VMDK_DESCRS=$(ls "${VM_TO_RESTORE}" | grep ".vmdk" | grep -v "\-flat.vmdk")
  159. VMDKS_FOUND=$(grep -iE '(scsi|ide)' "${VM_TO_RESTORE}/${VM_VMX}" | grep -i fileName | awk -F " " '{print $1}')
  160. VM_DISPLAY_NAME=$(grep -i "displayName" "${VM_TO_RESTORE}/${VM_VMX}" | awk -F '=' '{print $2}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
  161. VM_ORIG_FOLDER_NAME=$(echo "${VM_TO_RESTORE##*/}")
  162. 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')
  163.  
  164. #figure out the VMDK rename, esepcially important if original backup had VMDKs spread across multiple datastores
  165. #restoration will not support that since I can't assume the original system will be availabl with same ds/etc.
  166. #files will be restored to single VMFS volume without disrupting original backup
  167.  
  168. NUM_OF_VMDKS=0
  169. TMP_IFS=${IFS}
  170. IFS=${ORIG_IFS}
  171. for VMDK in ${VMDKS_FOUND};
  172. do
  173. #extract the SCSI ID and use it to check for valid vmdk disk
  174. SCSI_ID=$(echo ${VMDK%%.*})
  175. grep -i "${SCSI_ID}.present" "${VM_TO_RESTORE}/${VM_VMX}" | grep -i "true" > /dev/null 2>&1
  176. #if valid, then we use the vmdk file
  177. if [ $? -eq 0 ]; then
  178. grep -i "${SCSI_ID}.deviceType" "${VM_TO_RESTORE}/${VM_VMX}" | grep -i "scsi-hardDisk" > /dev/null 2>&1
  179. #if we find the device type is of scsi-disk, then proceed
  180. if [ $? -eq 0 ]; then
  181. DISK=$(grep -i ${SCSI_ID}.fileName "${VM_TO_RESTORE}/${VM_VMX}")
  182. else
  183. #if the deviceType is NULL for IDE which it is, thanks for the inconsistency VMware
  184. #we'll do one more level of verification by checking to see if an ext. of .vmdk exists
  185. #since we can not rely on the deviceType showing "ide-hardDisk"
  186. grep -i ${SCSI_ID}.fileName "${VM_TO_RESTORE}/${VM_VMX}" | grep -i ".vmdk" > /dev/null 2>&1
  187. if [ $? -eq 0 ]; then
  188. DISK=$(grep -i ${SCSI_ID}.fileName "${VM_TO_RESTORE}/${VM_VMX}")
  189. fi
  190. fi
  191.  
  192.  
  193. if [ "${DISK}" != "" ]; then
  194. SCSI_CONTROLLER=$(echo ${DISK} | awk -F '=' '{print $1}')
  195. RENAME_DESTINATION_LINE_VMDK_DISK="${SCSI_CONTROLLER} = \"${VM_DISPLAY_NAME}-${NUM_OF_VMDKS}.vmdk\""
  196. if [ -z "${VMDK_LIST_TO_MODIFY}" ]; then
  197. VMDK_LIST_TO_MODIFY="${DISK},${RENAME_DESTINATION_LINE_VMDK_DISK}"
  198. else
  199. VMDK_LIST_TO_MODIFY="${VMDK_LIST_TO_MODIFY};${DISK},${RENAME_DESTINATION_LINE_VMDK_DISK}"
  200. fi
  201. DISK=''
  202. fi
  203. fi
  204. NUM_OF_VMDKS=$((NUM_OF_VMDKS+1))
  205. done
  206. IFS=${TMP_IFS}
  207. else
  208. logger "Support for .tgz not supported - \"${VM_TO_RESTORE}\" will not be backed up!"
  209. IS_TGZ=1
  210. fi
  211.  
  212. if [ ! "${IS_TGZ}" == "1" ]; then
  213. if [ "${DEVEL_MODE}" == "1" ]; then
  214. logger "\n################ DEBUG MODE ##############"
  215. logger "Virtual Machine: \"${VM_DISPLAY_NAME}\""
  216. logger "VM_VMX: \"${VM_VMX}\""
  217. logger "VM_ORG_FOLDER: \"${VM_ORIG_FOLDER_NAME}\""
  218. logger "VM_FOLDER_NAME: \"${VM_FOLDER_NAME}\""
  219. logger "VMDK_LIST_TO_MODIFY:"
  220. OLD_IFS="${IFS}"
  221. IFS=";"
  222. for i in ${VMDK_LIST_TO_MODIFY}
  223. do
  224. VMDK_1=$(echo $i | awk -F ',' '{print $1}')
  225. VMDK_2=$(echo $i | awk -F ',' '{print $2}')
  226. logger "${VMDK_1}"
  227. logger "${VMDK_2}"
  228. done
  229. unset IFS
  230. IFS="${OLD_IFS}"
  231. logger "##########################################\n"
  232. else
  233. #validates the datastore to restore is valid and available
  234. if [ ! -d "${DATASTORE_TO_RESTORE_TO}" ]; then
  235. logger "ERROR: Unable to verify datastore locateion: \"${DATASTORE_TO_RESTORE_TO}\"! Ensure this exists"
  236. #validates that all 4 required variables are defined before continuing
  237. 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!"
  238. #validates that a directory with the same VM does not already exists
  239. elif [ -d "${DATASTORE_TO_RESTORE_TO}/${VM_FOLDER_NAME}" ]; then
  240. 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!"
  241. else
  242. logger "################## Restoring VM: $VM_DISPLAY_NAME #####################"
  243. if [ "${DEVEL_MODE}" == "2" ]; then
  244. logger "==========> DEBUG MODE LEVEL 2 ENABLED <=========="
  245. fi
  246. logger "Start time: $(date)"
  247. logger "Restoring VM from: \"${VM_TO_RESTORE}\""
  248. logger "Restoring VM to Datastore: \"${DATASTORE_TO_RESTORE_TO}\" using Disk Format: \"${FORMAT_STRING}\""
  249.  
  250. VM_RESTORE_DIR="${DATASTORE_TO_RESTORE_TO}/${VM_FOLDER_NAME}"
  251.  
  252. #create VM folder on datastore if it doesn't already exists
  253. logger "Creating VM directory: \"${VM_RESTORE_DIR}\" ..."
  254. if [ ! "${DEVEL_MODE}" == "2" ]; then
  255. mkdir -p "${VM_RESTORE_DIR}"
  256. fi
  257.  
  258. #copy .vmx file
  259. logger "Copying \"${VM_VMX}\" file ..."
  260. if [ ! "${DEVEL_MODE}" == "2" ]; then
  261. cp "${VM_TO_RESTORE}/${VM_VMX}" "${VM_RESTORE_DIR}/${VM_VMX}"
  262. fi
  263.  
  264. #loop through all VMDK(s) and vmkfstools copy to destination
  265. logger "Restoring VM's VMDK(s) ..."
  266. #MAX=${#ORIGINAL_VMX_VMDK_LINES[*]}
  267. OLD_IFS="${IFS}"
  268. IFS=";"
  269. for i in ${VMDK_LIST_TO_MODIFY}
  270. do
  271. #retrieve individual VMDKs
  272. SOURCE_LINE_VMDK=$(echo "${i}" | awk -F ',' '{print $1}' | awk -F '=' '{print $2}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
  273. DESTINATION_LINE_VMDK=$(echo "${i}" | awk -F ',' '{print $2}' | awk -F '=' '{print $2}' | sed 's/"//g' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
  274. #retrieve individual VMDK lines in .vmx file to update
  275. ORIGINAL_VMX_LINE=$(echo "${i}" | awk -F ',' '{print $1}')
  276. MODIFIED_VMX_LINE=$(echo "${i}" | awk -F ',' '{print $2}')
  277.  
  278. #update restored VM to match VMDKs
  279. logger "Updating VMDK entry in \"${VM_VMX}\" file ..."
  280. if [ ! "${DEVEL_MODE}" == "2" ]; then
  281. sed -i "s#${ORIGINAL_VMX_LINE}#${MODIFIED_VMX_LINE}#g" "${VM_RESTORE_DIR}/${VM_VMX}"
  282. fi
  283.  
  284. echo "${SOURCE_LINE_VMDK}" | grep "/vmfs/volumes" > /dev/null 2>&1
  285. if [ $? -eq 0 ]; then
  286. #SOURCE_VMDK="${SOURCE_LINE_VMDK}"
  287. DS_VMDK_PATH=$(echo "${SOURCE_LINE_VMDK}" | sed 's/\/vmfs\/volumes\///g')
  288. VMDK_DATASTORE=$(echo "${DS_VMDK_PATH%%/*}")
  289. VMDK_VM=$(echo "${DS_VMDK_PATH##*/}")
  290. SOURCE_VMDK="${VM_TO_RESTORE}/${VMDK_DATASTORE}/${VMDK_VM}"
  291. else
  292. SOURCE_VMDK="${VM_TO_RESTORE}/${SOURCE_LINE_VMDK}"
  293. fi
  294. DESTINATION_VMDK="${VM_RESTORE_DIR}/${DESTINATION_LINE_VMDK}"
  295.  
  296. if [ ! "${DEVEL_MODE}" == "2" ]; then
  297. if [ ${RESTORE_DISK_FORMAT} -eq 1 ]; then
  298. if [ "${VER}" == "4" ]; then
  299. ${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -d zeroedthick "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
  300. else
  301. ${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
  302. fi
  303. elif [ ${RESTORE_DISK_FORMAT} -eq 2 ]; then
  304. ${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -d 2gbsparse "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
  305. elif [ ${RESTORE_DISK_FORMAT} -eq 3 ]; then
  306. ${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -d thin "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
  307. elif [ ${RESTORE_DISK_FORMAT} -eq 4 ]; then
  308. if [ "${VER}" == "4" ]; then
  309. ${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -d eagerzeroedthick "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
  310. else
  311. ${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" "${DESTINATION_VMDK}" 2>&1 | tee "${REDIRECT}"
  312. fi
  313. fi
  314. else
  315. logger "\nSOURCE: \"${SOURCE_VMDK}\""
  316. logger "\tORIGINAL_VMX_LINE: -->${ORIGINAL_VMX_LINE}<--"
  317. logger "DESTINATION: \"${DESTINATION_VMDK}\""
  318. logger "\tMODIFIED_VMX_LINE: -->${MODIFIED_VMX_LINE}<--"
  319. fi
  320. done
  321. unset IFS
  322. IFS="${OLD_IFS}"
  323.  
  324. #register VM on ESX(i) host
  325. logger "Registering $VM_DISPLAY_NAME ..."
  326.  
  327. if [ ! "${DEVEL_MODE}" == "2" ]; then
  328. ${VMWARE_CMD} solo/registervm "${VM_RESTORE_DIR}/${VM_VMX}"
  329. fi
  330.  
  331. logger "End time: $(date)"
  332. logger "################## Completed restore for $VM_DISPLAY_NAME! #####################\n"
  333. fi
  334. fi
  335. fi
  336. VMDK_LIST_TO_MODIFY=''
  337. done
  338. unset IFS
  339.  
  340. endTimer
  341. }
  342.  
  343. ####################
  344. # #
  345. # Start of Script #
  346. # #
  347. ####################
  348.  
  349. IS_4I=0
  350.  
  351. if [ ! -f /bin/bash ]; then
  352. IS_4I=1
  353. fi
  354.  
  355. #read user input
  356. while getopts ":c:l:d:" ARGS; do
  357. case $ARGS in
  358. c) CONFIG_FILE="${OPTARG}"
  359. ;;
  360. l)
  361. LOG_OUTPUT="${OPTARG}"
  362. ;;
  363. d)
  364. DEVEL_MODE="${OPTARG}"
  365. ;;
  366. :)
  367. echo "Option -${OPTARG} requires an argument."
  368. exit 1
  369. ;;
  370. *)
  371. usage
  372. exit 1
  373. ;;
  374. esac
  375. done
  376.  
  377. #performs a check on the number of commandline arguments + verifies $2 is a valid file
  378. sanityCheck $#
  379.  
  380. ghettoVCBrestore ${CONFIG_FILE}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement