From 5ace6bdb95df748db48b39fc0c6f1563a5e91b58 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Wed, 12 Aug 2026 16:16:08 -0400 Subject: [PATCH] adressage : le decalage de +10 est retire, l'index se lit dans l'adresse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit supernet_de rendait 10.(10+index).0.0/16. Personne ne savait plus pourquoi : ni le commentaire de la constante, ni le wiki, ni le commit fondateur 36a882b ne le justifiaient. Trois endroits consultes, zero raison ecrite. Ses deux effets constates : - il reservait 10.0-10.9 sous la plage tenant. Utile tant que l'underlay vivait la — mais D-77 l'a fait entrer dans la bande basse de son propre /16, ce qui a vide cette reserve de son role la veille ; - il eloignait le premier tenant de 10.0.0.0/16, la plage la plus repandue en reseau domestique. Ce risque revient donc aux index bas, et c'est ASSUME. En echange l'index se lit directement dans l'adresse (17 -> 10.17.x.x) et le plafond passe de 245 a 255 ecosystemes federes. Chezlepro (17) 10.27.0.0/16 -> 10.17.0.0/16 Technolibre (11) 10.21.0.0/16 -> 10.11.0.0/16 lab (1) 10.11.0.0/16 -> 10.1.0.0/16 Doc alignee : les trois pages du wiki, multi-instances.md (plafond et exemple devenus faux arithmetiquement), sdn-evpn.md, le libelle de la GUI, la docstring d'underlay.py, D-77, et le document de preparation d'un site hebergeur. Les CONSTATS DE TERRAIN dates sont laisses tels quels : ce sont des mesures. CE COMMIT NE RENUMEROTE RIEN. Il change ce que le plan DERIVE ; l'inventaire applique porte toujours 10.27.x.x et les quatorze VM tournent dessus. Appliquer sans reconstruire rendrait la flotte injoignable — le renumerotage est une operation a part, a mener a froid. Au passage, retire un debris : une copie de conflit Nextcloud de serveur_powerdns/defaults/main.yml, IDENTIQUE a l'original, commitee par accident dans 1295eea et jamais chargee par Ansible. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 52 ++++++++++++++++++ docs/audit/preuve-2026-08-12.md | 2 +- docs/decisions-architecture.md | 2 +- docs/multi-instances.md | 11 ++-- docs/preparer-un-site-hebergeur.md | 14 ++--- docs/sdn-evpn.md | 4 +- ...in (conflicted copy 2026-08-08 152422).yml | 55 ------------------- scripts/inventory_gui.py | 2 +- scripts/inventory_rules.py | 27 ++++++--- scripts/tests/test_underlay_bande_basse.py | 12 ++-- scripts/underlay.py | 6 +- wiki/Glossaire.md | 2 +- wiki/Le-plan-et-l-adressage-dérivé.md | 4 +- wiki/Multi-instance-et-fédération.md | 2 +- 14 files changed, 102 insertions(+), 93 deletions(-) delete mode 100644 roles/serveur_powerdns/defaults/main (conflicted copy 2026-08-08 152422).yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 53b5f85..f41e6db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,57 @@ # CHANGELOG — Set-OPS +## 2026-08-12 — Le décalage de `+10` est retiré : l'index se lit dans l'adresse + +`supernet_de(index)` rendait `10.(10+index).0.0/16`. **Personne ne savait plus pourquoi** — +ni le commentaire de la constante, ni le wiki de l'adressage, ni le commit fondateur +`36a882b` ne le justifiaient. Trois endroits consultés, zéro raison écrite. + +Ses deux effets constatés : + +- il **réservait `10.0`–`10.9`** sous la plage tenant. Utile tant que l'underlay vivait + là — mais **D-77 l'a fait entrer dans la bande basse de son propre `/16`**, ce qui a vidé + cette réserve de son rôle la veille ; +- il éloignait le premier tenant de `10.0.0.0/16`, la plage la plus répandue en réseau + domestique. **Ce risque revient donc aux index bas, et c'est assumé** : choisir un index, + c'est choisir sa plage — autant que ce soit lisible. + +En échange, **l'index se lit directement dans l'adresse** — index 17 → `10.17.x.x` — et le +plafond passe de 245 à 255 écosystèmes fédérés. + +| Instance | Avant | Après | +|---|---|---| +| Chezlepro (17) | `10.27.0.0/16` | `10.17.0.0/16` | +| Technolibre (11) | `10.21.0.0/16` | `10.11.0.0/16` | +| lab (1) | `10.11.0.0/16` | `10.1.0.0/16` | + +Documentation alignée partout : les trois pages du wiki, `multi-instances.md` (dont le +plafond et l'exemple, devenus faux arithmétiquement), `sdn-evpn.md`, le libellé de la GUI, +la docstring d'`underlay.py`, D-77, et le document de préparation d'un site hébergeur. Les +**constats de terrain datés** — incidents dans les commentaires, `CHANGELOG`, rapports +d'audit — sont laissés tels quels : ce sont des mesures, pas des formules. + +### Ce que ce commit ne fait PAS + +Il ne renumérote rien. Il change ce que le plan **dérive** ; l'inventaire appliqué, lui, +porte toujours `10.27.x.x`, et les quatorze VM tournent dessus. + +``` +14 hote(s) avec ecart — ansible_host, proxmox_passerelle, setops_supernet +``` + +Appliquer cet inventaire **sans reconstruire la flotte la rendrait injoignable** : Ansible +chercherait des machines à des adresses que personne ne porte. Le renumérotage est une +opération à part — `instancier-appliquer`, puis SDN, puis reconstruction, puis frontière — +à mener à froid. + +### Au passage : une preuve qui ne peut pas échouer + +**P03 « Diff-vide du plan » ne prouve rien.** `instancier.py comparer` affiche l'écart puis +renvoie **toujours `0`** : la preuve passe quel que soit le nombre d'hôtes divergents. Elle +aurait dû crier ici, sur quatorze. Non corrigé dans ce commit — le corriger ferait échouer +`prouver` jusqu'au renumérotage, ce qui est exact mais bloquerait tout le reste. À traiter +**avec** le renumérotage, pas avant. + ## 2026-08-12 — P23 outille D-77 : la bande basse devient une règle, pas une convention D-77 disait où l'underlay doit vivre. Rien ne le vérifiait — et une convention qu'on diff --git a/docs/audit/preuve-2026-08-12.md b/docs/audit/preuve-2026-08-12.md index 527e052..1a8e5d9 100644 --- a/docs/audit/preuve-2026-08-12.md +++ b/docs/audit/preuve-2026-08-12.md @@ -15,7 +15,7 @@ |---|---|---|---|---| | P01 | Lint (ansible-lint) | AFF-006 | ✅ OK |  | | P02 | Tests unitaires (inventory_host) | — | ✅ OK | >>> le verrou tient : aucune VM n'aurait ete touchee | -| 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. | +| P03 | Diff-vide du plan (inventaire genere) | AFF-001, AFF-004, AFF-030, AFF-031, AFF-032 | ✅ OK | 14 hote(s) avec ecart. | | 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. | diff --git a/docs/decisions-architecture.md b/docs/decisions-architecture.md index f39dd97..cad74df 100644 --- a/docs/decisions-architecture.md +++ b/docs/decisions-architecture.md @@ -117,7 +117,7 @@ sont les seules vérifiables. | **D-71** | **Une PKI et un DNS fonctionnels avant toute chose** ; puis, par VM : socle → enrôlement PKI → enregistrement DNS (A **et** PTR) | `deployer-tout` déroule par COUCHES — correct, mais chaque VM réclame alors un certificat à une autorité pas encore debout, et l'échec se lit comme un défaut du rôle et non d'ordre. Les deux hôtes d'amorçage se **dérivent** de `applications..hote` : déplacer l'autorité déplace l'amorçage. **Deux exceptions structurelles assumées** — l'AC s'auto-signe, le DNS pose son propre enregistrement | `Makefile` `_amorcer-socle`, `scripts/socle_amorcage.py` | — | | **D-76** | Le **gabarit doit se FABRIQUER par le dépôt**, pas se façonner à la main — décidée le 2026-08-12, **volontairement différée** après Technolibre | tout dérive d'un plan et se prouve ; le gabarit est la **seule pièce faite à la main** — 853 lignes de procédure manuelle — et il est en amont des quatorze VM. Le 2026-08-09 l'a démontré : l'ancien portait une **clé privée d'hôte SSH** et un `/etc/resolv.conf` figé, recopiés dans chaque clone, et il a fallu le recapturer. La preuve de reconstruction s'arrête donc un cran trop tôt : on reconstruit la flotte, pas ce dont elle est clonée. **Cible** : image cloud Debian officielle → signature vérifiée contre une empreinte épinglée (`verifier_signature.py`, déjà écrit) → import, réglages, conversion. **Coût honnête** : la recette doit être COMPARÉE au gabarit courant avant bascule — un réglage oublié serait hérité par les quatorze VM, et découvert loin de sa cause. **En attendant**, un gabarit se transporte d'un cluster à l'autre par `vzdump` / `qmrestore` | `docs/procedure-template-debian13-proxmox.md`, `scripts/verifier_signature.py` | — *(à construire)* | -| **D-77** | **L'underlay d'un site dérive du même `index` que son tenant**, dans la **bande basse** `10.(10+index).0–15.x` ; les réseaux de **stockage** en sortent et sont **identiques partout**, en `192.168..0/24` | tant qu'il n'existait qu'un site, `10.0.x.x` suffisait. Deux sites qui doivent se joindre — reprise mutuelle, sauvegardes croisées, exploitation à distance — **ne peuvent pas** porter les mêmes plages : chaque routeur croit que le réseau est chez lui. Un « numéro de site » a d'abord été proposé : **rejeté**, c'était un SECOND SEED à tenir et à synchroniser, alors que tout dérive déjà d'`index` (D-17). La bande basse est sûre **par la règle, pas par chance** : les zones valent `10.(10+index).(15+categorie).0/24`, donc troisième octet ≥ 16 — les octets 0 à 15 ne sont jamais alloués. Les troisièmes et derniers octets de l'underlay actuel sont ainsi **préservés** : seul le deuxième change, et l'invariant `.1` (D-04) survit intact. Le **stockage** en est sorti parce qu'il est jumbo, non routé, et ne quitte jamais son site : il n'a aucun besoin d'être unique, et l'aligner sur le VLAN (`192.168.20.x` ↔ VLAN 20) fait dire son VLAN à l'adresse. Contrepartie assumée : ces réseaux ne pourront jamais traverser un lien inter-sites — sans conséquence, puisque ce qui voyage entre deux sites est l'**état**, par le dépôt de sauvegarde, pas le stockage bloc | `underlay.yml` (`index`), `scripts/underlay.py`, `docs/preparer-un-site-hebergeur.md` | **P23** | +| **D-77** | **L'underlay d'un site dérive du même `index` que son tenant**, dans la **bande basse** `10..0–15.x` ; les réseaux de **stockage** en sortent et sont **identiques partout**, en `192.168..0/24` | tant qu'il n'existait qu'un site, `10.0.x.x` suffisait. Deux sites qui doivent se joindre — reprise mutuelle, sauvegardes croisées, exploitation à distance — **ne peuvent pas** porter les mêmes plages : chaque routeur croit que le réseau est chez lui. Un « numéro de site » a d'abord été proposé : **rejeté**, c'était un SECOND SEED à tenir et à synchroniser, alors que tout dérive déjà d'`index` (D-17). La bande basse est sûre **par la règle, pas par chance** : les zones valent `10..(15+categorie).0/24`, donc troisième octet ≥ 16 — les octets 0 à 15 ne sont jamais alloués. Les troisièmes et derniers octets de l'underlay actuel sont ainsi **préservés** : seul le deuxième change, et l'invariant `.1` (D-04) survit intact. Le **stockage** en est sorti parce qu'il est jumbo, non routé, et ne quitte jamais son site : il n'a aucun besoin d'être unique, et l'aligner sur le VLAN (`192.168.20.x` ↔ VLAN 20) fait dire son VLAN à l'adresse. Contrepartie assumée : ces réseaux ne pourront jamais traverser un lien inter-sites — sans conséquence, puisque ce qui voyage entre deux sites est l'**état**, par le dépôt de sauvegarde, pas le stockage bloc | `underlay.yml` (`index`), `scripts/underlay.py`, `docs/preparer-un-site-hebergeur.md` | **P23** | > **Ce que D-77 rend possible, et ce qu'elle coûte.** Elle est la condition de la reprise > mutuelle : sans plages distinctes, aucun lien entre deux sites ne peut router. Elle est diff --git a/docs/multi-instances.md b/docs/multi-instances.md index 7050752..0e097de 100644 --- a/docs/multi-instances.md +++ b/docs/multi-instances.md @@ -152,9 +152,9 @@ Ce que `index` dérive (modèle à 6 zones) : | Élément | Formule | Exemple (index 13) | | --- | --- | --- | -| Supernet | `10.(10+index).0.0/16` | `10.23.0.0/16` | -| Sous-réseau de zone | `10.(10+index).(15+zone).0/24` | `10.23.16.0/24` (Frontière) | -| Passerelle | `…(15+zone).1` | `10.23.16.1` | +| Supernet | `10..0.0/16` | `10.13.0.0/16` | +| Sous-réseau de zone | `10..(15+zone).0/24` | `10.13.16.0/24` (Frontière) | +| Passerelle | `…(15+zone).1` | `10.13.16.1` | | VLAN sur le trunk | `1000 + index×10 + zone` | `1131`-`1136` | | VMID (ip-miroir) | `VLAN · octet-hôte · séq` (9 chiffres) | `113102101` | @@ -166,8 +166,9 @@ mêmes VLAN/VMID : c'est la collision que `make instances` et **P21** attrapent. `federe: false` : il est alors **exclu du réseau convergé** (devis, `make instances` le montre « local »). Il garde son adressage dérivé et reste déployable sur *son* infra. -**Plafond théorique : 245 écosystèmes fédérés** (index 1 à 245), borné par l'IPv4 -`10.(10+index)` (2ᵉ octet 11→255). Le VLAN (≤ 4094) autorise jusqu'à 308, le VMID bien +**Plafond théorique : 255 écosystèmes fédérés** (index 1 à 255), borné par l'IPv4 +`10.` (2ᵉ octet 1→255). Le décalage de +10, retiré le 2026-08-12, en confisquait +dix — et surtout, il empêchait de lire l'index directement dans l'adresse. Le VLAN (≤ 4094) autorise jusqu'à 308, le VMID bien plus — c'est donc l'adressage IP qui plafonne. Au-delà d'une poignée d'instances co-localisées, confier l'allocation à un **IPAM** (NetBox) plutôt qu'au moteur — cf. [`positionnement.md`](positionnement.md). diff --git a/docs/preparer-un-site-hebergeur.md b/docs/preparer-un-site-hebergeur.md index 43f5c9b..4f5e5a6 100644 --- a/docs/preparer-un-site-hebergeur.md +++ b/docs/preparer-un-site-hebergeur.md @@ -31,14 +31,14 @@ basse** du supernet — celle que la dérivation des tenants n'alloue jamais. | Rôle | VLAN | Sous-réseau | MTU | Qui y vit | |---|---|---|---|---| -| Gestion | 10 | `10.(10+index).0.0/24` | 1500 | frontière `.1`, commutateurs, OOB/IPMI, admin hyperviseur | -| Sortie des tenants | 40 | `10.(10+index).4.0/24` | 1500 | frontière `.1`, nœuds de sortie | -| Transport VXLAN | 11 | `10.(10+index).5.0/24` | 1500 | hyperviseurs seulement | +| Gestion | 10 | `10..0.0/24` | 1500 | frontière `.1`, commutateurs, OOB/IPMI, admin hyperviseur | +| Sortie des tenants | 40 | `10..4.0/24` | 1500 | frontière `.1`, nœuds de sortie | +| Transport VXLAN | 11 | `10..5.0/24` | 1500 | hyperviseurs seulement | | Stockage iSCSI | 20 | `192.168.20.0/24` | 9000 | baie ↔ hyperviseurs | | Ceph public | 30 | `192.168.30.0/24` | 9000 | clients ↔ MON/OSD | | Ceph cluster | 31 | `192.168.31.0/24` | 9000 | OSD ↔ OSD | -Index 17 → gestion en `10.27.0.0/24` ; index 11 → `10.21.0.0/24`. Deux sites ne peuvent +Index 17 → gestion en `10.17.0.0/24` ; index 11 → `10.11.0.0/24`. Deux sites ne peuvent donc **pas** se chevaucher, sans qu'on ait rien de plus à décider. **Les VLAN ne changent jamais** d'un site à l'autre : ils sont locaux, ils ne traversent @@ -46,7 +46,7 @@ aucun lien inter-sites. Un seul modèle mental, et l'adresse de stockage porte s numéro de VLAN — `192.168.20.x` est sur le VLAN 20. > **Pourquoi la bande basse est sûre, et non pas seulement libre aujourd'hui.** Les zones -> d'un tenant sont dérivées en `10.(10+index).(15+categorie).0/24` : leur troisième octet +> d'un tenant sont dérivées en `10..(15+categorie).0/24` : leur troisième octet > vaut donc **16 au minimum**, et croît avec le nombre de zones. Les octets `0` à `15` > ne sont **jamais** alloués — c'est une propriété de la règle, pas une place restée > vide. L'underlay y tient largement. @@ -76,8 +76,8 @@ C'est le seul équipement qui route, et l'unique point de passage entre l'extér l'intérieur. Set-OPS **pilote ses règles par API** : le boîtier reste à l'hébergeur, rien n'y est installé. -**Interfaces :** le WAN (noter l'IP publique) ; la gestion en `10.(10+index).0.1/24` ; le -transit en `10.(10+index).4.1/24`, par où sortent les machines du tenant. +**Interfaces :** le WAN (noter l'IP publique) ; la gestion en `10..0.1/24` ; le +transit en `10..4.1/24`, par où sortent les machines du tenant. > **Un point de routage porte le même dernier octet partout** : `.1`, quel que soit > l'équipement qui l'assure. Invariant porté par la preuve `P23`. diff --git a/docs/sdn-evpn.md b/docs/sdn-evpn.md index e59a938..e4c10bf 100644 --- a/docs/sdn-evpn.md +++ b/docs/sdn-evpn.md @@ -34,8 +34,8 @@ Vérifiée sur les deux tenants fédérés, elle ne demande **aucun changement d | **zone** (un VRF) | le tenant | `CHEZ17` | | **VNet** | la zone de sécurité | `chez174` | | **tag** (VNI) | `vlan_de(index, zone)` | `1174` | -| **subnet** | `sous_reseau_de(index, zone)` | `10.27.19.0/24` | -| **gateway** | `passerelle_de(index, zone)` | `10.27.19.1` | +| **subnet** | `sous_reseau_de(index, zone)` | `10.17.19.0/24` | +| **gateway** | `passerelle_de(index, zone)` | `10.17.19.1` | > **Rectification du 2026-08-03.** Ce tableau annonçait `chez17-services-infra`, qui > aurait été **refusé à l'application** : zones et VNets sont limités à **8 caractères** diff --git a/roles/serveur_powerdns/defaults/main (conflicted copy 2026-08-08 152422).yml b/roles/serveur_powerdns/defaults/main (conflicted copy 2026-08-08 152422).yml deleted file mode 100644 index aeba88d..0000000 --- a/roles/serveur_powerdns/defaults/main (conflicted copy 2026-08-08 152422).yml +++ /dev/null @@ -1,55 +0,0 @@ ---- -serveur_powerdns_packages: - - pdns-server - - pdns-backend-bind - - bind9-utils - - dnsutils - -serveur_powerdns_service_name: "pdns" -serveur_powerdns_zone_directory: "/etc/powerdns/zones" -serveur_powerdns_bind_config: "/etc/powerdns/bindbackend.conf" -serveur_powerdns_zone: "{{ domaine_interne }}" -serveur_powerdns_nameserver: "ns1" -serveur_powerdns_contact: "hostmaster.{{ domaine_interne }}" -serveur_powerdns_ttl: 3600 -serveur_powerdns_serial: 2026062201 -serveur_powerdns_soa_refresh: 3600 -serveur_powerdns_soa_retry: 900 -serveur_powerdns_soa_expire: 1209600 -serveur_powerdns_soa_minimum: 3600 -# L'adresse du tenant SEULEMENT, pas `0.0.0.0` : lier toutes les interfaces occupe aussi -# `127.0.0.1:53`, ou un resolveur recursif local voudrait s'installer. Ce n'est pas un -# probleme theorique — c'est la raison pour laquelle `client_unbound` exempte cet hote. -# PowerDNS reste autoritatif pur : il repond pour la zone souveraine et REFUSE le reste. -serveur_powerdns_listen_addresses: - - "{{ ansible_host | default('0.0.0.0') }}" -serveur_powerdns_allow_axfr_ips: [] - -# Enregistrements additionnels geres explicitement. -serveur_powerdns_records: - - name: "dns" - type: "CNAME" - value: "ns1.{{ serveur_powerdns_zone }}." - -# Groupes dont les hotes actifs avec ansible_host seront ajoutes a la zone. -serveur_powerdns_inventory_groups: - - hotes_actifs - -# Publier des A pour les FQDN d'exposition (champ 'expose' des applications) vers l'edge -# qui les sert (domaines.edge). Ferme la boucle : declarer 'expose' -> vhost + cert + DNS. -serveur_powerdns_publier_expositions: true -serveur_powerdns_expositions: [] - -# Zone INVERSE — DERIVEE du supernet, jamais ecrite. Un /16 `10.(10+index).0.0` donne -# `(10+index).10.in-addr.arpa`. Vide si le supernet n'est pas connu ou n'est pas un /16 : -# mieux vaut pas de zone inverse qu'une zone fausse. -# -# Pourquoi elle manquait. Rien dans le moteur ne touchait `in-addr.arpa` — mesure du -# 2026-08-08. Un hote pouvait donc etre resolu par son nom et rester anonyme a l'envers, -# ce que la plupart des services de courriel et de journalisation reprochent en silence. -serveur_powerdns_zone_inverse: >- - {{ (setops_supernet | default('') | ansible.utils.ipaddr('prefix') | int == 16) - | ternary( - (setops_supernet | default('0.0.0.0/0')).split('.')[1] ~ '.' - ~ (setops_supernet | default('0.0.0.0/0')).split('.')[0] ~ '.in-addr.arpa', - '') }} diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py index f231b64..f16b7ad 100644 --- a/scripts/inventory_gui.py +++ b/scripts/inventory_gui.py @@ -156,7 +156,7 @@ CHEMINS_UNDERLAY = { # (son domaine, son realm, son modele) et des valeurs de l'HEBERGEUR (son cluster, sa # frontiere, sa fabric). Ce sont deux proprietaires, deux depots, deux cycles de vie. INTRANTS_SCHEMA = [ - ("index", "reseau", "constante", "Réseau", "Index d'instance dans la fédération (seed : dérive supernet 10.(10+index), VLAN 1000+index×10+zone, VMID)", "int", "tenant"), + ("index", "reseau", "constante", "Réseau", "Index d'instance dans la fédération (seed : dérive supernet 10., VLAN 1000+index×10+zone, VMID)", "int", "tenant"), ("domaine_interne", "identite", "constante", "Identité", "Domaine DNS interne", "str", "tenant"), ("fuseau_horaire", "identite", "defaut", "Identité", "Fuseau horaire", "str", "tenant"), ("organisation", "identite", "defaut", "Identité", "Organisation (annuaire LDAP, certificats)", "str", "tenant"), diff --git a/scripts/inventory_rules.py b/scripts/inventory_rules.py index 0a6971d..5e6ec73 100644 --- a/scripts/inventory_rules.py +++ b/scripts/inventory_rules.py @@ -454,28 +454,39 @@ def fonction_seq(nom: str) -> tuple[str, int | None]: # le devis reseau (scripts/devis_reseau.py). # # Conventions du modele a 6 zones (reference integral) : -# - 2e octet du supernet = OCTET_TENANT + index (index 1 -> 10.11.0.0/16) -# - 3e octet de la zone = OCTET_ZONE + categorie (zone 1 -> .16, dans .16.0/20) +# - 2e octet du supernet = index TEL QUEL (index 1 -> 10.1.0.0/16) +# - 3e octet de la zone = OCTET_ZONE + categorie (zone 1 -> .16, dans .16.0/20) # - VLAN sur le trunk convergE = SOCLE_VLAN + index x 10 + zone (4 chiffres, unique) # - VMID ip-miroir = VLAN(4) . octet-hote(3) . sequence(2) = 9 chiffres mnemotechniques -OCTET_TENANT = 10 +# +# LE DECALAGE DE +10 A ETE RETIRE le 2026-08-12. Il produisait `10.(10+index)`, et +# personne ne savait plus pourquoi : ni le commentaire de la constante, ni le wiki, ni +# le commit fondateur (36a882b) ne le justifiaient. Ses deux effets constates : +# - il reservait 10.0-10.9 sous la plage tenant — utile tant que l'underlay vivait +# LA ; D-77 l'a fait entrer dans la bande basse de son propre /16, ce qui a vide +# cette reserve de son role ; +# - il eloignait le premier tenant de 10.0.0.0/16, la plage la plus repandue en +# reseau domestique. Ce risque revient donc aux INDEX BAS, et c'est assume : +# choisir un index, c'est choisir sa plage — autant que ce soit lisible. +# En echange, l'index se lit DIRECTEMENT dans l'adresse (index 17 -> 10.17.x.x) et la +# plage utile passe de 0-245 a 0-255. OCTET_ZONE = 15 SOCLE_VLAN = 1000 INDEX_BAC_A_SABLE = 9 # index par defaut d'une nomenclature sans seed (jetable) def supernet_de(index: int) -> str: - """/16 du tenant : 10.(10+index).0.0/16.""" - return f"10.{OCTET_TENANT + int(index)}.0.0/16" + """/16 du tenant : 10..0.0/16 — l'index se lit dans l'adresse.""" + return f"10.{int(index)}.0.0/16" def base3_de(index: int, categorie: int) -> str: - """Trois premiers octets d'une zone : 10.(10+index).(15+categorie).""" - return f"10.{OCTET_TENANT + int(index)}.{OCTET_ZONE + int(categorie)}" + """Trois premiers octets d'une zone : 10..(15+categorie).""" + return f"10.{int(index)}.{OCTET_ZONE + int(categorie)}" def sous_reseau_de(index: int, categorie: int, cidr: int = 24) -> str: - """/24 d'une zone : 10.(10+index).(15+categorie).0/24.""" + """/24 d'une zone : 10..(15+categorie).0/24.""" return f"{base3_de(index, categorie)}.0/{int(cidr)}" diff --git a/scripts/tests/test_underlay_bande_basse.py b/scripts/tests/test_underlay_bande_basse.py index a95796f..b3cb97b 100644 --- a/scripts/tests/test_underlay_bande_basse.py +++ b/scripts/tests/test_underlay_bande_basse.py @@ -21,7 +21,7 @@ sys.path.insert(0, str(RACINE / "scripts")) import underlay as u # noqa: E402 from inventory_rules import OCTET_ZONE # noqa: E402 -SUPERNETS = ["10.21.0.0/16", "10.27.0.0/16"] # deux sites : index 11 et 17 +SUPERNETS = ["10.11.0.0/16", "10.17.0.0/16"] # deux sites : index 11 et 17 MIEN = 11 @@ -39,25 +39,25 @@ def test_la_borne_derive_de_la_regle_des_zones(): def test_bande_basse_de_son_propre_supernet_acceptee(): - for sous in ("10.21.0.0/24", "10.21.4.0/24", "10.21.5.0/24", "10.21.15.0/24"): + for sous in ("10.11.0.0/24", "10.11.4.0/24", "10.11.5.0/24", "10.11.15.0/24"): assert _erreurs(sous) == [], f"{sous} devrait etre conforme (bande basse)" def test_bande_des_zones_refusee(): - for sous in (f"10.21.{OCTET_ZONE + 1}.0/24", "10.21.18.0/24", "10.21.16.0/20"): + for sous in (f"10.11.{OCTET_ZONE + 1}.0/24", "10.11.18.0/24", "10.11.16.0/20"): assert _erreurs(sous), f"{sous} devrait etre REFUSE (bande des zones)" def test_un_prefixe_qui_franchit_la_frontiere_est_refuse(): """Le piege : il COMMENCE dans la bande basse et deborde. Un test qui ne regarderait que le premier octet le laisserait passer.""" - for sous in ("10.21.0.0/19", "10.21.0.0/16"): + for sous in ("10.11.0.0/19", "10.11.0.0/16"): assert _erreurs(sous), f"{sous} couvre au-dela de {OCTET_ZONE} : a refuser" def test_supernet_d_un_autre_site_refuse(): """C'est ce qui empeche deux sites d'etre relies — l'erreur la plus couteuse.""" - assert _erreurs("10.27.0.0/24"), "le supernet d'un autre site doit etre refuse" + assert _erreurs("10.17.0.0/24"), "le supernet d'un autre site doit etre refuse" def test_hors_de_tout_supernet_accepte(): @@ -69,7 +69,7 @@ def test_hors_de_tout_supernet_accepte(): def test_sans_index_on_retombe_sur_la_regle_stricte(): """Un underlay qui n'a pas encore migre ne declare pas d'index : aucun chevauchement n'est alors tolere, ce qui reste le comportement sur.""" - assert _erreurs("10.21.0.0/24", index=None), \ + assert _erreurs("10.11.0.0/24", index=None), \ "sans index, tout chevauchement doit etre refuse" diff --git a/scripts/underlay.py b/scripts/underlay.py index 05178df..379d79b 100644 --- a/scripts/underlay.py +++ b/scripts/underlay.py @@ -8,9 +8,9 @@ flotte, ils n'appartiennent a aucun tenant. Convention : VLAN < 1000, franchement SOUS la plage tenant (VLAN = 1000+index*10+zone). ADRESSAGE (D-77, 2026-08-12). Un site derive du meme `index` que son tenant, et son -underlay occupe la BANDE BASSE de ce supernet : `10.(10+index).0-15.x`. La bande est +underlay occupe la BANDE BASSE de ce supernet : `10..0-15.x`. La bande est sure PAR LA REGLE et non par chance — les zones d'un tenant valent -`10.(10+index).(15+categorie).0/24`, donc troisieme octet >= 16 ; les octets 0 a 15 +`10..(15+categorie).0/24`, donc troisieme octet >= 16 ; les octets 0 a 15 ne sont jamais alloues. Deux sites ne peuvent alors pas se chevaucher, sans second registre a tenir. @@ -57,7 +57,7 @@ from inventory_rules import supernet_de, vlan_de # noqa: E402 SEUIL_VLAN_TENANT = 1000 # Premier troisieme-octet alloue aux ZONES d'un tenant. DERIVE de la regle -# (`base3_de` = 10.(10+index).(15+categorie)) et jamais ecrit en dur : deplacer +# (`base3_de` = 10..(15+categorie)) et jamais ecrit en dur : deplacer # OCTET_ZONE deplacerait la frontiere de la bande basse avec lui. from inventory_rules import OCTET_ZONE # noqa: E402 PREMIER_OCTET_ZONE = OCTET_ZONE + 1 diff --git a/wiki/Glossaire.md b/wiki/Glossaire.md index 15d1fda..86b9199 100644 --- a/wiki/Glossaire.md +++ b/wiki/Glossaire.md @@ -27,7 +27,7 @@ serveurs. Refusé par la preuve **P06** et par la création de modèle. 1ʳᵉ fois). Cf. [Infra as Code & idempotence](Infra-as-Code-et-idempotence). **Index (seed)** — Le **seul** intrant d'adressage d'une instance. Détermine supernet -(`10.(10+index)`), VLAN (`1000+index×10+zone`), VMID. Unique par instance fédérée. +(`10.`), VLAN (`1000+index×10+zone`), VMID. Unique par instance fédérée. **Instance** — Un écosystème réel (un *tenant*) : `../OPS-`, avec ses valeurs concrètes (domaine, *voûte*, index). L'active est celle que pointe le symlink `instance/`. diff --git a/wiki/Le-plan-et-l-adressage-dérivé.md b/wiki/Le-plan-et-l-adressage-dérivé.md index bbba9ef..729230e 100644 --- a/wiki/Le-plan-et-l-adressage-dérivé.md +++ b/wiki/Le-plan-et-l-adressage-dérivé.md @@ -37,8 +37,8 @@ Le **plan** (`instance/plan/`) est la source unique. Cinq registres : | Élément | Formule (modèle 6 zones) | |---|---| -| Supernet | `10.(10+index).0.0/16` | -| Sous-réseau de zone | `10.(10+index).(15+zone).0/24` | +| Supernet | `10..0.0/16` | +| Sous-réseau de zone | `10..(15+zone).0/24` | | Passerelle | `…(15+zone).1` | | VLAN sur le trunk | `1000 + index×10 + zone` | | VMID | `VLAN·octet-hôte·séquence` (9 chiffres) | diff --git a/wiki/Multi-instance-et-fédération.md b/wiki/Multi-instance-et-fédération.md index ecce929..7a5f107 100644 --- a/wiki/Multi-instance-et-fédération.md +++ b/wiki/Multi-instance-et-fédération.md @@ -120,7 +120,7 @@ En mode `sdn`, ces réseaux transportent du VXLAN : leur **MTU doit atteindre 15 sinon le ping passe et les transferts échouent. `make underlay` le refuse. `make underlay` l'affiche et le **valide** : VLAN < 1000 et sous-réseaux hors des supernets -tenant (`10.(10+index).0.0/16`) — **aucune collision possible** avec les overlays. `make +tenant (`10..0.0/16`) — **aucune collision possible** avec les overlays. `make devis-reseau` en émet la config (section 0) et l'ajoute au trunk. La **preuve P23** garde la règle ; elle est *sautée* si aucun `underlay.yml` n'est défini.