6. Scrivere plugin di Nagios personalizzati

I plugin sono file eseguibili lanciati da Nagios per determinare lo stato di un host o un servizio. Di default, Nagios contiene numerosi plugin ufficiali che dovrebbero soddisfare la maggior parte delle esigenze; inoltre, è possibile attingere ai numerosi plugin presenti sul sito Monitoring Exchange, alcuni dei quali sono disponibili anche tramite il sistema dei package e port di OpenBSD.

Eppure, nonostante l'abbondanza di plugin, ci possono essere casi in cui nessuno sia adatto a monitorare un particolare servizio, rendendo quindi necessaria la scrittura di plugin personalizzati, su misura per le proprie esigenze. Ma per fortuna non è per nulla complicato!

Nagios non lega gli sviluppatori a un particolare linguaggio di programmazione: i plugin possono essere programmi C compilati o script in Perl, shell, Python o altri linguaggi. Nagios non si interessa dei meccanismi interni dei plugin; però, chiede agli sviluppatori di seguire alcune semplici linee guida, giusto per rispettare un certo standard.

6.1 Opzioni della riga di comando

La riga di comando di un plugin deve soddisfare alcuni requisiti:

6.2 Codici di ritorno dei plugin

Nagios determina lo stato di un host o un servizio in base al codice di ritorno del plugin. I codici di ritorno validi sono:

Valore numerico Stato servizio/host Descrizione stato servizio Descrizione stato host
0 Ok/Up Il plugin è stato in grado di controllare il servizio e sembra funzionare correttamente L'host è su e ha risposto in tempi accettabili
1 Warning Il plugin è stato in grado di controllare il servizio, ma non sembra funzionare correttamente o ha superato qualche soglia di "warning" L'host è su, ma qualche soglia di "warning" è stata superata
2 Critical/Down Il servizio non è attivo o ha superata qualche soglia critica L'host è giù o è stata superata qualche soglia critica
3 Unknown Sono stati passati argomenti non validi alla riga di comando o c'è stato un errore interno Sono stati passati argomenti non validi alla riga di comando o c'è stato un errore interno

I valori delle soglie di warning e critical sono solitamente impostati tramite le opzioni della riga di comando (vd. sopra).

6.3 Un plugin di esempio

Solo un paio di note prima di passare all'esempio pratico:

Bene, vediamo allora, come esempio, come potrebbe essere un plugin per monitorare la quantità di memoria libera sulla macchina locale:

/usr/local/libexec/nagios/check_free_mem.sh
#!/bin/ksh

################################################################################
# Sample Nagios plugin to monitor free memory on the local machine             #
# Author: Daniele Mazzocchio (http://www.kernel-panic.it/)                     #
################################################################################

VERSION="Version 1.0"
AUTHOR="(c) 2007-2009 Daniele Mazzocchio (danix@kernel-panic.it)"

PROGNAME=`/usr/bin/basename $0`

# Constants
BYTES_IN_MB=$(( 1024 * 1024 ))
KB_IN_MB=1024

# Exit codes
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3

# Helper functions #############################################################

function print_revision {
   # Print the revision number
   echo "$PROGNAME - $VERSION"
}

function print_usage {
   # Print a short usage statement
   echo "Usage: $PROGNAME [-v] -w <limit> -c <limit>"
}

function print_help {
   # Print detailed help information
   print_revision
   echo "$AUTHOR\n\nCheck free memory on local machine\n"
   print_usage

   /bin/cat <<__EOT

Options:
-h
   Print detailed help screen
-V
   Print version information

-w INTEGER
   Exit with WARNING status if less than INTEGER MB of memory are free
-w PERCENT%
   Exit with WARNING status if less than PERCENT of memory is free
-c INTEGER
   Exit with CRITICAL status if less than INTEGER MB of memory are free
-c PERCENT%
   Exit with CRITICAL status if less than PERCENT of memory is free
-v
   Verbose output
__EOT
}

# Main #########################################################################

# Total memory size (in MB)
tot_mem=$(( `/sbin/sysctl -n hw.physmem` / BYTES_IN_MB))
# Free memory size (in MB)
free_mem=$(( `/usr/bin/vmstat | /usr/bin/tail -1 | /usr/bin/awk '{ print $5 }'` / KB_IN_MB ))
# Free memory size (in percentage)
free_mem_perc=$(( free_mem * 100 / tot_mem ))

# Verbosity level
verbosity=0
# Warning threshold
thresh_warn=
# Critical threshold
thresh_crit=

# Parse command line options
while [ "$1" ]; do
   case "$1" in
       -h | --help)
           print_help
           exit $STATE_OK
           ;;
       -V | --version)
           print_revision
           exit $STATE_OK
           ;;
       -v | --verbose)
           : $(( verbosity++ ))
           shift
           ;;
       -w | --warning | -c | --critical)
           if [[ -z "$2" || "$2" = -* ]]; then
               # Threshold not provided
               echo "$PROGNAME: Option '$1' requires an argument"
               print_usage
               exit $STATE_UNKNOWN
           elif [[ "$2" = +([0-9]) ]]; then
               # Threshold is a number (MB)
               thresh=$2
           elif [[ "$2" = +([0-9])% ]]; then
               # Threshold is a percentage
               thresh=$(( tot_mem * ${2%\%} / 100 ))
           else
               # Threshold is neither a number nor a percentage
               echo "$PROGNAME: Threshold must be integer or percentage"
               print_usage
               exit $STATE_UNKNOWN
           fi
           [[ "$1" = *-w* ]] && thresh_warn=$thresh || thresh_crit=$thresh
           shift 2
           ;;
       -?)
           print_usage
           exit $STATE_OK
           ;;
       *)
           echo "$PROGNAME: Invalid option '$1'"
           print_usage
           exit $STATE_UNKNOWN
           ;;
   esac
done

if [[ -z "$thresh_warn" || -z "$thresh_crit" ]]; then
   # One or both thresholds were not specified
   echo "$PROGNAME: Threshold not set"
   print_usage
   exit $STATE_UNKNOWN
elif [[ "$thresh_crit" -gt "$thresh_warn" ]]; then
   # The warning threshold must be greater than the critical threshold
   echo "$PROGNAME: Warning free space should be more than critical free space"
   print_usage
   exit $STATE_UNKNOWN
fi

if [[ "$verbosity" -ge 2 ]]; then
   # Print debugging information
   /bin/cat <<__EOT
Debugging information:
  Warning threshold: $thresh_warn MB
  Critical threshold: $thresh_crit MB
  Verbosity level: $verbosity
  Total memory: $tot_mem MB
  Free memory: $free_mem MB ($free_mem_perc%)
__EOT
fi

if [[ "$free_mem" -lt "$thresh_crit" ]]; then
   # Free memory is less than the critical threshold
   echo "MEMORY CRITICAL - $free_mem_perc% free ($free_mem MB out of $tot_mem MB)"
   exit $STATE_CRITICAL
elif [[ "$free_mem" -lt "$thresh_warn" ]]; then
   # Free memory is less than the warning threshold
   echo "MEMORY WARNING - $free_mem_perc% free ($free_mem MB out of $tot_mem MB)"
   exit $STATE_WARNING
else
   # There's enough free memory!
   echo "MEMORY OK - $free_mem_perc% free ($free_mem MB out of $tot_mem MB)"
   exit $STATE_OK
fi