Romain Tiennot

Technicien Superieur en Informatique

Aller au contenu | Aller au menu | Aller à la recherche

Keyword - VM_ID

Fil des billets

Création de Snapshot automatique

esxi_4.1.jpg
J’ai conçu un script permettant d’effectuer des snapshots en se basant sur un fichier nommé « listSnapshot » ou il est indiqué les noms des machines virtuelles. De plus, il créé un fichier de log qui sera automatiquement envoyé par email. On peut y voir l’état des machines virtuelles, l’ID des machines virtuelles et si le snapshot s’est fait correctement.

Dans mon cas, le script va :

  • Lire le fichier texte nommé listSnapshot
  • Indiquer les l'ID des machines à sauvegarder dans un répertoire "vms_list" dans "/tmp"
  • L'etat de la machines virtuelles
  • Créer un fichier de log
  • Envoi le fichier de log par email

Dans un premier temps, il faut transferer gràce à WinSCP le fichier "snapshot.sh" dans le répertoire :"/vmfs/volumes/<datastore1>/" puis le rendre exécutable en SSH : (pour activer le SSH, vous pouvez consulter mon article))

chmod +x snapshot.sh

Ensuite, il faut créer le fichier "listSnapshot" avec la commande :

vi listSnapshot

Indiquer le nom des machinves virtuelles sous la forme suivante :

VM01
VM02
VM03

Sauvegarder et quitter gràce à ":wq".

Pour effectuer la sauvegarde, il faut saisir la commande suivante en SSH :

./sauvegarde.sh

Pour automatiser l’execution des scripts, il existe sous linux « Cron » qui est l’equivalent des taches planifié sous Windows. Sous Esxi, le fichier de configuration se trouve « /var/spool/cron/crontabs/root ». J’ai rajouté deux lignes à la suite indiquant : Executer le script « snapshot.sh » en tenant compte du fichier « listSnapshot » du Lundi au Vendredi à 22h01

0 20 * * 1-4 /vmfs/volumes/4d2aed1f-7a700542-ecbc-00237d9db922/snapshot.sh


Pour que le fichier de configuration cron soit pris en compte, il faut redemarrer le service avec les commandes suivante :

Kill $(cat /vaar/run/crond.pid)

Busybox crond
Attention, lors du prochain redemarrage, le fichier de configuration cron sera reinitialisé. Pour eviter de perdre la configuration, j’ai rajouté dans le script de demarrage du serveur quatre ligne qui rajoutera automatiquement les lignes de configuration dans le fichier cron et redemarrera le service :

/bin/kill $(cat /var/run/crond.pid)
/bin/echo "0 20 * * 1-4 /vmfs/volumes/4d2aed1f-7a700542-ecbc-00237d9db922/snapshot.sh" >> /var/spool/cron/crontabs/root
/bin/busybox crond
#!/bin/sh
#############################################################################
#		Debut du fichier de log												#
#############################################################################
export jour=$(date '+%A %d %B %Y')
export log=$(date +%D)
export log2=$(date '+%d%m%y')
export heure=$(($(date +%H)+2))
export minute=$(date '+%M:%S')
echo -en "HELO ESXI\n" >> /tmp/snap_$log2
echo -en "MAIL FROM: <ESXI@tiennot.fr>\n" >> /tmp/snap_$log2
echo -en "RCPT TO: <romain@tiennot.fr>\n" >> /tmp/snap_$log2
echo -en "RCPT TO: <admin@tiennot.fr>\n" >> /tmp/snap_$log2
echo -en "DATA\n" >> /tmp/snap_$log2
echo -en "From: ESXI@tiennot.fr\n" >> /tmp/snap_$log2
echo -en "To: romain@tiennot.fr\n" >> /tmp/snap_$log2
echo -en "To: admin@tiennot.fr\n" >> /tmp/snap_$log2
echo -en "Subject: ESXI - " >> /tmp/snap_$log2
echo -en $jour" - "$heure":"$minute >> /tmp/snap_$log2
echo -en "\n" >> /tmp/snap_$log2
echo -en "\n" >> /tmp/snap_$log2
echo -en "############################## Début du SCRIPT ##############################\n" >> /tmp/snap_$log2
 
#############################################################################
#		Boucle fichier - Création du snapshot								#
#############################################################################
#création de la variable du chemin vim-cmd
export VMWARE_CMD=/bin/vim-cmd
${VMWARE_CMD} vmsvc/getallvms | sed 's/[[:blank:]]\{3,\}/   /g' | awk -F'   ' '{print "\""$1"\";\""$2"\";\""$3"\""}' |  sed 's/\] /\]\";\"/g' | sed '1,1d' > /tmp/vms_list
#debut de la boucle qui lit ligne par ligne
while read line
do
export jour=$(date '+%A %d %B %Y')
export log=$(date +%D)
export log2=$(date '+%d%m%y')
export heure=$(($(date +%H)+2))
export minute=$(date '+%M:%S')
NUM_VM=$((NUM_VM + 1))
echo -en "--------------------------------- "$NUM_VM". "$line" -------------------------------\n" >> /tmp/snap_$log2
#affiche ce qu'il y a ecrit sur la ligne:nom de la machine virtuelle
echo -en $log" - "$heure":$(date '+%M:%S') || info : Nom de la machine Virtuelle : "$line".\n" >> /tmp/snap_$log2
#cherche l'ID de la machine virtuelle
${VMWARE_CMD} vmsvc/getallvms | sed 's/[[:blank:]]{3,}/ /g' | awk -F' ' '{}' | sed 's/] /]";"/g' | sed '1,1d'
#création de la variable de l'ID de la machine virtuelle
export VM_ID=`grep -E ""${line}"" /tmp/vms_list | awk -F ";" '{print $1}' | sed 's/"//g'`
if [[ "${VM_ID}" = "" ]]; then
echo -en $log" - "$heure":$(date '+%M:%S') || info : ERREUR, "$line" n'existe pas.\n" >> /tmp/snap_$log2
echo -en "\n" >> /tmp/snap_$log2
continue
fi
#affiche l'ID de la machine virtuelle
echo -en $log" - "$heure":$(date '+%M:%S') || info : ID de la machine Virtuelle : "$VM_ID".\n" >> /tmp/snap_$log2
#création de la variable du Status de la machine virtuelle
ORGINAL_VM_POWER_STATE=$(${VMWARE_CMD} vmsvc/power.getstate ${VM_ID} | tail -1)
#affiche le status de la machine virtuelle
if [[ "${ORGINAL_VM_POWER_STATE}" = "Powered off" ]]; then
VM_ETAT="Eteint"
fi
if [[ "${ORGINAL_VM_POWER_STATE}" = "Powered on" ]]; then
VM_ETAT="Allumé"
fi
if [[ "${ORGINAL_VM_POWER_STATE}" = "Suspended" ]]; then
VM_ETAT="Suspendu"
fi
echo -en $log" - "$heure":$(date '+%M:%S') || info : Etat de la machine Virtuelle : "$VM_ETAT".\n" >> /tmp/snap_$log2
NOM_SNAP="ESXI_"$line"_"$(date +%D)
echo -en $log" - "$heure":$(date '+%M:%S') || info : Création du Snapshot "$NOM_SNAP" pour "$line".\n" >> /tmp/snap_$log2
${VMWARE_CMD} vmsvc/snapshot.create ${VM_ID} "${NOM_SNAP}" "${NOM_SNAP}" > /dev/null 2>&1
echo -en $log" - "$heure":$(date '+%M:%S') || debug : Merci de patienter durant la création du snapshot : "$NOM_SNAP".\n" >> /tmp/snap_$log2
echo -en $log" - "$heure":$(date '+%M:%S') || debug : Succès, le snapshot a été créé.\n" >> /tmp/snap_$log2
echo -en "\n" >> /tmp/snap_$log2
done < "/vmfs/volumes/4d27644c-244cadc9-7b49-000c297ad13c/listSnapshot"
 
