#!/usr/bin/bash
#
# Start virtual system
# Copyright (C) 2013-2024 by Thomas Dreibholz
# Copyright (C) 2014 by Forough Golkar <forough.golkar87@gmail.com>
# Copyright (C) 2013 by Nima Fallah Darya <nima.darya@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 3 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, see <http://www.gnu.org/licenses/>.
#
# Contact: dreibh@simula.no

# Bash options:
set -e


# ###### Main program #######################################################
if [ $# -lt 1 ] ; then
   echo >&2 "Usage: $0 VM_name [start_delay num_cpus memory gethosttime_disabled vnc_address vnc_port vnc_password vnc_keymap options]"
   exit 1
fi

NORNET_DIRECTORY="/etc/nornet"


# ====== Get NorNet user name ===============================================
if [ -e $NORNET_DIRECTORY/nornetapi-config ] ; then
   . $NORNET_DIRECTORY/nornetapi-config
elif [ -e ./nornetapi-config ] ; then
   . ./nornetapi-config
fi
if [ "$NorNet_LocalNode_NorNetUser" = "" ] ; then
   NorNet_LocalNode_NorNetUser="nornetpp"
fi


# ====== Obtain machine status ==============================================
NAME="$1"
STARTDELAY="$2"
NUMCPUS=$3
MEMORY=$4
GETHOSTTIMEDISABLED=$5
VNCADDRESS="$6"
VNCPORT=$7
VNCPASSWORD="$8"
VNCKEYMAP="$9"
OPTIONS="${10}"
if [ "$VNCADDRESS" = "" ] ; then
   VNCADDRESS="$NorNet_Server_DefaultVNCAddress"
fi
if [ "$VNCKEYMAP" = "" ] ; then
   VNCKEYMAP="$NorNet_Server_DefaultVNCKeymap"
   if [ "$VNCKEYMAP" = "" ] ; then
      VNCKEYMAP="en-us"
   fi
fi
if [ "$VNCPASSWORD" = "" ] ; then
   VNCPASSWORD="$NorNet_Server_DefaultVNCPassword"
fi

if [ `Check-VSystem "$NAME"` != "running" ] ; then
   echo "`env LANG=C date +%FT%H:%M:%S`: Starting $NAME"

   # ====== VirtualBox ======================================================
   if [ "$NorNet_Server_VirtualizationSystem" = "" -o "$NorNet_Server_VirtualizationSystem" = "VirtualBox" ] ; then
      # ====== Set options ==================================================
      if [ "$NUMCPUS" != "" ] ; then
         sudo -u $NorNet_LocalNode_NorNetUser VBoxManage modifyvm "$NAME" --cpus "$NUMCPUS" || true
      fi
      if [ "$MEMORY" != "" ] ; then
         sudo -u $NorNet_LocalNode_NorNetUser VBoxManage modifyvm "$NAME" --memory "$MEMORY" || true
      fi
      if [ "$OPTIONS" = "default" ] ; then
         OPTIONS="--chipset piix3 --audio none --mouse ps2 --keyboard ps2 --usb off --hpet on --pae on --hwvirtex on --nestedpaging on --largepages on --vtxvpid on"
      fi
      if [ "$OPTIONS" != "" ] ; then
         sudo -u $NorNet_LocalNode_NorNetUser VBoxManage modifyvm "$NAME" $OPTIONS || true
      fi
      sudo -u $NorNet_LocalNode_NorNetUser VBoxManage setextradata "$NAME" \
         "VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled" $GETHOSTTIMEDISABLED || true

      # ====== Set VNC options ==============================================
      vncOptions=""
      if [ "$VNCPORT" != "" ] ; then
         if [ $VNCPORT -gt 0 -a "$VNCADDRESS" != "" -a "$VNCPASSWORD" != "" ] ; then
            version=( `VBoxManage --version | tr '.' ' '` )
            # echo "`env LANG=C date +%FT%H:%M:%S`: VirtualBox version is ${version[0]}.${version[1]}"
            if [ ${version[0]} -eq 4 -a ${version[1]} -lt 2 ] ; then            
               vncOptions="--vrde off --vnc --vncport $VNCPORT"
               if [ "$VNCPASSWORD" != "" ] ; then
                  vncOptions="$vncOptions --vncpass \"$VNCPASSWORD\""
               fi
            else
               sudo -u $NorNet_LocalNode_NorNetUser VBoxManage setproperty vrdeextpack VNC
               sudo -u $NorNet_LocalNode_NorNetUser VBoxManage modifyvm "$NAME" \
                  --vrdeproperty "VNCPassword=$VNCPASSWORD" \
                  --vrdeauthlibrary null \
                  --vrdeport=$VNCPORT
               if [ ${version[0]} -ge 5 ] ; then
                  sudo -u $NorNet_LocalNode_NorNetUser VBoxManage modifyvm "$NAME" --vrde on
               fi
            fi
         fi
      fi

      # ====== Start the virtual system =====================================
      touch "/var/log/nornet-server-$NAME.log"
      touch "/var/run/nornet-server-$NAME.pid"
      chown $NorNet_LocalNode_NorNetUser:$NorNet_LocalNode_NorNetUser "/var/log/nornet-server-$NAME.log" "/var/run/nornet-server-$NAME.pid"
      # Note: The "permission denied" error is a false positive from libjpeg-turbo8. Bug #1014487 and #1031718 => filtering it out!"
      sudo -u $NorNet_LocalNode_NorNetUser /bin/sh -c \
         "nohup </dev/null VBoxHeadless --startvm \"$NAME\" $vncOptions >\"/var/log/nornet-server-$NAME.log\" 2>&1 & echo \$! >\"/var/run/nornet-server-$NAME.pid\" 2>&1" || true


   # ====== KVM =============================================================
   elif [ "$NorNet_Server_VirtualizationSystem" = "KVM" ] ; then
      # ====== Set options ==================================================
      if [ "$NUMCPUS" != "" ] ; then
         virsh setvcpus "$NAME" "$NUMCPUS" --maximum --config || true
         virsh setvcpus "$NAME" "$NUMCPUS" --config || true
      fi
      if [ "$MEMORY" != "" ] ; then
         MEMORY=$(($MEMORY*1024))
         virsh setmaxmem "$NAME" "$MEMORY" --config || true
         virsh setmem    "$NAME" "$MEMORY" --config || true
      fi
      OLD_MACHINE_FILE=`mktemp --suffix=.xml`
      NEW_MACHINE_FILE=`mktemp --suffix=.xml`
      virsh dumpxml "$NAME" >$OLD_MACHINE_FILE && \
      if [ $VNCPORT -ne 0 -a "$VNCADDRESS" != "" -a "$VNCPASSWORD" != "" ] ; then
         xmlstarlet ed \
            -d '/domain/devices/graphics[@type="vnc"]' \
            \
            -s '/domain/devices' --type 'elem' -n 'graphics' -v "" \
            -a '/domain/devices/graphics[not(@type)]' --type 'attr'  -n 'type'     -v "vnc"          \
            -a '/domain/devices/graphics[@type="vnc"]' --type 'attr' -n 'port'     -v "$VNCPORT"     \
            -a '/domain/devices/graphics[@type="vnc"]' --type 'attr' -n 'autoport' -v "no"           \
            -a '/domain/devices/graphics[@type="vnc"]' --type 'attr' -n 'keymap'   -v "$VNCKEYMAP"   \
            -a '/domain/devices/graphics[@type="vnc"]' --type 'attr' -n 'passwd'   -v "$VNCPASSWORD" \
            \
            -s '/domain/devices/graphics[@type="vnc"]' --type 'elem' -n 'listen' -v "" \
            -a '/domain/devices/graphics[@type="vnc"]/listen' --type 'attr' -n 'type'    -v "address"     \
            -a '/domain/devices/graphics[@type="vnc"]/listen' --type 'attr' -n 'address' -v "$VNCADDRESS" \
         $OLD_MACHINE_FILE >$NEW_MACHINE_FILE
      else
         xmlstarlet ed \
            -d '/domain/devices/graphics[@type="vnc"]' \
         $OLD_MACHINE_FILE >$NEW_MACHINE_FILE
      fi && \
      chown $NorNet_LocalNode_NorNetUser $OLD_MACHINE_FILE $NEW_MACHINE_FILE

      # ====== Start the virtual system =====================================
      touch "/var/run/nornet-server-$NAME.pid"
      virsh create --file $NEW_MACHINE_FILE || virsh create --file $OLD_MACHINE_FILE --paused || true
      rm -f $OLD_MACHINE_FILE $NEW_MACHINE_FILE


   # ====== Invalid NorNet_Server_VirtualizationSystem setting ==============
   else
      echo >&2 "ERROR: Bad setting $NorNet_Server_VirtualizationSystem for NorNet_Server_VirtualizationSystem!"
      exit 1
   fi


   # ====== Give the system time to boot ====================================
   if [ "$STARTDELAY" != "" ] ; then
      echo "`env LANG=C date +%FT%H:%M:%S`: Waiting $STARTDELAY seconds ..."
      sleep "$STARTDELAY"
   fi

else
   echo "`env LANG=C date +%FT%H:%M:%S`: $NAME is already running -> okay."
fi
