Que titulo Tete! Bueno, mas allá de lo largo del titulo de este post, hoy me encontraba un poco con ganas de repasar programacion en Shell Scripts de bash asi que tome un viejo script que encontré en internet hace un tiempo. En aquel momento lo habia modificado un poco para que anduviese asi que me decidi mejorarlo mas aun porque la verdad cada vez que añadia una nueva maquina virtual tenia que cambiar muchisimas lineas de código.
La gente de VirtualBox provee en sus paquete una herramienta llamada VBoxManage que es para aquellos que empleamos virtualbox como gestor de maquinas virtuales y necesitamos ejecutarlas en un servidor sin necesidad de hacer uso del modo gráfico e interactivo donde tenemos que arrancar los host virtualizados a mano. Este ejecutable nos permite gestionar completamente la administracion de host virtualizados desde linea de comandos con la posibilidad de ejecutarlas de fondo sin activacion del entorno grafico al que todos estamos acostumbrados.
El script gestiona VBoxManage para permitir iniciar/detener/ver el estado de cuantas maquinas virtuales tengamos, lo anexan al directorio /etc/init.d/ y como enlace al /etc/rcX.d de su preferencia, en mi caso que uso debian en el /etc/rc2.d/ y ya podemos empezar a usarlo luego de adecuarlo a nuestras necesidades solo modificando unas pocas variables con nuestro editor de textos favorito. En las variables a modificar especificaremos datos como nombre de las maquinas virtuales, usuario con el que se ejecuta Virtualbox, tiempo máximo de espera para el apagado de una maquina virtual.
A continuación mi script, tada!!!
#!/bin/bash
##
## virtualbox-daemon-mcy.sh
##
## Version : 0.2 27.01.2012 03:05:43
##
## Descripcion: Demonio de inicio de Maquinas virtuales de VirtualBox
## El objetivo es automatizar el inicio de maquinas virtuales de
## Virtualbox en modo headless ( que es cuando nose ejecutan en modo
## interactivo, sin interfaz grafica, sino en background ). Se soportan
## el inicio de clientes windows como Linux y se mantiene un log por
## fechas de cuando se arranco/detuvo/guardo una sesion. Los logs se
## almacenan en el $HOME/.VBoxLogs del usuario que tiene las VM.
##
## Copyright 2012 Cesar Yanez <emanceyan@gmail.com>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
## MA 02110-1301, USA.
### MODIFICABLE POR USUARIO ### MODIFICABLE POR USUARIO #######
##
## Info: VMs Windows ###
##
## Ayuda:
## VBX_WIN_TOTAL : cantidad de Maquinas Virtuales con Win
##
## VBX_WIN_NAMEX : nombre de la maquina virtual X con Win
## VBX_WIN_USERX : usuario admin de la maquina virtual X
## VBX_WIN_PASSX : password admin de la maquina virtual X
## VBX_WIN_NUMIPX : numero ip de la maquina virtual X
##
## Si hay mas de 4 maquinas virtuales con windows copiar
## y repetir secciones sin repetir numeros
##
VBX_WIN_TOTAL=1
VBX_WIN_NAME1="Windows XP"
VBX_WIN_USER1="cesar"
VBX_WIN_PASS1="cesar"
VBX_WIN_NUMIP1="192.168.1.140"
VBX_WIN_NAME2=""
VBX_WIN_USER2=""
VBX_WIN_PASS2=""
VBX_WIN_NUMIP2=""
VBX_WIN_NAME3=""
VBX_WIN_USER3=""
VBX_WIN_PASS3=""
VBX_WIN_NUMIP3=""
## Info: VMs Linux ###
##
## Ayuda:
## VBX_LIN_TOTAL : cantidad de Maquinas Virtuales con Linux
##
## VBX_LIN_NAMEX : nombre de la maquina virtual X con Linux
##
VBX_LIN_TOTAL=1
VBX_LIN_NAME1="DebianSqueeze"
VBX_LIN_NAME2=""
VBX_LIN_NAME3=""
VBX_LIN_NAME3=""
### Info: Usuario que es propietario de las maquinas virtuales
###
VBX_USR="rondamon"
### Maxima cantidad de tiempo a esperar para que se apague una
### sesion
MAX_SEC=30
### MODIFICABLE POR USUARIO ### MODIFICABLE POR USUARIO #######
###### NO MODIFICAR ###### NO MODIFICAR ###### NO MODIFICAR ####
setEnvVar(){
RPC_NET=`which net`
SYS_SU=`which su`
SYS_AWK=`which awk`
SYS_GREP=`which grep`
SYS_TR=`which tr`
SYS_WC=`which wc`
SYS_CUT=`which cut`
SYS_MKD=`which mkdir`
SYS_CHW=`which chown`
CUR_USR=`whoami`
VBX_MNG=`which VBoxManage`
VBX_USR_HOME=`$SYS_GREP $VBX_USR /etc/passwd|$SYS_CUT -d: -f6`
VBX_DIR_LOGS=$VBX_USR_HOME/.VBoxLogs
VBX_LOG_START=$VBX_DIR_LOGS/start.`date '+%d%m%y'`.logs
VBX_LOG_STOP=$VBX_DIR_LOGS/stop.`date '+%d%m%y'`.logs
VBX_LOG_SAVE=$VBX_DIR_LOGS/save.`date '+%d%m%y'`.logs
if [ ! -d $VBX_DIR_LOGS ]; then
$SYS_MKD $VBX_DIR_LOGS
fi
$SYS_CHW $VBX_USR:$VBX_USR $VBX_DIR_LOGS
}
checkVmRunning(){
VM_TOTAL=`expr $VBX_WIN_TOTAL + $VBX_LIN_TOTAL`
VM_TOTAL_RUNNING=`$SYS_SU $VBX_USR -c "$VBX_MNG list runningvms |$SYS_WC -l"`
if [ $VM_TOTAL_RUNNING -eq $VM_TOTAL ]; then
echo " - Todas las VMs estan ejecutandose"
return 10
elif [ $VM_TOTAL_RUNNING -eq 0 ]; then
echo " - Ninguna VMs en ejecucion"
return 0
elif [ $VM_TOTAL_RUNNING -ne $VM_TOTAL ]; then
echo " - Algunas VMs estan ejecutandose"
return 5
fi
}
checkStatusVms(){
if [ "$1" = " " ]; then
return 10
elif [ "$1" != " " ]; then
## VM_STATUS=`$SYS_SU -c "$VBX_MNG showvminfo $1 |$SYS_GREP ^State |$SYS_AWK '{print $2}'" $VBX_USR`
VM_STATUS=`$SYS_SU $VBX_USR -c "$VBX_MNG showvminfo \"$1\" |$SYS_GREP ^State |$SYS_TR -s ' ' ' '|$SYS_CUT -d ' ' -f 2"`
### echo VMSTATUSSSSSS $VM_STATUS
if [ "$VM_STATUS" = "saved" ]; then return 1
elif [ "$VM_STATUS" = "powered" ]; then return 2
elif [ "$VM_STATUS" = "running" ]; then return 3
fi
fi
}
startWindows(){
for i in `seq 1 $VBX_WIN_TOTAL`; do
NAMEL="VBX_WIN_NAME$i"; NAMELL='eval "echo \$$NAMEL"'
checkStatusVms "`eval $NAMELL`"
STS=$?
if [ $STS -eq 1 ] || [ $STS -eq 2 ]; then
echo " - Iniciando VM Windows: " `eval $NAMELL`
$SYS_SU $VBX_USR -c "$VBX_MNG startvm \"`eval $NAMELL`\" -type headless >> ${VBX_LOG_START} 2>&1"
elif [ $STS -eq 3 ]; then
echo " - La VM `eval $NAMELL` ya esta ejecutandose"
fi
done
}
stopWindows(){
for i in `seq 1 $VBX_WIN_TOTAL`; do
NAMEL="VBX_WIN_NAME$i"; NAMELL='eval "echo \$$NAMEL"'
NAMEU="VBX_WIN_USER$i"; NAMEUU='eval "echo \$$NAMEU"'
NAMEP="VBX_WIN_PASS$i"; NAMEPP='eval "echo \$$NAMEP"'
NAMEI="VBX_WIN_NUMIP$i"; NAMEII='eval "echo \$$NAMEI"'
checkStatusVms "`eval $NAMELL`"
STS=$?
if [ $STS -eq 2 ]; then
echo " - "`eval $NAMELL`" esta apagada"; return 0
elif [ $STS -eq 1 ]; then
echo " - "`eval $NAMELL`" esta guardada"; return 0
elif [ $STS -eq 3 ]; then
echo -n " - "`eval $NAMELL`" deteniendo ..."
## $RPC_NET rpc SHUTDOWN -t 0 -C "Apagado desde el servidor de maquinas vituales" -f -I \"`eval $NAMEII`\" -U `eval $NAMEUU`%`eval $NAMEPP`
$SYS_SU $VBX_USR -c "$VBX_MNG controlvm \"`eval $NAMELL`\" acpipowerbutton >> ${VBX_LOG_STOP} 2>&1"
for j in `seq 1 $MAX_SEC`; do
sleep 1; echo -n "$j."
done
echo ''; return 1
fi
done
}
saveWindows(){
for i in `seq 1 $VBX_WIN_TOTAL`; do
NAMEL="VBX_WIN_NAME$i"; NAMELL='eval "echo \$$NAMEL"'
checkStatusVms "`eval $NAMELL`"
STS=$?
if [ $STS -eq 2 ] || [ $STS -eq 1 ]; then echo ''
elif [ $STS -eq 3]; then
echo " - Salvando VM Windows: " `eval $NAMELL`
$SYS_SU $VBX_USR -c "$VBX_MNG controlvm \"`eval $NAMELL`\" savestate >> ${VBX_LOG_SAVE} 2>&1"
fi
done
}
startLinux(){
for i in `seq 1 $VBX_LIN_TOTAL`; do
NAMEL="VBX_LIN_NAME$i"; NAMELL='eval "echo \$$NAMEL"'
checkStatusVms "`eval $NAMELL`"
STS=$?
if [ $STS -eq 1 ] || [ $STS -eq 2 ]; then
echo " - Iniciando VM Linux: " `eval $NAMELL`
$SYS_SU $VBX_USR -c "$VBX_MNG startvm \"`eval $NAMELL`\" -type headless >> ${VBX_LOG_START} 2>&1"
elif [ $STS -eq 3 ]; then
echo " - La VM Linux `eval $NAMELL` ya esta ejecutandose"
fi
done
}
stopLinux(){
for i in `seq 1 $VBX_LIN_TOTAL`; do
NAMEL="VBX_LIN_NAME$i"; NAMELL='eval "echo \$$NAMEL"'
checkStatusVms "`eval $NAMELL`"
STS=$?
if [ $STS -eq 2 ]; then
echo " - "`eval $NAMELL`" esta apagada"
return 0
elif [ $STS -eq 1 ]; then
echo " - "`eval $NAMELL`" esta guardada"
return 0
elif [ $STS -eq 3 ]; then
echo -n " - "`eval $NAMELL`" deteniendo ..."
$SYS_SU $VBX_USR -c "$VBX_MNG controlvm \"`eval $NAMELL`\" acpipowerbutton >> ${VBX_LOG_STOP} 2>&1"
for j in `seq 1 $MAX_SEC`; do
sleep 1; echo -n "$j."
done
echo ''; return 1
fi
done
}
saveLinux(){
for i in `seq 1 $VBX_LIN_TOTAL`; do
NAMEL="VBX_LIN_NAME$i"; NAMELL='eval "echo \$$NAMEL"'
checkStatusVms "`eval $NAMELL`"
STS=$?
if [ $STS -eq 2 ] || [ $STS -eq 1 ]; then echo ''
elif [ $STS -eq 3]; then
echo " - Guardando VM Linux: " `eval $NAMELL`
$SYS_SU $VBX_USR -c "$VBX_MNG controlvm "`eval $NAMELL`" savestate >> ${VBX_LOG_SAVE} 2>&1"
fi
done
}
statusVm(){
for i in `seq 1 $VBX_WIN_TOTAL`; do
NAMEL="VBX_WIN_NAME$i"; NAMELL='eval "echo \$$NAMEL"'
checkStatusVms "`eval $NAMELL`"
STS=$?
if [ $STS -eq 1 ]; then
echo " - STATUS: "`eval $NAMELL`" esta guardada"
elif [ $STS -eq 2 ]; then
echo " - STATUS: "`eval $NAMELL`" esta apagada"
elif [ $STS -eq 3 ]; then
echo " - STATUS: "`eval $NAMELL`" esta ejecutandose"
fi
done
for i in `seq 1 $VBX_LIN_TOTAL`; do
NAMEL="VBX_LIN_NAME$i"; NAMELL='eval "echo \$$NAMEL"'
checkStatusVms "`eval $NAMELL`"
STS=$?
if [ $STS -eq 1 ]; then
echo " - STATUS: "`eval $NAMELL`" esta guardada"
elif [ $STS -eq 2 ]; then
echo " - STATUS: "`eval $NAMELL`" esta apagada"
elif [ $STS -eq 3 ]; then
echo " - STATUS: "`eval $NAMELL`" esta ejecutandose"
fi
done
echo ''
}
setEnvVar
echo ''
echo '#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*'
echo '* Script de Arranque y Apagado de Maquinas Virtuales (VMs) #'
echo '#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*'
echo ''
case $1 in
start)
echo '*** Iniciando VMs, espere a que inicien los sistemas ***'
startLinux
startWindows
;;
stop)
echo '*** Deteniendo VMs, espere a que terminen de apagar los sistemas ***'
stopLinux
stopWindows
## si no se apago la VM se guarda su estado para proteccion del filesystem
checkVmRunning
STS=$?
if [ $STS -ne 0 ]; then
saveWindows
saveLinux
elif [ $STS -eq 0 ]; then echo ''; echo " - Todas las VMs Apagadas"; echo ''
fi
;;
status)
statusVm
;;
restart)
$0 stop; $0 start
;;
*)
echo ''; echo "Modo de Uso: $0 {start|stop|status|restart}"; echo ''
;;
esac
###### NO MODIFICAR ###### NO MODIFICAR ###### NO MODIFICAR ####
Algunas cosas a mejorar a futuro son el tema del apagado con sistemas Windows, ya que lo hice por llamada rpc del ejecutable net del paquete de samba, pero no pude conseguir que funcione en todos los sistemas windows donde he probado, de todas formas si quieren probarlo deben descomentar la linea numero 171 dentro de la función stopWindows y comentar la linea 172. De otra forma asi tal como esta por defecto en el caso de host Windows procederá a un apagado normal como si hubieramos pulsado el boton de apagado comun y corriente.
Casi me olvido, esa pequeñes de script va con licencia GPL asi que sientanse libres de modificarlo como quieran y adaptarlo a sus necesidades.
Dejo link de descarga mediafire: http://www.mediafire.com/?4b8s692dhlgqc7p
Saludos a todos


