From 9960cfd68e20bc0990ea47270a82b9d034f351c1 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Mon, 24 Aug 2026 20:35:52 -0400 Subject: [PATCH] instancier : accepter un adressage declare, pour les plans sans index Un SITE decrit les machines de l'hebergeur : pas d'index, pas de cohabitation avec les tenants, il vit dans le reseau d'administration. Rien ne peut donc deriver d'un seed inexistant. L'explicite (`ip`, `vmid`, `vlan`) gagne sur le derive, et les deux chemins se rejoignent sur un seul jeu de hostvars. La garde reste entiere : une machine sans adresse -- ni declaree ni derivable -- est toujours refusee. Revele en preparant le plan du site : l'underlay ne dit PAS quel pont Proxmox porte quel reseau. Les tenants ne s'en apercevaient pas, leur pont etant un VNet derive de leur index. Un SITE n'en a pas. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ scripts/instancier.py | 30 ++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e55b050..ea59ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # CHANGELOG — Set-OPS +## 2026-08-24 — Un plan peut désormais déclarer son adressage, faute d'index à en dériver + +Un **SITE** décrit les machines de l'hébergeur. Il n'a pas d'index — il ne cohabite pas +avec les tenants, il vit dans le réseau d'administration — et rien ne peut donc se dériver +d'un seed qui n'existe pas. + +`instancier` accepte maintenant un adressage **déclaré** (`ip`, `vmid`, `vlan`, `cidr`, +`passerelle` au plan), et l'explicite gagne sur le dérivé. Les deux chemins se rejoignent +sur un seul jeu de `hostvars` : un tenant ne déclare rien et tout descend de son index ; +un site déclare, parce qu'il n'y a rien d'où descendre. + +**La garde reste entière** : une machine sans adresse — ni déclarée ni dérivable — est +toujours refusée. C'est l'absence d'adresse qui est fautive, pas l'absence de dérivation. + +### Ce que la préparation a révélé + +**Le réseau d'administration `10.17.0.0/24` est à l'intérieur du supernet que l'index 17 +dérive pour Chezlepro** (`10.17.0.0/16`). Pas de collision réelle — les zones d'un tenant +commencent à `10.17.16.0` — mais le nom trompe, et un jour ça mordra. + +**L'underlay ne dit pas quel pont Proxmox porte quel réseau.** Il déclare les VLAN, les +sous-réseaux, les passerelles ; il documente `vmbr0` pour la grappe et `vmbr3` pour le +transport VXLAN — en commentaire. Rien ne dit par où une VM rejoint le plan +d'administration. Les tenants ne s'en apercevaient pas : leur pont est un VNet SDN, dérivé +de leur index. Un SITE, lui, n'en a pas. + +C'est un intrant manquant, pas un détail : sans lui, un plan de site ne peut pas dire à +quoi rattacher ses machines. + ## 2026-08-24 — Quinze invites pour un seul mot de passe `flotte-creer` appelait `make creer-vm` **une fois par hôte**, et chaque appel ajoutait diff --git a/scripts/instancier.py b/scripts/instancier.py index 3c00ad2..066df4a 100644 --- a/scripts/instancier.py +++ b/scripts/instancier.py @@ -186,16 +186,27 @@ def generer() -> dict: # # On refuse en BLOC plutot qu'a la premiere fautive : l'exploitant corrige son plan # une fois, pas une machine a la fois. + # UN SITE N'A PAS D'INDEX, DONC RIEN NE SE DERIVE (2026-08-24). + # + # Un SITE decrit les machines de l'HEBERGEUR : elles vivent dans le reseau + # d'administration, pas dans un supernet de tenant, et il n'y en a qu'un jeu par site. + # Leur adressage est donc DECLARE, pas derive — il n'y a pas de seed dont le faire + # descendre, et inventer un index pour un site le ferait cohabiter avec les tenants. + # + # La garde reste entiere pour les deux mondes : une machine sans adresse — ni derivee + # ni declaree — est refusee. C'est l'absence d'adresse qui est fautive, pas l'absence + # de derivation. sans_fonction = [ nom for nom, srv in serveurs.items() - if not (deriver_nomenclature(str(srv.get("fonction", "")), - fonction_seq(nom)[1], nomenclature) or {}).get("adresse_ip") + if not str(srv.get("ip", "")).strip() + and not (deriver_nomenclature(str(srv.get("fonction", "")), + fonction_seq(nom)[1], nomenclature) or {}).get("adresse_ip") ] if sans_fonction: connues = ", ".join(sorted((nomenclature.get("fonctions") or {}))) or "(aucune)" raise SystemExit( - "Machines sans adresse derivable — leur `fonction` n'est pas declaree dans " - "`nomenclature.fonctions` :\n" + "Machines sans adresse : ni declaree (`ip:` au plan, cas d'un SITE), ni " + "derivable — leur `fonction` n'est pas dans `nomenclature.fonctions` :\n" + "".join(f" - {n} : fonction « {serveurs[n].get('fonction', '')} »\n" for n in sans_fonction) + f"Fonctions connues de ce plan : {connues}") @@ -207,6 +218,17 @@ def generer() -> dict: for nom, srv in serveurs.items(): _, seq = fonction_seq(nom) d = deriver_nomenclature(str(srv.get("fonction", "")), seq, nomenclature) or {} + # L'EXPLICITE GAGNE SUR LE DERIVE. Un SITE declare `ip`, `vmid` et `vlan` ; un + # tenant ne declare rien et tout descend de son index. Les deux chemins se + # rejoignent ici, et un seul jeu de hostvars en sort. + if str(srv.get("ip", "")).strip(): + d = dict(d) + d["adresse_ip"] = srv["ip"] + d["cidr"] = srv.get("cidr", 24) + d["passerelle"] = srv.get("passerelle") or d.get("passerelle") + d["vlan"] = srv.get("vlan", d.get("vlan")) + d["vmid"] = srv.get("vmid", d.get("vmid")) + d["zone"] = None # pas de zone : pas de VNet SDN a deriver hostvars = { # Supernet du tenant, DERIVE du seed comme tout le reste. Il repond a la # question « quels clients mon service doit-il accepter ? », posee par