#!/bin/sh
#
# Copyright 2016-2021 VMware, Inc. All rights reserved.
#
# nsx-opsAgent:
#   Start/Stop the NSX OpsAgent
#
# Tell chkconfig to start us with starting rank 98 and shutdown rank 2.
# chkconfig: 2345 98 2
# description: NSX OpsAgent
#

### BEGIN INIT INFO
# Provides:          nsx-opsagent
# Required-Start:    $network $named $local_fs
# Required-Stop:     $network $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: NSX OpsAgent
### END INIT INFO

# Load the LSB shell functions
[ -f /lib/lsb/init-functions ] && . /lib/lsb/init-functions

# variables
PATH=/bin:/sbin:/usr/bin:/usr/local/bin:$PATH

PROG=/usr/bin/opsAgent
PROG_TAG=NSX-OpsAgent
OPSAGENT_PIDDIR=/var/run/vmware/nsx-opsagent
OPSAGENT_MAX_QUICK_RESTARTS="100"
OPSAGENT_MAX_RESTARTS="1000"
OPSAGENT_CFG_FILE=/etc/vmware/nsx-opsagent/nsx-opsAgent.xml
WATCHDOG_ARGS="-d -s ${PROG_TAG} -q ${OPSAGENT_MAX_QUICK_RESTARTS} -t ${OPSAGENT_MAX_RESTARTS}"
WATCHDOG=/opt/vmware/nsx-opsagent/bin/watchdog.sh
MONITORING_PIDDIR=/var/run/vmware/nsx-monitoring

nsx_group="nsx"
nsx_opsagent_user="nsx-opsagent"
nsx_agent_group="nsx-agent"
nsx_mpa_group="mpa"
nsx_proxy_group="nsx-proxy"
nsx_nestdb_group="nestdb"
nsx_sha_group="nsx-sha"

SHUTDOWN_TIMEOUT=5
TERMINATE_ATTEMPTS=5

# <instrumentation> #

test -f /etc/init.d/functions && . /etc/init.d/functions

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

start() {
   prog_log "${PROG_TAG} start"

   groupadd -f $nsx_group
   groupadd -f $nsx_agent_group
   groupadd -f $nsx_mpa_group
   groupadd -f $nsx_proxy_group
   groupadd -f $nsx_nestdb_group
   groupadd -f $nsx_sha_group
   if ! getent passwd $nsx_opsagent_user > /dev/null; then
      useradd --system -N -g $nsx_group \
      --shell /usr/sbin/nologin -M --comment "NSX OpsAgent" $nsx_opsagent_user
      if [ $? -ne 0 ]; then
         prog_log "Failed to add $nsx_opsagent_user user"
         exit 1
      fi
   else
     # in case of upgrade opsagent user might already be assigned
     # to `nsx-opsagent` primary group
     usermod -a -G $nsx_group $nsx_opsagent_user
     if [ $? -ne 0 ]; then
        prog_log "Failed to add $nsx_opsagent_user user to $nsx_group group"
        exit 1
     fi
   fi

   usermod -a -G $nsx_agent_group,$nsx_mpa_group,$nsx_proxy_group,$nsx_nestdb_group,$nsx_sha_group $nsx_opsagent_user
   if [ $? -ne 0 ]; then
      prog_log "Failed to add $nsx_opsagent_user user to other groups"
      exit 1
   fi

   if [ ! -z "$(pidof -s "${PROG}")" ] ; then
      prog_log "${PROG_TAG} service is already running"
      return
   fi

   if [ ! -f "${PROG}" ]; then
      prog_log "${PROG_TAG} service binary is missing"
      exit 1
   fi

   if [ -e /etc/init.d/nsxa ] ; then
      rm -f /etc/init.d/nsxa
   fi

   # nsx root run dir
   mkdir -m 0755 -p /var/run/vmware
   mkdir -m 0770 -p /var/run/vmware/nsx
   chgrp $nsx_group /var/run/vmware/nsx

   # nsx root log dir
   mkdir -p /var/log/vmware
   chmod 0775 /var/log/vmware
   chgrp $nsx_group /var/log/vmware
   mkdir -p /var/log/vmware/nsx
   chmod 0770 /var/log/vmware/nsx
   chgrp $nsx_group /var/log/vmware/nsx

   # metrics
   mkdir -m 0750 -p /var/log/vmware/nsx/metrics
   chown $nsx_opsagent_user:$nsx_group /var/log/vmware/nsx/metrics

   mkdir -p "${OPSAGENT_PIDDIR}"
   chmod 0770 "${OPSAGENT_PIDDIR}"
   chown -R $nsx_opsagent_user:$nsx_group "${OPSAGENT_PIDDIR}"

   chmod 600 "${OPSAGENT_CFG_FILE}"
   chown $nsx_opsagent_user:$nsx_group "${OPSAGENT_CFG_FILE}"

   mkdir -p "${MONITORING_PIDDIR}"
   chmod 0770 "${MONITORING_PIDDIR}"
   chown -R $nsx_opsagent_user:$nsx_group "${MONITORING_PIDDIR}"

   # remove configuration in /etc/sudoers from Flash if upgrade case
   out=`grep -n "nsx-opsagent ALL=(ALL)NOPASSWD" /etc/sudoers | awk -F : '{print $1}'`
   if [ "$out" ]; then
      sed -i -e '/nsx-opsagent/d' /etc/sudoers
   fi

   if_file_path="/etc/sysconfig/network-scripts"
   if cat "/etc/os-release" | grep -q "sles"; then
       if_file_path="/etc/sysconfig/network"
   fi

   # workaround for vtep loosing IP address
   if [ -d $if_file_path ]; then
      for fn in $(ls $if_file_path/ifcfg-nsx-vtep* 2>/dev/null); do
         ifname=$(basename $fn | cut -c7-)
         for i in $(seq 5); do
            if ip addr show $ifname 2>/dev/null | grep -q 'inet '; then
               break
            fi
            ifup $ifname
            sleep 1
         done
      done
   fi

   ulimit -c unlimited
   export TCMALLOC_SAMPLE_PARAMETER="524288"
   su -m $nsx_opsagent_user -s /bin/bash \
      -c "${WATCHDOG} ${WATCHDOG_ARGS} '${PROG}' >/dev/null 2>&1"
   prog_log "${PROG_TAG} service is running"
}

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|status|restart}"
      exit 1
   ;;
esac
