frontiere : lire ses reglages a la racine du depot de site
Some checks are pending
verifier / verifier (push) Waiting to run

`opnsense.yml` decrivait le monde physique depuis les group_vars d'un tenant. Le devis et
le GUI le cherchent desormais d'abord a la racine du depot de site, comme underlay.yml et
proxmox-hebergeur.yml, par la meme derivation depuis le symlink.

CE QUE LE MAUVAIS RANGEMENT A COUTE : l'adresse d'API de la frontiere y etait restee a
10.0.0.1 apres migration vers 10.17.0.1. `make frontiere-appliquer` restait suspendu sur
une adresse morte, sans aucun message — trouve par l'exploitant en lancant la commande
dans son terminal, apres que j'aie moi-meme conclu deux fois a tort.

DEUX LECONS, ecrites plutot que corrigees en silence :
- un objet range chez celui qui n'en est pas responsable derive sans que personne le voie ;
- mes commandes s'executent dans ma session : l'exploitant ne voit pas leur sortie. Une
  commande lente ressemble alors a un blocage, et un blocage a une commande lente. Pour
  toute ecriture longue sur du materiel, c'est a lui de la lancer.

Les anciens emplacements restent lus : un site pas encore migre continue de fonctionner.
make verifier 41/41.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-23 00:47:32 -04:00
parent caee04385b
commit d1db332ed3
5 changed files with 57 additions and 20 deletions

View file

@ -374,15 +374,18 @@ def main() -> int:
api = Frontiere(url, v["vault_opnsense_api_key"], v["vault_opnsense_api_secret"],
bool(intr.get("opnsense_api_verifier_certs")))
# SETOPS_INSTANCE designe ici l'HEBERGEUR, pas le tenant actif. SETOPS_INVENTAIRE,
# exporte par le Makefile, gagnerait sur lui (instancier.py) : le devis d'un site
# lirait l'inventaire d'un tenant d'ailleurs. Sans effet tant qu'hebergeur et tenant
# actif coincident — c'est-a-dire jusqu'au second site (mesure du 2026-08-18).
env_heb = {**os.environ, "SETOPS_INSTANCE": str(base)}
env_heb.pop("SETOPS_INVENTAIRE", None)
# NE PAS FORCER SETOPS_INSTANCE VERS L'HEBERGEUR (2026-08-22). Le devis a besoin d'un
# TENANT — il lit son inventaire pour resoudre les flux — et l'hebergeur n'en est pas
# un : depuis que le monde physique a son propre depot (SITE-<nom>), il ne porte ni
# plan ni inventaire. Ce qui vient de l'hebergeur (underlay, proxmox-hebergeur, voute)
# est DERIVE du symlink `underlay.yml`, jamais de cette variable.
#
# L'hypothese « le depot de l'hebergeur est aussi une instance » n'a tenu que tant que
# les deux etaient confondus. La separation l'a revelee, ce qui est son interet.
env_devis = {k: v for k, v in os.environ.items() if k != "SETOPS_INVENTAIRE"}
sortie = subprocess.run([sys.executable, str(RACINE / "scripts" / "devis_opnsense.py"),
"--json"], cwd=RACINE, capture_output=True, text=True,
env=env_heb)
env=env_devis)
if sortie.returncode != 0:
raise SystemExit("Le devis ne se genere pas :\n" + sortie.stderr.strip()[:400])
devis = json.loads(sortie.stdout)

View file

@ -260,12 +260,17 @@ def appliquer(api: Cluster, p: dict) -> int:
def main() -> int:
api, base = Cluster.depuis_hebergeur()
# `base` est l'HEBERGEUR : SETOPS_INVENTAIRE (exporte par le Makefile) gagnerait sur
# SETOPS_INSTANCE et ferait lire l'inventaire du tenant actif. Cf. prouver.py P03.
env_heb = {**os.environ, "SETOPS_INSTANCE": str(base)}
env_heb.pop("SETOPS_INVENTAIRE", None)
# NE PAS FORCER SETOPS_INSTANCE VERS L'HEBERGEUR (2026-08-22). Le devis a besoin d'un
# TENANT — il lit son inventaire pour resoudre les flux — et l'hebergeur n'en est pas
# un : depuis que le monde physique a son propre depot (SITE-<nom>), il ne porte ni
# plan ni inventaire. Ce qui vient de l'hebergeur (underlay, proxmox-hebergeur, voute)
# est DERIVE du symlink `underlay.yml`, jamais de cette variable.
#
# L'hypothese « le depot de l'hebergeur est aussi une instance » n'a tenu que tant que
# les deux etaient confondus. La separation l'a revelee, ce qui est son interet.
env_devis = {k: v for k, v in os.environ.items() if k != "SETOPS_INVENTAIRE"}
r = subprocess.run([sys.executable, str(RACINE / "scripts" / "devis_proxmox_fw.py"), "--json"],
cwd=RACINE, capture_output=True, text=True, env=env_heb)
cwd=RACINE, capture_output=True, text=True, env=env_devis)
if r.returncode != 0:
raise SystemExit("Le devis ne se genere pas :\n" + r.stderr.strip()[:400])
devis = json.loads(r.stdout)

