frontiere : rendre les flux inter-tenants, sans encore les declarer

Le mot `voisins_site` etait accepte par la validation mais AUCUN generateur ne
le rendait : zero regle au devis, et rien ne le signalait. Deux causes, toutes
deux fermees.

flux_frontiere() ne retenait que les flux `externe`. Or deux tenants de la meme
fabric vivent sur des VLAN distincts, routes par la frontiere : leur trafic la
traverse, donc elle doit le porter.

Et le rendu manquait : une regle inter-tenant s'attache au meme lien de transit
que le reste -- les tenants s'y distinguent par leur ALIAS SOURCE, pas par une
interface. Ma mise en garde precedente reposait sur un modele faux.

LA REGLE APPARTIENT AU SITE, pas a l'un des deux tenants : c'est son runner qui
prepare le terrain, aucun ecosysteme n'ouvre de porte chez un autre.

Les declarations de chainage restent RETIREES : le devis obtenu ouvrait plus que
voulu -- maillage complet entre tous les caches, et un egress 3142 vers
l'Internet au lieu du seul voisin. Deux raffinements a faire avant de declarer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-24 17:32:35 -04:00
parent 6547eb2fac
commit c391d1ed30

View file

@ -222,12 +222,24 @@ ROLE_SOCLE = "serveur_debian"
def flux_frontiere(flux_par_role: dict[str, list[dict]]) -> list[tuple[str, dict]]: def flux_frontiere(flux_par_role: dict[str, list[dict]]) -> list[tuple[str, dict]]:
"""[(role, flux)] pour tout flux dont le pair inclut `externe`, trie.""" """[(role, flux)] pour tout flux que la FRONTIERE doit porter, trie.
Deux familles, et pas une :
`externe` — le nord-sud : l'Internet d'un cote, un tenant de l'autre.
`voisins_site` — l'est-ouest INTER-TENANT. Deux tenants de la meme fabric vivent
sur des VLAN distincts, routes par la frontiere : leur trafic la
traverse, donc elle doit le porter.
OUBLIER LA SECONDE, C'ETAIT DECLARER UN FLUX QUE PERSONNE N'APPLIQUE (2026-08-24). Le
mot `voisins_site` etait accepte par la validation, le devis rendait zero regle, et
rien ne le signalait — le chainage des caches n'aurait simplement jamais fonctionne.
"""
retenus = [ retenus = [
(role, fl) (role, fl)
for role, flux in sorted(flux_par_role.items()) for role, flux in sorted(flux_par_role.items())
for fl in flux for fl in flux
if "externe" in _pairs(fl) if "externe" in _pairs(fl) or "voisins_site" in _pairs(fl)
] ]
retenus.sort(key=lambda rf: (rf[1].get("sens", ""), rf[0], str(rf[1].get("port")))) retenus.sort(key=lambda rf: (rf[1].get("sens", ""), rf[0], str(rf[1].get("port"))))
return retenus return retenus
@ -421,6 +433,23 @@ def construire(tenants: list[tuple[str, str, dict]]) -> dict:
portees.append((f"SETOPS_ADMIN_{etiquette}_GESTION", if_gestion)) portees.append((f"SETOPS_ADMIN_{etiquette}_GESTION", if_gestion))
if admin_par_if[etiquette]["wan"]: if admin_par_if[etiquette]["wan"]:
portees.append((f"SETOPS_ADMIN_{etiquette}_WAN", if_wan)) portees.append((f"SETOPS_ADMIN_{etiquette}_WAN", if_wan))
elif entrant and "voisins_site" in _pairs(fl):
# UN FLUX ENTRE TENANTS DU MEME SITE.
#
# Ce n'est ni `flotte` (mon ecosysteme) ni `externe` (l'Internet) : le
# paquet vient d'un VOISIN pose sur la meme fabric. Il arrive par le meme
# lien de transit que tout le reste — les tenants ne se distinguent pas
# par une interface mais par leur ALIAS SOURCE, deja construit plus haut
# (`SETOPS_TENANT_<etiquette>`).
#
# LA REGLE APPARTIENT AU SITE, PAS A L'UN DES DEUX TENANTS. C'est le
# runner de site qui prepare le terrain : il configure les VNets, les
# routes et les flux pour que les plans des tenants tiennent. Aucun
# ecosysteme n'ouvre de porte chez un autre.
portees = [
(f"SETOPS_TENANT_{p2}{n2['index']}", if_transit)
for nom2, p2, n2 in tenants if nom2 != nom
]
elif entrant: elif entrant:
# Un service publie est joint DEPUIS INTERNET par le WAN, et le plus # Un service publie est joint DEPUIS INTERNET par le WAN, et le plus
# souvent aussi depuis le VLAN d'administration — le poste de # souvent aussi depuis le VLAN d'administration — le poste de