#!/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 # 2020-12-03 v1.4 <axel.hahn@iml.unibe.ch> added support of multiple front- and backends # 2021-12-14 v1.5 <axel.hahn@iml.unibe.ch> use updated haproxy paser in sourced file # 2022-04-01 v1.6 <axel.hahn@iml.unibe.ch> use wget default params; shell fixes # 2022-10-21 v1.7 <axel.hahn@unibe.ch> remove grep: warning: stray \ before white space # 2023-07-28 v1.8 <axel.hahn@unibe.ch> add help page # ====================================================================== . $(dirname $0)/inc_pluginfunctions export self_APPVERSION=1.8 . $(dirname $0)/inc_haproxy_cfg.sh tmpfile=/tmp/check_haproxy_status_$$ tmpfile2=/tmp/check_haproxy_status2_$$ tmpfileping=/tmp/check_haproxy_status3_$$ # ---------------------------------------------------------------------- # functions # ---------------------------------------------------------------------- # 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 stats data from column [name] function getColumn(){ typeset -i _iNumber=$1 local _filter=$2 test -z "$_filter" && _filter='.*' grep "$_filter" $tmpfile | grep -v "stats_frontend" | cut -f 2,$_iNumber -d ',' } # get sum of all stats data from column [name] function getColSum(){ getColumn $1 $2 | rev | cut -f 1 -d "," | rev | while read myvalue do echo +$myvalue done } function checkStatus(){ local _value=$1 local _must=$2 echo $_value | grep "$_must" >/dev/null if [ $? -eq 0 ]; then echo $_value | grep -v "$_must" | grep "." >/dev/null && echo ERROR else echo ERROR fi } # show help function showHelp(){ local _self; _self=$(basename $0) cat <<EOF $( ph.showImlHelpHeader ) Check HA Proxy statistics on frontend and backend. It shows if the status is OPEN or UP and show counts of current connectons. The plugin reads $HAPROXYcfgfile to detect the required statistics url and get csv data. It requires wget to handle the http request. Non OK values occur: UNKNOWN - if $HAPROXYcfgfile cannot be read - haproxy is not in http mode - the url wasn't detected - the detected status url doesn't send a response ERROR - a frontend status is not OPEN - a backend status is not UP The plugin sends performance data. SYNTAX: $_self [-h] OPTIONS: -h or --help show this help. EXAMPLE: $_self EOF } # ---------------------------------------------------------------------- # MAIN # ---------------------------------------------------------------------- # --- check param -h case "$1" in "--help"|"-h") showHelp exit 0 ;; *) esac ph.require wget if [ ! -f $HAPROXYcfgfile ]; then ph.abort "UNKNOWN: config file does not exist: $HAPROXYcfgfile" fi if ! cat $HAPROXYcfgfile >/dev/null; then ph.abort "UNKNOWN: unable to read ha proxy config $HAPROXYcfgfile ... $(ls -l $HAPROXYcfgfile)" fi if ! cat $HAPROXYcfgfile | grep " mode .*http" >/dev/null; then ph.abort "UNKNOWN: haproxy is not in http mode" fi # ---------------------------------------------------------------------- # build url # ---------------------------------------------------------------------- url=$( getStatusUri ) if [ -z "$url" ]; then ph.abort "UNKNOWN: Unable to detect url for status page." fi url="${url};csv;norefresh" # remove password for showing url in output urlmasked=$( echo $url | sed "s#\(://\)\(.*@\)#\1#g" ) # ---------------------------------------------------------------------- # check output # ---------------------------------------------------------------------- # --- get status page wget -T 5 -t 1 --no-check-certificate -O $tmpfile $url 2>/dev/null if [ $? -ne 0 ]; then rm -f $tmpfile ph.abort "UNKNOWN: url $urlmasked did not respond. $(wget -T 5 -t 1 --no-check-certificate -O - -S $url)" fi colLimit=$(getColnumber "slim") colCurrentConnections=$(getColnumber "scur") colStatus=$(getColnumber "status") statusFront=$(getColumn $colStatus ",FRONTEND," | cut -f 2 -d "," | tr "\n" " ") statusBack=$( getColumn $colStatus ",BACKEND," | cut -f 2 -d "," | tr "\n" " ") typeset -i iMaxConnFront=$(getColSum $colLimit ",FRONTEND,") typeset -i iMaxConnBack=$( getColSum $colLimit ",BACKEND,") typeset -i iFrontend=$(getColSum $colCurrentConnections ",FRONTEND,") typeset -i iFrontendFree=$iMaxConnFront-$iFrontend typeset -i iBackend=$( getColSum $colCurrentConnections ",BACKEND," ) typeset -i iBackendFree=$iMaxConnBack-$iBackend statusExt= if [ "$( checkStatus ""$statusFront"" 'OPEN' )" = "ERROR" ]; then ph.setStatus "critical" statusExt="${statusExt}ERROR: a frontend status is not OPEN\n" fi if [ "$( checkStatus ""$statusBack"" 'UP' )" = "ERROR" ]; then ph.setStatus "critical" statusExt="${statusExt}ERROR: a backend status is not UP\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 $tmpfile $tmpfile2 2>/dev/null ph.exit # ----------------------------------------------------------------------