View Single Post
  #10  
Old 9th May 2010, 10:07
dfed dfed is offline
Junior Member
 
Join Date: Apr 2010
Posts: 16
Thanks: 0
Thanked 1 Time in 1 Post
Default

Ok I've tweaked it out as far as I am going to with bash. I'll redo some scripts in perl because I've thought of some additions to functionality i want to do, but that's for later.

For now, here's the breakdown:

Three scripts, one to start/stop, one to gather info, and one to ssh remote commands to unixy guests. This works with any type of OS VBox allows, and won't fail with windows guests.

First, throw this in cron at whatever interval you like:

~/bin/refreshvmconfig :
Code:
#!/bin/bash
for x in `VBoxManage list vms | grep '"' | cut -d'"' -f2 | sort -u`; do VBoxManage showvminfo "${x}" --machinereadable | egrep -e "name=" -e "ostype=" -e "VMState=" | cut -d'"' -f2 | cut -d'_' -f1 | xargs echo; done > ~/config/hosts.conf
make sure you have ~/bin and ~/config directories made int he home directory of whatever user is running VBox. Also, you'll want to exchange ssh keys with this user and root or a privileged user on the guest.

Next, this will allow you to start/stop based on VM name, all or OS name. This means if you want to shut down all Windows7 guests at once, you can:

~/bin/vgsvc :
Code:
#!/bin/bash
#Written by dfed with no guarantee this pile of crap will work.
#script to start/stop/restart one or all VM's installed on system via VirtualBox
#
# If we've not had 2 variables passed in the command line, failboat has sailed.
if [[ "${#}" -lt 1 ]]; then
    echo "Usage: ${0} <start|stop|restart|list> <VM Name|OS Name|all>" >&2
    exit 1;
elif [[ "${#}" -gt 2 ]]; then
    echo "Usage: ${0} <start|stop|restart|list> <VM Name|OS Name|all>" >&2
    exit 1;
fi
# First, declare some arrays to use later:
declare -a list
	list=($(cat ~/config/hosts.conf | awk '{print $1}'))
declare -a os
        os=($(cat ~/config/hosts.conf | awk '{print $2}' | sort -u))
# Sanity check on ${1}:
if [[ "${1}" == "list" ]]; then
        echo "Virtuals currently installed are:"
		cat ~/config/hosts.conf | sort -u; 
	echo "Usage: ${0} <start|stop|restart|list> <VM Name|OS Name|all>" >&2; exit 1;
elif [[ "${1}" == "stop" ]]; then
	com=${1}
elif [[ "${1}" == "start" ]]; then
	com=${1}
elif [[ "${1}" == "restart" ]]; then
	com=${1}
else echo "Usage: ${0} <start|stop|restart|list> <VM Name|OS Name|all>" >&2; exit 1;
fi
# Sanity check on ${2}:
checkvm=($(for z in ${list[@]}; do echo ${z} | grep ${2}; done))
checkos=($(for y in ${os[@]}; do echo ${y} | grep ${2}; done))
if [[ "${2}" == ${checkvm} ]]; then
	vm=${2}
elif [[ "${2}" == ${checkos} ]]; then
	declare -a vm
		vm=($(cat ~/config/hosts.conf | grep ${2} | awk '{print $1}'))
elif [[ "${2}" == "all" ]]; then 
	vm=${list[@]}
else echo "Virtual Machine OS/Name ${2} not found.  Use ${0} \"list\" to determine VM names or operating systems installed." >&2; exit 1;
fi
echo "Working to ${com} ${vm[@]}"
# Let's do some work.
if [[ "${com}" == "start" ]]; then 
	for x in ${vm[@]}; do nohup VBoxHeadless --startvm ${x} 2> /dev/null > /dev/null &
		echo "Started VM ${x}"
	done
elif [[ "${com}" == "stop" ]]; then
	for x in ${vm[@]}; do VBoxManage controlvm ${x} poweroff 2>&1 > /dev/null
		echo "Stopped VM ${x}"
	done
elif [[ "${com}" == "restart" ]]; then
	for x in ${vm[@]}; do VBoxManage controlvm ${x} poweroff 2>&1 > /dev/null && nohup VBoxHeadless --startvm ${x} 2> /dev/null > /dev/null &
		echo "Restarted VM ${x}"
	done
fi
/opt/virtuals/bin/refreshvmconfig
exit 0
That will also refresh your config file with the state of whatever you start/stopped. This should be called from whatever init.d script you come up with to start vm's automatically at boot.

Next, issue commands over ssh to unixy guests:

