Skip to content

Instantly share code, notes, and snippets.

@murank
Created January 22, 2017 07:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save murank/5e1cb151a30c45bfc88b285781afea32 to your computer and use it in GitHub Desktop.
Save murank/5e1cb151a30c45bfc88b285781afea32 to your computer and use it in GitHub Desktop.
A trivial script to managee VMs on VirtualBox
# A trivial script to managee VMs on VirtualBox
test "$debug" == "y" && set -x
error() {
echo "$*" >&2
}
usage() {
error "Usage: $0 list"
error " up [--gui] <vm>"
error " down <vm>"
error " suspend <vm>"
error " sandbox [list|begin|rollback|commit] <vm>"
}
check_vm_exists() {
local vm="$1"
if [ -z "$vm" ]; then
error "Target vm is not specified."
error
usage
return 1
fi
if ! VBoxManage list vms | grep "\"$vm\"" > /dev/null; then
error "No such vm: $vm"
return 2
fi
return 0
}
execute() {
if ! "$@"; then
error "Fail to execute command: $@"
return 1
fi
return 0
}
wait_state() {
local vm="$1"
local expected="$2"
local timeout=60
for i in `seq 0 $timeout`; do
execute VBoxManage showvminfo "$vm" --machinereadable | grep "VMState=\"$expected\"" > /dev/null && break
echo -n .
if [ $i -ge $timeout ]; then
echo "timeout"
return 1
fi
sleep 1
done
echo done
return 0
}
action_list() {
VBoxManage list vms | sed -e 's/[^"]*"\([^"]*\)"[^"]*/\1/' | sort
}
action_up() {
case $1 in
"--gui") local type=gui; local vm="$2" ;;
*) local type=headless; local vm="$1" ;;
esac
check_vm_exists "$vm" || return 1
execute VBoxManage startvm --type $type "$vm" || return 2
}
action_down() {
local vm="$1"
check_vm_exists "$vm" || return 1
echo -n "Shutting down $vm"
execute VBoxManage controlvm "$vm" acpipowerbutton || return 2
wait_state "$vm" poweroff
}
action_suspend() {
local vm="$1"
check_vm_exists "$vm" || return 1
echo "Suspending $vm..."
execute VBoxManage controlvm "$vm" savestate || return 2
}
sandbox_prefix=Sandbox
action_sandbox_list() {
local vm="$1"
VBoxManage snapshot "$vm" list --machinereadable | awk "BEGIN { cnt=0 } /^SnapshotName[^=]*=\"$sandbox_prefix-/ { match(\$0, /\"[^\"]*\"/); print substr(\$0, RSTART+1, RLENGTH-2); cnt++ } END { if(cnt==0) {print \"$vm has not begun sandbox\"} }"
}
find_latest_sandbox_no() {
local vm="$1"
VBoxManage snapshot "$vm" list --machinereadable | awk "BEGIN { max_no=0; prefix_len=length(\"$sandbox_prefix \") } /^SnapshotName[^=]*=\"$sandbox_prefix-/ { match(\$0, /\"[^\"]*\"/); no=substr(\$0, RSTART+1+prefix_len, RLENGTH-2-prefix_len); if(no>max_no){max_no=no} } END { print max_no }"
}
action_sandbox_begin() {
local vm="$1"
local next_no=$(expr $(find_latest_sandbox_no "$vm") + 1)
echo "Taking snapshot..."
execute VBoxManage snapshot "$vm" take "$sandbox_prefix-$next_no"
}
action_sandbox_commit() {
local vm="$1"
local latest=$(find_latest_sandbox_no "$vm")
if [ $latest -eq 0 ]; then
error "$vm has not begun sandbox"
return 1
fi
echo "Committing changes..."
execute VBoxManage snapshot "$vm" delete "$sandbox_prefix-$latest"
}
action_sandbox_rollback() {
local vm="$1"
local latest=$(find_latest_sandbox_no "$vm")
if [ $latest -eq 0 ]; then
error "$vm has not begun sandbox"
return 1
fi
if VBoxManage showvminfo "$vm" --machinereadable | grep 'VMState="running"' > /dev/null; then
local type=$(VBoxManage showvminfo "$vm" --details | awk '/^Session type:/ { print $3 }')
execute VBoxManage controlvm "$vm" savestate || return 2
fi
echo "Rolling back changes..."
execute VBoxManage snapshot "$vm" restore "$sandbox_prefix-$latest" && \
execute VBoxManage snapshot "$vm" delete "$sandbox_prefix-$latest" || return 2
if [ -n "$type" ]; then
execute VBoxManage startvm --type $type "$vm"
fi
}
action_sandbox() {
local vm="$2"
check_vm_exists "$vm" || return 1
local prefix=Sandbox
case $1 in
"list") action_sandbox_list "$vm" ;;
"begin") action_sandbox_begin "$vm" ;;
"rollback") action_sandbox_rollback "$vm" ;;
"commit") action_sandbox_commit "$vm" ;;
*)
error "Unknown command: sandbox $1"
error
usage
return 1
;;
esac
}
case $1 in
"list") action_list ;;
"up") action_up "$2" "$3" ;;
"down") action_down "$2" ;;
"suspend") action_suspend "$2" ;;
"sandbox") action_sandbox "$2" "$3" ;;
"") usage;;
*) echo "Unknown command: $1" >&2; echo >&2; usage ;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment