#!/bin/bash
# Etersoft, 2010
# 2010 (c) Devaev Maxim, <mdevaev@etersoft.ru>
#
# vbox - client for remote virtualbox machines
#
#####


#####
check_display()
{
	xset -b >/dev/null 2>&1
}

fatal()
{
	echo "$@"
	exit 1
}

xfatal()
{
	check_display || fatal "$@"
	xmessage -center "$@" || fatal "$@"
	exit 1
}


#####
if [ "$UID" == "0" ]; then
	xfatal "Do not run \"vbox\" from a \"root\" account!"
fi

if [ -z "$SSH_AUTH_SOCK" ]; then
	xfatal "Run ssh-agent, use \"eval \`ssh-agent\`\" or \"eval \`ssh-agent -u\`\", and then, run \"ssh-add\""
fi

if ! ssh-add -l > /dev/null; then
	xfatal "Missing ssh key. Run \"ssh-add\", plz ;-)"
fi


#####
init_environment()
{
	[ -n "$VBOX_HOST" ] || VBOX_HOST="virtualbox"
	[ -n "$VBOX_SSH_PORT" ] || VBOX_SSH_PORT="22"

	local config_dir="$XDG_CONFIG_HOME"
	[ -d "$config_dir" ] || config_dir="$HOME/.config"
	if [ ! -e $config_dir/vbox.conf ]; then
		echo "Copying default vbox configuration from server..."
		scp -P "$VBOX_SSH_PORT" "$VBOX_HOST":/etc/vbox/vbox.conf "$config_dir"/vbox.conf
	fi
	. "$config_dir"/vbox.conf

	for var in VBOX_USER VBOX_HOST VBOX_SSH_PORT VBOX_SSH_OPTIONS VBOX_NXCLIENT VBOX_NXCLIENT_CONFIG VBOX_PROTOCOL \
		DHCP_HOST DHCP_SSH_PORT; do
		[ -n "`eval echo \\$"$var"`" ] || xfatal "Variable \$$var is not defined in $config_dir/vbox.conf"
	done

	local nxclient_config="$HOME/.nx/config/"`basename "$VBOX_NXCLIENT_CONFIG"`
	if [ ! -e "$nxclient_config" ]; then
		echo "Copying default nxclient configuration from server..."
		mkdir -p `dirname "$nxclient_config"`
		scp -P "$VBOX_SSH_PORT" "$VBOX_HOST":"$VBOX_NXCLIENT_CONFIG" "$nxclient_config"
	fi
}


# FIXME: move to server
#####
get_vms_table()
{
	ssh "$VBOX_USER"@"$VBOX_HOST" -p "$VBOX_SSH_PORT" "/etc/rc.d/init.d/vboxmachines get_list"
}

print_vms_table()
{
	echo -n "Getting VirtualBox machines list at \"$VBOX_HOST\"... "
	vms_table=`get_vms_table`
	echo -e "OK\n"
	echo "++---------------------------------------------------------------------------------------------------------------------------------------++"
	printf "|| %10s | %30s | %36s | %30s | %15s ||\n" "State" "Machine name" "UUID" "Hostname" "IP"
	echo "++---------------------------------------------------------------------------------------------------------------------------------------++"
	echo -e "$vms_table"
	echo "++---------------------------------------------------------------------------------------------------------------------------------------++"
}


#####
connect_over_ssh()
{
	local vbox_command="$@"
	[ -n "$vbox_command" ] || vbox_command="VirtualBox"

	local x_forward="-Y"
	check_display || x_forward=""

	ssh $x_forward $VBOX_SSH_OPTIONS "$VBOX_USER"@"$VBOX_HOST" -p "$VBOX_SSH_PORT" "$vbox_command" ||
		xfatal "Try run in intranet \$ ssh-copy-id $VBOX_USER@$VBOX_HOST for copy ssh key."
}

connect_over_nx()
{
	check_display || xfatal "Can't run nx connection with broken DISPLAY variable"

	local nxclient=`which "$VBOX_NXCLIENT" 2>/dev/null`
	if [ ! -e "$nxclient" ]; then xfatal "Can't find \"$VBOX_NXCLIENT\" executable"; fi

	local nxclient_config="$HOME/.nx/config/"`basename "$VBOX_NXCLIENT_CONFIG"`

	"$nxclient" --autologin --session "$nxclient_config"
}



#####
help()
{
	echo
	echo -e "usage: vbox [flags] [command]"
	echo
	echo -e "Flags:"
	echo -e "\t--ssh - Enables SSH protocol for X11 windows"
	echo -e "\t--nx - Enables NX protocol for X11 windows"
	echo
	echo -e "Commands:"
	echo -e "\t-h, --help, help - Print this help (Surprise! ^_^)"
	echo -e "\t-l, --list, list - Print list of virtual machines with detailed info"
	echo -e "\t--start <VM>, start <VM> - Run <VM> (UUID or name) with headless mode"
	echo -e "\t--stop <VM>, stop <VM> - Halt <VM>"
	echo -e "\t--acpi-stop <VM>, acpi-stop <VM> - Poweroff over ACPI signal"
	echo -e "\t--sleep <VM>, sleep <VM> - Save state of <VM>"
	echo -e "\t--restart <VM>, restart <VM> - Hot restart <VM>"
	echo -e "\t--reset <VM>, reset <VM> - Hot reset <VM>"
	echo -e "\t--snapshot <VM> <SSNAME>, snapshot <VM> <SSNAME> - Make snapshot of <VM> (UUID or name)"
	echo -e "\t--info <VM>, info <VM> - Show info of <VM>"
	echo -e "\t--status <VM>, status <VM> - Show state of <VM>"
	echo
}


#####
# FIXME: add support for other vboxuser
init_environment
while true; do
	case "$1" in
		"--ssh") VBOX_PROTOCOL="ssh"; shift;;
		"--nx") VBOX_PROTOCOL="nx"; shift;;
		*) break;;
	esac
done

if [ "$#" -eq "0" ]; then
	case "$VBOX_PROTOCOL" in
		"ssh") connect_over_ssh;;
		"nx") connect_over_nx;;
		*) xfatal "Unknown protocol \"$VBOX_PROTOCOL\"";;
	esac
else
	case "$1" in
		"-h"|"--help"|"help") help;;
		"-l"|"--list"|"list") print_vms_table;;
		"--start"|"start") connect_over_ssh "VBoxManage --nologo startvm \"$2\" --type headless";;
		"--stop"|"stop") connect_over_ssh "VBoxManage --nologo controlvm \"$2\" poweroff";;
		"--acpi-stop"|"acpi-stop") connect_over_ssh "VBoxManage --nologo controlvm \"$2\" acpipowerbutton";;
		"--sleep"|"sleep") connect_over_ssh "VBoxManage --nologo controlvm \"$2\" savestate";;
		"--restart"|"restart") connect_over_ssh "VBoxManage --nologo controlvm \"$2\" poweroff; \
			VBoxManage --nologo startvm \"$2\" --type headless";;
		"--reset"|"reset") connect_over_ssh "VBoxManage --nologo controlvm \"$2\" reset";;
		"--snapshot"|"snapshot") connect_over_ssh "VBoxManage --nologo snapshot \"$2\" take \"$3\"";;
		"--info"|"info") connect_over_ssh "VBoxManage --nologo showvminfo \"$2\"";;
		"--status"|"status") connect_over_ssh "VBoxManage --nologo showvminfo \"$2\" | grep State";;
		*) connect_over_ssh "$@";;
	esac
fi

