Archivi tag: ntupdate

check_ntp_peers: script bash per il monitoraggio dei peer NTP mediante Nagios

Il protocollo NTP ci consente, in soldoni, di tenere aggiornate la data e l’ora di sistema, sincronizzandole con un’apposita sorgente di tempo. Per i sistemi *nix, nella stragrande maggioranza dei casi, è sufficiente configurare il servizio NTP (attivo mediante il demone ntpd, o, in alternativa, utilizzando l’accoppiata ntpdate + crontab) agendo sul suo file diconfigurazione (ovvero ntp.conf) e definendo le sorgenti alle quali sincronizzarsi.

ntpAd esempio:

server ntp1.inrim.it
server ntp2.inrim.it

Ora, per saggiare lo stato di sincronizzazione del nostro server, a parte il classico comando date, è possibile utilizzare un apposito tool per le interrogazioni NTP, ovvero ntpq:

[root@linuxbox ~]# ntpq
ntpq> pe
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*ntp1.inrim.it   .CTD.            1 u    4   64  377   45.819    0.219   2.655
+ntp2.inrim.it   .CTD.            1 u  903 1024  377   48.974    1.788   0.978

In particolare, con il comando pe, sono riuscito a recuperare la lista dei peers (ovvero le sorgenti di tempo) con i relativi valori di offset (i quali rappresentano la discrepanza, in ms, tra l’ora locale di sistema e quella del peer stesso), di jitter (ovvero il ritardo, anch’esso espresso in ms, accumulato tra 2 aggiornamenti immediatamente successivi) e di delay (RTT, in ms, associato alla comunicazione con il time server remoto). Da notare, inoltre, che il campo refid indica qual è (se esiste, dipende dallo stratum, specificato dal campo st) la sorgente di tempo utilizzata a loro volta dai server che sto interrogando (rispettivamente ntp1.inrim.it ed ntp2.inrim.it), mentre il carattere * mostra quale dei 2 server da me definiti all’interno del file ntp.conf sto utilizzando per sincronizzare la data e l’ora di sistema.

Dopo questa breve carrellata introduttiva veniamo al dunque, per cui riporto il contenuto dello scrip bash in grado di tenere sotto controllo i valori associati alle sorgenti NTP definite sul nostro sistema:

#!/bin/bash

warn_values=$1
crit_values=$2

warn_delay=`echo $warn_values | awk -F "," '{print $1}'`
warn_offset=`echo $warn_values | awk -F "," '{print $2}'`
warn_jitter=`echo $warn_values | awk -F "," '{print $3}'`

