Skip to content

Instantly share code, notes, and snippets.

@jorgebraz
Created April 4, 2012 03:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jorgebraz/2297565 to your computer and use it in GitHub Desktop.
Save jorgebraz/2297565 to your computer and use it in GitHub Desktop.
VirtualBox Headless VM helper
#!/bin/bash
# SGR (Select Graphic Rendition) parameters
# Code Effect Note
# 0 Reset / Normal all attributes off
# 1 Bright (increased intensity) or Bold
# 2 Faint (decreased intensity) not widely supported
# 3 Italic: on not widely supported. Sometimes treated as inverse.
# 4 Underline: Single
# 5 Blink: Slow less than 150 per minute
# 6 Blink: Rapid MS-DOS ANSI.SYS; 150 per minute or more; not widely supported
# 7 Image: Negative inverse or reverse; swap foreground and background
# 8 Conceal not widely supported
# 9 Crossed-out Characters legible, but marked for deletion. Not widely supported.
# 10 Primary(default) font
# 11–19 n-th alternate font Select the n-th alternate font. 14 being the fourth alternate font, up to 19 being the 9th alternate font.
# 20 Fraktur hardly ever supported
# 21 Bright/Bold: off or Underline: Double bold off not widely supported, double underline hardly ever
# 22 Normal color or intensity neither bright, bold nor faint
# 23 Not italic, not Fraktur
# 24 Underline: None not singly or doubly underlined
# 25 Blink: off
# 26 Reserved
# 27 Image: Positive
# 28 Reveal conceal off
# 29 Not crossed out
# 30–37 Set text color 30 + x, where x is from the color table below
# 38 Set xterm-256 text color next arguments are 5;x where x is color index (0..255)
# 39 Default text color implementation defined (according to standard)
# 40–47 Set background color 40 + x, where x is from the color table below
# 48 Set xterm-256 background color next arguments are 5;x where x is color index (0..255)
# 49 Default background color implementation defined (according to standard)
# 50 Reserved
# 51 Framed
# 52 Encircled
# 53 Overlined
# 54 Not framed or encircled
# 55 Not overlined
# 56–59 Reserved
# 60 ideogram underline or right side line hardly ever supported
# 61 ideogram double underline or double hardly ever supported
# line on the right side
# 62 ideogram overline or left side line hardly ever supported
# 63 ideogram double overline or double hardly ever supported
# line on the left side
# 64 ideogram stress marking hardly ever supported
# 90–99 Set foreground color, high intensity aixterm (not in standard)
# 100–109 Set background color, high intensity aixterm (not in standard)
# Styled-echo.
# Argument $1 = message
# Argument $2 = color
# Argument $3 = style
# Argument $4 = background color
# Argument $5 = background color
function secho()
{
if [ "$1" == "--help" ]; then
echo "help"
return
fi
local reset="\e[0m"
local style_bold='\e[1m'
local style_underline='\e[4m'
local style_blink='\e[5m'
local style_negative='\e[7m'
local style_default="$reset"
local color_black='\e[30m'
local color_red='\e[31m'
local color_green='\e[32m'
local color_yellow='\e[33m'
local color_blue='\e[34m'
local color_magenta='\e[35m'
local color_cyan='\e[36m'
local color_white='\e[37m'
local color_default='\e[39m'
local bg_black='\e[40m'
local bg_red='\e[41m'
local bg_green='\e[42m'
local bg_yellow='\e[43m'
local bg_blue='\e[44m'
local bg_magenta='\e[45m'
local bg_cyan='\e[46m'
local bg_white='\e[47m'
local bg_default='\e[49m'
local default_msg="This is the default message!"
color=$(eval "echo \$color_${2}")
style=$(eval "echo \$style_${3}")
background=$(eval "echo \$bg_${4}")
message=${1:-$default_msg} # Defaults to default message.
newline=${5:-1} # Defaults to default message.
if [ "$color" == "" ]; then
color=${color_default} # Defaults to black, if not specified.
fi
if [ "$style" == "" ]; then
style=${style_default} # Defaults to black, if not specified.
fi
if [ "$background" == "" ]; then
background=${bg_default} # Defaults to black, if not specified.
fi
if [ $newline -eq 1 ]; then
newline="\n"
else
newline=""
fi
printf "${style}${background}${color}${message}${reset}${newline}"
return
}
source "$(pwd)/secho.sh"
function start_spinner {
# $1 : msg to display
_spinner "start" "${1}" &
# set global spinner pid
_sp_pid=$!
disown
}
function stop_spinner {
# $1 : command exit status
_spinner "stop" $1 $_sp_pid
unset _sp_pid
}
function _spinner() {
# $1 start/stop
#
# on start: $2 display message
# on stop : $2 process exit status
# $3 spinner function pid (supplied from stop_spinner)
local on_success="DONE"
local on_fail="FAIL"
case $1 in
start)
# calculate the column where spinner and status msg will be displayed
let column=$(tput cols)-${#2}-8
# display message and position the cursor in $column column
echo -ne ${2}
printf "%${column}s"
# start spinner
i=1
sp='\|/-'
delay=0.15
while :
do
if [ $i != 1 ]; then
printf "\b\b${sp:i++%${#sp}:1}]"
else
echo -n "[ "
printf "\b${sp:i++%${#sp}:1}]"
fi
#printf "\b${sp:i++%${#sp}:1}]"
sleep $delay
done
;;
stop)
if [[ -z ${3} ]]; then
echo "spinner is not running.."
exit 1
fi
kill $3 > /dev/null 2>&1
# inform the user uppon success or failure
printf "\b\b"
if [[ $2 -eq 0 ]]; then
#printf "${green}${on_success}${nc}"
secho "$on_success" green default default 0
else
#printf "${red}${on_fail}${nc}"
secho "$on_fail" red negative default 0
fi
echo -n "]"
echo ""
;;
*)
echo "invalid argument, try {start/stop}"
exit 1
;;
esac
}
#!/bin/bash
source "$(pwd)/secho.sh"
source "$(pwd)/spinner.sh"
SELECTED_VM=""
DOT_FOLDER=~/.vmh
CONF_FILE=~/.vmh/conf
SELECTED_VM_FILE=~/.vmh/selected_vm
function connect() # Connects to the selected Virtual Machine, starting it if needed
{
local STATE=$(_state)
local SLEEP=15
if [ "$STATE" == 'running' ]; then
echo "Starting a secure shell connection to $SELECTED_VM"
shell
fi
if [ "$STATE" != 'running' ]; then
read -n1 -s -p "The Virtual machine $VM is not started, do you want to start it? (Y/n)" ANSWER
case "$ANSWER" in
"" | [yY] | [yY][Ee][Ss] )
start
echo "Starting a secure shell connection to $SELECTED_VM"
shell
;;
[nN] | [n|N][O|o] )
echo ""
echo "Exiting";
$(exit 1)
;;
* )
echo ""
echo "y/n"
$(exit 1)
;;
esac
fi
}
function start() # Starts the selected Virtual Machine
{
local STATE=$(_state)
local SLEEP=15
if [ "$STATE" == 'running' ]; then
echo "The VM $VM is already powered on!"
fi
if [ "$STATE" != 'running' ]; then
echo "Powering $VM on will take a few seconds"
VBoxManage startvm $SELECTED_VM --type headless
start_spinner "Booting up..."
#trap "kill -9 $! > /dev/null 2>&1;trap 1 2 3 8 15" 1 2 3 8 15
trap "kill -9 $! > /dev/null 2>&1;trap INT TERM KILL" INT TERM KILL
local READY=""
local IP="value"
while [[ "$READY" != "succeeded" ]]
do
sleep 1
IP=$(_ip)
if [ "$IP" != "value" ]; then
READY=$(nc -zn $IP 22 | grep -o "succeeded")
fi
done
stop_spinner $?
fi
}
function stop() # Stops the selected Virtual Machine
{
local STATE=$(_state)
local SLEEP=15
if [ "$STATE" != 'running' ]; then
echo "The VM $SELECTED_VM is already powered off!"
fi
if [ "$STATE" == 'running' ]; then
echo "Powering $SELECTED_VM off will take a few seconds"
VBoxManage controlvm $SELECTED_VM acpipowerbutton
#start_spinner "Shutting down..."
#trap "kill -9 $! > /dev/null 2>&1;trap 1 2 3 8 15" 1 2 3 8 15
trap "kill -9 $! > /dev/null 2>&1;trap INT TERM KILL" INT TERM KILL
local ELAPSED=0
while [[ "$STATE" == 'running' ]]
do
sleep 2
let ELAPSED+=2
STATE=$(_state)
if [ "$ELAPSED" -gt 15 ]; then
VBoxManage controlvm $SELECTED_VM acpipowerbutton
ELAPSED=0
fi
done
stop_spinner $?
fi
}
function restart() # Restarts the selected Virtual Machine
{
VBoxManage controlvm $SELECTED_VM reset
}
function shell() # Establishes a secure shell connection to the selected Virtual Machine
{
ssh $(_ip)
}
function properties() # Enumerates properties for the selected Virtual Machine
{
VBoxManage guestproperty enumerate $SELECTED_VM
}
function status() # Shows the status for the selected Virtual Machine
{
VBoxManage showvminfo $SELECTED_VM | grep State
}
function list() # Lists Virtual Machines available for selection
{
VBoxManage list vms | awk '{ print $1 }'
}
function use() # Select a Virtual Machine from the available VMs
{
VMS=($(list))
if [ "$1" == "" ]; then
secho "${#VMS[*]} Virtual machines found:" green bold
for i in ${!VMS[*]}; do
string="${VMS[$i]:1:${#VMS[$i]}-2}"
echo "[$i] $string"
done
read -e -p "Which VM do you want to use? " ANSWER
else
ANSWER=$1
fi
# No answer
if [ "$ANSWER" == "" ]; then
secho "You must select a VM, either by typing number or name..." red bold
use
else
# $ANSWER is a digit
if [[ $ANSWER = *[[:digit:]]* ]]; then
VM=${VMS[$ANSWER]}
VM="${VM:1:${#VM}-2}"
else
# Serach for $ANSWER in $VMS array
for item in ${VMS[*]}; do
item="${item:1:${#item}-2}"
if [ "$item" == "$ANSWER" ]; then
VM=$ANSWER
fi
done;
fi
if [ "$VM" == "" ]; then
secho "The Virtual Machine your selecting doesn't exist, please select another" red bold
use
else
SELECTED_VM="$VM"
fi
fi
_select_vm
}
function _help
{
secho "Usage: " green bold
grep "^function" $0 \
| grep -v "^function _" \
| sed s/function/vmhelper/ \
| sed s/\(\)/\ \<Virtual\ Machine\>\ /
}
function _interactive
{
actions="list use status properties restart start stop help _help"
interactive=0;
for action in ${actions[*]}; do
if [ "$action" == "$1" ]; then
interactive=1;
fi
done;
if [ "$interactive" -eq 1 ]; then
echo ""
message=$(secho "What else? [help] # " blue negative)
read -e -p "$message " ANSWER
echo ""
_dispatch $ANSWER
fi
}
function _dispatch
{
if [ "$(type -t $1)" == "function" ]; then
if [ "$1" == "help" ]; then
_help
else
$(echo "$1")
fi
_interactive $1
exit
else
if [ -n "$1" ]; then
secho "Unrecognized command <$1> " red bold
fi
_help
_interactive "_help"
exit
fi
}
function _select_vm
{
echo "SELECTED_VM=${SELECTED_VM}" > $SELECTED_VM_FILE
secho " ${SELECTED_VM} is selected " black bold cyan
}
function _state
{
VBoxManage showvminfo $SELECTED_VM | grep State | awk '{ print $2 }' | egrep -v ^'\('
}
function _ip
{
VBoxManage guestproperty get $SELECTED_VM "/VirtualBox/GuestInfo/Net/0/V4/IP" | awk '{ print $2 }'
}
function _dot_files
{
if [ ! -d $DOT_FOLDER ]; then
mkdir $DOT_FOLDER
fi
if [ -f $CONF_FILE ]; then
source $CONF_FILE
else
touch $CONF_FILE
fi
if [ -f $SELECTED_VM_FILE ]; then
source $SELECTED_VM_FILE
else
touch $SELECTED_VM_FILE
fi
}
_dot_files
# Check for selected Virtual Machine
if [ -n "$2" ]; then
use $2
if [ "$1" == "use" ]; then
exit
fi
else
if [ "$SELECTED_VM" == "" ]; then
use
fi
fi
_select_vm
_dispatch $1
@jorgebraz
Copy link
Author

USAGE

First give it execution permission
$ chmod +x vm-helper.sh

Now just
$ ./vm-helper.sh FUNCTION VMNAME

Examples

$ ./vm-helper launch MyVM
$ ./vm-helper start MyVM
$ ./vm-helper stop MyVM

@jorgebraz
Copy link
Author

I should probably rename function launch to connect

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment