diff --git a/CHANGELOG.md b/CHANGELOG.md index 01762c5..7181c79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,39 @@ # CHANGELOG — Set-OPS +## 2026-10-05 (95) — Une régression publiée : le devis des pools vide, et une comparaison qui ne testait rien + +**Ce qui s'est passé.** (94) a fait passer la découverte des locataires par la face réseau, qui +ne publiait que cinq champs de leur nomenclature. Le devis des pools dérive les VMID par +`deriver_nomenclature`, qui lit aussi `fonctions` : sans ce champ, **chaque pool de locataire +s'est retrouvé vide** (0 membre, toutes les VM « sans VMID »), sans erreur. Publié dans +`d0a6002`. + +**Pourquoi la vérification ne l'a pas vu.** Pour prouver « identique à HEAD », j'ai lancé +l'**ancien script** (`git show HEAD:scripts/X.py`) à côté du nouveau. Mais il importait le +**nouveau** module de découverte : pour tous les consommateurs de la découverte, la +comparaison comparait le nouveau code à lui-même. Sept « IDENTIQUE » qui ne testaient rien. + +**Ce que ça a coûté** : un devis publié faux. Rien n'applique les pools automatiquement, et le +clonage nomme son pool par une lecture directe de la nomenclature, non touchée. + +**Corrigé** : +- la face publie aussi `fonctions` ; faces republiées. Les pools retrouvent leurs 13 VM par + locataire ; +- **la comparaison refaite correctement** : un `git worktree` à `d6591cb` (avant toute + l'étape 3), arbre complet, même environnement. Les sept sorties du site (commutateur, + frontière, Proxmox, SDN ×2, pools, inventaire du site) sont **identiques octet pour octet**. + Une seule différence apparente — `instance_active` à la frontière — venait du worktree, sans + lien `instance` : la frontière lit le lien et non `SETOPS_INSTANCE`, une des devinettes de + contexte que la conception doit supprimer. Avec le même lien : identique ; +- garde de régression dans `test_contexte.py` (105 contrôles) : chaque pool porte autant de + VM que le locataire en publie, aucune sans VMID. + +**La leçon, retenue** : comparer à l'ancien code se fait dans un **arbre complet**, jamais en +lançant l'ancien script seul ; vérifier `git diff --stat` après une édition scriptée avant de +comparer ; accompagner chaque « identique » d'un témoin qui doit changer. + +**Validation** : `make verifier` conforme, 92/92. + ## 2026-10-05 (94) — Étape 3 : le site découvre ses locataires par leur face réseau **Le chemin** (`docs/conception-contextes.md` §6), étape 3. La découverte des locataires diff --git a/scripts/contexte.py b/scripts/contexte.py index 36fb674..531e3ae 100644 --- a/scripts/contexte.py +++ b/scripts/contexte.py @@ -540,10 +540,11 @@ class Locataire(Ecosysteme): "sources": sources, "index": self.index, "zones": zones, - # Ce que le site lit de sa nomenclature (decouverte, frontiere, SDN, commutateur) : - # ces cinq champs, et rien d'autre (releve du 2026-10-05). + # Ce que le site lit de sa nomenclature (decouverte, frontiere, SDN, commutateur, pools). + # `fonctions` manquait au premier releve : les pools en derivent les VMID — le devis + # des pools s'est retrouve vide, publie ainsi avant d'etre vu (2026-10-05). "nomenclature": {k: self.nomenclature()[k] for k in - ("index", "categories", "reservations", "cidr_hote", "federe") + ("index", "categories", "reservations", "cidr_hote", "federe", "fonctions") if k in self.nomenclature()}, "machines": machines, "groupes": groupes, diff --git a/scripts/tests/test_contexte.py b/scripts/tests/test_contexte.py index 3111aa5..0bff86d 100644 --- a/scripts/tests/test_contexte.py +++ b/scripts/tests/test_contexte.py @@ -579,6 +579,25 @@ def decouverte_lit_la_face() -> None: f"la decouverte du site lit l'index publie : {avant}, puis 99 une fois la face alteree") +def pools_complets() -> None: + """Chaque pool porte toutes les VM que le locataire publie (regression du 2026-10-05 : la + face ne publiait pas `fonctions`, et le devis des pools s'est retrouve vide, sans erreur).""" + import devis_proxmox_pools + import devis_reseau + couples = C.couples_hebergeur() + if not couples: + print("SAUTE aucun site frere : aucun pool a confronter") + return + site = couples[0][0] + with C._monter(site): + pools = {b["tenant"]: b for b in devis_proxmox_pools.construire(devis_reseau.decouvrir_du_site())["pools"]} + for _s, loc in couples: + b = pools.get(loc.nom) or {} + attendu = len((loc.face_publiee() or {}).get("machines") or {}) + verifier(len(b.get("membres") or []) == attendu and not b.get("sans_vmid"), + f"pool {loc.nom} : {len(b.get('membres') or [])} VM sur {attendu} publiees, aucune sans VMID") + + def main() -> int: with tempfile.TemporaryDirectory() as tmp: d = Path(tmp) @@ -599,6 +618,7 @@ def main() -> int: proxmox_lit_la_face() frontiere_lit_la_face() decouverte_lit_la_face() + pools_complets() if ECHECS: print(f"\n{len(ECHECS)} echec(s).") return 1