-
Hahn Axel (hahn) authoredHahn Axel (hahn) authored
check_couchdb 9.76 KiB
#!/bin/bash
# ======================================================================
#
# Icinga/ Nagios Check
# COUCHDB
#
# ----------------------------------------------------------------------
#
# REQUIREMENTS:
# - curl
#
# SYNTAX:
# - check_couchdb [-h] [-c CFGFILE] -m MODE
#
# ----------------------------------------------------------------------
# 2023-08-28 v0.1 <axel.hahn@unibe.ch> first lines
# 2023-08-28 v0.2 <axel.hahn@unibe.ch> first check "up"
# 2023-08-28 v0.3 <axel.hahn@unibe.ch> add check "replication"
# 2023-08-28 v0.4 <axel.hahn@unibe.ch> add check "pending"
# 2023-08-28 v0.5 <axel.hahn@unibe.ch> add checks "open_databases" + "open_os_files"
# 2023-08-28 v0.6 <axel.hahn@unibe.ch> add check "httpd_methods"
# 2023-08-29 v0.7 <axel.hahn@unibe.ch> add check "httpd"
# 2023-08-29 v0.8 <axel.hahn@unibe.ch> add check "httpd_status_codes"
# ======================================================================
. $(dirname $0)/inc_pluginfunctions
export self_APPVERSION=0.8
cfgfile=/etc/icingaclient/.couchdb
export RESPONSE
# ----------------------------------------------------------------------
# FUNCTIONS
# ----------------------------------------------------------------------
# show help
function showHelp(){
local _self; _self=$(basename $0)
cat <<EOF
$( ph.showImlHelpHeader )
Show couchdb status.
SYNTAX:
$_self [-h] [-t FILE] -m MODE
OPTIONS:
-h or --help show this help.
-c CFGFILE set a custom config file
default: /etc/icingaclient/.couchdb
-m MODE test a value; for debugging purposes the full json
response will be shown
MODE is one of
httpd Show counters for http request types
httpd_methods Show counters for http request methods
httpd_status_codes Show counters per http status code
open_databases show number of open databases
open_os_files show number of file descriptors CouchDB has open
replication show last replication status
pending show count of pending updates for nodes, dbs and users
replication show last replication status
up show general couchdb health status
EXAMPLE:
$_self -m up
Check if couchdb is up and running
$_self -m httpd_methods
Show counters and change rate per sec of GET, POST, and other methods
$_self -c /opt/couchdb/myconfig.sh -m up
Source another config to define COUCH_URL
EOF
}
# get couchdb status by given url and a filter
# The check aborts here if no data were found.
# Response is written into global var RESPONSE
#
# param string url to request; the part behind couchdb base url
# param string string to search for in the content
function abortOnWrongResponse(){
_path="$1"
_filter="$2"
RESPONSE=$( curl -s "${COUCH_URL}${_path}" )
if ! grep "$_filter" <<< "$RESPONSE" >/dev/null ; then
echo "ERROR: Wrong response from $_path - it does not contain $_filter"
curl -si "${COUCH_URL}${_path}"
ph.abort
fi
}
# ----------------------------------------------------------------------
# MAIN
# ----------------------------------------------------------------------
# --- check param -h
case "$1" in
"--help"|"-h")
showHelp
exit 0
;;
*)
esac
ph.require jq
sMode=$(ph.getValueWithParam '' "m" "$@")
cfgfile=$(ph.getValueWithParam "${cfgfile}" "c" "$@")
if [ ! -f "$cfgfile" ]; then
echo "ERROR: Config file [${cfgfile}] does not exist."
ph.abort
fi
. "$cfgfile" || exit 1
if [ -z "$COUCH_URL" ]; then
echo "ERROR: I have no couchdb url + authentication yet."
echo "set 'export COUCH_URL=http://USER:PW@localhost:5984' in $cfgfile"
ph.abort
fi
# ----------------------------------------------------------------------
case "${sMode}" in
# ............................................................
"httpd")
REQ=/_node/_local/_stats/couchdb/httpd
abortOnWrongResponse "${REQ}" '"value":'
typeset -i _iValue
typeset -i _iDelta
_status=$( jq 'with_entries(.value |= .value)' <<< "${RESPONSE}" | grep '^ "' | grep -v '\{' | sed 's#[", ]##g' )
# this returns:
# aborted_requests:0
# bulk_requests:0
# requests:185531
# ...
ph.status "Couchdb :: Http request methods"
printf "%30s %10s %10s\n" "Property" "Counter" "Delta" | tr ' ' '_'
for myVar in $( grep "^[a-z\_]" <<< "$_status" | cut -f 1 -d ':' )
do
_iValue=$( grep "^${myVar}:" <<< "$_status" | cut -f 2 -d ':' )
_label="couchdb-hp-${myVar//_/-}" # underscrore to minus
_iDelta=$( ph.perfdeltaspeed "${_label}" $_iValue )
printf "%30s %10s %10s per sec\n" "$myVar" $_iValue $_iDelta
ph.perfadd "${myVar}" "$_iDelta" "" ""
done
echo
;;
# ............................................................
"httpd_methods")
REQ=/_node/_local/_stats/couchdb/httpd_request_methods
abortOnWrongResponse "${REQ}" '"value":'
typeset -i _iValue
typeset -i _iDelta
_status=$( jq 'with_entries(.value |= .value)' <<< "${RESPONSE}" | sed 's#[", ]##g' | grep '^[A-Z]' )
# this returns:
# COPY:0
# DELETE:1
# GET:188183
# HEAD:0
# ...
ph.status "Couchdb :: Http request methods"
printf "%10s %10s %10s\n" "Method" "Counter" "Delta" | tr ' ' '_'
for myVar in $( grep "^[A-Z]" <<< "$_status" | cut -f 1 -d ':' )
do
_iValue=$( grep "^$myVar:" <<< "$_status" | cut -f 2 -d ':' )
_label="couchdb-hm-${myVar//_/-}" # underscrore to minus
_iDelta=$( ph.perfdeltaspeed "${_label}" $_iValue)
printf "%10s %10s %10s per sec\n" "$myVar" $_iValue $_iDelta
ph.perfadd "${myVar}" "$_iDelta" "" ""
done
# echo "${_status}" | jq
;;
# ............................................................
"httpd_status_codes")
REQ=/_node/_local/_stats/couchdb/httpd_status_codes
abortOnWrongResponse "${REQ}" '"value":'
typeset -i _iValue
typeset -i _iDelta
_status=$( jq 'with_entries(.value |= .value)' <<< "${RESPONSE}" | sed 's#[", ]##g' | grep '^[1-9]' )
# this returns:
# 200:199460
# 201:0
# 202:0
# 204:0
# ...
ph.status "Couchdb :: Http status codes"
printf "%10s %10s %10s\n" "Status" "Counter" "Delta" | tr ' ' '_'
for myVar in $( grep "^[1-9]" <<< "$_status" | cut -f 1 -d ':' )
do
_iValue=$( grep "^$myVar:" <<< "$_status" | cut -f 2 -d ':' )
_label="couchdb-hs-${myVar//_/-}" # underscrore to minus
_iDelta=$( ph.perfdeltaspeed "${_label}" $_iValue)
printf "%10s %10s %10s per sec\n" "$myVar" $_iValue $_iDelta
ph.perfadd "http${myVar}" "$_iDelta" "" ""
done
;;
# ............................................................
"open_databases"|"open_os_files")
REQ=/_node/_local/_stats/couchdb/${sMode}
abortOnWrongResponse "${REQ}" '"value":'
typeset -i _iValue
# descr=$( jq '.desc' <<< "${RESPONSE}" | tr -d '"')
_iValue=$( jq '.value' <<< "${RESPONSE}" )
ph.perfadd "${sMode}" "$_iValue" "" ""
ph.status "Couchdb :: ${sMode} = $_iValue"
# echo "$descr"
# echo "Reponse: of ${REQ}";
# echo "${RESPONSE}" | jq
;;
# ............................................................
"pending")
REQ=/_up
abortOnWrongResponse "${REQ}" '"status":"'
_status=$( jq '.seeds[] | .pending_updates' <<< "${RESPONSE}" | grep -v "null" | tr -d '"')
typeset -i _iSumme
typeset -i _iTotal
_iTotal=0
for myvar in _nodes _dbs _users
do
_iSumme=0
for myvalue in $( grep "$myvar" <<< "$_status" | cut -f 2 -d ':' | tr -d ',')
do
_iSumme+=$myvalue
test "$myvalue" -gt 0 && ph.setStatus warning
done
ph.perfadd "$myvar" "$_iSumme" "" ""
_iTotal+=$_iSumme
done
ph.status "Couchdb :: pending updates: $_iTotal (values below 'pending_updates' in ${REQ})"
echo "Reponse: of ${REQ}";
echo "${RESPONSE}" | jq
;;
# ............................................................
"replication")
REQ=/_up
abortOnWrongResponse "${REQ}" '"status":"'
_status=$( jq '.seeds[] | .last_replication_status' <<< "${RESPONSE}" | grep -v "null" | tr -d '"')
# there can be multiple sections "seeds" and multiple line responses.
# remove all lines with "ok" and check if there is any "bad content" left
_nonok=$( echo "$_status" | grep -v "ok" )
if [ -n "$_nonok" ]; then
ph.setStatus critical
fi
ph.status "Couchdb :: replication (values 'last_replication_status' in ${REQ} are '$_status')"
echo "Reponse: of ${REQ}";
echo "${RESPONSE}" | jq
;;
# ............................................................
"up")
REQ=/_up
abortOnWrongResponse "${REQ}" '"status":"'
_status=$( jq '.status' <<< "${RESPONSE}" | tr -d '"')
if ! echo "$_status" | grep "ok" >/dev/null; then
ph.setStatus critical
fi
ph.status "Couchdb :: health status"
echo "Reponse of ${REQ}: ";
echo "${RESPONSE}" | jq
;;
# ............................................................
*)
echo "ERRROR: [${sMode}] is an INVALID mode"
showHelp
ph.abort
esac
ph.exit
# ----------------------------------------------------------------------