#!/bin/bash
# ======================================================================
#
# NAGIOS CLIENT CHECK :: apache requests
#
# ----------------------------------------------------------------------
# script checks output of "/server-status" and counts scoreboard chars
# ----------------------------------------------------------------------
# 2020-04-09  v1.0  <axel.hahn@iml.unibe.ch>
# 2021-03-11  v1.1  <axel.hahn@iml.unibe.ch>  more error checks for output data
# 2021-11-18  v1.2  <axel.hahn@iml.unibe.ch>  add timeout and max tries; use localhost instead of FQDN
# 2022-08-31  v1.3  <axel.hahn@iml.unibe.ch>  add help; shellfix corrections
# 2022-08-31  v1.4  <axel.hahn@iml.unibe.ch>  add help; shellfix corrections
# 2023-06-19  v1.5  <axel.hahn@unibe.ch>      no more tmpfile
# 2023-07-27  v1.6  <axel.hahn@unibe.ch>      update help page
# 2025-02-10  v1.7  <axel.hahn@unibe.ch>      harden sourcing files
# ======================================================================

# shellcheck source=/dev/null
. "$( dirname "$0" )/inc_pluginfunctions" || exit 1

export self_APPVERSION=1.7

# url=`hostname -f`/server-status
url=localhost/server-status

typeset -i iStart=0
typeset -i iEnd
typeset -i iCount=0

typeset -i iSlots=0
typeset -i iActive=0
typeset -i iIdle=0
typeset -i iUnused=0
typeset -i iUsage=0

paramsWget="-T 5 -t 1 --no-check-certificate"
#            ^    ^
#            |    tries = 1
#            timeout in seconds

# ----------------------------------------------------------------------
# functions
# ----------------------------------------------------------------------

function showHelp(){
    local _self; _self="$( basename "$0" )"
    cat <<EOF
$( ph.showImlHelpHeader )

Get Apache httpd server-status page $url.
You get output with the server status and values for each slot type.

The plugin sends performance data for
  - each slot type
  - active, idle, unused slots

The response is UNKNOWN if url was not reached within 5 seconds or if
the response does not contain a scoreboard.

You get a WARNING if the count of used slots (excluding idle and unused 
slots) is greater 75% of available slots.
You get an CRITICAL response if it is greater 90% of available slots.

Slot types of apache httpd:
    _ Waiting for Connection, 
    S Starting up, 
    R Reading Request
    W Sending Reply, 
    K Keepalive (read), 
    D DNS Lookup
    C Closing connection, 
    L Logging, 
    G Gracefully finishing
    I Idle cleanup of worker 
    . Open slot with no current process


SYNTAX:
$_self [-w WARN_LIMIT] [-c CRITICAL_LIMIT]

OPTIONS:

    -w VALUE       warning level  (default: 75)
    -c VALUE       critical level (default: 90)

    -h or --help   show this help.

PARAMETERS:

    None.


EXAMPLE:
$_self -w 60 -c 80

EOF
}

# ----------------------------------------------------------------------
# MAIN
# ----------------------------------------------------------------------

# --- check param -h
case "$1" in
    "--help"|"-h")
        showHelp
        exit 0
        ;;
    *)
esac

# ----------------------------------------------------------------------
# pre checks
# ----------------------------------------------------------------------
ph.require wget

# ----------------------------------------------------------------------
# check output
# ----------------------------------------------------------------------

# --- get /server-status page
data=$( wget $paramsWget -O - $url 2>/dev/null )
if [ $? -ne 0 ]; then
    ph.abort "UNKNOWN: request to url $url failed. $(wget $paramsWget -O - -S $url 2>&1)"
fi

# set default / override from command line params
typeset -i iWarnLimit=$(     ph.getValueWithParam 75 w "$@")
typeset -i iCriticalLimit=$( ph.getValueWithParam 90 c "$@")


# --- extract scoreboard
iStart=$( grep -n '<pre>'  <<< "$data" | cut -f 1 -d ':')
iEnd=$(   grep -n '</pre>' <<< "$data" | cut -f 1 -d ':')

if [ $iStart -eq 0 -o $iEnd -eq 0 ]; then
    ph.abort "UNKNOWN: url $url has no PRE tag for apache scroreboard. I guess it is not a server-status page."
fi

dataPre=$( sed -n "${iStart},${iEnd}p" <<< "$data" | sed 's#<.*>##g' | tr -d "\n" )


# --- count slots in the scoreboard

# total slots available
iSlots=$( echo -n "$dataPre" | wc -m )

if [ $iSlots -eq 0 ]; then
    ph.abort "UNKNOWN: url $url has no count of slots. I guess it is not a server-status page or option for Extended status is off."
fi

# running apache processes waiting for a request
iIdle=iCount=$(echo -n "$dataPre" | sed -e "s/[^_]//g" | wc -m)

# count of processes apache still can create
iUnused=iCount=$(echo -n "$dataPre" | sed -e "s/[^\.]//g" | wc -m)

# count of actively used slots
iActive=$iSlots-$iIdle-$iUnused

iUsage=$iActive*100/$iSlots
ph.setStatusByLimit $iUsage $iWarnLimit $iCriticalLimit


# --- output
ph.status "Apache: $iSlots slots ...  active: $iActive  wait: $iIdle  unused: $iUnused ($iUsage % usage)"
grep "^<dt" <<< "$data" | sed 's#<dt>##'| sed 's#</dt>##'
echo

# --- add performnce data
ph.perfadd "apache-active"    "${iActive}" "" "" 0 $iSlots

echo "Slots:"
for mychar in S R W K D C L G I _ .
do
  iCount=$(echo -n "$dataPre" | sed -e "s/[^${mychar}]//g" | wc -m)
  label=$(echo apache-${mychar} | tr [:upper:] [:lower:] | sed "s#_#idle#" | sed "s#\.#unused#")

  echo "  - ${mychar}: ${iCount}"
  ph.perfadd "${label}"    "${iCount}" "" "" 0 $iSlots
done

ph.exit

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