#!/bin/bash
# -----------------------------------------------------------------------------
# Copyright (c) 2007..2010 - RZ Uni FR
# Copyright (c) 2007..2010 - OpenSLX GmbH
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
#
# If you have any feedback please consult http://openslx.org/feedback and
# send your suggestions, praise, or complaints to feedback@openslx.org
#
# General information about OpenSLX can be found at http://openslx.org/
# -----------------------------------------------------------------------------
# vmgrid
# - This is the generic wrapper for the several virtualization solutions...
################################################################################
. /etc/opt/openslx/openslx.conf
################################################################################
### Define default dirs / get configs
################################################################################
PLUGINCONFROOT=${OPENSLX_DEFAULT_CONFDIR}/plugins
PLUGINCONFVMGRID=${PLUGINCONFROOT}/vmgrid
RWSHARE=/var/opt/openslx/plugins/vmgrid/share
# include general configuration from vmgrid
[ -f ${PLUGINCONFVMGRID}/vmgrid.conf ] && \
. ${PLUGINCONFVMGRID}/vmgrid.conf
# load general virtualization information
[ -f ${PLUGINCONFROOT}/virtualization/virtualization.conf ] && \
. ${PLUGINCONFROOT}/virtualization/virtualization.conf
# get the vmchooser_active var
[ -f ${PLUGINCONFROOT}/vmchooser/vmchooser.conf ] && \
. ${PLUGINCONFROOT}/vmchooser/vmchooser.conf
################################################################################
### Functions used throughout the script
################################################################################
# function to write to stdout and logfile
LOGFILE=${OPENSLX_DEFAULT_LOGDIR}/run-vmgrid.${USER}.$$.log
writelog () {
# write to stdout
echo -e "$1"
# log into file
echo -e "$1" >> ${LOGFILE}
# log into share dir, so that log is available in vm as well
echo -e "$1" >> ${vmgrid_rwmnt}/logs/run-vmgrid.${USER}.$$.log
}
# remove config dirs when exit
cleanexit () {
if echo "${RMDIRS}" 2>/dev/null | grep -q ${vmgrid_virt}; then
writelog "${vmgrid_virt} exited. Cleanning up... \c"
rm -rf ${RMDIRS} >/dev/null 2>&1
writelog "done"
fi
exit "$1"
}
################################################################################
### Get XML file and dir
################################################################################
# check if mem or graphical mode set
headless=1
while [ $# -gt 0 ]; do
case "$1" in
-h|--help)
echo -e "Usage: run-vmgrid.sh [-g] [--mem <memory size in MB>] \c"
echo -e "[/path/]filename[.xml]"
exit
;;
-g)
headless=0
;;
--mem)
# get a result which can be divided through 4
forcemem=$2
echo $2 | grep -q '[1-9][0-9]\{2,3\}$' && forcemem=$(expr $2 / 4 \* 4)
shift
;;
*)
xmlfile=$@
break
;;
esac
shift
done
# absolute or relative path?
if ls ${xmlfile} 2>/dev/null | grep '/' >/dev/null 2>&1; then
xmlpath=$(dirname ${xmlfile})
xmlfile=$(basename ${xmlfile})
else
xmlpath=${vmgrid_xmlpath}
fi
# full path
xmlfile="${xmlpath}/${xmlfile%.xml}.xml"
################################################################################
### Sanity checks
################################################################################
# test if the xml file is valid
if ! [ -r "${xmlfile}" ]; then
writelog "${xmlfile} not a readable XML file!"
run-vmgrid.sh -h &
exit 1
fi
# start to log, create shrare log dir
mkdir -m 1777 -p ${vmgrid_rwmnt}/logs
echo "Starting to log at $(date)" \
>${vmgrid_rwmnt}/logs/run-vmgrid.${USER}.$$.log
# test how many instances running
runningvms=$(ps aux | grep "run-vmgrid.sh " | grep -v grep | wc -l)
# 2 steps, /w only one is seems not to work
runningvms=$(expr ${runningvms} - 1)
# if Xen use different method
if [ "${vmgrid_virt}" = "xen" ]; then
runningvms=$(xm list 2>/dev/null | grep -vE "Domain-0|Name.*ID" | wc -l)
runningvms=$(expr ${runningvms} + 1)
fi
# check value
if [ ${runningvms} -le 0 ]; then
writelog "Error in value: Running VMs: ${runningvms}. Exit!"
exit 1
fi
# check if vmchooser plugin installed
if [ -n "${vmchooser_active}" ] && [ ${runningvms} -gt 1 ]; then
# only allow one instance of vmgrid
writelog "Already 1 VMs running and vmchooser plugin is active."
writelog "Can't start ${xmlfile}, exiting!"
exit 1
# else allow max. 4 instances
elif [ ${runningvms} -gt 4 ]; then
writelog "Already 4 VMs running, exiting!"
exit 1
fi
VM_ID="0${runningvms}"
# test if XML file
if ! grep '<?xml' "${xmlfile}" >/dev/null 2>&1; then
writelog \
"Submitted configuration file ${xmlfile} seems to have wrong XML format"
exit 1
fi
################################################################################
### Logo for console
################################################################################
cat <<EOL
__ __
.----.--.--.-----.___.--.--.--------.-----.----.|__|.--| |
| _| | | |___| | | | _ | _|| || _ |
|__| |_____|__|__| \___/|__|__|__|___ |__| |__||_____|
|_____|
OpenSLX virtual machine environment preparation script ...
EOL
################################################################################
### Read needed variables from XML file
################################################################################
writelog "Starting configuration..."
writelog "\tVM-ID:\t\t\t${VM_ID}"
writelog "\tLogfile:\t\t${OPENSLX_DEFAULT_LOGDIR}/run-vmgrid.${USER}.$$.log"
writelog "\t/tmp info:\t\t$(df -h | grep " /tmp$" | awk '{print $2}') \c"
writelog "$(grep "/tmp " /proc/mounts | awk '{print $1" "$2" "$3" "$4}')"
writelog "\tVM XML dir:\t\t$(dirname ${xmlfile})"
if ! grep '<?xml' "${xmlfile}" >/dev/null 2>&1; then
writelog \
"Submitted configuration file ${xmlfile} seems to have wrong XML format"
exit 1
fi
writelog "\tXML file:\t\t$xmlfile"
writelog "VM config:"
# name of the virt image or dir
imgname=$(grep -io '<image_name param=.*"' ${xmlfile} \
| sed -e "s/&.*;/; /g" | awk -F '"' '{ print $2 }')
# image mode
imgmode=$(grep -io '<image_mode param=.*"' ${xmlfile} \
| sed -e "s/&.*;/; /g" | awk -F '"' '{ print $2 }')
# get boot attr
boot=$(grep -io 'boot param=.*"' ${xmlfile} | awk -F '"' '{ print $2 }')
diskless=0
# special rw image
if [ "${imgmode}" = "rwimg" ]; then
# maybe you want to use an empty rw imgae?
# define only for writelog, will be set in the plugin include again!
vmpath="{special rw image}"
# add new path for rwimg
imgpath=${vmgrid_rwmnt}/specialrwimages
unset $imgname
mkdir -m 1777 -p ${imgpath}
# diskless boot
elif [ "${boot}" = "n" ] && [ -z "${imgname}" ]; then
diskless=1
vmpath="{diskless boot}"
# imagename /w full path
elif echo ${imgname} 2>/dev/null | grep -q '^/' >/dev/null 2>&1; then
imgpath=$(dirname ${imgname})
imgname=$(basename ${imgname})
vmpath=${imgpath}/${imgname}
# get path from var
else
imgpath=${vmgrid_imgpath}
vmpath=${imgpath}/${imgname}
fi
# check if virtual machine container file exists, only if not rwimg
if ! [ -e "${vmpath}" ] && [ "${imgmode}" != "rwimg" ] && [ ${diskless} -eq 0 ];
then
writelog "Virtual machine image or directory ${vmpath} not found!"
exit 1
fi
# name of the virt machine, sed because of Windows formatting
vm_name=$(grep -o 'short_description param=.*"' ${xmlfile} \
| sed -e "s/&.*;/; /g" | awk -F '"' '{print $2}')
# if ${vm_name} not defined use ${xmlfile}
vm_name=${vm_name:-${xmlfile%.xml}}
# define vm_shortname since vm_name can be very long
vm_shortname=$(basename ${xmlfile%.xml} | sed -e "s, ,-,g")
# vm_name = displayname, define for old scripts
displayname=${vm_name}
[ "${imgmode}" != "rwimg" ] && [ ${diskless} -eq 0 ] \
&& writelog "\tVM Image dir:\t\t${imgpath}"
writelog "\tVM file/dir:\t\t$vmpath"
# is there an additional configuration provided?
additional_config=$(grep -o 'additional_config param=.*"' ${xmlfile} \
| sed -e "s/&.*;/; /g" | awk -F '"' '{print $2}')
# image is for the following virtual machine
xmlvirt=$(grep -o 'virtualmachine param=.*"' ${xmlfile} \
| sed -e "s/&.*;/; /g" | awk -F '"' '{print $2}')
# make a guess from the filename extension if ${xmlvirt} is empty
# (not set within the XML file)
# TODO: implement possibility to submit own configuration files
if [ -z "${xmlvirt}" ] && [ -n "${additional_config}" ]; then
writelog "No virtual machine parameter defined in ${xmlfile}"
writelog "Trying to guess VM...\c"
case "$(cat ${additional_config} | tr [A-Z] [a-z])" in
*config.version*|*virtualhw.version*|*independent-nonpersistent*|*vmdk*)
xmlvirt="vmware"
;;
*innotek*|*virtualbox*)
xmlvirt="virtualbox"
;;
*qemu*|*kvm*)
xmlvirt="qemukvm"
;;
*)
xmlvirt="none"
;;
esac
elif [ -z "${xmlvirt}" ]; then
case "$(echo ${imgname##*.} | tr [A-Z] [a-z])" in
vmdk)
xmlvirt="vmware"
;;
vbox)
xmlvirt="virtualbox"
;;
img|qcow*)
xmlvirt="qemukvm"
;;
*)
xmlvirt="none"
;;
esac
writelog "result:\t${xmlvirt}"
fi
# check for virt
if [ "${vmgrid_virt}" != "${xmlvirt}" ]; then
writelog "The virtual machine specified in ${xmlfile}"
writelog "does not match the virtualization used here (${vmgrid_virt})"
exit 1
fi
# definition of the client system
vmostype=$(grep -io '<os param=.*"' ${xmlfile} | awk -F '"' '{ print $2 }' \
| tr [A-Z] [a-z])
# definition of the networking the client system is connected to
network_kind=$(grep -io '<network param=.*"' ${xmlfile} \
| awk -F '"' '{ print $2 }' | tr [A-Z] [a-z])
network_card=$(grep -io '<netcard param=.*"' ${xmlfile} \
| awk -F '"' '{ print $2 }'| tr [A-Z] [a-z])
# define redirects
redirects=$(grep -ic '<redirect name=.*"' ${xmlfile})
[ -z "${redirects}" ] && redirects=0
(( i=1 ))
while [ ${i} -le ${redirects} ]; do
# get only the $i-th line
redirect_name[$i]=$(grep -m ${i} -io '<redirect.*' ${xmlfile} | tail -n 1 \
| grep -o "name=\".*" | awk -F '"' '{ print $2 }')
redirect_proto[$i]=$(grep -m ${i} -io '<redirect.*' ${xmlfile} | tail -n 1 \
| grep -o "proto=\".*" | awk -F '"' '{ print $2 }')
redirect_hport[$i]=$(grep -m ${i} -io '<redirect.*' ${xmlfile} | tail -n 1 \
| grep -o "hostport=\".*" | awk -F '"' '{ print $2 }')
redirect_gport[$i]=$(grep -m ${i} -io '<redirect.*' ${xmlfile} | tail -n 1 \
| grep -o "guestport=\".*" | awk -F '"' '{ print $2 }')
(( i=$i+1 ))
done
writelog "\tVirtualization:\t\t$xmlvirt"
writelog "\tVM name:\t\t$vm_name"
writelog "\tVM short name:\t\t$vm_shortname"
###############################################################################
### Declaration of default variables
###############################################################################
# make sure cpu_cores is not empty
cpu_cores=${cpu_cores:-"1"}
#vmgrid::maxvcpus
#vmgrid::minvcpus
# check for CPU virtualization flags
#vmgrid::vt
# total amount of memory defined in stage 3
permem=60
# get a result which can be divided through 4
mem=$(expr ${totalmem} / 100 \* ${permem} / 4 \* 4)
#vmgrid::maxmem
#vmgrid::minmem
# configuring ethernet mac address: first 3 bytes are fixed (00:50:56)
# 4th byte is the VM-ID
# last two bytes are taken from the bridge of the host
# define one MAC per guest
macguestpart="00:50:56:${VM_ID}"
machostpart=$(echo ${machostaddr} | awk -F ":" '{print $(NF-1)":"$NF}')
macaddr=$(echo "${macguestpart}:${machostpart}" | tr [a-z] [A-Z])
# ide is expected default, test for the virtual disk image type should
# be done while creating the runscripts ...
# TODO: cdrom / floppy?
ide="TRUE"
scsi="FALSE"
hddrv="ide"
audio="false"
remotedesktopport="590${VM_ID}"
# add rw share
sharepath="${vmgrid_rwmnt}/folders/${vm_shortname}"
mkdir -p ${sharepath}
chmod -f 1777 "${vmgrid_rwmnt}/folders"
sharename="share"
# set hostname: using original hostname and adding string
hostname="vmgrid${VM_ID}-$(hostname)"
writelog "\tVM Hostname:\t\t$hostname"
################################################################################
### Setup the rest of the environment and run the configured vm
################################################################################
# Copy guest configuration (with added information) config.xml to be accessed
# via virtual floppy
# TODO: virt-floppy needed?
# Get all virtual machine specific stuff from the respective include file
# TODO: rename to run-vuirt.include
if [ -e ${PLUGINCONFROOT}/${vmgrid_virt}/run-virt.include ] ; then
writelog "Starting ${vmgrid_virt} specific part ..."
self=${vmgrid_virt}
. ${PLUGINCONFROOT}/${vmgrid_virt}/run-virt.include
else
writelog "Failed because of missing ${vmgrid_virt} plugin"
exit 1
fi
# start graphical mode
if [ ${headless} -eq 0 ]; then
if [ -z "${VIRTCMD}" ]; then
writelog "Grapical mode not available, exiting!"
cleanexit 1
fi
writelog "Starting ${vmgrid_virt} in graphical mode..."
${VIRTCMD} ${VIRTCMDOPTS} 2>/dev/null
# start headless
elif [ -n "${VIRTCMDHL}" ]; then
writelog "Starting ${vmgrid_virt} in headless mode..."
${VIRTCMDHL} ${VIRTCMDOPTSHL} 2>/dev/null
else
writelog "${vmgrid_virt}: No headless mode defined, exiting!"
cleanexit 1
fi
# postrun for scripts after virtualization finishes
if [ -n "${POSTRUN}" ]; then
eval ${POSTRUN} >/dev/null 2>&1
fi
cleanexit 0
exit 0