Set-OPS-Public/roles/serveur_loki/templates/sonde-frontiere.sh.j2
Daniel Allaire c733d2df1c la frontiere journalise a nouveau, et une garde veille cette fois
Doctrine posee par l exploitant : des lors que le site a son Loki, la
journalisation de la frontiere et des hyperviseurs doit y etre dirigee.

CE QUI ETAIT CASSE. La destination syslog d OPNsense pointait
10.17.20.11:3100 - une adresse de TENANT, sur le port de Loki, en UDP, ce
que Loki ne sait pas lire. La VM a ete rasee ; une cible morte a arrete
TOUTE la journalisation pendant dix jours. La destination a ete eteinte
pour reparer et jamais remplacee. Deux fautes en une : plus de journaux, et
une cible chez un locataire, ce que D-87 refuse dans l autre sens.

L intention etait juste - bonnes facilites, info et au-dessus. On l a
REPRISE telle quelle et change uniquement la destination : ces choix
avaient ete faits, ce n etait pas a nous de les redecider.

UN TRADUCTEUR, parce que Loki ne parle pas syslog : loki.source.syslog dans
l Alloy qui tourne DEJA sur le collecteur. Port 1514 et non 514, donc
ecoute sans privilege - un collecteur qui aurait besoin des droits du
systeme pour entendre un equipement serait un mauvais echange.

UNE REGLE DE RELABEL SANS GARDE N IGNORE PAS : ELLE EFFACE. Trois quarts d
heure sur un symptome absurde - la configuration deposee portait
host = "bifrost-1", visible dans le fichier, et le flux arrivait sans
etiquette. Sans regex, la regle correspond TOUJOURS, meme quand sa source n
existe pas, et pose host = "". Loki jette une etiquette vide, et celle de l
ecouteur disparaissait avec elle.

Et la verification finale a corrige une seconde erreur, la mienne :
label/host/values rendait une liste en CACHE. La requete directe rendait
bien un flux. Un index qui ne montre pas une chose ne prouve pas qu elle n
existe pas.

LA GARDE, qui manquait depuis l incident. journaux-frontiere demande a LOKI
ce qu il a RECU, pas a la frontiere ce qu elle croit avoir envoye : la
destination est le seul juge, et un emetteur qui parle a un trou noir se
porte tres bien. La fenetre est DERIVEE du debit observe - environ 1500
lignes par minute - pas choisie.

Trois etats eprouves sur une copie : frontiere muette rc=2, Loki
injoignable rc=3, debit normal rc=0. Le 3 compte autant que le 2 : « je ne
peux rien affirmer » n est pas « c est casse ».

Mesure : 46 681 lignes recues en 30 min, site a 68 services tous OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-10 19:38:19 -04:00

54 lines
2.3 KiB
Django/Jinja

#!/bin/bash
# GENERE par Set-OPS (role serveur_loki). Ne pas editer a la main.
#
# SONDE « journaux-frontiere » — l'equipement qui voit TOUT parle-t-il encore ?
#
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
# Mise en defaut PAR PARAMETRE : `serveur_loki_sonde_frontiere_etiquette` (nom inconnu).
#
# POURQUOI CETTE SONDE EXISTE, ET POURQUOI ELLE EST LA PLUS IMPORTANTE DU LOT.
#
# La destination syslog de la frontiere a pointe une VM de TENANT, rasee depuis. Une cible
# morte a arrete TOUTE la journalisation d'OPNsense pendant DIX JOURS, et rien ne l'a
# signale : le boitier fonctionnait, le pare-feu filtrait, les regles s'appliquaient — il
# n'ecrivait simplement plus nulle part. On ne l'a su qu'en allant chercher un evenement
# qui n'avait jamais ete ecrit.
#
# Remettre la destination sans poser cette garde, ce serait reconstruire la meme panne en
# esperant s'en souvenir. Un equipement muet ne se plaint pas.
set -uo pipefail
URL={{ serveur_loki_sonde_url }}
ETIQ="{{ serveur_loki_sonde_frontiere_etiquette }}"
FENETRE={{ serveur_loki_sonde_frontiere_fenetre }}
# ON DEMANDE A LOKI CE QU'IL A RECU, pas a la frontiere ce qu'elle croit avoir envoye.
# La destination est le seul juge : un emetteur qui « envoie » vers un trou noir se porte
# tres bien, et c'est exactement ce qui s'est passe.
rep=$(curl -sk --max-time 15 -G "${URL}/loki/api/v1/query" \
--data-urlencode "query=count_over_time({host=\"${ETIQ}\", job=\"syslog\"}[${FENETRE}])" \
2>/dev/null)
[[ -n "${rep}" ]] || { echo "Loki ne repond pas sur ${URL} — la sonde ne peut rien affirmer."; exit 3; }
n=$(printf '%s' "${rep}" | python3 -c '
import json, sys
try:
d = json.load(sys.stdin)
except Exception:
print("-1"); raise SystemExit
r = (d.get("data") or {}).get("result") or []
print(int(sum(float(x.get("value", [0, 0])[1]) for x in r)))
' 2>/dev/null)
: "${n:=-1}"
perf="lignes=${n} fenetre=${FENETRE}"
if (( n < 0 )); then
echo "Reponse illisible de Loki — impossible de dire si la frontiere journalise. | ${perf}"
exit 3
fi
if (( n == 0 )); then
echo "LA FRONTIERE NE JOURNALISE PLUS : aucune ligne de « ${ETIQ} » depuis ${FENETRE}. | ${perf}"
exit 2
fi
echo "Frontiere journalise : ${n} ligne(s) recue(s) en ${FENETRE}. | ${perf}"
exit 0