sondes : les six premieres, et le patron qui les rend eprouvables
Ajout de meta/supervision.yml a six roles, chacun deposant sa propre sonde
selon le contrat des greffons Nagios.
DEUX PRINCIPES POSES AU DOCUMENT DE CONCEPTION, parce que la premiere
sonde les a imposes :
1. UNE SONDE DOIT POUVOIR ETRE MISE EN DEFAUT PAR PARAMETRE. Cible et
seuils sont des variables du role : on la prouve rouge avec un port ferme
ou un seuil impossible, sur une machine reelle, sans rien casser, et
aussi souvent qu on veut. Une sonde qu on ne peut prouver qu en cassant un
service ne sera prouvee qu une fois.
2. LA SONDE VIT LA OU VIT LA VERITE. « Ce noeud est-il collecte ? » est
une sonde de serveur_prometheus, pas de client_metrique : une seule y voit
les N noeuds, et surtout elle voit le cas SILENCIEUX — celui qui a cesse d
etre collecte ne peut pas s en plaindre.
LES SIX : cache-apt (artefacts, repond + place), resolution (resolveur,
zone interne ET Internet — deux chemins distincts), forge (forgejo, son
propre /api/healthz), collecte (prometheus, 15/15 cibles), tableaux
(grafana, base ok), ingestion (loki, PRET a ingerer, pas seulement en
ecoute).
TROIS FOIS J AI ECRIT LA SONDE AVANT DE MESURER, ET TROIS FOIS ELLE A EU
TORT. La forge : port 443 et chemin des depots INVENTES — elle ecoute en
3000 derriere l edge et n a legitimement aucun depot. Loki : j ai conclu
« panne persistante » sur deux lectures prises a quelques secondes d
intervalle, juste apres un redemarrage ; l anneau etait ACTIVE et la
reponse est passee a ready moins d une minute plus tard. Le delai de
stabilisation est desormais un AVERTISSEMENT nomme, pas une panne.
On demande au service ce qu il pense de lui-meme quand il sait le dire
(healthz, /ready, /api/health) plutot que d inventer un critere de l
exterieur.
make prouver : CONFORME.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-10 02:48:55 -04:00
|
|
|
#!/bin/bash
|
|
|
|
|
# GENERE par Set-OPS (role serveur_forgejo). Ne pas editer a la main.
|
|
|
|
|
#
|
|
|
|
|
# SONDE « forge » — la forge est-elle en etat de servir ?
|
|
|
|
|
#
|
|
|
|
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
|
|
|
|
# Mise en defaut PAR PARAMETRE : `serveur_forgejo_sonde_url` (port ferme).
|
|
|
|
|
#
|
|
|
|
|
# ON DEMANDE A FORGEJO CE QU'IL PENSE DE LUI-MEME. `/api/healthz` verifie sa BASE et son
|
|
|
|
|
# CACHE et rend `pass` ou non. C'est plus juste que tout ce qu'on inventerait de
|
|
|
|
|
# l'exterieur : une forge dont la base est tombee sert encore ses pages statiques et
|
|
|
|
|
# repond a `/api/v1/version` — elle a l'air vivante et ne peut plus rien faire.
|
|
|
|
|
#
|
|
|
|
|
# PREMIERE VERSION FAUSSE, ET INSTRUCTIVE (2026-09-10). Elle visait le port 443 et
|
|
|
|
|
# comptait les depots sous `/var/lib/forgejo/repositories`. Les deux etaient INVENTES :
|
|
|
|
|
# la forge du tenant ecoute en 3000 derriere l'edge, et elle n'a legitimement AUCUN depot
|
|
|
|
|
# — elle est neuve. La sonde criait donc deux fois sur un service sain. On lit la verite
|
|
|
|
|
# du role, on ne la suppose pas.
|
|
|
|
|
set -uo pipefail
|
|
|
|
|
|
|
|
|
|
URL={{ serveur_forgejo_sonde_url }}
|
|
|
|
|
|
frontiere posee, et cinq sondes qui disaient faux
Application de ce que l entree precedente avait prepare : 49 regles creees,
5 retirees. Cibles Prometheus 2/8 -> 8/8, hotes dans Loki 1/7 -> 7/7.
Puis correction de ce que l application a revele. Cinq defauts, tous de la
meme famille : un reglage qui ne suit pas l interrupteur dont il depend.
- la sonde de Loki interrogeait en HTTPS un Loki servant en clair ;
- la sonde de la forge visait http:// sur un port 443 chiffre, puis
validait un certificat emis pour le FQDN en interrogeant 127.0.0.1 ;
- la sonde du runner comparait six depots a UNE branche quand le plan en
declare une par depot. Elle contredisait la declaration qu elle etait
censee verifier : elle n accusait pas la machine, elle s accusait
elle-meme.
Le tenant restait juste dans les cinq cas. C est le site, qui deploie ces
roles autrement, qui les a tous reveles d un coup.
La sonde des journaux, elle, avait deux defauts a la naissance. Elle criait
une perte deja reparee, faute de dire sur QUELLE fenetre - un ecart sans sa
fenetre n est pas une mesure, c est un nombre. Et elle alertait sur la
cicatrice plutot que sur la plaie : le compteur d Alloy est cumulatif, donc
six machines restaient orange pour toujours. Ce qui alerte est desormais la
CROISSANCE. En echange, un cas muet leve maintenant : zero envoi et zero
rejet n est pas la sante, c est un agent qui ne fait rien.
Enfin, le runner ne pouvait plus cloner le genome. Defaut PREEXISTANT,
revele par le redeploiement et non cause par lui - le diff des regles
generees le montre. generer_nftables(site=True) lisait le plan du TENANT :
derive se resolvait donc a 3000, le port que Forgejo ecoute derriere un
edge, alors que le plan du site dit 443 et explique pourquoi. La forge
ouvrait un port que personne n ecoute et laissait 443 ferme a toute la
flotte.
Mesure finale : Icinga 51/51, Prometheus 8/8, Loki 7/7, prouver 64 OK,
lint 0 defaut sur 82 fichiers. Controles negatifs sur des COPIES des
sondes : les quatre rendent CRITICAL.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-10 10:27:12 -04:00
|
|
|
# `-k`, ET C'EST DELIBERE (2026-09-10). Des que le schema suit `serveur_forgejo_tls`, la
|
|
|
|
|
# sonde parle en HTTPS a `127.0.0.1` — alors que le certificat step-ca est emis pour le
|
|
|
|
|
# FQDN de la machine. La verification echoue, curl ne rend RIEN, et le test « sortie vide »
|
|
|
|
|
# ci-dessous traduisait cela en « la forge ne repond pas » : un CRITICAL sur une forge qui
|
|
|
|
|
# servait le genome au meme instant.
|
|
|
|
|
#
|
|
|
|
|
# Valider le certificat ici reviendrait a mesurer la PKI depuis le mauvais endroit — c'est
|
|
|
|
|
# le travail de la sonde `certificat`, qui compare le cert SERVI a celui du disque. Celle-ci
|
|
|
|
|
# demande a Forgejo ce qu'il pense de lui-meme ; le transport n'est pas son sujet.
|
|
|
|
|
sortie=$(curl -sk --max-time 10 "${URL}/api/healthz" 2>/dev/null)
|
sondes : les six premieres, et le patron qui les rend eprouvables
Ajout de meta/supervision.yml a six roles, chacun deposant sa propre sonde
selon le contrat des greffons Nagios.
DEUX PRINCIPES POSES AU DOCUMENT DE CONCEPTION, parce que la premiere
sonde les a imposes :
1. UNE SONDE DOIT POUVOIR ETRE MISE EN DEFAUT PAR PARAMETRE. Cible et
seuils sont des variables du role : on la prouve rouge avec un port ferme
ou un seuil impossible, sur une machine reelle, sans rien casser, et
aussi souvent qu on veut. Une sonde qu on ne peut prouver qu en cassant un
service ne sera prouvee qu une fois.
2. LA SONDE VIT LA OU VIT LA VERITE. « Ce noeud est-il collecte ? » est
une sonde de serveur_prometheus, pas de client_metrique : une seule y voit
les N noeuds, et surtout elle voit le cas SILENCIEUX — celui qui a cesse d
etre collecte ne peut pas s en plaindre.
LES SIX : cache-apt (artefacts, repond + place), resolution (resolveur,
zone interne ET Internet — deux chemins distincts), forge (forgejo, son
propre /api/healthz), collecte (prometheus, 15/15 cibles), tableaux
(grafana, base ok), ingestion (loki, PRET a ingerer, pas seulement en
ecoute).
TROIS FOIS J AI ECRIT LA SONDE AVANT DE MESURER, ET TROIS FOIS ELLE A EU
TORT. La forge : port 443 et chemin des depots INVENTES — elle ecoute en
3000 derriere l edge et n a legitimement aucun depot. Loki : j ai conclu
« panne persistante » sur deux lectures prises a quelques secondes d
intervalle, juste apres un redemarrage ; l anneau etait ACTIVE et la
reponse est passee a ready moins d une minute plus tard. Le delai de
stabilisation est desormais un AVERTISSEMENT nomme, pas une panne.
On demande au service ce qu il pense de lui-meme quand il sait le dire
(healthz, /ready, /api/health) plutot que d inventer un critere de l
exterieur.
make prouver : CONFORME.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-10 02:48:55 -04:00
|
|
|
[[ -n "${sortie}" ]] || { echo "La forge ne repond pas sur ${URL}."; exit 2; }
|
|
|
|
|
|
|
|
|
|
verdict=$(printf '%s' "${sortie}" | python3 -c '
|
|
|
|
|
import json, sys
|
|
|
|
|
try:
|
|
|
|
|
d = json.load(sys.stdin)
|
|
|
|
|
except Exception:
|
|
|
|
|
print("2|reponse illisible de /api/healthz"); raise SystemExit
|
|
|
|
|
etat = d.get("status")
|
|
|
|
|
mauvais = sorted(n for n, v in (d.get("checks") or {}).items()
|
|
|
|
|
if any((c or {}).get("status") != "pass" for c in (v or [])))
|
|
|
|
|
if etat == "pass" and not mauvais:
|
|
|
|
|
print("0|" + ", ".join(sorted(d.get("checks") or {})) + " : pass")
|
|
|
|
|
else:
|
|
|
|
|
print("2|statut " + str(etat) + (" ; en defaut : " + ", ".join(mauvais) if mauvais else ""))
|
|
|
|
|
' 2>/dev/null)
|
|
|
|
|
|
|
|
|
|
code=${verdict%%|*}
|
|
|
|
|
texte=${verdict#*|}
|
|
|
|
|
[[ -n "${code}" ]] || { echo "Verdict de sante illisible."; exit 2; }
|
|
|
|
|
|
|
|
|
|
if [[ "${code}" == "0" ]]; then
|
|
|
|
|
echo "Forge en etat de servir — ${texte}."
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
|
|
|
|
echo "Forge EN DEFAUT — ${texte}."
|
|
|
|
|
exit 2
|