Skip to content
Snippets Groups Projects
check_haproxy_status 7.30 KiB
#!/bin/bash
# ======================================================================
#
# NAGIOS CLIENT CHECK :: haproxy status
# show current requests to frontend and backend
#
# ----------------------------------------------------------------------
# settings values are parsed by a given section.
# if it fails it scans other sections .. finally default and global
# see getCfgvar
# ----------------------------------------------------------------------
# 2020-04-27  v1.0  <axel.hahn@iml.unibe.ch>
# 2020-04-28  v1.1  <axel.hahn@iml.unibe.ch>  added status and max connections for frontend and backend
# 2020-04-29  v1.2  <axel.hahn@iml.unibe.ch>  parse ini section by given section
# 2020-06-03  v1.3  <axel.hahn@iml.unibe.ch>  added ping to each backend server
# ======================================================================

. `dirname $0`/inc_pluginfunctions

cfgfile=/etc/haproxy/haproxy.cfg
cfgfile2=/tmp/haproxy.config

tmpfile=/tmp/check_haproxy_status_$$
tmpfile2=/tmp/check_haproxy_status2_$$
tmpfileping=/tmp/check_haproxy_status3_$$



# ----------------------------------------------------------------------
# pre checks
# ----------------------------------------------------------------------
ph.reqire wget

if [ ! -f $cfgfile ]; then
  ph.abort "UNKNOWN: config file does not exist: $cfgfile"
fi

cat $cfgfile >/dev/null
if [ $? -ne 0 ]; then
  ph.abort "UNKNOWN: unable to read ha proxy config $cfgfile ... `ls -l $cfgfile`"
fi

cat $cfgfile | grep "\ mode\ .*http" >/dev/null
if [ $? -ne 0 ]; then
  ph.abort "UNKNOWN: haproxy is not in http mode"
fi


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

# rewrite the ha proxy config file to parse it by section
function cfgrewriter(){
  local _section=
  IFS=''
  while read line
  do
    echo $line | grep "^[a-z]" >/dev/null
    if [ $? -eq 0 ]; then
        _section=$line
        echo "# new section: $_section"
    fi
    echo $line | grep "^\ \ [a-z]*" >/dev/null
    if [ $? -eq 0 ]; then
        echo -n "$_section: "
        echo $line | sed "s#\ \ # #g"
    fi
  done < $cfgfile
}

# get a value from a given a given section
function _getCfgVarFromSection(){
  local _var=$1
  local _section=$2

  grep "^${_section}:\ \ ${_var}\ " $cfgfile2 >/dev/null && (
    typeset -i local _iColumnVal=`echo "${_section}:  $_var" | wc -c`+1
    grep "^${_section}:\ \ ${_var}\ " $cfgfile2 | cut -c ${_iColumnVal}-
  )
}

# get a value from config - with autoscan of other sections
function getCfgvar(){
  local _var=$1
  local _section=$2

  _getCfgVarFromSection      "${_var}" "${_section}"                  \
    || _getCfgVarFromSection "${_var}" "frontend stats_frontend"      \
    || _getCfgVarFromSection "${_var}" "frontend couchdb_frontend"    \
    || _getCfgVarFromSection "${_var}" "frontend postgresql_frontend" \
    || _getCfgVarFromSection "${_var}" "frontend opencpu"             \
    || _getCfgVarFromSection "${_var}" "frontend apache_fop"          \
    || _getCfgVarFromSection "${_var}" "defaults"                     \
    || _getCfgVarFromSection "${_var}" "global"

}

# find a column number of a given field name in haproxy csv
function getColnumber(){
  cat $tmpfile | head -1 | sed 's#,#\n#g' | grep -n "^$1$" | cut -f 1 -d ':'
}

# get column #N 
function getColumn(){
  typeset -i local _iNumber=$1
  local _filter=$2
  test -z $_filter && _filter='.*'
  grep "$_filter" $tmpfile | grep -v "stats_frontend" | cut -f 2,$_iNumber -d ','
}

# ----------------------------------------------------------------------
# build url
# ----------------------------------------------------------------------

cfgrewriter >$cfgfile2

# getCfgvar "bind"       "frontend stats_frontend" 
# getCfgvar "stats auth" "frontend stats_frontend"
# exit

proto=http
auth=
host=localhost
typeset -i port=80
uri=