#############################################################################
#		Fin du fichier de log												#
#############################################################################
echo -en "\n" >> /tmp/snap_$log2
echo -en "############################## Fin du SCRIPT ##############################\n" >> /tmp/snap_$log2
echo -en "\n" >> /tmp/snap_$log2
echo -en "\n" >> /tmp/snap_$log2
echo -en "." >> /tmp/snap_$log2
 
"/usr/bin/nc" "SERVEUR_SMTP" "25" < "/tmp/snap_$log2"

Voici la vidéo :

A bientôt, Romain

Sauvegarder automatique machine virtuelle sous ESXi 4.1 et 5.0

esxi_4.1.jpg Pour eviter de perdre nos machines virtuelles, je vais vous montrer comment sauvegarder les machines virtuelles en se basant sur un fichier texte ou l'on indique les noms des VM.

Pour effectuer ce script, je me suis basé sur celui de ghettoVCB disponible sur le site VMware.

Dans mon cas, le script va :

  • Lire le fichier texte nommé listSauvegarde
  • Indiquer les l'ID des machines à sauvegarder dans un répertoire "vms_list" dans "/tmp"
  • Avec l'ID il va supprimer l'ensemble des snapshots (obligatoire pour sauvegarder les VM)
  • Créer un fichier de log
  • Envoi le fichier de log par email
  • Création d'une arborescence claire pour la sauvegarde

Dans un premier temps, il faut transferer gràce à WinSCP le fichier "sauvegarde.sh" dans le répertoire :"/vmfs/volumes/<datastore1>/" puis le rendre exécutable en SSH : (pour activer le SSH, vous pouvez consulter mon article))

chmod +x sauvegarde.sh

Ensuite, il faut créer le fichier "listSauvegarde" avec la commande :

vi listSauvegarde

Indiquer le nom des machinves virtuelles sous la forme suivante :

VM01
VM02
VM03

Sauvegarder et quitter gràce à ":wq".

Pour effectuer la sauvegarde, il faut saisir la commande suivante en SSH :

./sauvegarde.sh –f listSauvegarde

Pour automatiser l’execution des scripts, il existe sous linux « Cron » qui est l’equivalent des taches planifié sous Windows. Sous Esxi, le fichier de configuration se trouve « /var/spool/cron/crontabs/root ». J’ai rajouté deux lignes à la suite indiquant : Executer le script « sauvegarde.sh » en tenant compte du fichier « listeSauvegarde » le Vendredi à 22h01

« 0 20 * * 5 /vmfs/volumes/4d2aed1f-7a700542-ecbc-00237d9db922/sauvegarde.sh -f /vmfs/volumes/4d2aed1f-7a700542-ecbc-00237d9db922/listSauvegarde »


Pour que le fichier de configuration cron soit pris en compte, il faut redemarrer le service avec les commandes suivante :

Kill $(cat /vaar/run/crond.pid)

Busybox crond
Attention, lors du prochain redemarrage, le fichier de configuration cron sera reinitialisé. Pour eviter de perdre la configuration, j’ai rajouté dans le script de demarrage du serveur quatre ligne qui rajoutera automatiquement les lignes de configuration dans le fichier cron et redemarrera le service :

/bin/kill $(cat /var/run/crond.pid)
/bin/echo "0 20 * * 5 /vmfs/volumes/4d2aed1f-7a700542-ecbc-00237d9db922/sauvegarde.sh -f /vmfs/volumes/4d2aed1f-7a700542-ecbc-00237d9db922/listSauvegarde" >> /var/spool/cron/crontabs/root
/bin/busybox crond

