#!/bin/bash
# Function: Start and stop services required for running KVM/QEMU virtual machines
#           See kvm for caller
#
#           And some special services which must run as root:
#           nettxlen: Increase the Transmit Queue Length for network Interfaces of running domains
#
# Installation & Setup:
# - Copy the file into the directory /usr/local/sbin and make it executable
# - You can add it to sudo with NOPASSWD option, so you can execute the command without password
#   <YOUR-USERNAME>   ALL = NOPASSWD: /usr/local/sbin/kvm_services  # KVM Service Control
#
#  (c) 2021 Robert Lange (sd2k9@sethdepot.org)
#  GNU General Public Licence applies
#
#  Project URL: https://github.com/sd2k9/documentation
 
# ------------------------------------------------------------------------------

# *** Settings ***
# Treat uninitialised variable as error and exit script
set -u
# Test mode: True when defined (only echo commands)
readonly TESTMODE=

# Mode, set by command line
declare mode=

# ------------------------------------------------------------------------------

# Abort on tool error (errorcode <> 0)
function abort_on_error() {
    local err
    err=$1
    shift
    if [ $err -ne 0 ]; then
	   echo "Program execution failed with error code $err!"
	   exit 1
    fi
}

# Execute this tool
# Caution: Use "\"text with spaces\"" to escape spaces
function exec_tool() {
    echo "$@"
   if [[ -z "$TESTMODE" ]]; then
       eval "$@"
       abort_on_error $?
   fi
}

# Reconfigure firehol
function firehol_reconfig() {
    # Enforce rebuild of firewall
    exec_tool touch /etc/firehol/firehol.conf
    # Restart
    exec_tool /usr/sbin/firehol condrestart
    # Enfore rebuild of firewall the next time it is restarted
    exec_tool touch /etc/firehol/firehol.conf
}


# ------------------------------------------------------------------------------

# *** Command line parsing
get_options() {
  local opt

  while [ -n "$*" ] ; do
      opt="$1"
      shift
      case $opt in
        start|stop|disable|localnet|internet|stopnet|nettxlen)
          mode="$opt"
        ;;
        *)
           # Unknown Argument
  	   echo "Unknown argument!"
   	   exit 1
  	   ;;
      esac
  done
}


# *** Call Command Line Parsing and Program execution
# When no options supplied then call help
if [ -z "${1:-}" ]; then
    echo "Missing arguments!"
    exit 1
else
    get_options "$@"
fi
# When no mode found, call help
if [[ -z "$mode" ]]; then
    echo "Missing operation mode!"
    exit 1
fi

# ------------------------------------------------------------------------------

# *** Now execute actions, or done above

case $mode in
  start|stop|disable)
      # Build services list
      services="libvirtd.service virtlockd.service virtlogd.service"
      # Needed for start also? Disable for now: virt-guest-shutdown.target
      # For stop or disable list all services
      if [[ "$mode" != "start" ]]; then
          services="$services \
              libvirtd-admin.socket \
              libvirtd-ro.socket \
              libvirtd.socket \
              virtlockd.socket \
              virtlockd-admin.socket \
              virtlogd.socket \
              virtlogd-admin.socket \
              libvirt-guests.service \
              libvirtd-tcp.socket \
              libvirtd-tls.socket \
              virt-guest-shutdown.target"
      fi
      echo "$mode services"
      exec_tool systemctl $mode $services
  ;;
  localnet)
    echo "Firewall: Local access, no outwards network routing"
    # Define KVM-Mode for firehol, see its config file
    # No outwards network routing
    export FIREHOL_USER_FEATURES=kvm
    firehol_reconfig
  ;;
  internet)
    echo "Firewall: Allow network routing for internet access"
    # Define KVM-Mode for firehol, see its config file
    # WITH outwards network routing
    export FIREHOL_USER_FEATURES=kvm-net
    firehol_reconfig
  ;;
  stopnet)
      echo "Firewall: Remove network routing"
      firehol_reconfig
  ;;
  nettxlen)
      echo "Increase the Transmit Queue Length for network Interfaces of running domains"
      for dom in $(virsh --connect=qemu:///system list --state-running --name); do
	  echo -n "   Domain $dom:"
	  for netdev in $(virsh --connect=qemu:///system domiflist $dom | tail +3  | awk '!/^$/ {print $1}'); do
	      echo -n " $netdev"
	      ip link set $netdev txqueuelen 4096
	  done
	  echo
      done
  ;;
  *)
      # No mode
      echo "No mode selected! See help text for usage"
      exit 1
  ;;
esac
