adressage : le decalage de +10 est retire, l'index se lit dans l'adresse

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 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-12 16:16:08 -04:00
parent b7239149bb
commit 5ace6bdb95
14 changed files with 102 additions and 93 deletions

View file

@ -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

View file

@ -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. |

View file

@ -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.<step_ca\|powerdns>.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).015.x` ; les réseaux de **stockage** en sortent et sont **identiques partout**, en `192.168.<vlan>.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.<index>.015.x` ; les réseaux de **stockage** en sortent et sont **identiques partout**, en `192.168.<vlan>.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.<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** |
> **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

View file

@ -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.<index>.0.0/16` | `10.13.0.0/16` |
| Sous-réseau de zone | `10.<index>.(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.<index>` (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).

View file

@ -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.<index>.0.0/24` | 1500 | frontière `.1`, commutateurs, OOB/IPMI, admin hyperviseur |
| Sortie des tenants | 40 | `10.<index>.4.0/24` | 1500 | frontière `.1`, nœuds de sortie |
| Transport VXLAN | 11 | `10.<index>.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.<index>.(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.<index>.0.1/24` ; le
transit en `10.<index>.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`.

View file

@ -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**

View file

@ -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',
'') }}

View file

@ -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.<index>, 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"),

View file

@ -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.<index>.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.<index>.(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.<index>.(15+categorie).0/24."""
return f"{base3_de(index, categorie)}.0/{int(cidr)}"

View file

@ -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"

View file

@ -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.<index>.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.<index>.(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.<index>.(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

View file

@ -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.<index>`), VLAN (`1000+index×10+zone`), VMID. Unique par instance fédérée.
**Instance** — Un écosystème réel (un *tenant*) : `../OPS-<nom>`, avec ses valeurs concrètes
(domaine, *voûte*, index). L'active est celle que pointe le symlink `instance/`.

View file

@ -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.<index>.0.0/16` |
| Sous-réseau de zone | `10.<index>.(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) |

View file

@ -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.<index>.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.