Voici le script commenté : (Champ à modifier jusqu'a la ligne 125)

export VMWARE_CMD=/bin/vim-cmd
while read line
do
echo "VM_NAME: $line"
# get VM_ID
${VMWARE_CMD} vmsvc/getallvms | sed 's/[[:blank:]]{3,}/ /g' | awk -F' ' '{}' | sed 's/] /]";"/g' | sed '1,1d'
export VM_ID=`grep -E ""${line}"" /tmp/vms_list | awk -F ";" '{print $1}' | sed 's/"//g'`
echo "VM_ID: $VM_ID"
${VMWARE_CMD} vmsvc/snapshot.removeall $VM_ID
echo "--------------------"
done < /vmfs/volumes/4d27644c-244cadc9-7b49-000c297ad13c/listSauvegarde # Chemin du fichier listSauvegarde
 
 
 
##################################################################
# Author: William Lam
# Created Date: 11/17/2008
# http://www.virtuallyghetto.com/
# http://communities.vmware.com/docs/DOC-8760
##################################################################
 
# directory that all VM backups should go (e.g. /vmfs/volumes/SAN_LUN1/mybackupdir)
VM_BACKUP_VOLUME=/vmfs/volumes/Sauvegarde
 
# Format output of VMDK backup
# zeroedthick
# 2gbsparse
# thin
# eagerzeroedthick
DISK_BACKUP_FORMAT=thin
 
# Number of backups for a given VM before deleting
VM_BACKUP_ROTATION_COUNT=1
 
# Shutdown guestOS prior to running backups and power them back on afterwards
# This feature assumes VMware Tools are installed, else they will not power down and loop forever
# 1=on, 0 =off
POWER_VM_DOWN_BEFORE_BACKUP=0
 
# enable shutdown code 1=on, 0 = off
ENABLE_HARD_POWER_OFF=0
 
# if the above flag "ENABLE_HARD_POWER_OFF "is set to 1, then will look at this flag which is the # of iterations
# the script will wait before executing a hard power off, this will be a multiple of 60seconds 
# (e.g) = 3, which means this will wait up to 180seconds (3min) before it just powers off the VM
ITER_TO_WAIT_SHUTDOWN=3
 
# Number of iterations the script will wait before giving up on powering down the VM and ignoring it for backup
# this will be a multiple of 60 (e.g) = 5, which means this will wait up to 300secs (5min) before it gives up
POWER_DOWN_TIMEOUT=5
 
# enable compression with gzip+tar 1=on, 0=off
ENABLE_COMPRESSION=0
 
############################
####### NEW PARAMS #########
############################
 
# Disk adapter type: buslogic, lsilogic or ide
ADAPTER_FORMAT=buslogic
 
# Include VMs memory when taking snapshot
VM_SNAPSHOT_MEMORY=1
 
# Quiesce VM when taking snapshot (requires VMware Tools to be installed)
VM_SNAPSHOT_QUIESCE=1
 
##########################################################
# NON-PERSISTENT NFS-BACKUP ONLY
# 
# ENABLE NON PERSISTENT NFS BACKUP 1=on, 0=off
 
ENABLE_NON_PERSISTENT_NFS=1
 
# umount NFS datastore after backup is complete 1=yes, 0=no
UNMOUNT_NFS=0
 
# IP Address of NFS Server
NFS_SERVER="172.16.0.254"
 
# Path of exported folder residing on NFS Server (e.g. /some/mount/point )
NFS_MOUNT=/ESXI
 
# Non-persistent NFS datastore display name of choice
NFS_LOCAL_NAME=Sauvegarde
 
# Name of backup directory for VMs residing on the NFS volume
NFS_VM_BACKUP_DIR=ESXI
 
############################
######### EMAIL ############
############################ 
 
# Email debug 1=yes, 0=no
EMAIL_DEBUG=1
 
# Email log 1=yes, 0=no 
EMAIL_LOG=1
 
# Email SMTP server
EMAIL_SERVER=172.16.0.253
 
# Email SMTP server port
EMAIL_SERVER_PORT=25
 
# Email FROM
EMAIL_FROM=ESXI@tiennot.fr
 
# Email RCPT
EMAIL_TO=romain@tiennot.fr
########################## DO NOT MODIFY PAST THIS LINE ##########################
 
# RSYNC LINK 1=yes, 0 = no
RSYNC_LINK=0
 
LOG_LEVEL="info"
VMDK_FILES_TO_BACKUP="all"
# default 15min timeout
SNAPSHOT_TIMEOUT=15
 
LAST_MODIFIED_DATE=09/28/2010
VER=1
 
# Directory naming convention for backup rotations (please ensure there are no spaces!)
VM_BACKUP_DIR_NAMING_CONVENTION="$(date +%F_%H-%M-%S)"
 
printUsage() {
        echo "###############################################################################"
        echo "#"
        echo "# Script de sauvegarde ESXI"
        echo "# Author: William Lam"
        echo "# Modifier: Romain Tiennot"
        echo "# http://romain.tiennot.fr/"
        echo "# Created: 19/02/2011"
        echo "# Last modified: ${LAST_MODIFIED_DATE} version ${VER}"
        echo "#"
        echo "###############################################################################"
        echo
        echo "Usage: $0 -f [VM_BACKUP_UP_LIST] -c [VM_CONFIG_DIR] -l [LOG_FILE] -d [DEBUG_LEVEL] -g [GLOBAL_CONF] -e [VM_EXCLUSION_LIST]"
        echo
        echo "OPTIONS:"
	echo "   -a     Backup all VMs on host"
        echo "   -f     List of VMs to backup"
	echo "   -c     VM configuration directory for VM backups"
	echo "   -g     Path to global ghettoVCB configuration file"
        echo "   -l     File to output logging"
	echo "   -d     Debug level [info|debug|dryrun] (default: info)"
        echo
        echo "(e.g.)"
        echo -e "\nBackup VMs stored in a list"
        echo -e "\t$0 -f vms_to_backup"
	echo -e "\nBackup all VMs residing on this host"
        echo -e "\t$0 -a"
	echo -e "\nBackup all VMs residing on this host except for the VMs in the exclusion list"
        echo -e "\t$0 -a -e vm_exclusion_list"
	echo -e "\nBackup VMs based on specific configuration located in directory"
        echo -e "\t$0 -f vms_to_backup -c vm_backup_configs"
	echo -e "\nBackup VMs using global ghettoVCB configuration file"
        echo -e "\t$0 -f vms_to_backup -g /global/ghettoVCB.conf"
        echo -e "\nOutput will log to /tmp/ghettoVCB.log"
        echo -e "\t$0 -f vms_to_backup -l /tmp/ghettoVCB.log"
	echo -e "\nDry run (no backup will take place)"
        echo -e "\t$0 -f vms_to_backup -d dryrun"
        echo
        exit 1
}
 
logger() {
	LOG_TYPE=$1
        MSG=$2
 
	if [[ "${LOG_LEVEL}" == "debug" ]] && [[ "${LOG_TYPE}" == "debug" ]] || [[ "${LOG_TYPE}" == "info" ]] || [[ "${LOG_TYPE}" == "dryrun" ]]; then
		TIME=$(date +%F" "%H:%M:%S)
       		if [ "${LOG_TO_STDOUT}" -eq 1 ]; then
               		echo -e "${TIME} -- ${LOG_TYPE}: ${MSG}"
        	else
       	        	echo -e "${TIME} -- ${LOG_TYPE}: ${MSG}" >> "${LOG_OUTPUT}"
		fi
 
		if [ "${EMAIL_LOG}" -eq 1 ]; then
			echo -ne "${TIME} -- ${LOG_TYPE}: ${MSG}\r\n" >> "${EMAIL_LOG_OUTPUT}"		
		fi
	fi
}
 
sanityCheck() {
        NUM_OF_ARGS=$1
 
	if [ "${USE_GLOBAL_CONF}" -eq 1 ]; then
                reConfigureGhettoVCBConfiguration "${GLOBAL_CONF}"
        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 [[ ${NUM_OF_ARGS} -lt 1 ]] || [[ ${NUM_OF_ARGS} -gt 12 ]]; then
		logger "info" "ERROR: Incorrect number of arguments!"
                printUsage
        fi
 
	if [[ ! -f "${VM_FILE}" ]] && [[ "${USE_VM_CONF}" -eq 0 ]] && [[ "${BACKUP_ALL_VMS}" -eq 0 ]]; then
		logger "info" "ERROR: \"${VM_FILE}\" is not valid VM input file!"
		printUsage
	fi
 
	if [[ ! -f "${VM_EXCLUSION_FILE}" ]] && [[ "${EXCLUDE_SOME_VMS}" -eq 1 ]]; then
		logger "info" "ERROR: \"${VM_EXCLUSION_FILE}\" is not valid VM exclusion input file!"
		printUsage
	fi
 
 	if [[ ! -d "${CONFIG_DIR}" ]] && [[ "${USE_VM_CONF}" -eq 1 ]]; then
		logger "info" "ERROR: \"${CONFIG_DIR}\" is not valid directory!"
                printUsage
       	fi
 
	if [[ ! -f "${GLOBAL_CONF}" ]] && [[ "${USE_GLOBAL_CONF}" -eq 1 ]]; then
		logger "info" "ERROR: \"${GLOBAL_CONF}\" is not valid global configuration file!"
                printUsage
        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 "info" "ERROR: Unable to locate *vimsh*! You're not running ESX(i) 3.5+ or 4.0+!"
                echo "ERROR: Unable to locate *vimsh*! You're not running ESX(i) 3.5+ or 4.0+!"
                exit 1
        fi
 
        ESX_VERSION=$(vmware -v | awk '{print $3}')
        if [[ "${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.0+!"
                        exit 1
                fi
        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
		elif [ -f /bin/nc ]; then 
			NC_BIN=/bin/nc
		fi
                echo -ne "HELO $(hostname -s)\r\n" >> "${EMAIL_LOG_OUTPUT}"
                echo -ne "MAIL FROM: <${EMAIL_FROM}>\r\n" >> "${EMAIL_LOG_OUTPUT}"
                echo -ne "RCPT TO: <${EMAIL_TO}>\r\n" >> "${EMAIL_LOG_OUTPUT}"
                echo -ne "DATA\r\n" >> "${EMAIL_LOG_OUTPUT}"
		echo -ne "From: ${EMAIL_FROM}\r\n" >> "${EMAIL_LOG_OUTPUT}"
		echo -ne "To: ${EMAIL_TO}\r\n" >> "${EMAIL_LOG_OUTPUT}"
		echo -ne "Subject: ESXI - $(date)\r\n" >> "${EMAIL_LOG_OUTPUT}" 
        else 
		EMAIL_LOG=0
	fi
 
        if [ ${ENABLE_NON_PERSISTENT_NFS} -eq 1 ]; then
                ${VMWARE_CMD} hostsvc/summary/fsvolume | awk '{print $1}' | grep "^${NFS_LOCAL_NAME}" > /dev/null 2>&1
                if [ ! $? -eq 0 ]; then
                        #1 = readonly
                        #0 = readwrite
                        ${VMWARE_CMD} hostsvc/datastore/nas_create "${NFS_LOCAL_NAME}" "${NFS_SERVER}" "${NFS_MOUNT}" 0
                fi
        fi
 
        if [ ! "`whoami`" == "root" ]; then
                logger "info" "This script needs to be executed by \"root\"!"
		echo "ERROR: This script needs to be executed by \"root\"!"
                exit 1
        fi
}
 
startTimer() {
        START_TIME=$(date)
        S_TIME=$(date +%s)
}
 
endTimer() {
        END_TIME=$(date)
        E_TIME=$(date +%s)
        DURATION=$(echo $((E_TIME - S_TIME)))
 
        #calculate overall completion time
        if [ ${DURATION} -le 60 ]; then
                logger "info" "Backup Duration: ${DURATION} Seconds"
        else
                logger "info" "Backup Duration: $(awk 'BEGIN{ printf "%.2f\n", '${DURATION}'/60}') Minutes"
        fi
}
 
captureDefaultConfigurations() {
	DEFAULT_VM_BACKUP_VOLUME="${VM_BACKUP_VOLUME}"
	DEFAULT_DISK_BACKUP_FORMAT="${DISK_BACKUP_FORMAT}"
	DEFAULT_VM_BACKUP_ROTATION_COUNT="${VM_BACKUP_ROTATION_COUNT}"
	DEFAULT_POWER_VM_DOWN_BEFORE_BACKUP="${POWER_VM_DOWN_BEFORE_BACKUP}"
	DEFAULT_ENABLE_HARD_POWER_OFF="${ENABLE_HARD_POWER_OFF}"
	DEFAULT_ITER_TO_WAIT_SHUTDOWN="${ITER_TO_WAIT_SHUTDOWN}"
	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}"
	DEFAULT_EMAIL_LOG="${EMAIL_LOG}"
	DEFAULT_EMAIL_DEBUG="${EMAIL_DEBUG}"
}
 
useDefaultConfigurations() {
	VM_BACKUP_VOLUME="${DEFAULT_VM_BACKUP_VOLUME}"
	DISK_BACKUP_FORMAT="${DEFAULT_DISK_BACKUP_FORMAT}"
	VM_BACKUP_ROTATION_COUNT="${DEFAULT_VM_BACKUP_ROTATION_COUNT}"
	POWER_VM_DOWN_BEFORE_BACKUP="${DEFAULT_POWER_VM_DOWN_BEFORE_BACKUP}"
	ENABLE_HARD_POWER_OFF="${DEFAULT_ENABLE_HARD_POWER_OFF}"
	ITER_TO_WAIT_SHUTDOWN="${DEFAULT_ITER_TO_WAIT_SHUTDOWN}"
	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"
	EMAIL_LOG=0
	EMAIL_DEBUG=0
}
 
reConfigureGhettoVCBConfiguration() {
	GLOBAL_CONF=$1
 
	if [ -f "${GLOBAL_CONF}" ]; then
                . "${GLOBAL_CONF}"
        else
                useDefaultConfigurations
        fi
}
 
reConfigureBackupParam() {
        VM=$1
 
        if [ -e "${CONFIG_DIR}/${VM}" ]; then
                logger "info" "CONFIG - USING CONFIGURATION FILE = ${CONFIG_DIR}/${VM}"
                . "${CONFIG_DIR}/${VM}"
        else
                useDefaultConfigurations
        fi
}
 
dumpHostInfo() {
	logger "debug" "HOST BUILD: $(vmware -v)"
	logger "debug" "HOSTNAME: $(hostname)\n"
}
 
findVMDK() {
        VMDK_TO_SEARCH_FOR=$1
 
	if [ "${USE_VM_CONF}" -eq 1 ]; then
		logger "debug" "findVMDK() - Searching for VMDK: \"${VMDK_TO_SEARCH_FOR}\" to backup"
 
		OLD_IFS2="${IFS}"
        	IFS=","
	        for k in ${VMDK_FILES_TO_BACKUP}
        	do
                	VMDK_FILE=$(echo $k | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//')
		        if [ "${VMDK_FILE}" == "${VMDK_TO_SEARCH_FOR}" ]; then
				logger "debug" "findVMDK() - Found VMDK! - \"${VMDK_TO_SEARCH_FOR}\" to backup"
        	                isVMDKFound=1
			fi	
	        done
		IFS="{OLD_IFS2}"
	fi
}
 
getVMDKs() {
	#get all VMDKs listed in .vmx file
        VMDKS_FOUND=`grep -iE '(scsi|ide)' "${VMX_PATH}" | grep -i fileName | awk -F " " '{print $1}'`

        TMP_IFS=${IFS}
        IFS=${ORIG_IFS}
        #loop through each disk and verify that it's currently present and create array of valid VMDKS
        for DISK in ${VMDKS_FOUND};
        do
        	#extract the SCSI ID and use it to check for valid vmdk disk
                SCSI_ID=`echo ${DISK%%.*}`
                grep -i "${SCSI_ID}.present" "${VMX_PATH}" | grep -i "true" > /dev/null 2>&1
                #if valid, then we use the vmdk file
                if [ $? -eq 0 ]; then
			#verify disk is not independent
			grep -i "${SCSI_ID}.mode" "${VMX_PATH}" | grep -i "independent" > /dev/null 2>&1 
			if [ $? -eq 1 ]; then
	                	grep -i "${SCSI_ID}.deviceType" "${VMX_PATH}" | 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 "${VMX_PATH}" | awk -F "\"" '{print $2}'`
                                	VMDKS="${DISK}:${VMDKS}"
	                        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 "${VMX_PATH}" | grep -i ".vmdk" > /dev/null 2>&1
	                                if [ $? -eq 0 ]; then
        	                	        DISK=`grep -i ${SCSI_ID}.fileName "${VMX_PATH}" | awk -F "\"" '{print $2}'`
                	                        VMDKS="${DISK}:${VMDKS}"
                        	        fi
                        	fi
			fi
                fi
         done
         IFS=${TMP_IFS}
}
 
dumpVMConfigurations() {
	logger "info" "CONFIG - GHETTOVCB_PID = ${GHETTOVCB_PID}"
	logger "info" "CONFIG - VM_BACKUP_VOLUME = ${VM_BACKUP_VOLUME}"
        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}"
	logger "info" "CONFIG - POWER_DOWN_TIMEOUT = ${POWER_DOWN_TIMEOUT}"
	logger "info" "CONFIG - SNAPSHOT_TIMEOUT = ${SNAPSHOT_TIMEOUT}"
        logger "info" "CONFIG - LOG_LEVEL = ${LOG_LEVEL}"
	if [ -z "${LOG_OUTPUT}" ]; then
		logger "info" "CONFIG - BACKUP_LOG_OUTPUT = stdout"
	else
		logger "info" "CONFIG - BACKUP_LOG_OUTPUT = ${LOG_OUTPUT}"
	fi
        logger "info" "CONFIG - VM_SNAPSHOT_MEMORY = ${VM_SNAPSHOT_MEMORY}"
        logger "info" "CONFIG - VM_SNAPSHOT_QUIESCE = ${VM_SNAPSHOT_QUIESCE}"
        logger "info" "CONFIG - VMDK_FILES_TO_BACKUP = ${VMDK_FILES_TO_BACKUP}"
	logger "info" "CONFIG - EMAIL_LOG = ${EMAIL_LOG}"
	if [ "${EMAIL_LOG}" -eq 1 ]; then
		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_FROM = ${EMAIL_FROM}"
		logger "info" "CONFIG - EMAIL_TO = ${EMAIL_TO}"
	fi
	logger "info" "\n"
}
 
checkVMBackupRotation() {
	local BACKUP_DIR_PATH=$1
 
	#default rotation if variable is not defined
        if [ -z ${VM_BACKUP_ROTATION_COUNT} ]; then
                VM_BACKUP_ROTATION_COUNT=1
        fi
 
	LIST_BACKUPS=$(ls -t "${BACKUP_DIR_PATH}")
	BACKUPS_TO_KEEP=$(ls -t "${BACKUP_DIR_PATH}" | head -"${VM_BACKUP_ROTATION_COUNT}")
 
	ORIG_IFS=${IFS}
        IFS='
'
        for i in ${LIST_BACKUPS};
        do
                FOUND=0
                for j in ${BACKUPS_TO_KEEP};
                do
                        if [ $i == $j ]; then
                                FOUND=1
                        fi
                done
 
                if [ $FOUND -eq 0 ]; then
			logger "debug" "Removing $BACKUP_DIR_PATH/$i"
			rm -rf "$BACKUP_DIR_PATH/$i"
 
			#NFS I/O error handling hack
			if [ $? -ne 0 ]; then
				NFS_IO_HACK_COUNTER=0
				NFS_IO_HACK_STATUS=0
				NFS_IO_HACK_FILECHECK="$BACKUP_DIR_PATH/nfs_io.check"		
 
				while [ "${NFS_IO_HACK_STATUS}" -eq 0 -a "${NFS_IO_HACK_COUNTER}" -lt 60 ]; 
				do
					sleep 1
					NFS_IO_HACK_COUNTER=$((NFS_IO_HACK_COUNTER+1))
					touch "${NFS_IO_HACK_FILECHECK}"
 
					if [ $? -eq 0 ]; then
						NFS_IO_HACK_STATUS=1
					fi	
				done
 
				rm -rf "${NFS_IO_HACK_FILECHECK}"
 
				if [ "${NFS_IO_HACK_STATUS}"  -eq 1 ]; then
					logger "info" "Slept ${NFS_IO_HACK_COUNTER} seconds to work around NFS I/O error"
				else 
					logger "info" "Slept ${NFS_IO_HACK_COUNTER} seconds but failed work around for NFS I/O error"
				fi
			fi
                fi
        done
	IFS=${ORIG_IFS}
}
 
ghettoVCB() {
	VM_INPUT=$1
	VM_OK=0
	VM_FAILED=0
	VMDK_FAILED=0
 
	captureDefaultConfigurations
 
	dumpHostInfo	
 
	if [ "${USE_GLOBAL_CONF}" -eq 1 ]; then
		logger "info" "CONFIG - USING GLOBAL GHETTOVCB CONFIGURATION FILE = ${GLOBAL_CONF}"
	fi
 
	if [ "${USE_VM_CONF}" -eq 0 ]; then
		dumpVMConfigurations
	fi
 
	#dump out all virtual machines allowing for spaces now
	${VMWARE_CMD} vmsvc/getallvms | sed 's/[[:blank:]]\{3,\}/   /g' | awk -F'   ' '{print "\""$1"\";\""$2"\";\""$3"\""}' |  sed 's/\] /\]\";\"/g' | sed '1,1d' > /tmp/vms_list

	if [ "${BACKUP_ALL_VMS}" -eq 1 ]; then
		${VMWARE_CMD} vmsvc/getallvms | sed 's/[[:blank:]]\{3,\}/   /g' | awk -F'   ' '{print ""$2""}' | sed '1,1d' | sed '/^$/d' > "${VM_INPUT}"
	fi
 
	ORIG_IFS=${IFS}
	IFS='
'
	for VM_NAME in `cat "${VM_INPUT}" | grep -v "#" | sed '/^$/d' | sed -e 's/^[[:blank:]]*//;s/[[:blank:]]*$//'`;
        do
		IGNORE_VM=0
		if [ "${EXCLUDE_SOME_VMS}" -eq 1 ]; then
			grep -E "${VM_NAME}" "${VM_EXCLUSION_FILE}" > /dev/null 2>&1
			if [ $? -eq 0 ]; then
				IGNORE_VM=1
			fi
		fi
 
		VM_ID=`grep -E "\"${VM_NAME}\"" /tmp/vms_list | awk -F ";" '{print $1}' | sed 's/"//g'`

		#ensure default value if one is not selected or variable is null
                if [ -z ${VM_BACKUP_DIR_NAMING_CONVENTION} ]; then
                        VM_BACKUP_DIR_NAMING_CONVENTION="$(date +%F_%k-%M-%S)"
                fi
 
		if [[ "${USE_VM_CONF}" -eq 1 ]] && [[ ! -z ${VM_ID} ]]; then
                        reConfigureBackupParam "${VM_NAME}"
                        dumpVMConfigurations
                fi
 
		VMFS_VOLUME=`grep -E "\"${VM_NAME}\"" /tmp/vms_list | awk -F ";" '{print $3}' | sed 's/\[//;s/\]//;s/"//g'`
		VMX_CONF=`grep -E "\"${VM_NAME}\"" /tmp/vms_list | awk -F ";" '{print $4}' | sed 's/\[//;s/\]//;s/"//g'`
		VMX_PATH="/vmfs/volumes/${VMFS_VOLUME}/${VMX_CONF}"
		VMX_DIR=`dirname "${VMX_PATH}"`
 
		#ignore VM as it's in the exclusion list
		if [ "${IGNORE_VM}" -eq 1 ]; then 
			logger "debug" "Ignoring ${VM_NAME} for backup since its located in exclusion list\n"			
		#checks to see if we can pull out the VM_ID
		elif [ -z ${VM_ID} ]; then
			logger "info" "ERROR: failed to locate and extract VM_ID for ${VM_NAME}!\n"
			VM_FAILED=1
 
		elif [ "${LOG_LEVEL}" == "dryrun" ]; then
			logger "dryrun" "###############################################"
			logger "dryrun" "Virtual Machine: $VM_NAME"
			logger "dryrun" "VM_ID: $VM_ID"
			logger "dryrun" "VMX_PATH: $VMX_PATH"
			logger "dryrun" "VMX_DIR: $VMX_DIR"
			logger "dryrun" "VMX_CONF: $VMX_CONF"
			logger "dryrun" "VMFS_VOLUME: $VMFS_VOLUME"
			logger "dryrun" "VMDK(s): "
			getVMDKs
			OLD_IFS="${IFS}"
                        IFS=":"
                        for j in ${VMDKS};
                        do
				logger "dryrun" "\t${j}"
			done
			IFS="${OLD_IFS}"
			VMDKS=""	
			logger "dryrun" "###############################################\n"
 
                #checks to see if the VM has any snapshots to start with
                elif ls "${VMX_DIR}" | grep -q delta > /dev/null 2>&1; then
	                logger "info" "Snapshot found for ${VM_NAME}, backup will not take place\n"
			VM_FAILED=1
 
                elif [[ -f "${VMX_PATH}" ]] && [[ ! -z "${VMX_PATH}" ]]; then
		 	#nfs case and backup to root path of your NFS mount 	
	                if [ ${ENABLE_NON_PERSISTENT_NFS} -eq 1 ] ; then 
	                	BACKUP_DIR="/vmfs/volumes/${NFS_LOCAL_NAME}/${NFS_VM_BACKUP_DIR}/${VM_NAME}"
                                if [[ -z ${VM_NAME} ]] || [[ -z ${NFS_LOCAL_NAME} ]] || [[ -z ${NFS_VM_BACKUP_DIR} ]]; then
                                        logger "info" "ERROR: Variable BACKUP_DIR was not set properly, please ensure all required variables for non-persistent NFS backup option has been defined"
                                        exit 1
                                fi
 
	              	#non-nfs (SAN,LOCAL)  	
	                else
	                	BACKUP_DIR="${VM_BACKUP_VOLUME}/${VM_NAME}"
                                if [[ -z ${VM_BACKUP_VOLUME} ]]; then
                                        logger "info" "ERROR: Variable VM_BACKUP_DIR was not defined"
                                        exit 1
                                fi
	                fi
 
			#initial root VM backup directory
			if [ ! -d "${BACKUP_DIR}" ]; then
				mkdir -p "${BACKUP_DIR}"
				if [ ! -d "${BACKUP_DIR}" ]; then
					logger "info" "Unable to create \"${BACKUP_DIR}\"! - Ensure VM_BACKUP_VOLUME was defined correctly"
					exit 1
				fi
	                fi
 
			# directory name of the individual Virtual Machine backup followed by naming convention followed by count
			VM_BACKUP_DIR="${BACKUP_DIR}/${VM_NAME}-${VM_BACKUP_DIR_NAMING_CONVENTION}"
			mkdir -p "${VM_BACKUP_DIR}"
 
			cp "${VMX_PATH}" "${VM_BACKUP_DIR}"
 
			#extract all valid VMDK(s) from VM
			getVMDKs
 
			ORGINAL_VM_POWER_STATE=$(${VMWARE_CMD} vmsvc/power.getstate ${VM_ID} | tail -1)
			CONTINUE_TO_BACKUP=1	
 
			#section that will power down a VM prior to taking a snapshot and backup and power it back on
			if [ ${POWER_VM_DOWN_BEFORE_BACKUP} -eq 1 ]; then
				START_ITERATION=0
				logger "info" "Powering off initiated for ${VM_NAME}, backup will not begin until VM is off..."
 
				${VMWARE_CMD} vmsvc/power.shutdown ${VM_ID} > /dev/null 2>&1
				while ${VMWARE_CMD} vmsvc/power.getstate ${VM_ID} | grep -i "Powered on" > /dev/null 2>&1;
				do
					#enable hard power off code
					if [ ${ENABLE_HARD_POWER_OFF} -eq 1 ]; then
						if [ ${START_ITERATION} -ge ${ITER_TO_WAIT_SHUTDOWN} ]; then
							logger "info" "Hard power off occured for ${VM_NAME}, waited for $((ITER_TO_WAIT_SHUTDOWN*60)) seconds" 
							${VMWARE_CMD} vmsvc/power.off ${VM_ID} > /dev/null 2>&1 
							#this is needed for ESXi, even the hard power off did not take affect right away
							sleep 60
							break
						fi
					fi
 
					logger "info" "VM is still on - Iteration: ${START_ITERATION} - sleeping for 60secs (Duration: $((START_ITERATION*60)) seconds)"
        	                        sleep 60
 
					#logic to not backup this VM if unable to shutdown
					#after certain timeout period
					if [ ${START_ITERATION} -ge ${POWER_DOWN_TIMEOUT} ]; then
						logger "info" "Unable to power off ${VM_NAME}, waited for $((POWER_DOWN_TIMEOUT*60)) seconds! Ignoring ${VM_NAME} for backup!"
						VM_FAILED=1
						CONTINUE_TO_BACKUP=0
						break
					fi
					START_ITERATION=$((START_ITERATION + 1))
				done
				if [ ${CONTINUE_TO_BACKUP} -eq 1 ]; then
					logger "info" "VM is powerdOff"
				fi
			fi
 
			if [ ${CONTINUE_TO_BACKUP} -eq 1 ]; then 
				logger "info" "Initiate backup for ${VM_NAME}"
				startTimer
 
				SNAP_SUCCESS=1
				VM_VMDK_FAILED=0
 
				#powered on VMs only
                        	if [[ ! ${POWER_VM_DOWN_BEFORE_BACKUP} -eq 1 ]] && [[ "${ORGINAL_VM_POWER_STATE}" != "Powered off" ]]; then
					SNAPSHOT_NAME="ghettoVCB-snapshot-$(date +%F)"
					logger "info" "Creating Snapshot \"${SNAPSHOT_NAME}\" for ${VM_NAME}"
        	                        ${VMWARE_CMD} vmsvc/snapshot.create ${VM_ID} "${SNAPSHOT_NAME}" "${SNAPSHOT_NAME}" "${VM_SNAPSHOT_MEMORY}" "${VM_SNAPSHOT_QUIESCE}" > /dev/null 2>&1
 
					logger "debug" "Waiting for snapshot \"${SNAPSHOT_NAME}\" to be created"
					logger "debug" "Snapshot timeout set to: $((SNAPSHOT_TIMEOUT*60)) seconds"
                                        START_ITERATION=0
					while [ $(${VMWARE_CMD} vmsvc/snapshot.get ${VM_ID} | wc -l) -eq 1 ]
					do
						if [ ${START_ITERATION} -ge ${SNAPSHOT_TIMEOUT} ]; then
							logger "info" "Snapshot timed out, failed to create snapshot: \"${SNAPSHOT_NAME}\" for ${VM_NAME}"
							SNAP_SUCCESS=0
							break
						fi
 
						logger "debug" "Waiting for snapshot creation to be completed - Iteration: ${START_ITERATION} - sleeping for 60secs (Duration: $((START_ITERATION*30)) seconds)"
                                                sleep 60
 
						START_ITERATION=$((START_ITERATION + 1))
					done
                	        fi
 
				if [ ${SNAP_SUCCESS} -eq 1 ]; then 
					OLD_IFS="${IFS}"
					IFS=":"
					for j in ${VMDKS};
					do
						VMDK="${j}"
						isVMDKFound=0
 
						findVMDK "${VMDK}"
 
						if [[ $isVMDKFound -eq 1 ]] || [[ "${VMDK_FILES_TO_BACKUP}" == "all" ]]; then 
							#added this section to handle VMDK(s) stored in different datastore than the VM
							echo ${VMDK} | grep "^/vmfs/volumes" > /dev/null 2>&1
							if [ $? -eq 0 ]; then
								SOURCE_VMDK="${VMDK}"
								DS_UUID="$(echo ${VMDK#/vmfs/volumes/*})"
								DS_UUID="$(echo ${DS_UUID%/*/*})"
								VMDK_DISK="$(echo ${VMDK##/*/})"
								mkdir -p "${VM_BACKUP_DIR}/${DS_UUID}"
								DESTINATION_VMDK="${VM_BACKUP_DIR}/${DS_UUID}/${VMDK_DISK}"
							else
								SOURCE_VMDK="${VMX_DIR}/${VMDK}"
								DESTINATION_VMDK="${VM_BACKUP_DIR}/${VMDK}"
							fi
 
							#support for vRDM and deny pRDM
							grep "vmfsPassthroughRawDeviceMap" "${SOURCE_VMDK}" > /dev/null 2>&1
							if [ $? -eq 1 ]; then
								FORMAT_OPTION="UNKNOWN"
								if [ "${DISK_BACKUP_FORMAT}" == "zeroedthick" ]; then
									if [ "${VER}" == "4" ]; then
										FORMAT_OPTION="zeroedthick"
									else
										FORMAT_OPTION=""
									fi
		        		        	        elif [ "${DISK_BACKUP_FORMAT}" == "2gbsparse" ]; then
									FORMAT_OPTION="2gbsparse"
		                		        	elif [ "${DISK_BACKUP_FORMAT}" == "thin" ]; then
									 FORMAT_OPTION="thin"
				                	        elif [ "${DISK_BACKUP_FORMAT}" == "eagerzeroedthick" ]; then
									if [ "${VER}" == "4" ]; then
										FORMAT_OPTION="eagerzeroedthick"
                        	        				else
										FORMAT_OPTION=""
	                                        			fi
	        	                        		fi
 
								if  [ "${FORMAT_OPTION}" == "UNKNOWN" ]; then
									logger "info" "ERROR: wrong DISK_BACKUP_FORMAT \"${DISK_BACKUP_FORMAT}\ specified for ${VM_NAME}"
									VM_VMDK_FAILED=1
								else
									VMDK_OUTPUT=$(mktemp /tmp/ghettovcb.XXXXXX)
									tail -f "${VMDK_OUTPUT}" &
									TAIL_PID=$!
 
									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					
									else 
										logger "debug" "${VMKFSTOOLS_CMD} -i \"${SOURCE_VMDK}\" -a \"${ADAPTER_FORMAT}\" -d \"${FORMAT_OPTION}\" \"${DESTINATION_VMDK}\""
										${VMKFSTOOLS_CMD} -i "${SOURCE_VMDK}" -a "${ADAPTER_FORMAT}" -d "${FORMAT_OPTION}" "${DESTINATION_VMDK}" > "${VMDK_OUTPUT}" 2>&1
									fi
 
									VMDK_EXIT_CODE=$?
									kill "${TAIL_PID}"
									cat "${VMDK_OUTPUT}" >> "${REDIRECT}"
									echo >> "${REDIRECT}"
									echo
									rm "${VMDK_OUTPUT}"
 
									if [ "${VMDK_EXIT_CODE}" != 0 ] ; then
										logger "info" "ERROR: error in backing up of \"${SOURCE_VMDK}\" for ${VM_NAME}"
										VM_VMDK_FAILED=1
									fi
								fi
							else
                	        	        		logger "info" "WARNING: A physical RDM \"${SOURCE_VMDK}\" was found for ${VM_NAME}, which will not be backed up"
								VM_VMDK_FAILED=1
                        				fi
						fi
					done
					IFS="${OLD_IFS}"
				fi
 
				#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
 
	                                #do not continue until all snapshots have been committed
        	                        logger "info" "Removing snapshot from ${VM_NAME} ..."
                	                while ls "${VMX_DIR}" | grep -q delta;
                        	        do
                                	        sleep 5
	                                done
        	                fi
 
				if [[ ${POWER_VM_DOWN_BEFORE_BACKUP} -eq 1 ]] && [[ "${ORGINAL_VM_POWER_STATE}" == "Powered on" ]]; then
        	                        #power on vm that was powered off prior to backup
                	                logger "info" "Powering back on ${VM_NAME}"
                        	        ${VMWARE_CMD} vmsvc/power.on ${VM_ID} > /dev/null 2>&1
	                        fi
 
				TMP_IFS=${IFS}
                	        IFS=${ORIG_IFS}
	                        if [ ${ENABLE_COMPRESSION} -eq 1 ]; then
        	                        logger "info" "Compressing VM backup \"${BACKUP_DIR}/${VM_NAME}-${VM_BACKUP_DIR_NAMING_CONVENTION}.gz\"..."
					if [ ${IS_4I} -eq 1 ]; then
						busybox tar -cz -C "${BACKUP_DIR}" "${VM_NAME}-${VM_BACKUP_DIR_NAMING_CONVENTION}" -f "${BACKUP_DIR}/${VM_NAME}-${VM_BACKUP_DIR_NAMING_CONVENTION}.gz"
					else 
						tar -cz -C "${BACKUP_DIR}" "${VM_NAME}-${VM_BACKUP_DIR_NAMING_CONVENTION}" -f "${BACKUP_DIR}/${VM_NAME}-${VM_BACKUP_DIR_NAMING_CONVENTION}.gz"
					fi
                	                rm -rf "${VM_BACKUP_DIR}"
					checkVMBackupRotation "${BACKUP_DIR}"
	                        else
        	                        checkVMBackupRotation "${BACKUP_DIR}"
                	        fi
                        	IFS=${TMP_IFS}
	                        VMDKS=""
 
				endTimer
				if [ ${SNAP_SUCCESS} -ne 1 ]; then
					logger "info" "ERROR: Unable to backup ${VM_NAME} due to snapshot creation!\n"
					VM_FAILED=1
				elif [ ${VM_VMDK_FAILED} -ne 0 ]; then
					logger "info" "ERROR: Unable to backup ${VM_NAME} due to error in VMDK backup!\n"
					VMDK_FAILED=1
				else
					logger "info" "Successfully completed backup for ${VM_NAME}!\n"
					VM_OK=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}
						SYMLINK_SRC="$(echo "${SYMLINK_DST%*-*-*-*_*-*-*}")-symlink"
				                logger "info" "Creating symlink \"${SYMLINK_SRC}\" to \"${SYMLINK_DST}\""
				                ln -s "${SYMLINK_DST}" "${SYMLINK_SRC}"
				        fi
 
				fi
	                else
				if [ ${CONTINUE_TO_BACKUP} -eq 0 ]; then
					logger "info" "ERROR: Failed to backup ${VM_NAME}!\n"
					VM_FAILED=1
				else
        	                	logger "info" "ERROR: Failed to lookup ${VM_NAME}!\n"
					VM_FAILED=1
				fi
	                fi	
		fi
        done
	unset IFS
 
        if [[ ${ENABLE_NON_PERSISTENT_NFS} -eq 1 ]] && [[ ${UNMOUNT_NFS} -eq 1 ]] ; then
		${VMWARE_CMD} hostsvc/datastore/destroy ${NFS_LOCAL_NAME}	
	fi
}
 
getFinalStatus() {
	if [[ "${LOG_TYPE}" == "dryrun" ]]; then
		FINAL_STATUS="###### Final status: OK, only a dryrun. ######"
		EXIT=0
	elif [[ $VM_OK == 1 ]] && [[ $VM_FAILED == 0 ]] && [[ $VMDK_FAILED == 0 ]]; then
		FINAL_STATUS="###### Final status: All VMs backed up OK! ######"
		EXIT=0
	elif [[ $VM_OK == 1 ]] && [[ $VM_FAILED == 0 ]] && [[ $VMDK_FAILED == 1 ]]; then
		FINAL_STATUS="###### Final status: WARNING: All VMs backed up, but some disk(s) failed! ######"
		EXIT=3
	elif [[ $VM_OK == 1 ]] && [[ $VM_FAILED == 1 ]] && [[ $VMDK_FAILED == 0 ]]; then
		FINAL_STATUS="###### Final status: ERROR: Only some of the VMs backed up! ######"
		EXIT=4
	elif [[ $VM_OK == 1 ]] && [[ $VM_FAILED == 1 ]] && [[ $VMDK_FAILED == 1 ]]; then
		FINAL_STATUS="###### Final status: ERROR: Only some of the VMs backed up, and some disk(s) failed! ######"
		EXIT=5
	elif [[ $VM_OK == 0 ]] && [[ $VM_FAILED == 1 ]]; then
		FINAL_STATUS="###### Final status: ERROR: All VMs failed! ######"
		EXIT=6
	elif [[ $VM_OK == 0 ]]; then
		FINAL_STATUS="###### Final status: ERROR: No VMs backed up! ######"
		EXIT=7
	fi
	logger "info" "$FINAL_STATUS\n"
}
 
sendMail() {
	#close email message
	if [ "${EMAIL_LOG}" -eq 1 ]; then
        	echo -en ".\r\n" >> "${EMAIL_LOG_OUTPUT}"
	        echo -en "QUIT\r\n" >> "${EMAIL_LOG_OUTPUT}"
 
		"${NC_BIN}" "${EMAIL_SERVER}" "${EMAIL_SERVER_PORT}" < "${EMAIL_LOG_OUTPUT}" > /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
 
		if [ "${EMAIL_DEBUG}" -eq 1 ]; then
			logger "info" "Email log output will not be deleted and is stored in ${EMAIL_LOG_OUTPUT}\n"
		else
			rm -rf "${EMAIL_LOG_OUTPUT}"
		fi
	fi
}
 
####################
#		   #
# Start of Script  #
#		   #
####################
 
IS_4I=0
 
if [ ! -f /bin/bash ]; then
	IS_4I=1
fi
 
USE_VM_CONF=0
USE_GLOBAL_CONF=0
BACKUP_ALL_VMS=0
EXCLUDE_SOME_VMS=0
EMAIL_LOG_OUTPUT=/tmp/ghettoVCB-email-$$.log
 
#read user input
while getopts ":af:c:g:l:d:e:" ARGS; do
        case $ARGS in
		a)
			BACKUP_ALL_VMS=1
			VM_FILE="/tmp/backup_all_vms_on-$(hostname)"
			touch "${VM_FILE}"
			;;			
                f)      VM_FILE="${OPTARG}"
                        ;;
		e)
			VM_EXCLUSION_FILE="${OPTARG}"
			EXCLUDE_SOME_VMS=1
			;;
		c)
			CONFIG_DIR="${OPTARG}"
			USE_VM_CONF=1
			;;
		g)
			GLOBAL_CONF="${OPTARG}"
			USE_GLOBAL_CONF=1
			;;
                l)
                        LOG_OUTPUT="${OPTARG}"
                        ;;
                d)
                        LOG_LEVEL="${OPTARG}"
                        ;;
                :)
                        echo "Option -${OPTARG} requires an argument."
                        exit 1
                        ;;
                *)
			printUsage
                        exit 1
                        ;;
        esac
done
 
#performs a check on the number of commandline arguments + verifies $2 is a valid file
sanityCheck $# 
 
LOCKDIR=/tmp/ghettoVCB.lock
 
if mkdir "${LOCKDIR}"
then
	GHETTOVCB_PID=$$
 
	logger "info" "============================== ESXI LOG START ==============================\n"
	logger "debug" "Succesfully acquired lock directory - ${LOCKDIR}\n"
 
	# Remove lockdir when the script finishes, or when it receives a signal
	trap 'rm -rf "${LOCKDIR}"' 0    # remove directory when script finishes
	trap "exit 2" 1 2 3 13 15       # terminate script when receiving signal
 
	ghettoVCB ${VM_FILE}
 
	getFinalStatus
 
	logger "debug" "Succesfully removed lock directory - ${LOCKDIR}\n"
	logger "info" "============================== ESXI LOG END ================================\n"
 
	sendMail
 
	rm -rf "${LOCKDIR}"
	exit $EXIT
else 
	logger "info" "Failed to acquire lock, another instance of script may be running, giving up on ${LOCKDIR}\n"
	exit 1
fi

Voici la vidéo :