#!/bin/bash # GENERE par Set-OPS (role chrony). Ne pas editer a la main. # # SONDE « horloge » — la machine est-elle synchronisee, ET contre LA SOURCE DECLAREE ? # # LES DEUX MOITIES COMPTENT. Une machine peut etre parfaitement a l'heure en interrogeant # quatre serveurs publics : c'est le defaut de Debian, et il a tenu quatorze machines # jusqu'au 2026-09-11 sans que rien ne le dise. Mesurer la seule derive laisserait ce # retour en arriere invisible. # # POURQUOI L'HEURE MERITE UNE SONDE. step-ca emet des certificats a duree courte ; TLS # refuse un certificat pas encore valide ; Loki rejette une ligne trop loin dans le futur ; # les silences d'Icinga reposent sur des `ttl`. Une flotte dont les horloges divergent # tombe en panne de l'interieur, avec des symptomes qui ressemblent a tout sauf a une # horloge. # # Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2. # Mise en defaut PAR PARAMETRE : `chrony_sonde_ecart_max` (le baisser a 0). set -uo pipefail ECART_MAX={{ chrony_sonde_ecart_max }} ATTENDUS="{{ chrony_serveurs | join(' ') }}" if ! systemctl is-active --quiet chrony; then echo "chrony ne tourne pas : l'horloge derive sans que personne ne la corrige." \ "| ecart=U sources=0 declarees=0" exit 2 fi # `^*` marque la source RETENUE. Sans elle, chrony tourne mais ne suit personne. retenue=$(chronyc -n sources 2>/dev/null | awk '/^\^\*/ {print $2; exit}') sources=$(chronyc -n sources 2>/dev/null | tail -n +3 | wc -l) if [[ -z "${retenue}" ]]; then echo "chrony tourne mais n'a retenu AUCUNE source (${sources} candidate(s)) :" \ "l'heure n'est plus disciplinee." \ "| ecart=U sources=${sources} declarees=0" exit 2 fi # L'ecart en millisecondes, en valeur absolue. ecart=$(chronyc tracking 2>/dev/null \ | awk '/^Last offset/ {o=$4+0; if (o<0) o=-o; printf "%.0f", o*1000}') # `$4+0` FORCE LE NUMERIQUE. `chronyc` prefixe la valeur d'un `+` ou d'un `-` ; sans la # conversion, awk compare une CHAINE a zero et la valeur absolue ne mord pas. Le symptome # etait discret — `ecart=-0ms` en perfdata — et c'est precisement ce qu'un grapheur avale # sans rien dire. ecart=${ecart:-0} declarees=0 for s in ${ATTENDUS}; do [[ "${retenue}" == "${s}" ]] && declarees=1 done if [[ -n "${ATTENDUS}" && "${declarees}" -eq 0 ]]; then echo "L'heure vient de ${retenue}, qui n'est PAS la source declaree (${ATTENDUS}) :" \ "la machine est sortie de l'ecosysteme pour se synchroniser." \ "| ecart=${ecart}ms;${ECART_MAX} sources=${sources} declarees=0" exit 2 fi if (( ecart > ECART_MAX )); then echo "Synchronisee sur ${retenue}, mais l'ecart atteint ${ecart} ms" \ "(seuil ${ECART_MAX} ms) : les certificats a duree courte vont souffrir." \ "| ecart=${ecart}ms;${ECART_MAX} sources=${sources} declarees=1" exit 1 fi echo "Horloge disciplinee par ${retenue}, ecart ${ecart} ms." \ "| ecart=${ecart}ms;${ECART_MAX} sources=${sources} declarees=1" exit 0