#!/bin/bash # GENERE par Set-OPS (role serveur_ops_site). Ne pas editer a la main. # # LA FABRIC DIT-ELLE ENCORE CE QUE LE PLAN DIT ? (2026-09-28) # # Joue les plans de LECTURE (aucune ecriture) et consigne, pour chacun, ce qu'il resterait # a creer, retirer, mettre a jour ou corriger. La sonde « fabric » lit ce constat. # # POURQUOI : le 2026-09-28, aucune des 26 VM des locataires n'avait son pare-feu Proxmox # actif — les reconstructions clonent sans ses options —, et rien ne le signalait. Le meme # jour, un changement du moteur a fait vouloir a la frontiere une regle qui ne # correspondrait jamais ; seul un plan relu a la main l'a montre. Les plans existaient : # personne ne les jouait sans raison. # # Pourquoi un minuteur et pas la sonde elle-meme : une sonde dispose de quelques secondes, # et ces plans interrogent l'API du cluster et celle de la frontiere. set -uo pipefail RACINE={{ serveur_ops_site_racine }} UTIL={{ serveur_ops_site_utilisateur }} ETAT={{ serveur_ops_site_conformite_etat }} # Le devis du pare-feu Proxmox resout les flux d'un locataire : n'importe lequel suffit, # il est borne par `underlay.tenants`. TENANT=$(ls -d "${RACINE}"/OPS-* 2>/dev/null | head -1) TMP=$(mktemp); trap 'rm -f "${TMP}"' EXIT resultats=() for plan in {{ serveur_ops_site_conformite_plans | join(' ') }}; do runuser -u "${UTIL}" -- bash -lc "cd '${RACINE}/Set-OPS-public' && export PATH='${RACINE}/venv/bin':\$PATH && SETOPS_INSTANCE='${TENANT}' timeout 240 make ${plan}" > "${TMP}" 2>&1 rc=$? # La sortie passe par un FICHIER : `python3 -` lit deja son code sur l'entree standard. resultats+=("$(python3 - "${plan}" "${rc}" "${TMP}" <<'EOF' import json, re, sys plan, rc, texte = sys.argv[1], int(sys.argv[2]), open(sys.argv[3], errors="replace").read() a_faire = sum(int(n) for n in re.findall( r"(?:a creer|a retirer|a mettre a jour|noeuds a corriger)\s*:\s*(\d+)", texte)) detail = [re.sub(r"\s+", " ", l.strip()) for l in texte.splitlines() if re.match(r"\s*[-+~]\s", l)][:6] print(json.dumps({"plan": plan, "rc": rc, "a_faire": a_faire, "detail": detail})) EOF )") done python3 - "${ETAT}" "${resultats[@]}" <<'EOF' import json, sys, time, os etat, lignes = sys.argv[1], sys.argv[2:] doc = {"horodatage": int(time.time()), "plans": [json.loads(l) for l in lignes]} tmp = etat + ".tmp" with open(tmp, "w") as f: json.dump(doc, f) os.replace(tmp, etat) EOF