Les 33 roles serveur_* declarent maintenant une sonde. Les huit qui manquaient
sont ceux dont la verite ne ressemble pas a « ce service repond-il ».
Quatre marqueurs du site : ce que tasks/main.yml verifie UNE FOIS au deploiement
cesse d etre vrai sans que rien ne tombe. La racine du cache se retrouve chainee,
la forge du genome repond en n ayant plus rien dedans, un locataire n est plus
admis a resoudre, l isolation d un depot glisse.
serveur_ops_site ne sert rien : il detient un pouvoir. La sonde verifie que la
carte est la, que la voute du site est chiffree et que sa cle est en 0600 — sans
lire le contenu d aucun des trois.
serveur_icingaweb2 surveille la vitrine de la supervision elle-meme : si la
console meurt, tout reste vert et l exploitant est aveugle.
DEFAUT 1 — quatre gabarits qu Ansible aurait refuse de rendre. Jinja lit le
{# de ${#tableau[@]} comme un debut de commentaire. Le depot connaissait le
remede et l appliquait la ou quelqu un s etait fait prendre, nulle part ailleurs.
P76 rend desormais chaque gabarit de role, avec les delimiteurs qu Ansible en
tirerait — pas une recherche de motif.
DEFAUT 2 — la doctrine promettait 54 greffons et citait check_pgsql. La flotte a
monitoring-plugins-basic : 53, sans check_pgsql ni check_dns ni check_ldap. Le
paquet qui les porte traine samba et snmp sur chaque machine. Un greffon absent
sort en 127, qui n est pas un code Nagios.
21 controles negatifs sur les machines reelles du site. ansible-lint production
0/91, harnais 75 OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
91 lines
3.8 KiB
Django/Jinja
91 lines
3.8 KiB
Django/Jinja
#!/bin/bash
|
|
# GENERE par Set-OPS (role serveur_forge_site). Ne pas editer a la main.
|
|
#
|
|
# SONDE « genome-servi » — cette forge a-t-elle encore un genome a servir ?
|
|
#
|
|
# PAS UNE ENVELOPPE DE GREFFON. `check_http` dirait « 443 repond » — c'est deja ce que
|
|
# fait la sonde `forge` de `serveur_forgejo`. Ce qu'on mesure ici n'a pas d'equivalent
|
|
# standard : le CONTENU que cette forge est censee porter pour tous les locataires du site.
|
|
#
|
|
# SANS AUCUN JUSTIFICATIF. Cette route repond en anonyme (mesure du 2026-09-14) : la
|
|
# sonde n'a besoin d'aucun jeton, donc aucun secret ne dort sur disque pour elle. Elle ne
|
|
# voit que ce que voit un visiteur — ce qui suffit exactement.
|
|
#
|
|
# `/api/v1/orgs/<org>/repos` ET PAS `/api/v1/repos/search?owner=<org>`. La premiere
|
|
# ecriture de cette sonde utilisait la recherche, et l'epreuve du 2026-09-14 l'a mise en
|
|
# defaut : avec `owner=organisation-qui-nexiste-pas`, elle rendait quand meme les six
|
|
# depots de la forge et sortait VERTE. Le parametre etait simplement ignore. La sonde
|
|
# n'aurait donc jamais mesure le genome — seulement « cette forge a des depots ».
|
|
# La route par organisation, elle, rend 404 pour une organisation absente.
|
|
set -uo pipefail
|
|
|
|
ORG='{{ serveur_forge_site_organisation }}'
|
|
PORT={{ serveur_forge_site_port }}
|
|
MINIMUM={{ serveur_forge_site_sonde_depots_minimum }}
|
|
|
|
reponse=$(curl -sk --max-time 15 -w '\n%{http_code}' \
|
|
"https://127.0.0.1:${PORT}/api/v1/orgs/${ORG}/repos?limit=100" 2>/dev/null)
|
|
code=${reponse##*$'\n'}
|
|
corps=${reponse%$'\n'*}
|
|
|
|
case "${code}" in
|
|
200) : ;;
|
|
404)
|
|
echo "L'organisation « ${ORG} » n'existe pas sur cette forge : le genome du site n'a plus de proprietaire."
|
|
exit 2
|
|
;;
|
|
# « 000 » EST LE CODE DE CURL QUAND IL N'Y A PAS EU DE REPONSE DU TOUT — connexion
|
|
# refusee, delai depasse, TLS rompu. Ce n'est pas un code HTTP, et le confondre avec
|
|
# une erreur du serveur ferait dire « la forge rend 000 » la ou il faut dire « la forge
|
|
# ne repond pas ». La branche vide, elle, ne peut pas se produire : `-w` ecrit toujours
|
|
# un code.
|
|
000)
|
|
echo "L'API de la forge ne repond pas sur ${PORT} — le genome est injoignable pour tous les locataires du site."
|
|
exit 2
|
|
;;
|
|
*)
|
|
echo "L'API de la forge rend HTTP ${code} pour « ${ORG} » — le genome n'est pas servi."
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
# `empty` EST UN CHAMP DE L'API, pas une deduction. Forgejo sait qu'un depot n'a aucun
|
|
# commit et le dit. On ne devine rien, on lit.
|
|
lecture=$(printf '%s' "${corps}" | python3 -c '
|
|
import json, sys
|
|
try:
|
|
depots = json.load(sys.stdin)
|
|
except Exception:
|
|
print("ILLISIBLE"); raise SystemExit(0)
|
|
if not isinstance(depots, list):
|
|
print("ILLISIBLE"); raise SystemExit(0)
|
|
vides = sorted(r["full_name"] for r in depots if r.get("empty"))
|
|
# LE « | » N EST PAS DECORATIF : sans separateur toujours present, une liste
|
|
# vide ferait rendre a `${lecture#*|}` le NOMBRE lui-meme, et la sonde
|
|
# annoncerait « 6 » comme nom de depot vide.
|
|
print(len(depots), "|" + ",".join(vides))
|
|
' 2>/dev/null)
|
|
|
|
if [[ "${lecture}" == "ILLISIBLE" || -z "${lecture}" ]]; then
|
|
echo "L'API de la forge repond, mais sa reponse est illisible — la forge sert-elle encore Forgejo ?"
|
|
exit 2
|
|
fi
|
|
|
|
nombre=${lecture%% *}
|
|
vides=${lecture#*|}
|
|
|
|
if (( nombre < MINIMUM )); then
|
|
echo "La forge du genome ne porte que ${nombre} depot(s) pour « ${ORG} » (minimum ${MINIMUM}) : un ecosysteme neuf n'a rien a cloner."
|
|
exit 2
|
|
fi
|
|
|
|
# UN DEPOT VIDE NE FAIT PAS ECHOUER UN CLONE — il rend un arbre sans fichiers, et le
|
|
# deploiement qui suit se fait sur un moteur absent. C'est la panne la plus couteuse ici,
|
|
# parce qu'elle ne ressemble a rien.
|
|
if [[ -n "${vides}" ]]; then
|
|
echo "Depot(s) VIDE(s) dans le genome du site : ${vides}. Un clone y rendrait un arbre sans fichiers, sans echouer."
|
|
exit 2
|
|
fi
|
|
|
|
echo "Genome du site : ${nombre} depots servis sous « ${ORG} », aucun vide."
|
|
exit 0
|