Skip to content

Instantly share code, notes, and snippets.

@MagerValp
Created November 14, 2014 19:38
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save MagerValp/5219e8d3e343b4d0b57e to your computer and use it in GitHub Desktop.
Save MagerValp/5219e8d3e343b4d0b57e to your computer and use it in GitHub Desktop.
Start a linked clone of a VM and list available software updates.
#!/bin/bash
#
# Start a linked clone of a VM and list available software updates.
declare -r FUSION_PATH="/Applications/VMware Fusion.app"
declare -r GUEST_USER="swup"
declare -r GUEST_PASSWORD="swup"
# Exit status constants.
declare -ri EX_OK=0
declare -ri EX_USAGE=64 # The command was used incorrectly.
declare -ri EX_DATAERR=65 # Input data was incorrect in some way.
declare -ri EX_NOINPUT=66 # Input file did not exist or wasn't readable.
declare -ri EX_NOUSER=67 # The user specified did not exist.
declare -ri EX_NOHOST=68 # The host specified did not exist.
declare -ri EX_UNAVAILABLE=69 # A service is unavailable.
declare -ri EX_SOFTWARE=70 # An internal software error has been detected.
declare -ri EX_OSERR=71 # An operating system error has been detected.
declare -ri EX_OSFILE=72 # Some system file is unavailable.
declare -ri EX_CANTCREAT=73 # A specified output file cannot be created.
declare -ri EX_IOERR=74 # An error occurred while doing I/O.
declare -ri EX_TEMPFAIL=75 # Temporary failure.
declare -ri EX_PROTOCOL=76 # Remote protocol failure.
declare -ri EX_NOPERM=77 # Required permission missing.
declare -ri EX_CONFIG=78 # Something was unconfigured or misconfigured.
# ANSI escape codes.
# Reset.
declare -r ANSI_RESET=$'\x1b[0m'
# Attributes.
declare -r ANSI_BOLD=$'\x1b[1m'
declare -r ANSI_DIM=$'\x1b[2m'
declare -r ANSI_UL=$'\x1b[4m'
declare -r ANSI_BLINK=$'\x1b[5m'
declare -r ANSI_INVERT=$'\x1b[7m'
declare -r ANSI_HIDDEN=$'\x1b[8m'
declare -r ANSI_BOLDOFF=$'\x1b[21m'
declare -r ANSI_DIMOFF=$'\x1b[22m'
declare -r ANSI_ULOFF=$'\x1b[24m'
declare -r ANSI_BLINKOFF=$'\x1b[25m'
declare -r ANSI_INVERTOFF=$'\x1b[27m'
declare -r ANSI_HIDDENOFF=$'\x1b[28m'
# Foreground color.
declare -r ANSI_NOCOLOR=$'\x1b[39m'
declare -r ANSI_BLACK=$'\x1b[30m'
declare -r ANSI_RED=$'\x1b[31m'
declare -r ANSI_GREEN=$'\x1b[32m'
declare -r ANSI_YELLOW=$'\x1b[33m'
declare -r ANSI_BLUE=$'\x1b[34m'
declare -r ANSI_MAGENTA=$'\x1b[35m'
declare -r ANSI_CYAN=$'\x1b[36m'
declare -r ANSI_LTGRAY=$'\x1b[37m'
declare -r ANSI_DKGRAY=$'\x1b[90m'
declare -r ANSI_LTRED=$'\x1b[91m'
declare -r ANSI_LTGREEN=$'\x1b[92m'
declare -r ANSI_LTYELLOW=$'\x1b[93m'
declare -r ANSI_LTBLUE=$'\x1b[94m'
declare -r ANSI_LTMAGENTA=$'\x1b[95m'
declare -r ANSI_LTCYAN=$'\x1b[96m'
declare -r ANSI_WHITE=$'\x1b[97m'
# Background color.
declare -r ANSI_BGNOCOLOR=$'\x1b[49m'
declare -r ANSI_BGBLACK=$'\x1b[40m'
declare -r ANSI_BGRED=$'\x1b[41m'
declare -r ANSI_BGGREEN=$'\x1b[42m'
declare -r ANSI_BGYELLOW=$'\x1b[43m'
declare -r ANSI_BGBLUE=$'\x1b[44m'
declare -r ANSI_BGMAGENTA=$'\x1b[45m'
declare -r ANSI_BGCYAN=$'\x1b[46m'
declare -r ANSI_BGLTGRAY=$'\x1b[47m'
declare -r ANSI_BGDKGRAY=$'\x1b[100m'
declare -r ANSI_BGLTRED=$'\x1b[101m'
declare -r ANSI_BGLTGREEN=$'\x1b[102m'
declare -r ANSI_BGLTYELLOW=$'\x1b[103m'
declare -r ANSI_BGLTBLUE=$'\x1b[104m'
declare -r ANSI_BGLTMAGENTA=$'\x1b[105m'
declare -r ANSI_BGLTCYAN=$'\x1b[106m'
declare -r ANSI_BGWHITE=$'\x1b[107m'
# Exit with status and an error message.
function die() {
local exit_status="$1"
local message="$2"
echo "${ANSI_RED}${message}${ANSI_RESET}" 1>&2
exit "$exit_status"
}
# VMware Fusion support.
declare -r VMWARE_PATH="$FUSION_PATH/Contents/Library"
declare -r VMRUN="$VMWARE_PATH/vmrun"
if [[ ! -x "$VMWARE_PATH/vmrun" ]]; then
die $EX_UNAVAILABLE "'$VMWARE_PATH/vmrun' is not available"
fi
function vmrun() {
"$VMWARE_PATH/vmrun" -gu "$GUEST_USER" -gp "$GUEST_PASSWORD" "$@"
}
function vmrun_root() {
"$VMWARE_PATH/vmrun" -gu "root" -gp "$GUEST_PASSWORD" "$@"
}
# Create, launch, and destroy VM clones.
function create_linked_clone() {
local base_vmx="$1"
local clone_vmx="$2"
local clone_name="$3"
# FIXME: Use named snapshots.
vmrun clone "$base_vmx" "$clone_vmx" -cloneName="$clone_name" linked
}
function start_vm() {
local vmx="$1"
vmrun start "$vmx" nogui
}
function wait_for_boot() {
local vmx="$1"
local count=0
while ! vmrun listProcessesInGuest "$vmx" | grep -q "Finder"; do
sleep 1
done
}
function wait_for_internet() {
local vmx="$1"
vmrun_root runScriptInGuest "$vmx" /bin/bash \
"while ! ping -q -c 1 www.google.com &>/dev/null; do sleep 1; done"
}
function kill_vm() {
local vmx="$1"
local retval
vmrun stop "$vmx" hard
}
function delete_clone() {
local base_vmx="$1"
local clone_vmx="$2"
local clone_name="$3"
vmrun deleteVM "$clone_vmx"
# FIXME: Use named snapshots.
vmrun deleteSnapshot "$base_vmx" Clone #"$snapshot_name"
}
# Main.
function list_software_updates() {
local vmx="$1"
local d="--------"
echo "${ANSI_BLUE}$d$d$d$d$d$d$d$d$d${ANSI_RESET}"
vmrun_root runScriptInGuest "$vmx" /bin/bash \
"( /usr/bin/sw_vers; /usr/sbin/softwareupdate -v -l ) &> /tmp/output; sleep 1"
tempfile="${TMPDIR}/output.${RANDOM}${RANDOM}${RANDOM}${RANDOM}"
vmrun_root copyFileFromGuestToHost "$vmx" /tmp/output "$tempfile"
cat "$tempfile"
rm -f "$tempfile"
vmrun_root runProgramInGuest "$vmx" /bin/rm -f /tmp/output
echo "${ANSI_BLUE}$d$d$d$d$d$d$d$d$d${ANSI_RESET}"
}
function main() {
# Arguments
if [[ $# -ne 1 ]]; then
die $EX_USAGE "Usage: $(basename "$0") base_vm"
fi
local base_vmx="$1"
local clone_vmx="${base_vmx%.vmx}_clone.vmx"
local clone_name="swuprun_${RANDOM}${RANDOM}"
if [[ ! -f "$base_vmx" ]]; then
die $EX_NOINPUT "'$base_vmx' does not exist or is not a vmx file"
fi
if [[ -e "$clone_vmx" ]]; then
die $EX_CANTCREAT "'$clone_vmx' already exists"
fi
# Create a linked clone.
echo "Cloning VM"
if ! create_linked_clone "$base_vmx" "$clone_vmx" "$clone_name"; then
die $EX_CANTCREAT "Failed to create linked clone '$clone_vmx'"
fi
# Start the cloned VM.
echo "Starting clone"
if ! start_vm "$clone_vmx"; then
die $EX_UNAVAILABLE "Couldn't start VM"
fi
# Wait for the cloned VM to boot and our user to log in.
echo "Waiting for clone to boot"
if ! wait_for_boot "$clone_vmx"; then
die $EX_UNAVAILABLE "Failed while waiting for VM to boot"
fi
# Wait for internet access.
echo "Waiting for internet"
if ! wait_for_internet "$clone_vmx"; then
die $EX_UNAVAILABLE "Failed while waiting internet access"
fi
# Check for software updates.
list_software_updates "$clone_vmx"
# Shut down the cloned VM.
echo "Stopping clone"
if ! kill_vm "$clone_vmx"; then
die $EX_UNAVAILABLE "Failed to stop VM"
fi
# Remove the linked clone and associated snapshot.
echo "Deleting clone"
if ! delete_clone "$base_vmx" "$clone_vmx" "$clone_name"; then
die $EX_IOERR "Failed to delete VM"
fi
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment