iT邦幫忙

0

[已解決] ESXi 6.7 執行ghettoVCB.sh備份出現Operation not permitted

已經使用chmod +x /vmfs/volumes/LocalDisk/ghettoVCB-518/ghettoVCB.sh給執行權限了,不知道還有哪邊需要設定?
...........
果然是新電腦的BIOS內Secure Boot的問題,關閉即可正常執行*.sh檔。

看更多先前的討論...收起先前的討論...
config 貼出來看看
fireflybug iT邦研究生 5 級 ‧ 2018-12-17 09:26:55 檢舉
# Author: William Lam
# Created Date: 11/17/2008
# http://www.virtuallyghetto.com/
# http://communities.vmware.com/docs/DOC-8760

##################################################################
# User Definable Parameters
##################################################################

LAST_MODIFIED_DATE=2017_12_09
VERSION=1

# directory that all VM backups should go (e.g. /vmfs/volumes/SAN_LUN1/mybackupdir)
VM_BACKUP_VOLUME=/vmfs/volumes/datastore1

# 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=3

# 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

# Include VMs memory when taking snapshot
VM_SNAPSHOT_MEMORY=0

# Quiesce VM when taking snapshot (requires VMware Tools to be installed)
VM_SNAPSHOT_QUIESCE=0

# default 15min timeout
SNAPSHOT_TIMEOUT=15

# Allow VMs with snapshots to be backed up, this WILL CONSOLIDATE EXISTING SNAPSHOTS!
ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP=0

##########################################################
# NON-PERSISTENT NFS-BACKUP ONLY
#
# ENABLE NON PERSISTENT NFS BACKUP 1=on, 0=off

ENABLE_NON_PERSISTENT_NFS=0

# umount NFS datastore after backup is complete 1=yes, 0=no
UNMOUNT_NFS=0

# IP Address of NFS Server
NFS_SERVER=172.51.0.192

# NFS Version (v3=nfs v4=nfsv41) - Only v3 is valid for 5.5
NFS_VERSION=nfs

# Path of exported folder residing on NFS Server (e.g. /some/mount/point )
NFS_MOUNT=/upload

# Non-persistent NFS datastore display name of choice
NFS_LOCAL_NAME=backup

# Name of backup directory for VMs residing on the NFS volume
NFS_VM_BACKUP_DIR=mybackups

##########################################################
# EMAIL CONFIGURATIONS
#

# Email Alerting 1=yes, 0=no
EMAIL_ALERT=1
# Email log 1=yes, 0=no
EMAIL_LOG=1

# Email Delay Interval from NC (netcat) - default 1
EMAIL_DELAY_INTERVAL=2

# Email SMTP server
EMAIL_SERVER=192.168.100.3

# Email SMTP server port
EMAIL_SERVER_PORT=25

# Email FROM
EMAIL_FROM=root@ghettoVCB

# Comma seperated list of receiving email addresses
EMAIL_TO=roger.lin@t3ex-techiview.com,roger@infinity.idv.tw

# Comma seperated list of additional receiving email addresses if status is not "OK"
EMAIL_ERRORS_TO=

# Comma separated list of VM startup/shutdown ordering
VM_SHUTDOWN_ORDER=
VM_STARTUP_ORDER=

# RSYNC LINK 1=yes, 0 = no
RSYNC_LINK=0

# DO NOT USE - UNTESTED CODE
# Path to another location that should have backups rotated,
# this is useful when your backups go to a temporary location
# then are rsync'd to a final destination. You can specify the final
# destination as the ADDITIONAL_ROTATION_PATH which will be rotated after
# all VMs have been restarted
ADDITIONAL_ROTATION_PATH=

##########################################################
# SLOW NAS CONFIGURATIONS - By Rapitharian
##########################################################
#This Feature was added to the program to provide a fix for slow NAS devices similar to the Drobo and Synology devices. SMB and Home NAS devices.
#This Feature enables the device to perform tasks (Deletes/data save for large files) and has the script wait for the NAS to catchup.
#This code has been in production on the authors systems for the last 2 years.

# Enable use of the NFS IO HACK for all NAS commands 1=yes, 0=no
# 0 uses the script in it's original state.
ENABLE_NFS_IO_HACK=0

# Set this value to determine how many times the script tries to work arround I/O errors each time the NAS slows down.
# The script will skip past this loop if the NAS is responsive.
NFS_IO_HACK_LOOP_MAX=10

# This value determines the number of seconds to sleep, when the NFS device is unresponsive.
NFS_IO_HACK_SLEEP_TIMER=60

# ONLY USE THIS WITH EXTREMELY SLOW NAS DEVICES!
# This is a Brute-force/Mandatory delay added on top of any delay imposed by the NFS_IO_Hack.
# Set a delay timer to allow the NFS server to catch up to GhettoVCB's stream, when the NAS isn't responding timely.
# This acts like a cooldown period for the NAS.
# The value is measured in seconds. This causes the script to pause between each VM.
NFS_BACKUP_DELAY=0

##################################################################
# End User Definable Parameters
##################################################################

########################## DO NOT MODIFY PAST THIS LINE ##########################

# Do not remove workdir on exit: 1=yes, 0=no
WORKDIR_DEBUG=0
LOG_LEVEL="info"
VMDK_FILES_TO_BACKUP="all"

VERSION_STRING=${LAST_MODIFIED_DATE}_${VERSION}

# Directory naming convention for backup rotations (please ensure there are no spaces!)
# If set to "0", VMs will be rotated via an index, beginning at 0, ending at
# VM_BACKUP_ROTATION_COUNT-1
VM_BACKUP_DIR_NAMING_CONVENTION="$(date +%F_%H-%M-%S)"


printUsage() {
echo "###############################################################################"
echo "#"
echo "# ghettoVCB for ESX/ESXi 3.5, 4.x+, 5.x & 6.x"
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 "#"
echo "###############################################################################"
echo
echo "Usage: $(basename $0) [options]"
echo
echo "OPTIONS:"
echo " -a Backup all VMs on host"
echo " -f List of VMs to backup"
echo " -m Name of VM to backup (overrides -f)"
echo " -c VM configuration directory for VM backups"
echo " -g Path to global ghettoVCB configuration file"
echo " -l File to output logging"
echo " -w ghettoVCB work directory (default: /tmp/ghettoVCB.work)"
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 a single VM"
echo -e "\t$0 -m vm_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 (consider logging to local or remote datastore to persist logs)"
echo -e "\t$0 -f vms_to_backup -l /vmfs/volume/local-storage/ghettoVCB.log"
echo -e "\nDry run (no backup will take place)"
echo -e "\t$0 -f vms_to_backup -d dryrun"
echo
}

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}"
fi

if [[ -n "${LOG_OUTPUT}" ]] ; then
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() {
# ensure root user is running the script
if [ ! $(env | grep -e "^USER=" | awk -F = '{print $2}') == "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

# use of global ghettoVCB configuration
if [[ "${USE_GLOBAL_CONF}" -eq 1 ]] ; then
reConfigureGhettoVCBConfiguration "${GLOBAL_CONF}"
fi

# always log to STDOUT, use "> /dev/null" to ignore output
LOG_TO_STDOUT=1

#if no logfile then provide default logfile in /tmp

if [[ -z "${LOG_OUTPUT}" ]] ; then
LOG_OUTPUT="/tmp/ghettoVCB-$(date +%F_%H-%M-%S)-$$.log"
echo "Logging output to \"${LOG_OUTPUT}\" ..."
fi

touch "${LOG_OUTPUT}"
# REDIRECT is used by the "tail" trick, use REDIRECT=/dev/null to redirect vmkfstool to STDOUT only
REDIRECT=${LOG_OUTPUT}

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+, 4.x+, 5.x+ or 6.x!"
echo "ERROR: Unable to locate *vimsh*! You're not running ESX(i) 3.5+, 4.x+, 5.x+ or 6.x!"
exit 1
fi

ESX_VERSION=$(vmware -v | awk '{print $3}')
ESX_RELEASE=$(uname -r)

case "${ESX_VERSION}" in
6.0.0|6.5.0|6.7.0) VER=6; break;;
5.0.0|5.1.0|5.5.0) VER=5; break;;
4.0.0|4.1.0) VER=4; break;;
3.5.0|3i) VER=3; break;;
*) echo "You're not running ESX(i) 3.5, 4.x, 5.x & 6.x!"; exit 1; break;;
esac

NEW_VIMCMD_SNAPSHOT="no"
${VMWARE_CMD} vmsvc/snapshot.remove 2>&1 | grep -q "snapshotId"
[[ $? -eq 0 ]] && NEW_VIMCMD_SNAPSHOT="yes"

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
else
EMAIL_LOG=0
fi

TAR="tar"
[[ ! -f /bin/tar ]] && TAR="busybox tar"

# Enable multiextent VMkernel module if disk format is 2gbsparse (disabled by default in 5.1)
if [[ "${DISK_BACKUP_FORMAT}" == "2gbsparse" ]] && [[ "${VER}" -eq 5 || "${VER}" == "6" ]]; then
esxcli system module list | grep multiextent > /dev/null 2>&1
if [ $? -eq 1 ]; then
logger "info" "multiextent VMkernel module is not loaded & is required for 2gbsparse, enabling ..."
esxcli system module load -m multiextent
fi
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_VM_SNAPSHOT_MEMORY="${VM_SNAPSHOT_MEMORY}"
DEFAULT_VM_SNAPSHOT_QUIESCE="${VM_SNAPSHOT_QUIESCE}"
DEFAULT_ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP="${ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP}"
DEFAULT_VMDK_FILES_TO_BACKUP="${VMDK_FILES_TO_BACKUP}"
DEFAULT_EMAIL_LOG="${EMAIL_LOG}"
DEFAULT_WORKDIR_DEBUG="${WORKDIR_DEBUG}"
DEFAULT_VM_SHUTDOWN_ORDER="${VM_SHUTDOWN_ORDER}"
DEFAULT_VM_STARTUP_ORDER="${VM_STARTUP_ORDER}"
DEFAULT_RSYNC_LINK="${RSYNC_LINK}"
DEFAULT_BACKUP_FILES_CHMOD="${BACKUP_FILES_CHMOD}"
# Added the NFS_IO_HACK values below
DEFAULT_NFS_IO_HACK_LOOP_MAX="${NFS_IO_HACK_LOOP_MAX}"
DEFAULT_NFS_IO_HACK_SLEEP_TIMER="${NFS_IO_HACK_SLEEP_TIMER}"
DEFAULT_NFS_BACKUP_DELAY="${NFS_BACKUP_DELAY}"
DEFAULT_ENABLE_NFS_IO_HACK="${ENABLE_NFS_IO_HACK}"
}

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}"
VM_SNAPSHOT_MEMORY="${DEFAULT_VM_SNAPSHOT_MEMORY}"
VM_SNAPSHOT_QUIESCE="${DEFAULT_VM_SNAPSHOT_QUIESCE}"
ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP="${DEFAULT_ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP}"
VMDK_FILES_TO_BACKUP="${DEFAULT_VMDK_FILES_TO_BACKUP}"
EMAIL_LOG="${DEFAULT_EMAIL_LOG}"
WORKDIR_DEBUG="${DEFAULT_WORKDIR_DEBUG}"
VM_SHUTDOWN_ORDER="${DEFAULT_VM_SHUTDOWN_ORDER}"
VM_STARTUP_ORDER="${DEFAULT_VM_STARTUP_ORDER}"
RSYNC_LINK="${RSYNC_LINK}"
BACKUP_FILES_CHMOD="${BACKUP_FILES_CHMOD}"
# Added the NFS_IO_HACK values below
ENABLE_NFS_IO_HACK="${DEFAULT_ENABLE_NFS_IO_HACK_ON}"
NFS_IO_HACK_LOOP_MAX="${NFS_IO_HACK_LOOP_MAX}"
NFS_IO_HACK_SLEEP_TIMER="${DEFAULT_NFS_IO_HACK_SLEEP_TIMER}"
NFS_BACKUP_DELAY="${DEFAULT_NFS_BACKUP_DELAY}"
}

