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.
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