getCfgvar "bind" "frontend stats_frontend" | grep "\ ssl\ " >/dev/null && proto=https

auth=`getCfgvar "stats auth" "frontend stats_frontend"`
port=`getCfgvar "bind"       "frontend stats_frontend" | cut -f 2 -d ':' | cut -f 1 -d " "`
host=`getCfgvar "bind"       "frontend stats_frontend" | cut -f 1 -d ':'`
uri=` getCfgvar "stats uri"  "frontend stats_frontend"`

if [ "$host" = "*" ]; then
  host="localhost"
fi

url="$proto://${auth}@${host}:${port}${uri};csv;norefresh"
urlmasked="$proto://*password*@${host}:${port}${uri};csv;norefresh"


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


# --- get status page
wget --no-check-certificate -O $tmpfile $url 2>/dev/null
if [ $? -ne 0 ]; then
  rm -f $tmpfile $cfgfile2
  ph.abort "UNKNOWN: url $urlmasked did not respond. `wget --no-check-certificate -O - -S $url`"
fi


colLimit=`getColnumber "slim"`
colCurrentConnections=`getColnumber "scur"`
colStatus=`getColnumber "status"`

statusFront=`getColumn $colStatus ",FRONTEND," | cut -f 2 -d ","`
statusBack=` getColumn $colStatus ",BACKEND,"  | cut -f 2 -d ","`

typeset -i iMaxConnFront=`getColumn $colLimit ",FRONTEND,"`
typeset -i iMaxConnBack=` getColumn $colLimit ",BACKEND,"`

typeset -i iFrontend=`getColumn $colCurrentConnections ",FRONTEND,"`
typeset -i iFrontendFree=$iMaxConnFront-$iFrontend


typeset -i iBackend=` getColumn $colCurrentConnections ",BACKEND," `
typeset -i iBackendFree=$iMaxConnBack-$iBackend

statusExt=
if [ ! "$statusFront" = "OPEN" ]; then
  ph.setStatus "critical"
  statusExt="${statusExt}ERROR: frontend status is not OPEN - it is ${statusFront}\n"
fi

if [ ! "$statusBack" = "UP" ]; then
  ph.setStatus "critical"
  statusExt="${statusExt}ERROR: backend status is not UP - it is ${statusBack}\n"
fi

ph.status "FRONT: $statusFront - ${iFrontend} (max: ${iMaxConnFront}) .. BACK: $statusBack - $iBackend (max: ${iMaxConnBack})"
test -z "$statusExt" || echo "${statusExt}"
# echo; echo DEBUG: ; cat $tmpfile



ph.perfadd "frontend"      "${iFrontend}"
ph.perfadd "frontend-max"  "${iMaxConnFront}"
ph.perfadd "frontend-free" "${iFrontendFree}"

ph.perfadd "backend"       "${iBackend}"
ph.perfadd "backend-max"   "${iMaxConnBack}"
ph.perfadd "backend-free"  "${iBackendFree}"

# ----------------------------------------------------------------------
# show server connections and summary (FRONTEND/ BACKEND)
# ----------------------------------------------------------------------

getColumn $colCurrentConnections | sed -n "2,$ p" >$tmpfile2
while read line
do
	srv=`echo $line  | cut -f 1 -d ","`
	val=`echo $line  | cut -f 2 -d ","`
	label=`echo $srv | tr [:upper:] [:lower:]`

	# echo "${srv} - ${val}"
  echo -n "${srv} - ${val} "

  # v1.3: if it is a servername then ping to it
  echo ${srv} | grep "^[a-z0-9\-\.]" >/dev/null
  if [ $? -eq 0 ]; then
          ping -c 1 ${srv} >$tmpfileping
          grep "\ 0%\ packet\ loss" $tmpfileping >/dev/null
          if [ $? -eq 0 ]; then
            echo "- Ping OK"
          else
            echo "- Ping FAILED"
            cat $tmpfileping
            test "`ph.status`" = "OK" && ph.setStatus "warning"
          fi
          rm -f $tmpfileping
  else
          echo
  fi

  # performance data: send summary only
  # echo ${srv} | egrep "(FRONTEND|BACKEND)" >/dev/null && ph.perfadd "${label}" "${val}" 

done < $tmpfile2

rm -f $cfgfile2 $tmpfile $tmpfile2 2>/dev/null
ph.exit

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