reConfigureGhettoVCBConfiguration() {
GLOBAL_CONF=$1

if [[ -f "${GLOBAL_CONF}" ]]; then
source "${GLOBAL_CONF}"
else
useDefaultConfigurations
fi
}

reConfigureBackupParam() {
VM=$1

if [[ -e "${CONFIG_DIR}/${VM}" ]]; then
logger "info" "CONFIG - USING CONFIGURATION FILE = ${CONFIG_DIR}/${VM}"
source "${CONFIG_DIR}/${VM}"
else
useDefaultConfigurations
fi
}

dumpHostInfo() {
VERSION=$(vmware -v)
logger "debug" "HOST VERSION: ${VERSION}"
echo ${VERSION} | grep "Server 3i" > /dev/null 2>&1
[[ $? -eq 1 ]] && logger "debug" "HOST LEVEL: $(vmware -l)"
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|^sata|^nvme)' "${VMX_PATH}" | grep -i fileName | awk -F " " '{print $1}')

VMDKS=
INDEP_VMDKS=

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}')
echo "${DISK}" | grep "\/vmfs\/volumes" > /dev/null 2>&1

if [[ $? -eq 0 ]]; then
DISK_SIZE_IN_SECTORS=$(cat "${DISK}" | grep "VMFS" | grep ".vmdk" | awk '{print $2}')
else
DISK_SIZE_IN_SECTORS=$(cat "${VMX_DIR}/${DISK}" | grep "VMFS" | grep ".vmdk" | awk '{print $2}')
fi

DISK_SIZE=$(echo "${DISK_SIZE_IN_SECTORS}" | awk '{printf "%.0f\n",$1*512/1024/1024/1024}')
VMDKS="${DISK}###${DISK_SIZE}:${VMDKS}"
TOTAL_VM_SIZE=$((TOTAL_VM_SIZE+DISK_SIZE))
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}')
echo "${DISK}" | grep "\/vmfs\/volumes" > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
DISK_SIZE_IN_SECTORS=$(cat "${DISK}" | grep "VMFS" | grep ".vmdk" | awk '{print $2}')
else
DISK_SIZE_IN_SECTORS=$(cat "${VMX_DIR}/${DISK}" | grep "VMFS" | grep ".vmdk" | awk '{print $2}')
fi
DISK_SIZE=$(echo "${DISK_SIZE_IN_SECTORS}" | awk '{printf "%.0f\n",$1*512/1024/1024/1024}')
VMDKS="${DISK}###${DISK_SIZE}:${VMDKS}"
TOTAL_VM_SIZE=$((TOTAL_VM_SIZE_IN+DISK_SIZE))
fi
fi

else
#independent disks are not affected by snapshots, hence they can not be backed up
DISK=$(grep -i "^${SCSI_ID}.fileName" "${VMX_PATH}" | awk -F "\"" '{print $2}')
echo "${DISK}" | grep "\/vmfs\/volumes" > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
DISK_SIZE_IN_SECTORS=$(cat "${DISK}" | grep "VMFS" | grep ".vmdk" | awk '{print $2}')
else
DISK_SIZE_IN_SECTORS=$(cat "${VMX_DIR}/${DISK}" | grep "VMFS" | grep ".vmdk" | awk '{print $2}')
fi
DISK_SIZE=$(echo "${DISK_SIZE_IN_SECTORS}" | awk '{printf "%.0f\n",$1*512/1024/1024/1024}')
INDEP_VMDKS="${DISK}###${DISK_SIZE}:${INDEP_VMDKS}"
fi
fi
done
IFS=${TMP_IFS}
logger "debug" "getVMDKs() - ${VMDKS}"
}

dumpVMConfigurations() {
logger "info" "CONFIG - VERSION = ${VERSION_STRING}"
logger "info" "CONFIG - GHETTOVCB_PID = ${GHETTOVCB_PID}"
logger "info" "CONFIG - VM_BACKUP_VOLUME = ${VM_BACKUP_VOLUME}"
if [[ "${ENABLE_NON_PERSISTENT_NFS}" -eq 1 ]]; then
logger "info" "CONFIG - ENABLE_NON_PERSISTENT_NFS = ${ENABLE_NON_PERSISTENT_NFS}"
logger "info" "CONFIG - UNMOUNT_NFS = ${UNMOUNT_NFS}"
logger "info" "CONFIG - NFS_SERVER = ${NFS_SERVER}"
logger "info" "CONFIG - NFS_VERSION = ${NFS_VERSION}"
logger "info" "CONFIG - NFS_MOUNT = ${NFS_MOUNT}"
fi
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 - 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}"
logger "info" "CONFIG - BACKUP_LOG_OUTPUT = ${LOG_OUTPUT}"
logger "info" "CONFIG - ENABLE_COMPRESSION = ${ENABLE_COMPRESSION}"
logger "info" "CONFIG - VM_SNAPSHOT_MEMORY = ${VM_SNAPSHOT_MEMORY}"
logger "info" "CONFIG - VM_SNAPSHOT_QUIESCE = ${VM_SNAPSHOT_QUIESCE}"
logger "info" "CONFIG - ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP = ${ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP}"
logger "info" "CONFIG - VMDK_FILES_TO_BACKUP = ${VMDK_FILES_TO_BACKUP}"
logger "info" "CONFIG - VM_SHUTDOWN_ORDER = ${VM_SHUTDOWN_ORDER}"
logger "info" "CONFIG - VM_STARTUP_ORDER = ${VM_STARTUP_ORDER}"
logger "info" "CONFIG - RSYNC_LINK = ${RSYNC_LINK}"
logger "info" "CONFIG - BACKUP_FILES_CHMOD = ${BACKUP_FILES_CHMOD}"
logger "info" "CONFIG - EMAIL_LOG = ${EMAIL_LOG}"
if [[ "${EMAIL_LOG}" -eq 1 ]]; then
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}"
logger "info" "CONFIG - WORKDIR_DEBUG = ${WORKDIR_DEBUG}"
fi
if [[ "${ENABLE_NFS_IO_HACK}" -eq 1 ]]; then
logger "info" "CONFIG - ENABLE NFS IO HACK = ${ENABLE_NFS_IO_HACK}"
logger "info" "CONFIG - NFS IO HACK LOOP MAX = ${NFS_IO_HACK_LOOP_MAX}"
logger "info" "CONFIG - NFS IO HACK SLEEP TIMER = ${NFS_IO_HACK_SLEEP_TIMER}"
logger "info" "CONFIG - NFS BACKUP DELAY = ${NFS_BACKUP_DELAY}"
fi
logger "\n"
}

# Added the function below to allow reuse of the basics of the original hack in more places in the script.
# Rewrote the code to reduce the calls to the NAS when it slows. Why make a bad situation worse with extra calls?
NfsIoHack() {
# NFS I/O error handling hack
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 ]] && [[ "${NFS_IO_HACK_COUNTER}" -lt "${NFS_IO_HACK_LOOP_MAX}" ]]; do
touch "${NFS_IO_HACK_FILECHECK}"
if [[ $? -ne 0 ]] ; then
sleep "${NFS_IO_HACK_SLEEP_TIMER}"
NFS_IO_HACK_COUNTER=$((NFS_IO_HACK_COUNTER+1))
fi
[[ $? -eq 0 ]] && NFS_IO_HACK_STATUS=1
done

NFS_IO_HACK_SLEEP_TIME=$((NFS_IO_HACK_COUNTER*NFS_IO_HACK_SLEEP_TIMER))

rm -rf "${NFS_IO_HACK_FILECHECK}"

if [[ "${NFS_IO_HACK_SLEEP_TIME}" -ne 0 ]] ; then
if [[ "${NFS_IO_HACK_STATUS}" -eq 1 ]] ; then
logger "info" "Slept ${NFS_IO_HACK_SLEEP_TIME} seconds to work around NFS I/O error"
else
logger "info" "Slept ${NFS_IO_HACK_SLEEP_TIME} seconds but failed work around for NFS I/O error"
fi
fi
}

# Converted the section of code below to a function to be able to call it when a failed backup occurs.
Get_Final_Status_Sendemail() {
getFinalStatus

logger "debug" "Succesfully removed lock directory - ${WORKDIR}\n"
logger "info" "============================== ghettoVCB LOG END ================================\n"

sendMail
}

indexedRotate() {
local BACKUP_DIR_PATH=$1
local VM_TO_SEARCH_FOR=$2

#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}" | grep "${VM_TO_SEARCH_FOR}-[0-9]*")
i=${VM_BACKUP_ROTATION_COUNT}
while [[ $i -ge 0 ]]; do
if [[ -f ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i.gz ]]; then
if [[ $i -eq $((VM_BACKUP_ROTATION_COUNT-1)) ]]; then
rm -rf ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i.gz
# Added the NFS_IO_HACK check and function call here. Some NAS devices slow at this step.
if [[ $? -ne 0 ]] && [[ "${ENABLE_NFS_IO_HACK}" -eq 1 ]]; then
NfsIoHack
fi
if [[ $? -eq 0 ]]; then
logger "info" "Deleted ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i.gz"
else
logger "info" "Failure deleting ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i.gz"
fi
else
mv -f ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i.gz ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$((i+1)).gz
# Added the NFS_IO_HACK check and function call here. Some NAS devices slow at this step.
if [[ $? -ne 0 ]] && [[ "${ENABLE_NFS_IO_HACK}" -eq 1 ]]; then
NfsIoHack
fi
if [[ $? -eq 0 ]]; then
logger "info" "Moved ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i.gz to ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$((i+1)).gz"
else
logger "info" "Failure moving ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i.gz to ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$((i+1)).gz"
fi
fi
fi
if [[ -d ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i ]]; then
if [[ $i -eq $((VM_BACKUP_ROTATION_COUNT-1)) ]]; then
rm -rf ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i
# Added the NFS_IO_HACK check and function call here. Some NAS devices slow at this step.
if [[ $? -ne 0 ]] && [[ "${ENABLE_NFS_IO_HACK}" -eq 1 ]]; then
NfsIoHack
fi
if [[ $? -eq 0 ]]; then
logger "info" "Deleted ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i"
else
logger "info" "Failure deleting ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i"
fi
else
mv -f ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$((i+1))
# Added the NFS_IO_HACK check and function call here. Some NAS devices slow at this step.
if [[ $? -ne 0 ]] && [[ "${ENABLE_NFS_IO_HACK}" -eq 1 ]]; then
NfsIoHack
fi
if [[ $? -eq 0 ]]; then
logger "info" "Moved ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i to ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$((i+1))"
else
logger "info" "Failure moving ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i to ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$((i+1))"
fi
if [[ $i -eq 0 ]]; then
mkdir ${BACKUP_DIR_PATH}/${VM_TO_SEARCH_FOR}-$i
fi
fi
fi

i=$((i-1))
done
}