View file

@ -253,12 +253,17 @@ def appliquer(api: Cluster, p: dict, devis: dict) -> int:
def main() -> int:
api, base = Cluster.depuis_hebergeur()
# `base` est l'HEBERGEUR : SETOPS_INVENTAIRE (exporte par le Makefile) gagnerait sur
# SETOPS_INSTANCE et ferait lire l'inventaire du tenant actif. Cf. prouver.py P03.
env_heb = {**os.environ, "SETOPS_INSTANCE": str(base)}
env_heb.pop("SETOPS_INVENTAIRE", None)
# NE PAS FORCER SETOPS_INSTANCE VERS L'HEBERGEUR (2026-08-22). Le devis a besoin d'un
# TENANT — il lit son inventaire pour resoudre les flux — et l'hebergeur n'en est pas
# un : depuis que le monde physique a son propre depot (SITE-<nom>), il ne porte ni
# plan ni inventaire. Ce qui vient de l'hebergeur (underlay, proxmox-hebergeur, voute)
# est DERIVE du symlink `underlay.yml`, jamais de cette variable.
#
# L'hypothese « le depot de l'hebergeur est aussi une instance » n'a tenu que tant que
# les deux etaient confondus. La separation l'a revelee, ce qui est son interet.
env_devis = {k: v for k, v in os.environ.items() if k != "SETOPS_INVENTAIRE"}
r = subprocess.run([sys.executable, str(RACINE / "scripts" / "devis_sdn.py"), "--json"],
cwd=RACINE, capture_output=True, text=True, env=env_heb)
cwd=RACINE, capture_output=True, text=True, env=env_devis)
if r.returncode != 0:
raise SystemExit("Le devis ne se genere pas :\n" + r.stderr.strip()[:400])
devis = json.loads(r.stdout)

View file

@ -83,9 +83,21 @@ def intrants_frontiere() -> dict:
Lus chez l'HEBERGEUR, pas chez le tenant actif : un hebergeur sert plusieurs
tenants et n'a qu'une frontiere. Basculer l'instance active sur un invite ne doit
pas faire perdre au devis l'URL de gestion, l'adresse publique et les interfaces.
Repli sur l'instance active quand aucun underlay ne designe d'hebergeur.
A LA RACINE DU DEPOT DE SITE depuis le 2026-08-22, comme `underlay.yml` et
`proxmox-hebergeur.yml` : la frontiere est un objet du MONDE PHYSIQUE. Tant que ce
fichier vivait dans les `group_vars` d'un tenant, son adresse d'API a pu rester
perimee sans que personne la voie — rangee chez quelqu'un qui n'en est pas
responsable. L'applicateur est reste suspendu sur `10.0.0.1`, une adresse morte, sans
message : la panne la plus couteuse a diagnostiquer.
Les deux anciens emplacements restent lus, pour qu'un site non encore migre continue
de fonctionner.
"""
for base in (depot_hebergeur(), _inventaire().parent.parent.parent):
heb = depot_hebergeur()
if heb is not None and (heb / "opnsense.yml").is_file():
return yaml.safe_load((heb / "opnsense.yml").read_text(encoding="utf-8")) or {}
for base in (heb, _inventaire().parent.parent.parent):
if base is None:
continue
for nom in ("principal", "production", "lab"):

View file

@ -110,13 +110,25 @@ def _depot_hebergeur() -> Path | None:
def _fichier_frontiere() -> Path:
"""group_vars/opnsense.yml de l'hebergeur ; repli sur l'instance active."""
"""Les intrants de la frontiere — a la RACINE du depot de site depuis le 2026-08-22.
La frontiere est un objet du MONDE PHYSIQUE : ses reglages vivent avec `underlay.yml`
et `proxmox-hebergeur.yml`, pas dans les group_vars d'un tenant. Range chez un
locataire, ce fichier a garde une adresse d'API perimee sans que personne la voie —
et l'applicateur restait suspendu dessus, sans message.
Les anciens emplacements restent lus, pour un site pas encore migre.
"""
base = _depot_hebergeur()
if base:
racine = base / "opnsense.yml"
if racine.is_file():
return racine
for nom in ("principal", "production", "lab"):
p = base / "inventories" / nom / "group_vars" / "opnsense.yml"
if p.is_file():
return p
return racine # a creer la, pas ailleurs
return INVENTAIRE_DEFAUT.parent / "group_vars/opnsense.yml"