~/bin/vcmd-ssh :
Code:
#!/bin/bash
#Written by dfed with no guarantee this pile of crap will work.
#script to issue commands via ssh to guests based on OS
#
source ~/.bashrc
# If we've not had some variables passed in the command line, failboat has sailed.
if [[ "${#}" -lt 1 ]]; then
    echo "Usage: ${0} <OS Name|VM Name|all|list> <Command (in quotes)>" >&2
        exit 1;
elif [[ "${#}" -gt 2 ]]; then
    echo "Usage: ${0} <OS Name|VM Name|all|list> <Command (in quotes)>" >&2
        exit 1;
fi
# Some arrays to use later:
declare -a vms
	vms=($(cat ~/config/hosts.conf | awk '{print $1}' | sort -u))
declare -a os
        os=($(cat ~/config/hosts.conf | awk '{print $2}' | sort -u))
declare -a hosts
	hosts=($(cat ~/config/hosts.conf | grep "running" | grep -v "Windows" | grep -v "OS2" | grep -v "DOS" | grep -v "Other" | grep -v "Netware" | awk '{print $1" "$2}'| sort -u))
checkvm=($(for z in ${vms[@]}; do echo ${z} | grep "${1}"; done))
checkos=($(for y in ${os[@]}; do echo ${y} | grep "${1}"; done))
# Sanity checks on ${1}
if [[ "${1}" == "all" ]]; then
	first="all"
elif [[ "${1}" == "list" ]]; then
	echo "Virtuals currently running are:"
		cat ~/config/hosts.conf | grep "running" | awk -F"running" '{print $1}' | sort -u 
	echo "Usage: ${0} <OS Name|VM Name|all|list> <Command (in quotes)>" >&2; exit 1
elif [[ "${1}" == ${checkvm} ]]; then
	checkssh=($(for x in ${hosts[@]}; do echo ${x} | grep "${checkvm}"; done))
	if [[ ${checkvm} == ${checkssh} ]]; then
		first="vm" 
	else echo "Sorry, "${checkvm}" is not an ssh-capable VM or is not running."
	echo "Usage: ${0} <OS Name|VM Name|all|list> <Command (in quotes)>" >&2; exit 1
	fi
elif [[ "${1}" == ${checkos} ]]; then
	checkssh=($(for x in ${hosts[@]}; do echo ${x} | grep "${checkos}"; done))
	if [[ "${checkos}" == ${checkssh} ]]; then
		first="os"
	else echo "Sorry, "${checkos}" is not an ssh-capable OS or is not running."
	echo "Usage: ${0} <OS Name|VM Name|all|list> <Command (in quotes)>" >&2; exit 1
	fi
else echo "I'm sorry, "${1}" is not recognized.  Please use \"vcmd list\" to determine host or operating systems currently running."
	echo "Usage: ${0} <OS Name|VM Name|all|list> <Command (in quotes)>" >&2
	exit 1;
fi
# Let's do some work:
if [[ "${first}" == "all" ]]; then
	for w in `cat ~/config/hosts.conf | grep "running" | grep -v "Windows" | grep -v "OS2" | grep -v "DOS" | grep -v "Other" | grep -v "Netware" | awk '{print $1}'`; do ssh ${w} "uname -n; $2"; done
elif [[ "${first}" == "os" ]]; then
	for w in `cat ~/config/hosts.conf | grep "running" | grep ${1} | awk '{print $1}'`; do ssh ${w} "uname -n; $2"; done
elif [[ "${first}" == "vm" ]]; then
        ssh ${1} "uname -n; $2"
fi
exit 0
That will weed out non-unixy guests (or at least those not known to have ssh running out of the box.) it will also allow you to issue commands based on OS specific stuff, so you can yum upgrade the RedHats and aptitude upgrade the Debians.

Take note, I found that the VBoxManage showvminfo (vmname) command has a trigger you can append to use machine-readable outputs. So this:

Code:
VBoxManage showvminfo vmname --machinereadable
gives you something easier to parse via awk/sed than what I posted before.

Of course, all of the above assumes you have either set hostnames based on VM name with static IPs for guests on the host in /etc/hosts or you have DNS running and assign static ips manually or via dhcp server to the guest. If you are running guests with bridged nics I have yet to find a way to determine the IP of those without DNS/static assignments. If you are running natted or host only, you can use the VBoxManage command to determine the IP like so:

Code:
VBoxManage guestproperty enumerate (vmname)
Pipe to grep "Net" and you'll find the line.

That's it. Enjoy. If you find a way to script commands to Windows boxen from linux command line (via mono, or whatever, or using expect scripts and rdesktop) you can base a vcmd-win off the vcmd-ssh script or you can remove the grep for windows and run cygwin.

Cheers.

Last edited by dfed; 9th May 2010 at 10:12.
Reply With Quote