adressage : le site est une flotte, et P20 le regarde enfin
L'exploitant a demande si l'adressage derive ne valait pas pour toute flotte, site compris. Oui — decision du 12 septembre, index 37 pour le site. J'avais affirme le contraire a l'entree (11) du CHANGELOG, en recopiant un commentaire perime de huit jours au lieu de mesurer. Un commentaire perime se propage : celui-la s'etait aussi loge dans la docstring de ConsoleSite. P20 s'appelle « Adressage 100% derive du seed (aucun stocke) » et sa portee etait « l'instance liee + les modeles » : elle ne regardait jamais le site, qui stockait sous_reseau et passerelle pour ses sept zones. Elle juge desormais les deux natures d'un underlay et refuse une entree qui ne declare pas la sienne — on ne peut pas juger ce qu'on ne sait pas lire. Controle negatif joue : une zone remise a 10.36.31.0/24 est refusee, en nommant l'index dont elle aurait du descendre. Le loader derive sous_reseau et passerelle a la lecture, pour que rien ne change chez les consommateurs. Mesure : 14 valeurs retirees du fichier, zero ecart sur ce qu'ils lisent, et make underlay, devis-sdn et devis-reseau passent. Valide : make test a 0 echec, P20 verte sur 2 nomenclatures et 7 zones de site. P02 et P60 restent, pour les raisons deja consignees. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
cd0f94a50b
commit
d461492623
4 changed files with 152 additions and 6 deletions
57
CHANGELOG.md
57
CHANGELOG.md
|
|
@ -1,5 +1,62 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-09-20 (12) — Une décision appliquée à moitié se croit tenue
|
||||
|
||||
**83 preuves, `make test` à 0 échec.** L'exploitant a demandé : « n'avions-nous pas décidé
|
||||
d'un plan d'adressage dérivé pour chaque flotte, qu'elle soit tenant ou site ? » Oui. La
|
||||
décision est écrite dans l'underlay du site, datée du 12 septembre :
|
||||
|
||||
> *« sites et locataires se partagent la classe A, chacun avec SON index. Le site prend
|
||||
> 37, le locataire garde 17. `make instances` les compte ensemble depuis ce jour. »*
|
||||
|
||||
### Ce que l'entrée (11) affirmait, et qui était faux
|
||||
|
||||
Elle disait qu'un site *« déclare ses adresses, il n'a aucun seed dont les faire
|
||||
descendre »*. C'était la recopie d'un commentaire en tête de `SITE-Chezlepro/plan/serveurs.yml`
|
||||
— **périmé depuis le jour où le site a reçu son index**, et lu au lieu d'être mesuré.
|
||||
|
||||
Un commentaire périmé se propage : celui-ci s'est retrouvé le même jour dans la docstring
|
||||
de `ConsoleSite` et dans une entrée de CHANGELOG. C'est exactement ce que
|
||||
`CARTE-DU-SITE.md` décrit chez un locataire — **inerte et crédible** : le moteur ne le lit
|
||||
pas, donc rien ne le corrige ; un humain le lit, et le croit.
|
||||
|
||||
### La mesure
|
||||
|
||||
Les sept zones du site suivaient `10.<index>.<vlan>.0/24` **à la lettre** — et étaient
|
||||
pourtant **écrites** : `sous_reseau` et `passerelle` stockés pour chacune. C'est
|
||||
précisément ce que P20 interdit à un locataire, sous le titre *« Adressage 100 % dérivé du
|
||||
seed (aucun stocké) »*. Et la portée de P20 était *« l'instance liée + les modèles »* :
|
||||
**elle ne regardait jamais le site**.
|
||||
|
||||
Les valeurs concordaient parce qu'un humain les avait tapées juste, ce jour-là. Rien ne le
|
||||
garantissait : une zone écrite `10.36.x` serait passée sans un mot.
|
||||
|
||||
### Deux natures dans une seule liste
|
||||
|
||||
`reseaux:` mélangeait ce qui peut dériver et ce qui ne le peut pas. Chaque entrée déclare
|
||||
maintenant sa nature :
|
||||
|
||||
| `nature: fabric` | grappe, iSCSI, Ceph, transit, VXLAN, management | adressage dicté par les participants d'un lien physique (D-02, D-04) — il reste **écrit** |
|
||||
| `nature: site` | les sept zones du site | elles **descendent de son index**, et ne stockent plus rien |
|
||||
|
||||
Le loader dérive `sous_reseau` et `passerelle` à la lecture, pour que les consommateurs ne
|
||||
voient aucune différence. **Quatorze valeurs stockées ont disparu du fichier, et ce que
|
||||
les consommateurs lisent est identique — écart mesuré : zéro.** `make underlay`,
|
||||
`make devis-sdn` et `make devis-reseau` passent.
|
||||
|
||||
P20 juge désormais les deux natures, et refuse une entrée qui ne déclare pas la sienne :
|
||||
on ne peut pas juger ce qu'on ne sait pas lire. Contrôle négatif joué : une zone remise à
|
||||
`10.36.31.0/24` est refusée, en nommant l'index dont elle aurait dû descendre.
|
||||
|
||||
### Ce qui reste écrit, et qui est une dette nommée
|
||||
|
||||
Les **machines** du site gardent leurs `ip`, `vmid` et `noeud` dans son plan. Ce n'est plus
|
||||
une doctrine — « le site est le terrain, il n'a rien dont faire descendre » — puisque le
|
||||
seed existe maintenant pour elles aussi. C'est une dette, et la nommer est le minimum :
|
||||
*un objectif qu'on abandonne sans le dire devient un objectif qu'on croit atteint.*
|
||||
|
||||
**P02 et P60 restent**, pour les raisons déjà consignées.
|
||||
|
||||
## 2026-09-20 (11) — Deux fonctions qui doivent rendre la même forme finissent par ne plus la rendre
|
||||
|
||||
**83 preuves, `make test` à 0 échec, 8 tests de rendu.** La console avait deux
|
||||
|
|
|
|||
|
|
@ -774,9 +774,12 @@ class ConsoleLocataire(Console):
|
|||
class ConsoleSite(Console):
|
||||
"""Elle MATERIALISE : cree et detruit des VM, pose le reseau, avec la voute du site.
|
||||
|
||||
SON PLAN EST DECLARE, PAS DERIVE. Un site est le terrain : il ecrit `ip`, `vmid` et
|
||||
`noeud`, parce qu'il n'a aucun seed dont les faire descendre. Son inventaire n'est
|
||||
pas un fichier mais un SCRIPT.
|
||||
SES ZONES DERIVENT, SES MACHINES SONT ENCORE ECRITES. Un site a son propre index
|
||||
depuis le 2026-09-12 — le 37 pour celui-ci — et ses zones en descendent comme celles
|
||||
d'un locataire descendent du sien (P20 le garde). Ce qui reste ecrit dans son plan,
|
||||
ce sont les `ip`, `vmid` et `noeud` de ses MACHINES : une dette nommee, pas une
|
||||
doctrine. La docstring disait le contraire : elle recopiait un commentaire perime de
|
||||
huit jours au lieu de mesurer. Son inventaire, lui, n'est pas un fichier mais un SCRIPT.
|
||||
|
||||
ELLE A UN PLAN, ET ON LE LUI SERT. La charge du site servait cinq registres vides
|
||||
« pour ne pas fabriquer un faux plan de tenant ». Le site n'a pas de faux plan : il a
|
||||
|
|
|
|||
|
|
@ -946,9 +946,48 @@ def preuve_nomenclature_derivee() -> tuple[bool, str]:
|
|||
for z, c in (n.get("categories") or {}).items():
|
||||
for k in interdits_zone & set(c or {}):
|
||||
fautes.append(f"{rel}: categorie {z}.{k} stocke")
|
||||
# ── ET LE SITE, qui est une flotte comme une autre (2026-09-20) ────────────────
|
||||
#
|
||||
# CETTE PREUVE NE REGARDAIT QUE « l'instance liee + les modeles ». Le site a recu son
|
||||
# propre index le 2026-09-12 — decision ecrite dans son underlay : « sites et
|
||||
# locataires se partagent la classe A, chacun avec SON index » — et son adressage a
|
||||
# continue d'etre ECRIT : `sous_reseau` et `passerelle` pour chacune de ses sept
|
||||
# zones, exactement ce que les lignes ci-dessus interdisent a un locataire.
|
||||
#
|
||||
# Les valeurs concordaient parce qu'un humain les avait tapees juste. Rien ne le
|
||||
# garantissait : une zone ecrite `10.36.x` serait passee sans un mot. Une decision
|
||||
# appliquee a moitie est plus dangereuse qu'une decision non prise — on la croit tenue.
|
||||
#
|
||||
# LES DEUX NATURES NE SE JUGENT PAS PAREIL. Un lien de fabric PHYSIQUE (grappe, iSCSI,
|
||||
# Ceph, transit, VXLAN) tient son adressage des participants du lien, pas d'un seed :
|
||||
# D-02 et D-04 le disent, et il reste ecrit. Seules les zones du site derivent.
|
||||
import underlay as _u
|
||||
carte = _u.chemin()
|
||||
zones_site = 0
|
||||
if carte:
|
||||
brut = (yaml.safe_load(carte.read_text(encoding="utf-8")) or {}).get("underlay") or {}
|
||||
index = brut.get("index")
|
||||
for reseau in brut.get("reseaux") or []:
|
||||
nature = reseau.get("nature")
|
||||
nom = reseau.get("nom", "?")
|
||||
if nature not in ("site", "fabric"):
|
||||
fautes.append(f"{carte.name}: {nom} ne declare pas sa nature "
|
||||
f"(site|fabric) — on ne peut pas juger ce qu'on ne sait pas lire")
|
||||
continue
|
||||
if nature != "site":
|
||||
continue
|
||||
zones_site += 1
|
||||
for champ in ("sous_reseau", "passerelle"):
|
||||
if champ in reseau:
|
||||
fautes.append(f"{carte.name}: zone {nom}.{champ} stocke alors "
|
||||
f"qu'elle derive de l'index {index}")
|
||||
if reseau.get("vlan") is None:
|
||||
fautes.append(f"{carte.name}: zone {nom} sans vlan — rien dont deriver")
|
||||
|
||||
if fautes:
|
||||
return False, f"{len(fautes)} champ(s) d'adressage stockes : " + " | ".join(fautes[:4])
|
||||
return True, f"{len(cibles)} nomenclature(s) : adressage 100% derive du seed index."
|
||||
return True, (f"{len(cibles)} nomenclature(s) et {zones_site} zone(s) de site : "
|
||||
f"adressage 100% derive du seed index.")
|
||||
|
||||
|
||||
def preuve_pas_lab_code_en_dur() -> tuple[bool, str]:
|
||||
|
|
|
|||
|
|
@ -88,13 +88,60 @@ def chemin() -> Path | None:
|
|||
return p if p.exists() else None
|
||||
|
||||
|
||||
# --- LES ZONES DU SITE DERIVENT DE SON INDEX, COMME CELLES DE N'IMPORTE QUELLE FLOTTE ---
|
||||
#
|
||||
# LA DECISION EST DU 2026-09-12, SON APPLICATION DU 2026-09-20. Ce jour-la, l'exploitant a
|
||||
# tranche : « sites et locataires se partagent la classe A, chacun avec SON index ». Le
|
||||
# site a pris 37. Mais son `underlay.yml` a continue d'ECRIRE `sous_reseau` et
|
||||
# `passerelle` pour chacune de ses sept zones — exactement ce que P20 interdit a un
|
||||
# locataire, sous le titre « Adressage 100% derive du seed (aucun stocke) ».
|
||||
#
|
||||
# Les valeurs concordaient, parce qu'un humain les avait tapees juste ce jour-la. Rien ne
|
||||
# le garantissait : une zone ecrite `10.36.x` serait passee sans un mot, P20 ne regardant
|
||||
# que « l'instance liee + les modeles ». Une decision appliquee a moitie est plus
|
||||
# dangereuse qu'une decision non prise : on la croit tenue.
|
||||
#
|
||||
# DEUX NATURES DANS UNE SEULE LISTE, et c'est ce qui brouillait la lecture :
|
||||
#
|
||||
# nature: fabric les liens PHYSIQUES — grappe, iSCSI, Ceph, transit, VXLAN. Leur
|
||||
# adressage est dicte par les participants du lien (D-02, D-04) : il
|
||||
# ne descend d'aucun seed, et il reste donc ECRIT.
|
||||
# nature: site les zones du site lui-meme. Elles descendent de son index, comme
|
||||
# celles d'un tenant descendent du sien.
|
||||
#
|
||||
# CE QUI SE DERIVE, ET RIEN D'AUTRE : `sous_reseau` = `10.<index>.<vlan>.0/24` et
|
||||
# `passerelle` = `.1` de ce reseau. Les deux valeurs etaient deja deductibles de deux
|
||||
# champs presents — c'est le propre d'une valeur stockee pour rien.
|
||||
|
||||
def _resoudre_reseaux(underlay: dict | None) -> dict | None:
|
||||
"""Rend l'underlay avec ses zones de site RESOLUES. Idempotent.
|
||||
|
||||
Une zone qui porte deja ses valeurs les garde : la garde (P20) refusera qu'elle les
|
||||
porte, mais ce module ne doit rien casser sur un site pas encore converti.
|
||||
"""
|
||||
if not underlay:
|
||||
return underlay
|
||||
index = underlay.get("index")
|
||||
if index is None:
|
||||
return underlay
|
||||
for reseau in underlay.get("reseaux") or []:
|
||||
if reseau.get("nature") != "site":
|
||||
continue
|
||||
vlan = reseau.get("vlan")
|
||||
if vlan is None:
|
||||
continue
|
||||
reseau.setdefault("sous_reseau", f"10.{index}.{vlan}.0/24")
|
||||
reseau.setdefault("passerelle", f"10.{index}.{vlan}.1")
|
||||
return underlay
|
||||
|
||||
|
||||
def charger() -> dict | None:
|
||||
"""Le bloc `underlay` du fichier, ou None si absent/vide."""
|
||||
"""Le bloc `underlay` du fichier, RESOLU, ou None si absent/vide."""
|
||||
c = chemin()
|
||||
if not c:
|
||||
return None
|
||||
data = yaml.safe_load(c.read_text(encoding="utf-8")) or {}
|
||||
return data.get("underlay") or None
|
||||
return _resoudre_reseaux(data.get("underlay") or None)
|
||||
|
||||
|
||||
# --- LE PLAN DU SITE, a cote de sa carte ---------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue