-
-
Save nmcspadden/c0cf6ed12ac782ee5a1a3ae930835ae9 to your computer and use it in GitHub Desktop.
Start a linked clone of a VM and list available software updates.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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