diff --git a/scripts/devis_opnsense.py b/scripts/devis_opnsense.py index 7cfa528..05fd0f7 100644 --- a/scripts/devis_opnsense.py +++ b/scripts/devis_opnsense.py @@ -222,12 +222,24 @@ ROLE_SOCLE = "serveur_debian" 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 = [ (role, fl) for role, flux in sorted(flux_par_role.items()) 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")))) return retenus @@ -421,6 +433,23 @@ def construire(tenants: list[tuple[str, str, dict]]) -> dict: portees.append((f"SETOPS_ADMIN_{etiquette}_GESTION", if_gestion)) if admin_par_if[etiquette]["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_`). + # + # 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: # Un service publie est joint DEPUIS INTERNET par le WAN, et le plus # souvent aussi depuis le VLAN d'administration — le poste de