warn_delay_len=$((${#warn_delay} - 1))
warn_offset_len=$((${#warn_offset} - 1))
warn_jitter_len=$((${#warn_jitter} - 1))

crit_delay=`echo $crit_values | awk -F "," '{print $1}'`
crit_offset=`echo $crit_values | awk -F "," '{print $2}'`
crit_jitter=`echo $crit_values | awk -F "," '{print $3}'`

crit_delay_len=$((${#crit_delay} - 1))
crit_offset_len=$((${#crit_offset} - 1))
crit_jitter_len=$((${#crit_jitter} - 1))

if [[ "$warn_delay_len" -gt 5 ]];then
        echo "UNKNOWN: bad value for warning delay"
        echo "Usage: check_ntp_peers warndelay,warnoffset,warnjitter critdelay,critoffset,critjitter"
        exit 3;
fi

if [[ "$warn_offset_len" -gt 5 ]];then
        echo "UNKNOWN: bad value for warning offset"
        echo "Usage: check_ntp_peers warndelay,warnoffset,warnjitter critdelay,critoffset,critjitter"
        exit 3;
fi

if [[ "$warn_jitter_len" -gt 5 ]];then
        echo "UNKNOWN: bad value for warning jitter"
        echo "Usage: check_ntp_peers warndelay,warnoffset,warnjitter critdelay,critoffset,critjitter"
        exit 3;
fi

if [[ "$crit_delay_len" -gt 5 ]];then
        echo "UNKNOWN: bad value for critical delay"
        echo "Usage: check_ntp_peers warndelay,warnoffset,warnjitter critdelay,critoffset,critjitter"
        exit 3;
fi

if [[ "$crit_offset_len" -gt 5 ]];then
        echo "UNKNOWN: bad value for critical offset"
        echo "Usage: check_ntp_peers warndelay,warnoffset,warnjitter critdelay,critoffset,critjitter"
        exit 3;
fi

if [[ "$crit_jitter_len" -gt 5 ]];then
        echo "UNKNOWN: bad value for critical jitter"
        echo "Usage: check_ntp_peers warndelay,warnoffset,warnjitter critdelay,critoffset,critjitter"
        exit 3;
fi

ntp_delay=`/usr/sbin/ntpq -p | grep '*' | awk '{print $8}'`
ntp_offset=`/usr/sbin/ntpq -p | grep '*' | awk '{print $9}'`
ntp_jitter=`/usr/sbin/ntpq -p | grep '*' | awk '{print $10}'`

if [[ ! -z $warn_values ]];then
         if [[ ! -z $crit_values ]];then
                if [[ ! -z $warn_delay ]];then
                        if [[ ! -z $crit_delay ]];then
                                if [[ "$(echo $ntp_delay '>=' $warn_delay | bc)" -eq 1 ]] && [[ "$(echo $ntp_delay '<' $crit_delay | bc)" -eq 1 ]];then
                                        delay="NTP delay is $ntp_delay ms";
                                        delay_perf="| ntp_delay=$ntp_delay"
                                        retval_1=1;
                                elif [[ "$(echo $ntp_delay '>=' $crit_delay | bc)" -eq 1 ]];then
                                        delay="NTP delay is $ntp_delay ms";
                                        delay_perf="| ntp_delay=$ntp_delay"
                                        retval_1=2;
                                else
                                        delay="NTP delay is $ntp_delay ms";
                                        delay_perf="| ntp_delay=$ntp_delay"
                                        retval_1=0;
                                fi
                        else
                                echo "UNKNOWN: NTP critical delay is unknown"
                                exit 3;
                        fi
                else
                        echo "UNKNOWN: NTP warning delay is unknown"
                        exit 3;
                fi
                if [[ ! -z $warn_offset ]];then
                        if [[ ! -z $crit_offset ]];then
                                if [[ "$(echo $ntp_offset '<' 0 | bc)" -eq 1 ]];then
                                        warn_offset=$(echo "-1 * $warn_offset" | bc)
                                        crit_offset=$(echo "-1 * $crit_offset" | bc)
                                        if [[ "$(echo $ntp_offset '<=' $warn_offset | bc)" -eq 1 ]] && [[ "$(echo $ntp_offset '>' $crit_offset | bc)" -eq 1 ]];then
                                                offset="NTP offset is $ntp_offset ms";
                                                offset_perf=" ntp_offset=$ntp_offset"
                                                retval_2=1;
                                        elif [[ "$(echo $ntp_offset '<' $crit_offset | bc)" -eq 1 ]];then
                                                offset="NTP offset is $ntp_offset ms";
                                                offset_perf=" ntp_offset=$ntp_offset"
                                                retval_2=2;
                                        else
                                                offset="NTP offset is $ntp_offset ms";
                                                offset_perf=" ntp_offset=$ntp_offset"
                                                retval_2=0;
                                        fi
                                else
                                        if [[ "$(echo $ntp_offset '>=' $warn_offset | bc)" -eq 1 ]] && [[ "$(echo $ntp_offset '<' $crit_offset | bc)" -eq 1 ]];then
                                                offset="NTP offset is $ntp_offset ms";
                                                offset_perf=" ntp_offset=$ntp_offset"
                                                retval_2=1;
                                        elif [[ "$(echo $ntp_offset '>' $crit_offset | bc)" -eq 1 ]];then
                                                offset="NTP offset is $ntp_offset ms";
                                                offset_perf=" ntp_offset=$ntp_offset"
                                                retval_2=2;
                                        else
                                                offset="NTP offset is $ntp_offset ms";
                                                offset_perf=" ntp_offset=$ntp_offset"
                                                retval_2=0;
                                        fi
                                fi
                        else
                                echo "UNKNOWN: NTP critical offset is unknown"
                                exit 3;
                        fi
                else
                        echo "UNKNOWN: NTP warning offset is unknown"
                        exit 3;
                fi
                if [[ ! -z $warn_jitter ]];then
                        if [[ ! -z $crit_jitter ]];then
                                if [[ "$(echo $ntp_jitter '>' $warn_jitter | bc)" -eq 1 ]] && [[ "$(echo $ntp_jitter '<' $crit_jitter | bc)" -eq 1 ]];then
                                        jitter="NTP jitter is $ntp_jitter ms";
                                        jitter_perf=" ntp_jitter=$ntp_jitter"
                                        retval_3=1;
                                elif [[ "$(echo $ntp_offset '>' $crit_jitter | bc)" -eq 1 ]];then
                                        jitter="NTP jitter is $ntp_jitter ms";
                                        jitter_perf=" ntp_jitter=$ntp_jitter"
                                        retval_3=2;
                                else
                                        jitter="NTP jitter is $ntp_jitter ms";
                                        jitter_perf=" ntp_jitter=$ntp_jitter"
                                        retval_3=0;
                                fi
                        else
                                echo "UNKNOWN: NTP critical jitter is unknown"
                                exit 3;
                        fi
                else
                        echo "UNKNOWN: NTP warning jitter is unknown"
                        exit 3;
                fi
        else
                 echo "UNKNOWN: Critical values are unknown"
                 echo "Usage: check_ntp_peers warndelay,warnoffset,warnjitter critdelay,critoffset,critjitter"
                 exit 3;
        fi
else
        echo "UNKNOWN: Warning values are unknown"
        echo "Usage: check_ntp_peers warndelay,warnoffset,warnjitter critdelay,critoffset,critjitter"
        exit 3;
fi

if [[ "$retval_1" -eq 1 ]] || [[ "$retval_2" -eq 1 ]] || [[ "$retval_3" -eq 1 ]];then

        echo "WARNING: $delay $offset $jitter $delay_perf $offset_perf $jitter_perf"
        exit 1

elif [[ "$retval_1" -eq 2 ]] || [[ "$retval_2" -eq 2 ]] || [[ "$retval_3" -eq 2 ]];then

        echo "CRITICAL: $delay $offset $jitter $delay_perf $offset_perf $jitter_perf"
        exit 2

else

        echo "OK: $delay $offset $jitter $delay_perf $offset_perf $jitter_perf"
        exit 0

fi

Per prima cosa viene verificata la consistenza delle soglie di WARNING e CRITICAL per ciauscuno dei 3 valori monitorati (offset, jitter e delay), sia per quanto riguarda il numero di cifre utilizzate (5) che per ciò che concerne la coerenza logica (ad esempio il jitter/offset/delay di WARNING deve essere strettamente minore di quello CRITICAL).

A questo punto non ci rimane che configurare Nagios, editando, in prima istanza, il file /etc/nagios/objects/commands.cfg, dove verrà definito il comando che si avvarrà del suddetto plugin:

 # 'check_ntp_peers' command definition
define command{
        command_name check_ntp_peers
        command_line $USER1$/check_ntp_peers $ARG1$ $ARG2$
}

e successivamente associando uno specifico servizio all’host che rappresenta la nostra macchina, in modo da monitorare i valori associati all’NTP:

define service{
        use                             local-service         ; Name of service template to use
        host_name                       localhost
        service_description             NTP Peers Status
        check_command                   check_ntp_peers!80.000,2.000,2.000!90.000,3.000,3.000
        }

Facciamo il solito reload del nostro NMS:

[root@linuxbox ~]# service nagios reload

ed abbiamo finito.

Alla prossima.

PS: ho deciso di scrivere il suddetto scrip per sopperire alle limitazioni intrinseche del plugin Nagios (nativo) check_ntp_peer (senza la s finale). Nella fattispecie, quest’ultimo consente di ricavare solo ed esclusivamente il valore di offset associato alla sorgente di tempo remota e per funzionare è necessario che il server interrogato sia configurato in modo da rispondere alle query NTP (e quindi non solo alle richieste di sincronizzazione). Da notare che, nella stragrande maggioranza dei casi e per questioni di sicurezza, il server consentirà la sola sincronizzazione, ignorando gli altri tipi di query, come riportato nero su bianco (ad esempio) nella configurazione standard di ntpd:

restrict default kod nomodify notrap nopeer noquery
restrict -6 default kod nomodify notrap nopeer noquery