#!/bin/sh
#
# Copyright 2019 VMware, Inc. All rights reserved.
#
# nsx-vdpi:
#   Start/Stop the NSX VDPI
#
### BEGIN INIT INFO
# Provides:          nsx-vdpi
# Required-Start:    $network $local_fs
# Required-Stop:     $network $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: NSX VDPI
### END INIT INFO

#  lsb hook for systemd
if [ -f /lib/lsb/init-functions ] ; then
    . /lib/lsb/init-functions
fi

WATCHDOG=/opt/vmware/nsx-vdpi/bin/watchdog.sh

PROG=/opt/vmware/nsx-vdpi/bin/vdpi
PROG_RUN_DIR=/run/nsx-vdpi
PROG_TAG=NSX-VDPI
PROG_LOG_DIR=/var/log/vmware
PROG_LOG_FILE=${PROG_LOG_DIR}/nsx-vdpi.log
PROG_ARGS="--detach \
          --pidfile=/run/nsx-vdpi/vdpi.pid \
          --unixctl=/run/nsx-vdpi/vdpi.ctl \
          -vconsole:emer -vsyslog:err -vfile:info \
          --log-file=/var/log/vmware/nsx-vdpi.log \
          punix:/run/nsx-vdpi/vdpi.sock"

nsx_vdpi_user="nsx-vdpi"
nsx_vdpi_group="nsx-vdpi"

PROG_MAX_QUICK_RESTARTS="20"
WATCHDOG_ARGS="-d -s ${PROG_TAG} -q ${PROG_MAX_QUICK_RESTARTS} -p /run/nsx-vdpi/vdpi.pid"

SHUTDOWN_TIMEOUT=5
TERMINATE_ATTEMPTS=5

# <instrumentation> #

prog_log() {
   echo "${1}"
   logger -p daemon.info -t NSX "${1}"
}

pre_start() {
   if [ ! -d ${PROG_RUN_DIR} ] ; then
      mkdir -p "${PROG_RUN_DIR}"
      chmod 0770 "${PROG_RUN_DIR}"
      chown -R $nsx_vdpi_user:$nsx_vdpi_group "${PROG_RUN_DIR}"
   fi

   if [ ! -d ${PROG_LOG_DIR} ] ; then
      mkdir -p "${PROG_LOG_DIR}"
   fi
   touch ${PROG_LOG_FILE}
   chown $nsx_vdpi_user:$nsx_vdpi_group ${PROG_LOG_FILE}
}

start() {
   # Check if it is already running
   if [ -z "$(pidof -s "${PROG}")" ]; then
      pre_start
      export OPENSSL_MODULES=/opt/vmware/nsx-shared/lib64
      export OPENSSL_CONF=/opt/vmware/nsx-shared/lib64/openssl.cnf
      su -m $nsx_vdpi_user -s /bin/bash \
         -c "${WATCHDOG} ${WATCHDOG_ARGS} '${PROG} ${PROG_ARGS}' >/dev/null 2>&1"
      prog_log "${PROG_TAG} started"
   else
      prog_log "${PROG_TAG} is already running "
   fi
}

do_stop() {
   PIDOF="pidof -s -z"
   $PIDOF "${PROG}"
   if [ $? -ne 0 ]; then
     # Either "-z" is not supported or PROG is not running. In either case, it is
     # ok to switch PIDOF to "pidof -s". This is because if "-z" is actually supported,
     # PROG is not running, which is good.
     # We are forced to do this because systemd does not let us capture pidof's stderr
     # to determine if -z is unsupported.
     prog_log "${PROG_TAG} -z may not be supported for pidof"
     PIDOF="pidof -s"
   fi
   prog_log "${PROG_TAG} Using $PIDOF"

   if [ -z $($PIDOF "${PROG}") ]; then
     prog_log "${PROG_TAG} service is not running"
     return 0
   fi

   # This only stops the watchdog process.
   prog_log "Shutting down ${PROG_TAG} watchdog"
   ${WATCHDOG} -k "${PROG_TAG}"

   prog_log "Shutting down ${PROG_TAG} service"
   kill $($PIDOF "${PROG}") >/dev/null 2>&1

   local TERMINATE_ATTEMPT=0
   while [ $((TERMINATE_ATTEMPT)) -le $((TERMINATE_ATTEMPTS)) ] ; do
      local TIMEOUT=$SHUTDOWN_TIMEOUT
      while [ $((TIMEOUT)) -gt 0 ]; do
         if [ -z $($PIDOF "${PROG}") ]; then
            prog_log "${PROG_TAG} service is stopped, breaking from loop"
            break
         fi
         sleep 1
         echo -n "."
         TIMEOUT=$((TIMEOUT-1))
      done
      echo ""

      if [ -z $($PIDOF "${PROG}") ]; then
         prog_log "${PROG_TAG} service is stopped"
         break
      fi
      if [ $((TERMINATE_ATTEMPT)) -eq $((TERMINATE_ATTEMPTS)) ];then
         prog_log "Terminating ${PROG_TAG} Already attempted $TERMINATE_ATTEMPT/$TERMINATE_ATTEMPTS"
         break
      fi

      prog_log "Terminating ${PROG_TAG} (attempt $((TERMINATE_ATTEMPT+1))/$TERMINATE_ATTEMPTS)"
      kill -9 $($PIDOF "${PROG}")

      TERMINATE_ATTEMPT=$((TERMINATE_ATTEMPT+1))
   done

   if [ -z $($PIDOF "${PROG}") ]; then
      prog_log "${PROG_TAG} service is stopped"
      return 0
   else
      prog_log "Unable to stop ${PROG_TAG} service"
      return 1
   fi
}

stop() {
   do_stop
}

status() {
   local NAME="${1:-${PROG_TAG}}"
   if [ -n "$(pidof -xs "${PROG}")" ] ; then
      echo "${NAME} is running"
      exit 0
   else
      echo "${NAME} is not running"
      exit 3
   fi
}

#
# main
#
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        status
        ;;
  restart)
        stop
        start
        ;;
  *)
        echo $"Usage: $(basename ${0}) {start|stop|restart|status}"
        exit 1
esac
