51 lines
2.3 KiB
Django/Jinja
51 lines
2.3 KiB
Django/Jinja
#!/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
|