Skip to content
Snippets Groups Projects
Select Git revision
  • f50e8305f4f01c423169e2e43e285d93716c137e
  • master default protected
2 results

_index.md

Blame
  • check_couchdb 10.07 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"
    # 2024-01-25  v0.9  <axel.hahn@unibe.ch>  "httpd_status_codes" show total requests per sec
    # ======================================================================
    
    . $(dirname $0)/inc_pluginfunctions
    
    export self_APPVERSION=0.8
    
    cfgfile=/etc/icingaclient/.couchdb
    export RESPONSE
    
    NL="
    "
    
    # ----------------------------------------------------------------------
    # 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
            # ...
    
            out=""
            typeset -i iTotal=0
            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)
                iTotal+=$_iValue
                out+="$( printf "%10s %10s %10s per sec\n" "$myVar" $_iValue $_iDelta )$NL"
                ph.perfadd "http${myVar}" "$_iDelta"    "" ""
            done
            _iTotalDelta=$( ph.perfdeltaspeed "couchdb-hs-total" $iTotal)
    
            ph.status "Couchdb :: Http status codes - requests per sec: $_iTotalDelta"
            printf "%10s %10s %10s\n" "Status" "Counter" "Delta" | tr ' ' '_'
            echo "$out"
    
            ;;
    
        # ............................................................
        "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
    
    # ----------------------------------------------------------------------