sonde fabric : le pare-feu, le SDN, la frontiere et les acces disent-ils le plan ?
Un minuteur horaire sur le runner du site joue les plans de lecture et consigne l ecart ; la sonde lit le constat, et signale un constat perime. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a401481ae9
commit
79fcff3274
7 changed files with 173 additions and 0 deletions
|
|
@ -64,3 +64,16 @@ serveur_ops_site_cle_deposer: false
|
||||||
serveur_ops_site_cle_source: ""
|
serveur_ops_site_cle_source: ""
|
||||||
serveur_ops_site_cle_destination: >-
|
serveur_ops_site_cle_destination: >-
|
||||||
{{ serveur_ops_site_racine }}/.config/setops-vault-{{ serveur_ops_site_depot | lower }}
|
{{ serveur_ops_site_racine }}/.config/setops-vault-{{ serveur_ops_site_depot | lower }}
|
||||||
|
|
||||||
|
# LA CONFORMITE DE LA FABRIC (2026-09-28) — voir `templates/conformite-fabric.sh.j2`.
|
||||||
|
# Des plans de LECTURE seulement : aucun n'ecrit.
|
||||||
|
serveur_ops_site_conformite_plans:
|
||||||
|
- proxmox-fw-plan
|
||||||
|
- sdn-plan
|
||||||
|
- frontiere-plan
|
||||||
|
- vpn-admin-plan
|
||||||
|
serveur_ops_site_conformite_etat: "/var/lib/setops/conformite-fabric.json"
|
||||||
|
serveur_ops_site_conformite_horaire: "hourly"
|
||||||
|
# Au-dela, le constat est PERIME et la sonde passe au rouge : un minuteur mort ne doit pas
|
||||||
|
# laisser la derniere bonne nouvelle au vert.
|
||||||
|
serveur_ops_site_conformite_age_max_h: 3
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,9 @@ sondes:
|
||||||
service en disparaissant — on s''en apercoit quand un ecosysteme doit naitre. Et une
|
service en disparaissant — on s''en apercoit quand un ecosysteme doit naitre. Et une
|
||||||
voute dechiffree en transit ne fait echouer aucun deploiement : Ansible la lit tres
|
voute dechiffree en transit ne fait echouer aucun deploiement : Ansible la lit tres
|
||||||
bien, elle expose simplement tout.'
|
bien, elle expose simplement tout.'
|
||||||
|
- nom: fabric
|
||||||
|
ttl: 5400
|
||||||
|
raison: >-
|
||||||
|
Le pare-feu Proxmox, le SDN, la frontiere et les acces WireGuard disent-ils encore ce
|
||||||
|
que le plan dit ? Le 2026-09-28, aucune VM des locataires n'avait son pare-feu actif
|
||||||
|
et rien ne le signalait ; les plans existaient, personne ne les jouait sans raison.
|
||||||
|
|
|
||||||
|
|
@ -151,3 +151,48 @@
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0750"
|
mode: "0750"
|
||||||
|
|
||||||
|
# LA CONFORMITE DE LA FABRIC (2026-09-28). Un minuteur joue les plans de lecture et
|
||||||
|
# consigne l'ecart ; la sonde « fabric » le lit. Voir `templates/conformite-fabric.sh.j2`.
|
||||||
|
- name: Assurer le repertoire d'etat
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /var/lib/setops
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
||||||
|
- name: Deposer le constat de conformite de la fabric
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: conformite-fabric.sh.j2
|
||||||
|
dest: /usr/local/sbin/setops-conformite-fabric.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
||||||
|
- name: Deposer l'unite et le minuteur du constat
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "{{ item }}.j2"
|
||||||
|
dest: "/etc/systemd/system/{{ item }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
loop:
|
||||||
|
- setops-conformite-fabric.service
|
||||||
|
- setops-conformite-fabric.timer
|
||||||
|
|
||||||
|
- name: Activer le minuteur du constat
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: setops-conformite-fabric.timer
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
daemon_reload: true
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Deposer la sonde « fabric »
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sonde-fabric.sh.j2
|
||||||
|
dest: /usr/local/lib/setops/sondes/fabric.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
|
||||||
51
roles/serveur_ops_site/templates/conformite-fabric.sh.j2
Normal file
51
roles/serveur_ops_site/templates/conformite-fabric.sh.j2
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#!/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 = [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
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# GENERE par Set-OPS (role serveur_ops_site). Ne pas editer a la main.
|
||||||
|
[Unit]
|
||||||
|
Description=La fabric dit-elle encore ce que le plan dit ? (plans de lecture, aucune ecriture)
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/sbin/setops-conformite-fabric.sh
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
# GENERE par Set-OPS (role serveur_ops_site). Ne pas editer a la main.
|
||||||
|
[Unit]
|
||||||
|
Description=Constat de conformite de la fabric
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar={{ serveur_ops_site_conformite_horaire }}
|
||||||
|
OnBootSec=5min
|
||||||
|
RandomizedDelaySec=300
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
38
roles/serveur_ops_site/templates/sonde-fabric.sh.j2
Normal file
38
roles/serveur_ops_site/templates/sonde-fabric.sh.j2
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# GENERE par Set-OPS (role serveur_ops_site). Ne pas editer a la main.
|
||||||
|
#
|
||||||
|
# SONDE « fabric » — le pare-feu Proxmox, le SDN, la frontiere et les acces WireGuard
|
||||||
|
# disent-ils encore ce que le plan dit ?
|
||||||
|
#
|
||||||
|
# Contrat : docs/supervision-conception.md — une ligne, 0/1/2/3. Elle ne JOUE pas les
|
||||||
|
# plans (trop lents pour une sonde) : elle lit le constat du minuteur
|
||||||
|
# `setops-conformite-fabric`. Un constat trop VIEUX est une panne a part entiere : sans
|
||||||
|
# lui, un minuteur mort laisserait la derniere bonne nouvelle au vert pour toujours.
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
python3 - {{ serveur_ops_site_conformite_etat }} {{ serveur_ops_site_conformite_age_max_h }} <<'EOF'
|
||||||
|
import json, sys, time
|
||||||
|
etat, age_max = sys.argv[1], int(sys.argv[2])
|
||||||
|
try:
|
||||||
|
doc = json.load(open(etat))
|
||||||
|
except (OSError, ValueError):
|
||||||
|
print(f"Aucun constat lisible ({etat}) : le minuteur setops-conformite-fabric a-t-il tourne ?")
|
||||||
|
sys.exit(2)
|
||||||
|
age_h = (time.time() - doc["horodatage"]) / 3600
|
||||||
|
if age_h > age_max:
|
||||||
|
print(f"Constat PERIME : {age_h:.0f} h (seuil {age_max} h). Le minuteur ne mesure plus.")
|
||||||
|
sys.exit(2)
|
||||||
|
plans = doc["plans"]
|
||||||
|
illisibles = [p["plan"] for p in plans if p["rc"] != 0]
|
||||||
|
ecarts = [p for p in plans if p["rc"] == 0 and p["a_faire"] > 0]
|
||||||
|
perf = " ".join(f"{p['plan']}={p['a_faire'] if p['rc'] == 0 else -1}" for p in plans)
|
||||||
|
if illisibles:
|
||||||
|
print(f"Plan(s) illisible(s) : {', '.join(illisibles)} — la fabric n'a pas pu etre relue. | {perf}")
|
||||||
|
sys.exit(3)
|
||||||
|
if ecarts:
|
||||||
|
quoi = "; ".join(f"{p['plan']} : {p['a_faire']} ({(p['detail'] or ['?'])[0][:60]})" for p in ecarts)
|
||||||
|
print(f"ECART avec le plan — {quoi}. Relire le plan, puis appliquer ou corriger. | {perf}")
|
||||||
|
sys.exit(1)
|
||||||
|
print(f"Fabric conforme au plan ({len(plans)} plans, constat de {age_h * 60:.0f} min). | {perf}")
|
||||||
|
sys.exit(0)
|
||||||
|
EOF
|
||||||
Loading…
Reference in a new issue