diff --git a/CHANGELOG.md b/CHANGELOG.md index a0b041b..ebbf687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,74 @@ # CHANGELOG — Set-OPS +## 2026-08-04 — séparation des plans, et où vont les services de l'hébergeur + +### Deux VLAN pour séparer ce qui était mêlé + +Le VTEP vivait sur le VLAN 10, donc le transport tenant partageait son domaine de +diffusion avec l'administration des **équipements** (SVI du commutateur, OPNsense). +Plus grave : un nœud de sortie décapsule le trafic tenant et le remet dans sa table +principale — dont la route par défaut sort par `vmbr0`, **l'interface de gestion des +nœuds**. Le trafic des VM aurait emprunté le lien physique de l'interface web, de SSH +et du cluster. + +Ça défaisait ce que l'EVPN devait obtenir. `underlay.yml` déclare donc : + +``` +vlan 11 underlay-vxlan 10.0.5.0/24 SVI 10.0.5.1 transport VXLAN +vlan 41 sortie-tenant 10.0.6.0/24 aucun SVI trafic décapsulé +``` + +`sortie-tenant` n'a **volontairement pas de passerelle** : le commutateur le transporte +sans le router, donc le trafic tenant en clair ne traverse aucun SVI de gestion. Le +devis n'émet d'ailleurs pas d'`interface Vlan41` — le modèle a exprimé l'intention sans +qu'on ait à la commenter. + +Support prévu : `bond3` une fois doublé — `enp7s0` est libre sur les trois nœuds, et le +bond est déjà en `active-backup`, le mode qui convient sans MLAG. Aujourd'hui `bond3` +n'a **qu'une carte** : tout le trafic tenant, intra-zone compris, repose sur `enp8s0`. + +### Un défaut que ce changement a créé, et corrigé + +Le port du commutateur vers la frontière était figé sur le **seul** VLAN de transit. Les +`bifrost` ayant désormais une patte sur le 41, ce port serait resté muet : le devis +aurait eu l'air juste et le trafic ne serait jamais arrivé. Il **dérive maintenant des +rattachements déclarés** des hôtes `role: frontiere` → `allowed vlan 40,41`. + +### Vérification de la construction parallèle + +Le cluster actuel ne correspond pas à ce qui est planifié, et c'est voulu : on construit +à côté. Encore faut-il qu'il n'y ait pas de collision. Mesuré sur les 38 VM héritées : +étiquettes `7, 8, 9, 10, 12, 13, 14, 15, 1001, 1003` — aucune ne croise les VNI projetés +(`1111‑1116`, `1171‑1176`) ni les VLAN d'underlay. + +Deux points relevés : le VLAN 10 porte 4 VM héritées (il n'est donc pas purement de la +gestion), et `infra-pki-01` est encore branchée **à l'ancienne** — `vmbr3` + étiquette +`1174` — pas sur le VNet `t17serv`. À rebrancher à la bascule. + +### Où vont les services de l'hébergeur (D-46 à D-48) + +Constat : **aucun équipement de l'hébergeur n'est dans un inventaire Ansible**, et rien +ne sauvegarde leurs configurations. Ni les hyperviseurs, ni les commutateurs, ni la +frontière. + +Un hébergeur porte **trois** catégories : son **tenant** (son courriel, sa forge — un +client comme les autres), ses **opérations** (supervision de la fabric, journaux, +sauvegarde des configs, DNS d'underlay), et le **plan de contrôle** (déjà dehors). + +Les opérations vivent dans **le dépôt de l'hébergeur**, et leurs VM se rattachent à un +**pont VLAN, jamais un VNet** : un service qui observe la fabric ne peut pas dépendre +d'elle. Et la doctrine « hors flotte » ne vaut que pour les commutateurs et la +frontière — les hyperviseurs sont des Debian joignables en SSH. + +**Décision consignée, rien n'est construit.** `docs/hebergeur-exploitation.md`. + +### Question laissée ouverte + +L'index `0` réservé au tenant propre de chaque hébergeur — local par construction, donc +jamais à coordonner. Deux obstacles mesurés : il produit les VNI `1001`–`1006`, que le +parc hérité utilise déjà (`1001` TechnoLibre historique, `1003` KBR) ; et P21 +déclencherait une fausse collision entre deux dépôts d'hébergeurs. En attente. + ## 2026-08-03 (suite 17) — le plan de données existe (`make devis-sdn`) Ajouter un tenant n'ajoute pas qu'un plan : cela implique **1 zone EVPN + 6 VNets + diff --git a/docs/audit/preuve-2026-08-04.md b/docs/audit/preuve-2026-08-04.md new file mode 100644 index 0000000..5952337 --- /dev/null +++ b/docs/audit/preuve-2026-08-04.md @@ -0,0 +1,66 @@ +# Preuve de conformite — Set-OPS — 2026-08-04 + +> Genere par `make prouver` (`scripts/prouver.py`). **Rejouable** : relancer +> reproduit ce rapport. Chaque preuve rejoue l'outillage existant du depot ; +> aucune validation n'est reimplementee ici. Voir le mode d'emploi : +> [`docs/audit/README.md`](README.md), et le registre trace : +> [`docs/audit/affirmations.md`](affirmations.md). + +- **Instance** : `instance` — inventaire `instance/inventories/principal/hosts.yml` +- **Verdict** : ✅ CONFORME (30 OK · 0 echec · 0 saute) + +## Preuves + +| # | Preuve | Affirmations | Statut | Detail | +|---|---|---|---|---| +| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK | | +| P02 | Tests unitaires (inventory_host) | — | ✅ OK | 4 tests passes. | +| P03 | Diff-vide du plan (inventaire genere) | AFF-001, AFF-004, AFF-030, AFF-031, AFF-032 | ✅ OK | DIFF VIDE : le plan reproduit exactement l'inventaire actuel. Bascule possible. | +| P04 | Groupes <-> playbooks homonymes | AFF-008 | ✅ OK | | +| P05 | Dependances causales de groupes | AFF-009, AFF-084 | ✅ OK | | +| P06 | Validateurs de registres (serveurs/apps/bases/domaines) | AFF-003 | ✅ OK | Registre des domaines valide. | +| P07 | GUI (node --check) | AFF-033 | ✅ OK | JS du GUI : syntaxe valide (node --check). | +| P08 | Orchestration (couches + graphe) | AFF-070 | ✅ OK | Orchestration coherente : 30 groupes classes, aucun cycle, aucune arete en arriere. | +| P09 | Flux reseau (schema + matrice) | AFF-071 | ✅ OK | Flux coherents : 29 rôles, 70 flux, schéma + matrice OK. | +| P10 | Handlers <-> notify | AFF-034, AFF-035 | ✅ OK | Tout notify pointe vers un handler du meme role (49 roles). | +| P11 | Syntaxe des playbooks (--syntax-check) | AFF-083 | ✅ OK | playbook: playbooks/proxmox/cloner_vm_debian.yml | +| P12 | Existence des runbooks cites | AFF-010, AFF-011, AFF-012, AFF-083 | ✅ OK | 17/17 runbooks/registres cites presents. | +| P13 | Invariants structurels/doctrinaux | AFF-015, AFF-022, AFF-037, AFF-038, AFF-062 | ✅ OK | LICENSE, socle dossier, pas de couches paralleles, SSH clef-only, nftables off : OK. | +| P14 | Pas de chemin lab/ code en dur | AFF-097 | ✅ OK | Aucun chemin instance/inventories/lab/group_vars code en dur. | +| P15 | Modele public socle valide | AFF-022, AFF-099 | ✅ OK | Modele public socle : domaines/serveurs/applications/bases valides. | +| P16 | Inventaire Ansible complet (--list) | AFF-030 | ✅ OK | 14 hotes, 29 groupes (inventaire dechiffre et parse). | +| P17 | Tous les modeles valident (registres + underlay) | AFF-022, AFF-099 | ✅ OK | Les 1 modele(s) decouvert(s) valident. | +| P18 | Gabarit de voute complet | AFF-026 | ✅ OK | Gabarit de voute complet : 21 secret(s) exige(s), tous presents. Voute reelle : 24 cle(s), aucun manque. | +| P19 | Le GUI couvre le schema du plan | AFF-002, AFF-095 | ✅ OK | GUI : les 27 champ(s) des plans reels sont editables (2 plan(s) inspecte(s)), registres toleres : nomenclature. | +| P20 | Adressage 100% derive du seed (aucun stocke) | AFF-001, AFF-003 | ✅ OK | 2 nomenclature(s) : adressage 100% derive du seed index. | +| P21 | Federation : aucun index en collision | AFF-102 | ✅ OK | Federation coherente : 2 instance(s) federee(s), aucun index en collision. | +| P22 | Plan de recette a jour (genere du wiki) | AFF-002 | ✅ OK | Plan de recette à jour (19 sections). | +| P23 | Underlay sans collision avec la plage tenant | AFF-103 | ✅ OK | Underlay conforme : 7 reseau(x), aucune collision avec la plage tenant. | +| P24 | Frontiere nord/sud : acces d'administration declare | AFF-104 | ✅ OK | CONFORME : frontiere nord/sud, 26 regles, 2 routes, admin=192.168.254.2/32,192.168.255.0/24,192.168.255.2/32. | +| P25 | Pare-feu Proxmox : est-ouest intra-tenant derive | AFF-107 | ✅ OK | CONFORME : pare-feu Proxmox, 2 tenant(s), 36 groupe(s), 56 regle(s). | +| P26 | Integrations universelles : aucun hote laisse de cote | AFF-108 | ✅ OK | 14 hote(s) x 3 integration(s) universelle(s) : aucune lacune, aucune recopie (1 exemption(s) derivee(s) du service rendu). | +| P27 | Propriete des intrants : hebergeur et tenant separes | AFF-109 | ✅ OK | 8 cle(s) de cluster chez l'hebergeur, aucune recopiee dans les group_vars du tenant. | +| P28 | Pools Proxmox : un par tenant, sans collision | AFF-110 | ✅ OK | CONFORME : 2 pool(s) Proxmox, 28 VM placee(s), aucun nom ni VMID en collision. | +| P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 23 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 12, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv | +| P30 | SDN EVPN : zones, VNets et sous-reseaux derives | AFF-112 | ✅ OK | CONFORME : SDN EVPN, 2 zone(s), 12 VNet(s), 12 sous-reseau(x), aucune collision ; /!\ aucun noeud de sortie declare (VRF sans chemin vers l'exterieur). | + +## Couverture des affirmations ✅ du registre + +Chaque affirmation ✅ automatisable est couverte par la preuve indiquee ci-dessus. +Les ✅ **structurelles/doctrinales** non rejouables par une commande (ex. AFF-005 +`make`=aide, AFF-014 ciblage groupe, AFF-024 `instancier-appliquer`, AFF-051 autorite +d'AGENTS.md, AFF-073/075 gardes `make`, AFF-090 wiki) ont ete verifiees a l'audit ; +elles restent hors du harnais recurrent (rien d'executable a rejouer). + +## Declarations d'intention (⚪ invérifiables localement — assumees) + +Ces affirmations ne sont pas rejouables hors production ; elles sont **assumees** +comme declarations d'intention, non comme preuves : + +- **AFF-036** — « testables avec `--check` autant que possible » : verifiable seulement + contre une flotte vivante. +- **AFF-091** — contenu pedagogique du wiki : affirmations conceptuelles. +- **AFF-096** — « GUI 100 % francais » : revue exhaustive des libelles rendus, non automatisee. +- **AFF-007** — hote d'exemple `web-frontal-01` : placeholder assume. + +_Rapport genere le 2026-08-04._ diff --git a/docs/carte-set-ops.md b/docs/carte-set-ops.md index be518b7..3f5a45f 100644 --- a/docs/carte-set-ops.md +++ b/docs/carte-set-ops.md @@ -48,6 +48,7 @@ Ce que je re-découvre sinon. **Consulter avant de concevoir un nouveau mécanis | Voûte au déploiement | secret jamais en clair | `ANSIBLE_VAULT_PASSWORD_FILE` / `~/.config/setops-vault-pass` ; déréférencé par `lookup('vars', )` | — | | Multi-instance | un dépôt par écosystème ; l'active = symlink `instance/`, les autres **découvertes par convention** (dossiers frères, aucun registre) | active : symlink `instance/` ; découverte : `scripts/instances.py` / `devis_reseau.py` (glob `../*/plan/nomenclature.yml` avec `index`) ; garde-fou collision : preuve **P21** | `multi-instances.md` | | Exposition → edge | app expose un FQDN public servi par un edge | `plan/domaines.yml` + `expose` (applications) | `bindings-conception.md` §4 | +| Exploitation de l'hébergeur | ses **opérations** (supervision de la fabric, sauvegarde des configs, DNS d'underlay) n'appartiennent à aucun tenant et restent **hors overlay** | décidé, **non construit** : aucun équipement d'hébergeur n'est encore dans un inventaire | `hebergeur-exploitation.md` | | Authentification | web → Keycloak ; LDAP source unique ; secours par `sudo`, formulaire local non annoncé | `_connexion_locale: false` (grafana, forgejo, nextcloud) ; garde de version Forgejo ≥ 10 | `authentification.md` | | SDN EVPN | ajouter un tenant implique **1 zone + 6 VNets + 6 sous-réseaux**, tous dérivés du seed | `scripts/devis_sdn.py` (`make devis-sdn`) ; nommage dérivé du tenant (`CHEZ17`, `chez174`), ≤ 8 caractères ; garde **P30** | `sdn-evpn.md` §2 | | Pools Proxmox | un pool par tenant : les noms courts de VM sont **volontairement identiques** d'un tenant à l'autre (même fonction, même nom), et seule la console Proxmox en souffrait | `scripts/devis_proxmox_pools.py` (`make devis-proxmox-pools`) ; nom dérivé de l'`index` ; garde de collision = preuve **P28** | `decisions-architecture.md` D-37 | diff --git a/docs/decisions-architecture.md b/docs/decisions-architecture.md index 67323de..b614c20 100644 --- a/docs/decisions-architecture.md +++ b/docs/decisions-architecture.md @@ -56,6 +56,9 @@ sont les seules vérifiables. | **D-36** | Le panneau **nomme le propriétaire** de chaque section d'intrants | éditer une section « hébergeur » vaut pour tous ses tenants ; l'écran ne le disait pas | `scripts/inventory_gui.py` (`INTRANTS_SCHEMA`) | — | | **D-37** | Chaque tenant a son **pool Proxmox** ; les noms courts de VM restent **identiques** d'un tenant à l'autre | 11 serveurs sur 14 sont homonymes — c'est la preuve que la nomenclature est un gabarit ; le coût est humain (la console affiche le nom), et le pool le corrige sans rien renommer | `devis_proxmox_pools.py` | P28 | | **D-45** | L'**affinité de VM** (garder un groupe sur le même hyperviseur) attend **Proxmox 9** ; tenue à la main d'ici là | les *resource affinity rules* n'existent qu'en 9 ; en 8.4 seuls les groupes HA épinglent à des **nœuds**, pas des VM entre elles. Sans ressource HA déclarée, rien ne déplace ni ne sépare les VM — le sujet ne devient réel qu'en activant la HA | `sdn-evpn.md` | — | +| **D-46** | Un hébergeur porte **trois** catégories, pas deux : son **tenant**, ses **opérations**, le **plan de contrôle** | Chezlepro est hébergeur ET tenant, ce qui masquait des besoins n'appartenant à aucun tenant | `hebergeur-exploitation.md` §2 | — | +| **D-47** | Les **services d'exploitation** de l'hébergeur vivent dans **son dépôt**, et leurs VM se rattachent à un **pont VLAN, jamais un VNet** | un service qui observe la fabric ne peut pas dépendre d'elle : l'EVPN tombe, et la supervision tombe avec la raison de la panne | `hebergeur-exploitation.md` §1, §4 | — | +| **D-48** | Les **hyperviseurs** sont gérables par Ansible ; « hors flotte » ne vaut que pour les **commutateurs** et la **frontière** | ce sont des Debian joignables en SSH ; c'est la seule façon d'y poser un exportateur de métriques | `hebergeur-exploitation.md` §5 | — | | **D-18** | Chaque tenant a un **responsable désigné** | sans lui, « qui peut décider de déménager cette organisation ? » se pose au pire moment | `migration-tenant.md` §3 | — | | **D-38** | Toute authentification **web** passe par Keycloak ; LDAP est la **source unique** des comptes | une identité, un mot de passe ; aucun service ne tient son propre répertoire d'humains | `authentification.md` §1-2 | — | diff --git a/docs/hebergeur-exploitation.md b/docs/hebergeur-exploitation.md new file mode 100644 index 0000000..4aae758 --- /dev/null +++ b/docs/hebergeur-exploitation.md @@ -0,0 +1,86 @@ +# Les services d'exploitation de l'hébergeur + +> **Décision du 2026-08-04.** Tout ce qu'un hébergeur fait tourner n'appartient pas à un +> tenant. Ce document dit où va quoi, et pourquoi certains services ne peuvent pas vivre +> dans l'overlay qu'ils observent. **Rien n'est construit** : la décision est consignée, +> le chantier reste devant. + +## 1. Le test qui tranche + +Pour chaque service, une seule question : **de quoi doit-il survivre ?** + +Un service qui observe ou répare la fabric ne peut pas dépendre de la fabric. Mettez +Prometheus dans une zone EVPN pour surveiller les hyperviseurs, et le jour où le VXLAN +tombe vous perdez la supervision **et** la raison de la panne en même temps. Pire pour les +sauvegardes : on veut restaurer la configuration d'un commutateur précisément quand le +réseau est cassé. + +C'est le motif *in-band / out-of-band*, et il ne se contourne pas. + +## 2. Trois catégories, pas deux + +**Le tenant de l'hébergeur** — son courriel, sa forge, son nuage, son site. L'hébergeur +*comme entreprise*. Aucune différence avec un client : même plan, même machinerie, mêmes +preuves, même EVPN. Chezlepro est ici hébergeur **et** tenant, ce qui a longtemps masqué +la distinction (D-13). + +**Les opérations de l'hébergeur** — ce qui fait tenir la fabric. Doit rester **hors +overlay**. + +**Le plan de contrôle** — Set-OPS lui-même, les dépôts, la voûte. Déjà dehors, sur le +poste de l'opérateur et sa forge. Rien à changer. + +## 3. Ce qui n'a pas de maison aujourd'hui + +Constaté le 2026-08-04 : **aucun équipement de l'hébergeur n'est dans un inventaire +Ansible**, et rien ne sauvegarde leurs configurations. + +| Besoin | État | +|---|---| +| Supervision des hyperviseurs, commutateurs, frontière | personne | +| Journaux de ces équipements | personne | +| Sauvegarde de leurs configs (`running-config`, `config.xml`, `/etc/pve`) | personne | +| Résolution des noms d'underlay (`asgard`, `sleipnir-01`, `bifrost-1`) | personne | +| Certificats pour leurs interfaces web | personne | + +Ce n'est pas un oubli de conception : ces besoins tombaient entre les chaises. Ils ne sont +d'aucun tenant, et `underlay.yml` ne décrit que du matériel, sans service. + +## 4. Où ça va + +**Dans le dépôt de l'hébergeur** — celui qui porte déjà `underlay.yml` et +`proxmox-hebergeur.yml`. Ses services d'exploitation lui appartiennent au même titre que +sa fabric ; les loger ailleurs recréerait la confusion qu'on vient de défaire. + +Ce dépôt n'a pas d'inventaire Ansible aujourd'hui : c'est ce que le chantier ajoutera. + +**Rattachement réseau : un pont VLAN ordinaire, jamais un VNet du SDN.** C'est la +contrainte qui découle du §1, et la seule qui distingue ces VM de celles d'un tenant. + +## 5. Ce que ça ne change pas + +Les **commutateurs** et la **frontière** restent hors flotte : le premier n'a pas d'agent, +la seconde se pilote par API. Ils reçoivent des devis, pas des rôles (D-23). + +Les **hyperviseurs** sont un cas différent, et la doctrine « hors flotte » les englobait à +tort : ce sont des machines Debian, joignables en SSH. Rien n'empêche de les gérer par +Ansible depuis l'inventaire de l'hébergeur — c'est même la seule façon d'y poser un +`node_exporter` et un expéditeur de journaux. + +## 6. Question ouverte, non tranchée + +**L'index du tenant propre de l'hébergeur.** L'idée d'un `0` réservé — local par +construction, donc jamais à coordonner entre hébergeurs, et jamais porté par un tenant qui +déménage — est séduisante et reste **en attente**. + +Deux obstacles mesurés le 2026-08-04, à lever avant : + +- l'index 0 produit les VNI `1001`–`1006`, et le parc hérité utilise déjà `1001` + (TechnoLibre historique, 8 VM) et `1003` (KBR). C'est une condition de **séquence** : + la place se libère quand l'ancien monde s'éteint ; +- **P21** vérifie l'unicité des index entre dépôts frères. Si tout hébergeur a un tenant + `0`, poser deux dépôts d'hébergeurs côte à côte déclencherait une fausse collision — il + faudrait exempter `0`, donc inscrire dans la garde que cette valeur est locale. + +À noter au passage : la convention héritée était déjà `1000 + numéro de tenant`. La formule +de Set-OPS (`1000 + index×10 + zone`) en est un raffinement, pas une invention. diff --git a/scripts/devis_reseau.py b/scripts/devis_reseau.py index 30f97ba..aba6b07 100644 --- a/scripts/devis_reseau.py +++ b/scripts/devis_reseau.py @@ -302,25 +302,47 @@ def partie_acces(underlay: dict | None, tenants: list, vlans: str, return out -def section_frontiere(transit: dict | None, bord: bool = False, - ports: list[str] | None = None) -> list[str]: - """Port du switch vers le pare-feu de bordure. Porte le VLAN de transit, et lui seul. +def vlans_de_la_frontiere(underlay: dict | None, transit: dict | None) -> list[dict]: + """Reseaux que le port de la frontiere doit porter — DERIVES de ses rattachements. - Distinct du trunk vers Proxmox : les hyperviseurs n'ont aucune interface sur le - transit, et le pare-feu n'a rien a faire des VLAN tenants — il route vers eux, il - ne les etiquette pas. + Le transit ne suffit plus. Depuis la separation des plans (2026-08-04), la + frontiere a aussi une patte sur le VLAN de sortie tenant : c'est par la que le + trafic DECAPSULE lui parvient, sans traverser ni la gestion des noeuds ni celle + des equipements. Une liste figee sur le seul transit aurait produit un port muet + sur ce VLAN — le devis aurait eu l'air juste et le trafic ne serait jamais arrive. + """ + noms = {h.get("reseau") for h in underlay_mod.hotes(underlay) + if h.get("role") == "frontiere" and h.get("reseau")} + fab = underlay_mod.fabric_du_routeur(underlay) + reseaux = [r for r in underlay_mod.reseaux_de_fabric(underlay, fab) + if r.get("nom") in noms and r.get("vlan") is not None] + if not reseaux and transit: + reseaux = [transit] + return sorted(reseaux, key=lambda r: int(r["vlan"])) + + +def section_frontiere(transit: dict | None, bord: bool = False, + ports: list[str] | None = None, + underlay: dict | None = None) -> list[str]: + """Port du switch vers le pare-feu de bordure. + + Distinct du trunk vers Proxmox : le pare-feu n'a rien a faire des VLAN tenants — + il route vers eux, il ne les etiquette pas. """ if not transit: return ["! ----- 4b. Port vers la frontiere -----", "! Aucun reseau de transit declare dans underlay.yml (cle 'passerelle_sortie')."] + reseaux = vlans_de_la_frontiere(underlay, transit) + liste = ",".join(str(r["vlan"]) for r in reseaux) + detail = ", ".join(f"{r['vlan']} ({r['nom']})" for r in reseaux) return [ "! ----- 4b. Port vers la frontiere nord/sud -----", - f"! Porte le seul VLAN {transit['vlan']} ({transit['nom']}). En lien dedie,", - f"! remplacer par : switchport access vlan {transit['vlan']}.", + f"! Porte {detail}.", + "! Derive des rattachements declares des hotes `role: frontiere`.", "! Port terminal : rien derriere lui ne participe au spanning-tree.", ] + [ligne for port in (ports or [""]) - for ligne in bloc_trunk(port, str(transit["vlan"]), bord=bord)] + for ligne in bloc_trunk(port, liste, bord=bord)] def inventaire_de(nom_instance: str) -> Path | None: @@ -573,7 +595,8 @@ def generer(tenants: list[tuple[str, str, dict]], dialecte: str | None = None) - out += ["!"] + section_frontiere( transit, bord=bool(underlay_mod.stp(underlay)), ports=ports_ou_marqueur(hote_nomme(underlay, underlay_mod.routeur(underlay)), - "frontiere", "")) + "frontiere", ""), + underlay=underlay) out += ["!"] + section_rayons(underlay, ",".join(vlans_underlay + vlans_tenants)) out += ["!"] + section_routes(underlay, dialecte) out += section_stp(underlay, dialecte)