checkVMBackupRotation() {
local BACKUP_DIR_PATH=$1
local VM_TO_SEARCH_FOR=$2

#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}" | grep "${VM_TO_SEARCH_FOR}-[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}_[0-9]\{2\}-[0-9]\{2\}-[0-9]\{2\}")
BACKUPS_TO_KEEP=$(ls -t "${BACKUP_DIR_PATH}" | grep "${VM_TO_SEARCH_FOR}-[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}_[0-9]\{2\}-[0-9]\{2\}-[0-9]\{2\}" | head -"${VM_BACKUP_ROTATION_COUNT}")

ORIG_IFS=${IFS}
IFS='
'
for i in ${LIST_BACKUPS}; do
FOUND=0
for j in ${BACKUPS_TO_KEEP}; do
[[ $i == $j ]] && FOUND=1
done

if [[ $FOUND -eq 0 ]]; then
logger "debug" "Removing $BACKUP_DIR_PATH/$i"
rm -rf "$BACKUP_DIR_PATH/$i"

# Added the NFS_IO_HACK check and function call here. Also set the script to function the same, if the new feature is turned off.
# Added variables to the code to control the timers and loops.
# This code could be optimized based on the work in the NFS_IO_HACK function or that code could be used all the time with a few minor changes.
if [[ $? -ne 0 ]] && [[ "${ENABLE_NFS_IO_HACK}" -eq 1 ]]; then
NfsIoHack
else
#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 ]] && [[ "${NFS_IO_HACK_COUNTER}" -lt "${NFS_IO_HACK_LOOP_MAX}" ]]; do
sleep "${NFS_IO_HACK_SLEEP_TIMER}"
NFS_IO_HACK_COUNTER=$((NFS_IO_HACK_COUNTER+1))
touch "${NFS_IO_HACK_FILECHECK}"

[[ $? -eq 0 ]] && NFS_IO_HACK_STATUS=1
done

NFS_IO_HACK_SLEEP_TIME=$((NFS_IO_HACK_COUNTER*NFS_IO_HACK_SLEEP_TIMER))

rm -rf "${NFS_IO_HACK_FILECHECK}"

if [[ "${NFS_IO_HACK_STATUS}" -eq 1 ]] ; then
logger "info" "Slept ${NFS_IO_HACK_SLEEP_TIME} seconds to work around NFS I/O error"
else
logger "info" "Slept ${NFS_IO_HACK_SLEEP_TIME} seconds but failed work around for NFS I/O error"
fi
fi
fi
fi
done
IFS=${ORIG_IFS}
}

storageInfo() {
SECTION=$1

#SOURCE DATASTORE
SRC_DATASTORE_CAPACITY=$($VMWARE_CMD hostsvc/datastore/info "${VMFS_VOLUME}" | grep -i "capacity" | awk '{print $3}' | sed 's/,//g')
SRC_DATASTORE_FREE=$($VMWARE_CMD hostsvc/datastore/info "${VMFS_VOLUME}" | grep -i "freespace" | awk '{print $3}' | sed 's/,//g')
SRC_DATASTORE_BLOCKSIZE=$($VMWARE_CMD hostsvc/datastore/info "${VMFS_VOLUME}" | grep -i blockSizeMb | awk '{print $3}' | sed 's/,//g')
if [[ -z ${SRC_DATASTORE_BLOCKSIZE} ]] ; then
SRC_DATASTORE_BLOCKSIZE="NA"
SRC_DATASTORE_MAX_FILE_SIZE="NA"
else
case ${SRC_DATASTORE_BLOCKSIZE} in
1)SRC_DATASTORE_MAX_FILE_SIZE="256 GB";;
2)SRC_DATASTORE_MAX_FILE_SIZE="512 GB";;
4)SRC_DATASTORE_MAX_FILE_SIZE="1024 GB";;
8)SRC_DATASTORE_MAX_FILE_SIZE="2048 GB";;
esac
fi
SRC_DATASTORE_CAPACITY_GB=$(echo "${SRC_DATASTORE_CAPACITY}" | awk '{printf "%.1f\n",$1/1024/1024/1024}')
SRC_DATASTORE_FREE_GB=$(echo "${SRC_DATASTORE_FREE}" | awk '{printf "%.1f\n",$1/1024/1024/1024}')

#DESTINATION DATASTORE
DST_VOL_1=$(echo "${VM_BACKUP_VOLUME#/*/*/}")
DST_DATASTORE=$(echo "${DST_VOL_1%%/*}")
DST_DATASTORE_CAPACITY=$($VMWARE_CMD hostsvc/datastore/info "${DST_DATASTORE}" | grep -i "capacity" | awk '{print $3}' | sed 's/,//g')
DST_DATASTORE_FREE=$($VMWARE_CMD hostsvc/datastore/info "${DST_DATASTORE}" | grep -i "freespace" | awk '{print $3}' | sed 's/,//g')
DST_DATASTORE_BLOCKSIZE=$($VMWARE_CMD hostsvc/datastore/info "${DST_DATASTORE}" | grep -i blockSizeMb | awk '{print $3}' | sed 's/,//g')

if [[ -z ${DST_DATASTORE_BLOCKSIZE} ]] ; then
DST_DATASTORE_BLOCKSIZE="NA"
DST_DATASTORE_MAX_FILE_SIZE="NA"
else
case ${DST_DATASTORE_BLOCKSIZE} in
1)DST_DATASTORE_MAX_FILE_SIZE="256 GB";;
2)DST_DATASTORE_MAX_FILE_SIZE="512 GB";;
4)DST_DATASTORE_MAX_FILE_SIZE="1024 GB";;
8)DST_DATASTORE_MAX_FILE_SIZE="2048 GB";;
esac
fi

DST_DATASTORE_CAPACITY_GB=$(echo "${DST_DATASTORE_CAPACITY}" | awk '{printf "%.1f\n",$1/1024/1024/1024}')
DST_DATASTORE_FREE_GB=$(echo "${DST_DATASTORE_FREE}" | awk '{printf "%.1f\n",$1/1024/1024/1024}')

logger "debug" "Storage Information ${SECTION} backup: "
logger "debug" "SRC_DATASTORE: ${VMFS_VOLUME}"
logger "debug" "SRC_DATASTORE_CAPACITY: ${SRC_DATASTORE_CAPACITY_GB} GB"
logger "debug" "SRC_DATASTORE_FREE: ${SRC_DATASTORE_FREE_GB} GB"
logger "debug" "SRC_DATASTORE_BLOCKSIZE: ${SRC_DATASTORE_BLOCKSIZE}"
logger "debug" "SRC_DATASTORE_MAX_FILE_SIZE: ${SRC_DATASTORE_MAX_FILE_SIZE}"
logger "debug" ""
logger "debug" "DST_DATASTORE: ${DST_DATASTORE}"
logger "debug" "DST_DATASTORE_CAPACITY: ${DST_DATASTORE_CAPACITY_GB} GB"
logger "debug" "DST_DATASTORE_FREE: ${DST_DATASTORE_FREE_GB} GB"
logger "debug" "DST_DATASTORE_BLOCKSIZE: ${DST_DATASTORE_BLOCKSIZE}"
logger "debug" "DST_DATASTORE_MAX_FILE_SIZE: ${DST_DATASTORE_MAX_FILE_SIZE}"
if [[ "${SRC_DATASTORE_BLOCKSIZE}" != "NA" ]] && [[ "${DST_DATASTORE_BLOCKSIZE}" != "NA" ]]; then
if [[ "${SRC_DATASTORE_BLOCKSIZE}" -lt "${DST_DATASTORE_BLOCKSIZE}" ]]; then
logger "debug" ""
logger "debug" "SRC VMFS blocksze of ${SRC_DATASTORE_BLOCKSIZE}MB is less than DST VMFS blocksize of ${DST_DATASTORE_BLOCKSIZE}MB which can be an issue for VM snapshots"
fi
fi

logger "debug" ""
}

powerOff() {
VM_NAME="$1"
VM_ID="$2"
POWER_OFF_EC=0

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!"
POWER_OFF_EC=1
break
fi
START_ITERATION=$((START_ITERATION + 1))
done
if [[ ${POWER_OFF_EC} -eq 0 ]] ; then
logger "info" "VM is powerdOff"
fi
}

powerOn() {
VM_NAME="$1"
VM_ID="$2"
POWER_ON_EC=0

START_ITERATION=0
logger "info" "Powering on initiated for ${VM_NAME}"

${VMWARE_CMD} vmsvc/power.on ${VM_ID} > /dev/null 2>&1
while ${VMWARE_CMD} vmsvc/get.guest ${VM_ID} | grep -i "toolsNotRunning" > /dev/null 2>&1; do
logger "info" "VM is still not booted - 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 detect started tools on ${VM_NAME}, waited for $((POWER_DOWN_TIMEOUT*60)) seconds!"
POWER_ON_EC=1
break
fi
START_ITERATION=$((START_ITERATION + 1))
done
if [[ ${POWER_ON_EC} -eq 0 ]] ; then
logger "info" "VM is powerdOn"
fi
}

ghettoVCB() {
VM_INPUT=$1
VM_OK=0
VM_FAILED=0
VMDK_FAILED=0
PROBLEM_VMS=

dumpHostInfo

if [[ ${ENABLE_NON_PERSISTENT_NFS} -eq 1 ]] ; then
VM_BACKUP_VOLUME="/vmfs/volumes/${NFS_LOCAL_NAME}/${NFS_VM_BACKUP_DIR}"
if [[ "${LOG_LEVEL}" != "dryrun" ]] ; then
#1 = readonly
#0 = readwrite
logger "debug" "Mounting NFS: ${NFS_SERVER}:${NFS_MOUNT} to /vmfs/volume/${NFS_LOCAL_NAME}"
if [[ ${ESX_RELEASE} == "5.5.0" ]] || [[ ${ESX_RELEASE} == "6.0.0" || ${ESX_RELEASE} == "6.5.0" || ${ESX_RELEASE} == "6.7.0" ]] ; then
${VMWARE_CMD} hostsvc/datastore/nas_create "${NFS_LOCAL_NAME}" "${NFS_VERSION}" "${NFS_MOUNT}" 0 "${NFS_SERVER}"
else
${VMWARE_CMD} hostsvc/datastore/nas_create "${NFS_LOCAL_NAME}" "${NFS_SERVER}" "${NFS_MOUNT}" 0
fi
fi
fi

captureDefaultConfigurations

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' | fgrep "[" | fgrep "vmx-" | fgrep ".vmx" | fgrep "/" | awk -F' ' '{print "\""$1"\";\""$2"\";\""$3"\""}' | sed 's/\] /\]\";\"/g' > ${WORKDIR}/vms_list

if [[ "${BACKUP_ALL_VMS}" -eq 1 ]] ; then
${VMWARE_CMD} vmsvc/getallvms | sed 's/[[:blank:]]\{3,\}/ /g' | fgrep "[" | fgrep "vmx-" | fgrep ".vmx" | fgrep "/" | awk -F' ' '{print ""$2""}' | sed '/^$/d' > "${VM_INPUT}"
fi

ORIG_IFS=${IFS}
IFS='
'
if [[ ${#VM_SHUTDOWN_ORDER} -gt 0 ]] && [[ "${LOG_LEVEL}" != "dryrun" ]]; then
logger "debug" "VM Shutdown Order: ${VM_SHUTDOWN_ORDER}\n"
IFS2="${IFS}"
IFS=","
for VM_NAME in ${VM_SHUTDOWN_ORDER}; do
VM_ID=$(grep -E "\"${VM_NAME}\"" ${WORKDIR}/vms_list | awk -F ";" '{print $1}' | sed 's/"//g')
powerOff "${VM_NAME}" "${VM_ID}"
if [[ ${POWER_OFF_EC} -eq 1 ]]; then
logger "debug" "Error unable to shutdown VM ${VM_NAME}\n"
PROBLEM_VMS="${PROBLEM_VMS} ${VM_NAME}"
fi
done

IFS="${IFS2}"
fi

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
#VM_FAILED=0 #Excluded VM is NOT a failure. No need to set here, but listed for clarity
fi
fi

if [[ "${IGNORE_VM}" -eq 0 ]] && [[ -n "${PROBLEM_VMS}" ]] ; then
if [[ "${PROBLEM_VMS/$VM_NAME}" != "$PROBLEM_VMS" ]] ; then
logger "info" "Ignoring ${VM_NAME} as a problem VM\n"
IGNORE_VM=1
#A VM ignored due to a problem, should be treated as a failure
VM_FAILED=1
fi
fi

VM_ID=$(grep -E "\"${VM_NAME}\"" ${WORKDIR}/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}\"" ${WORKDIR}/vms_list | awk -F ";" '{print $3}' | sed 's/\[//;s/\]//;s/"//g')
VMX_CONF=$(grep -E "\"${VM_NAME}\"" ${WORKDIR}/vms_list | awk -F ";" '{print $4}' | sed 's/\[//;s/\]//;s/"//g')
VMX_PATH="/vmfs/volumes/${VMFS_VOLUME}/${VMX_CONF}"
VMX_DIR=$(dirname "${VMX_PATH}")

#storage info
if [[ ! -z ${VM_ID} ]] && [[ "${LOG_LEVEL}" != "dryrun" ]]; then
storageInfo "before"
fi

#ignore VM as it's in the exclusion list or was on problem list
if [[ "${IGNORE_VM}" -eq 1 ]] ; then
logger "debug" "Ignoring ${VM_NAME} for backup since it is located in exclusion file or problem 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): "

TOTAL_VM_SIZE=0
getVMDKs

OLD_IFS="${IFS}"
IFS=":"
for j in ${VMDKS}; do
J_VMDK=$(echo "${j}" | awk -F "###" '{print $1}')
J_VMDK_SIZE=$(echo "${j}" | awk -F "###" '{print $2}')
logger "dryrun" "\t${J_VMDK}\t${J_VMDK_SIZE} GB"
done

HAS_INDEPENDENT_DISKS=0
logger "dryrun" "INDEPENDENT VMDK(s): "
for k in ${INDEP_VMDKS}; do
HAS_INDEPENDENT_DISKS=1
K_VMDK=$(echo "${k}" | awk -F "###" '{print $1}')
K_VMDK_SIZE=$(echo "${k}" | awk -F "###" '{print $2}')
logger "dryrun" "\t${K_VMDK}\t${K_VMDK_SIZE} GB"
done

IFS="${OLD_IFS}"
VMDKS=""
INDEP_VMDKS=""

logger "dryrun" "TOTAL_VM_SIZE_TO_BACKUP: ${TOTAL_VM_SIZE} GB"
if [[ ${HAS_INDEPENDENT_DISKS} -eq 1 ]] ; then
logger "dryrun" "Snapshots can not be taken for indepdenent disks!"
logger "dryrun" "THIS VIRTUAL MACHINE WILL NOT HAVE ALL ITS VMDKS BACKED UP!"
fi

ls "${VMX_DIR}" | grep -q "\-delta\.vmdk" > /dev/null 2>&1;
if [[ $? -eq 0 ]]; then
if [ ${ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP} -eq 0 ]; then
logger "dryrun" "Snapshots found for this VM, please commit all snapshots before continuing!"
logger "dryrun" "THIS VIRTUAL MACHINE WILL NOT BE BACKED UP DUE TO EXISTING SNAPSHOTS!"
else
logger "dryrun" "Snapshots found for this VM, ALL EXISTING SNAPSHOTS WILL BE CONSOLIDATED PRIOR TO BACKUP!"
fi
fi

if [[ ${TOTAL_VM_SIZE} -eq 0 ]] ; then
logger "dryrun" "THIS VIRTUAL MACHINE WILL NOT BE BACKED UP DUE TO EMPTY VMDK LIST!"
fi
logger "dryrun" "###############################################\n"

#checks to see if the VM has any snapshots to start with
elif [[ -f "${VMX_PATH}" ]] && [[ ! -z "${VMX_PATH}" ]]; then
if ls "${VMX_DIR}" | grep -q "\-delta\.vmdk" > /dev/null 2>&1; then
if [ ${ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP} -eq 0 ]; then
logger "info" "Snapshot found for ${VM_NAME}, backup will not take place\n"
VM_FAILED=1
continue
elif [ ${ALLOW_VMS_WITH_SNAPSHOTS_TO_BE_BACKEDUP} -eq 1 ]; then
logger "info" "Snapshot found for ${VM_NAME}, consolidating ALL snapshots now (this can take awhile) ...\n"
$VMWARE_CMD vmsvc/snapshot.removeall ${VM_ID} > /dev/null 2>&1
fi
fi
#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_VOLUME 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}"

# Rsync relative path variable if needed
RSYNC_LINK_DIR="./${VM_NAME}-${VM_BACKUP_DIR_NAMING_CONVENTION}"

# Do indexed rotation if naming convention is set for it
if [[ ${VM_BACKUP_DIR_NAMING_CONVENTION} = "0" ]]; then
indexedRotate "${BACKUP_DIR}" "${VM_NAME}"
fi

mkdir -p "${VM_BACKUP_DIR}"

cp "${VMX_PATH}" "${VM_BACKUP_DIR}"

#new variable to keep track on whether VM has independent disks
VM_HAS_INDEPENDENT_DISKS=0

#extract all valid VMDK(s) from VM
getVMDKs

if [[ ! -z ${INDEP_VMDKS} ]] ; then
VM_HAS_INDEPENDENT_DISKS=1
fi

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
powerOff "${VM_NAME}" "${VM_ID}"
if [[ ${POWER_OFF_EC} -eq 1 ]]; then
VM_FAILED=1
CONTINUE_TO_BACKUP=0
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
echo "ERROR: Unable to backup ${VM_NAME} due to snapshot creation" >> ${VM_BACKUP_DIR}/STATUS.error
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=$(echo "${j}" | awk -F "###" '{print $1}')
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}"
harrytsai iT邦新手 5 級 ‧ 2018-12-17 12:00:14 檢舉
看一下ghettoVCB.sh 這個檔案的所在位置跟群組,還有你是在exsi 下操作,還是在vsphere操作,不同的環境用到的權限會不一樣。
fireflybug iT邦研究生 5 級 ‧ 2018-12-17 13:55:43 檢舉
直接在ESXi主機下操作,在5.1上都沒問題。權限與群組都是root。
個人猜測是系統變的比較嚴謹的問題,只是還找不到查不到在哪邊,官方秀出有支援6.X了
fireflybug iT邦研究生 5 級 ‧ 2018-12-17 13:55:45 檢舉
我再去查看看有人有相關問題嗎?感覺很少人在用6.7,要不是新的PC不能安裝5.X,我想我還是會用5.1,夠用了
fireflybug iT邦研究生 5 級 ‧ 2018-12-17 14:11:20 檢舉
我想大概跟新的主機BIOS的Secure Boot功能有關,有點覺得這功能很雞肋,上次忘了什麼功能無法使用也是因為它!今晚回家把主機BIOS這功能關閉試試
http://jawadchowdhury.com/cannot-change-acceptance-level-to-community-vsphere-6-5/
fireflybug iT邦研究生 5 級 ‧ 2018-12-17 14:12:34 檢舉
這功能關閉後,才能執行官方的兩個安裝
How to install
You can quickly install ghettoVCB by downloading and install either the VIB or offline bundle using the following commands:

Install VIB

esxcli software vib install -v /vghetto-ghettoVCB.vib -f
Install offline bundle

esxcli software vib install -d /vghetto-ghettoVCB-offline-bundle.zip -f

1 個回答

0
lovesharepc
iT邦新手 4 級 ‧ 2018-12-17 19:54:56

首先我可以肯定 ghettoVCB 可以在最新的 ESXi 6.7 執行

要麻煩你另外提供一下
1.執行指令以及完整的錯誤訊息
2.VM 的名稱 (esxcli vm process list)
3.ghettoVCB 的權限 (ls -l)

另外給您參考一下文章
https://noevertiredtotech.blogspot.com/2018/12/esxi-ghettovcb-vm.html

fireflybug iT邦研究生 5 級 ‧ 2018-12-18 09:19:59 檢舉

感謝,昨晚過於忙碌忘了測試關閉 Secure boot,我再找時間測試
.........
看起來真的是上面問題,造成下面無法安裝
.........
允許安裝非原廠 vib
esxcli software acceptance set --level=CommunitySupported

我要發表回答

立即登入回答