contexte : etape 3, le site decouvre ses locataires par leur face reseau
decouvrir_du_site part de underlay.tenants et prend index et zones dans la face publiee. Les sept sorties du site sont identiques a HEAD, a l'octet pres ; frontiere-plan ne voit rien a faire. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
013c1b5279
commit
d0a6002b87
5 changed files with 97 additions and 7 deletions
31
CHANGELOG.md
31
CHANGELOG.md
|
|
@ -1,5 +1,36 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 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
|
||||||
|
(`devis_reseau.decouvrir_du_site`) alimente tous les devis du site : frontière, Proxmox, SDN,
|
||||||
|
pools, commutateur, et l'inventaire du site. Elle lisait la nomenclature de chaque locataire.
|
||||||
|
|
||||||
|
**Fait** :
|
||||||
|
- relevé de ce que le site lit d'une nomenclature : **cinq champs** (`index`, `categories`,
|
||||||
|
`reservations`, `cidr_hote`, `federe`) ; la face réseau les publie (`nomenclature`) ;
|
||||||
|
- `decouvrir_du_site` part des noms que le site déclare (`underlay.tenants`) et prend index
|
||||||
|
et zones dans la face publiée de chacun. Ordre, filtre `federe`, avertissement pour un nom
|
||||||
|
sans dépôt et refus d'un site sans locataire inchangés. Sans face, la nomenclature, et elle
|
||||||
|
le dit ;
|
||||||
|
- faces republiées chez les deux locataires.
|
||||||
|
|
||||||
|
**Le critère** : les sept sorties des consommateurs du site sont **identiques octet pour
|
||||||
|
octet** à celles de la version de HEAD, lancée à part : commutateur (8,8 Ko), frontière
|
||||||
|
(167 Ko), Proxmox (63 Ko), SDN (ses deux formats), pools, inventaire du site (81 Ko).
|
||||||
|
`make frontiere-plan` contre la frontière réelle : rien à faire.
|
||||||
|
|
||||||
|
**Ce qui lit encore la nomenclature des locataires**, nommé : la découverte de la
|
||||||
|
**fédération** (`decouvrir`), qui sert sur le poste à garder les collisions d'index (P21) et à
|
||||||
|
lister les instances — légitime, ce n'est pas le site — et que `decouvrir_du_site` appelle
|
||||||
|
encore pour son repli ; `vpn_admin.py` (index pour le tunnel) ; `devis_proxmox_pools`
|
||||||
|
(nommer les VM, avec le plan). Ils partiront avec la matérialisation et la fin du repli.
|
||||||
|
|
||||||
|
**Éprouvé** :
|
||||||
|
- `test_contexte.py`, 103 contrôles : un index altéré dans la face publiée est celui que le
|
||||||
|
site découvre (17, puis 99) — la découverte lit bien la face.
|
||||||
|
- `make verifier` conforme, 92/92.
|
||||||
|
|
||||||
## 2026-10-05 (93) — Étape 3 : la frontière lit la face réseau
|
## 2026-10-05 (93) — Étape 3 : la frontière lit la face réseau
|
||||||
|
|
||||||
**Le chemin** (`docs/conception-contextes.md` §6), étape 3. Quatrième consommateur du site, le
|
**Le chemin** (`docs/conception-contextes.md` §6), étape 3. Quatrième consommateur du site, le
|
||||||
|
|
|
||||||
|
|
@ -182,8 +182,8 @@ les publie désormais (`sources_declarees`). La frontière, en trois temps : les
|
||||||
(P87), les entrées publiques (P88), l'administration (P89) et les sorties (P90) sont faites.
|
(P87), les entrées publiques (P88), l'administration (P89) et les sorties (P90) sont faites.
|
||||||
**L'étape 2 est terminée** (2026-10-05). Étape 3 : l'instancier lit la fiche déposée par le site, et
|
**L'étape 2 est terminée** (2026-10-05). Étape 3 : l'instancier lit la fiche déposée par le site, et
|
||||||
l'inventaire d'un locataire se génère sans son site, à l'octet près (P91). Le locataire publie sa face
|
l'inventaire d'un locataire se génère sans son site, à l'octet près (P91). Le locataire publie sa face
|
||||||
réseau (P92) ; les comptes de sauvegarde, le DNS public, le pare-feu Proxmox et la frontière du site
|
réseau (P92) ; les comptes de sauvegarde, le DNS public, le pare-feu Proxmox, la frontière et la
|
||||||
la lisent.
|
découverte des locataires du site la lisent.
|
||||||
|
|
||||||
Méthodes du contrat : `site.fiche_pour(locataire)`, `locataire.face_reseau()`. Une classe
|
Méthodes du contrat : `site.fiche_pour(locataire)`, `locataire.face_reseau()`. Une classe
|
||||||
n'ouvre jamais les fichiers de l'autre ; une preuve vérifiera la règle.
|
n'ouvre jamais les fichiers de l'autre ; une preuve vérifiera la règle.
|
||||||
|
|
|
||||||
|
|
@ -540,6 +540,11 @@ class Locataire(Ecosysteme):
|
||||||
"sources": sources,
|
"sources": sources,
|
||||||
"index": self.index,
|
"index": self.index,
|
||||||
"zones": zones,
|
"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).
|
||||||
|
"nomenclature": {k: self.nomenclature()[k] for k in
|
||||||
|
("index", "categories", "reservations", "cidr_hote", "federe")
|
||||||
|
if k in self.nomenclature()},
|
||||||
"machines": machines,
|
"machines": machines,
|
||||||
"groupes": groupes,
|
"groupes": groupes,
|
||||||
"administration": {"intrant": intrant, "tunnel": tunnel_admin_de(self.depot),
|
"administration": {"intrant": intrant, "tunnel": tunnel_admin_de(self.depot),
|
||||||
|
|
|
||||||
|
|
@ -619,6 +619,20 @@ def decouvrir() -> list[tuple[str, str, dict]]:
|
||||||
return tenants
|
return tenants
|
||||||
|
|
||||||
|
|
||||||
|
def _nomenclature_publiee(nom: str) -> dict | None:
|
||||||
|
"""Les champs de nomenclature que ce locataire publie dans sa face reseau, ou None."""
|
||||||
|
try:
|
||||||
|
import contexte
|
||||||
|
face = contexte.Locataire(DOSSIER_INSTANCES / nom).face_publiee()
|
||||||
|
except Exception:
|
||||||
|
face = None
|
||||||
|
if face is None or not face.get("nomenclature"):
|
||||||
|
print(f"note : {nom} n'a pas publie sa nomenclature dans sa face reseau — lecture de "
|
||||||
|
f"son plan (transition).", file=sys.stderr)
|
||||||
|
return None
|
||||||
|
return dict(face["nomenclature"])
|
||||||
|
|
||||||
|
|
||||||
def decouvrir_du_site() -> list[tuple[str, str, dict]]:
|
def decouvrir_du_site() -> list[tuple[str, str, dict]]:
|
||||||
"""Les tenants que CE SITE heberge — `decouvrir()` restreint par `underlay.tenants`.
|
"""Les tenants que CE SITE heberge — `decouvrir()` restreint par `underlay.tenants`.
|
||||||
|
|
||||||
|
|
@ -645,12 +659,23 @@ def decouvrir_du_site() -> list[tuple[str, str, dict]]:
|
||||||
portes = underlay_mod.tenants_du_site(underlay_mod.charger())
|
portes = underlay_mod.tenants_du_site(underlay_mod.charger())
|
||||||
if portes is None:
|
if portes is None:
|
||||||
return tenants
|
return tenants
|
||||||
connus = {nom for nom, _pfx, _n in tenants}
|
# LA FACE RESEAU D'ABORD (2026-10-05, docs/conception-contextes.md §6, etape 3). Les noms
|
||||||
|
# viennent du site (`underlay.tenants`) ; l'index et les zones, de ce que chaque locataire
|
||||||
|
# PUBLIE (`face-reseau.yml`, champ `nomenclature`) — plus de sa nomenclature. Sans face
|
||||||
|
# publiee (transition), sa nomenclature, et on le dit.
|
||||||
|
par_nom = {nom: (pfx, n) for nom, pfx, n in tenants}
|
||||||
|
retenus = []
|
||||||
for nom in portes:
|
for nom in portes:
|
||||||
if nom not in connus:
|
n = _nomenclature_publiee(nom)
|
||||||
print(f"ATTENTION : `tenants` de l'underlay nomme « {nom} », "
|
if n is None:
|
||||||
f"qu'aucun dossier frere ne fournit.", file=sys.stderr)
|
if nom not in par_nom:
|
||||||
retenus = [t for t in tenants if t[0] in set(portes)]
|
print(f"ATTENTION : `tenants` de l'underlay nomme « {nom} », "
|
||||||
|
f"qu'aucun dossier frere ne fournit.", file=sys.stderr)
|
||||||
|
continue
|
||||||
|
n = par_nom[nom][1]
|
||||||
|
if n.get("index") is not None and n.get("categories") and n.get("federe", True):
|
||||||
|
retenus.append((nom, prefixe(nom), n))
|
||||||
|
retenus.sort(key=lambda t: t[2]["index"])
|
||||||
if not retenus:
|
if not retenus:
|
||||||
raise SystemExit("Aucun tenant heberge sur ce site : `underlay.tenants` n'en "
|
raise SystemExit("Aucun tenant heberge sur ce site : `underlay.tenants` n'en "
|
||||||
"retient aucun de connu.")
|
"retient aucun de connu.")
|
||||||
|
|
|
||||||
|
|
@ -551,6 +551,34 @@ def frontiere_lit_la_face() -> None:
|
||||||
f"la frontiere lit la face publiee : {g} {port}/tcp sur le WAN, {avant} regle(s), 0 une fois le verdict bascule")
|
f"la frontiere lit la face publiee : {g} {port}/tcp sur le WAN, {avant} regle(s), 0 une fois le verdict bascule")
|
||||||
|
|
||||||
|
|
||||||
|
def decouverte_lit_la_face() -> None:
|
||||||
|
"""La decouverte du site lit l'index que le locataire publie, pas sa nomenclature."""
|
||||||
|
import devis_reseau
|
||||||
|
import yaml as _yaml
|
||||||
|
couples = C.couples_hebergeur()
|
||||||
|
if not couples:
|
||||||
|
print("SAUTE aucun site frere : aucune decouverte a confronter")
|
||||||
|
return
|
||||||
|
site, loc = couples[0]
|
||||||
|
chemin = loc.depot / C.NOM_FICHIER_FACE_RESEAU
|
||||||
|
original = chemin.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
def index_decouvert():
|
||||||
|
with C._monter(site):
|
||||||
|
return next((n["index"] for nom, _p, n in devis_reseau.decouvrir_du_site() if nom == loc.nom), None)
|
||||||
|
|
||||||
|
avant = index_decouvert()
|
||||||
|
try:
|
||||||
|
f = _yaml.safe_load(original)
|
||||||
|
f["nomenclature"]["index"] = 99
|
||||||
|
chemin.write_text(_yaml.safe_dump(f, allow_unicode=True, sort_keys=False), encoding="utf-8")
|
||||||
|
apres = index_decouvert()
|
||||||
|
finally:
|
||||||
|
chemin.write_text(original, encoding="utf-8")
|
||||||
|
verifier(avant == loc.index and apres == 99,
|
||||||
|
f"la decouverte du site lit l'index publie : {avant}, puis 99 une fois la face alteree")
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
d = Path(tmp)
|
d = Path(tmp)
|
||||||
|
|
@ -570,6 +598,7 @@ def main() -> int:
|
||||||
face_publiee()
|
face_publiee()
|
||||||
proxmox_lit_la_face()
|
proxmox_lit_la_face()
|
||||||
frontiere_lit_la_face()
|
frontiere_lit_la_face()
|
||||||
|
decouverte_lit_la_face()
|
||||||
if ECHECS:
|
if ECHECS:
|
||||||
print(f"\n{len(ECHECS)} echec(s).")
|
print(f"\n{len(ECHECS)} echec(s).")
|
||||||
return 1
|
return 1
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue