From 113e78ee02a00a62b1c3f3c1a7f46eef681c2dee Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Tue, 23 Jun 2026 20:20:40 -0400 Subject: [PATCH] Phase 1b : renommer nomenclature domaines -> fonctions Leve la collision de nom entre les familles fonctionnelles de la nomenclature (infra-pki, web-frontal...) et les domaines DNS. - docs/nomenclature.yml : cle domaines -> fonctions (+ commentaires). - inventory_gui.py : domaineDe/infoDomaine -> fonctionDe/infoFonction, nomenclature.fonctions, libelles et placeholder alignes. - inventory_rules.py : docstring. Aucun role ni inventaire impacte (nomenclature lue a la planification). Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 1 + docs/nomenclature.yml | 10 +++++----- scripts/inventory_gui.py | 28 ++++++++++++++-------------- scripts/inventory_rules.py | 2 +- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76e7893..1472c7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2026-06-23 ### Modifié +- **Phase 1b — clarté de nommage.** La clé `domaines:` de `docs/nomenclature.yml` (familles fonctionnelles : `infra-pki`, `web-frontal`…) est renommée **`fonctions:`** pour lever la collision avec les domaines DNS (`docs/domaines.yml`). L'auto-proposition du GUI suit (`fonctionDe` / `infoFonction`, `nomenclature.fonctions`, libellés « Fonction inconnue… », placeholder `fonction-NN`). Aucun rôle ni inventaire impacté : la nomenclature n'est consommée qu'au moment de la planification. - **Refonte « application-hub », Phase 1 — les liens deviennent explicites (inventaire inchangé, zéro régression).** L'application porte désormais tous ses liens : `groupe` (capacité/rôle), `hote` (VM), `port`, **`requiert`** (autres applications dont elle dépend) et **`expose`** (FQDN publics qui la publient). L'**exposition DNS quitte `docs/domaines.yml`** (le bloc `exposition` est retiré) et vit sur l'application via `expose` ; `docs/domaines.yml` ne décrit plus que les zones (autorité, edge, secondaires, dnssec, mail). `serveurs_nginx` dérive ses vhosts des **applications** (`expose` + edge du domaine), résolvant `application → hôte → IP` (rôle + `expositions.conf.j2` réécrits). Nouvelle règle partagée `expositions_des_applications` (+ `domaine_parent`) dans `inventory_rules.py`, exposée à Ansible par le filter plugin ; `valider_applications` valide `requiert` (applis connues), `expose` (domaine parent déclaré) et `port`. CLI (`applications.py --port/--requiert/--expose`, `domaines.py` affiche les expositions dérivées) et **GUI** (champs Port/Requiert/Expose sur la fiche Application, persistés) suivent ; l'API expose aussi le registre des domaines. Le groupe n'est plus une cible de liaison, seulement une capacité. *(Renommage `nomenclature.domaines:` → `fonctions:` reporté en Phase 1b ; génération de l'inventaire depuis le plan en Phase 3.)* ### Ajouté diff --git a/docs/nomenclature.yml b/docs/nomenclature.yml index 024da34..49a53dd 100644 --- a/docs/nomenclature.yml +++ b/docs/nomenclature.yml @@ -1,15 +1,15 @@ --- # Nomenclature Set-OPS : source unique pour hostnames, VMID, VLAN et adressage. # -# Derivations (tout part du domaine de l'hote) : -# hostname = - ex. web-frontal-03 +# Derivations (tout part de la FONCTION de l'hote ; "domaine" est reserve au DNS) : +# hostname = - ex. web-frontal-03 # VMID = 9 . categorie . service . NN ex. 9 5 3 03 -> 95303 # VLAN = categorie.vlan ex. 15 # IP = .(service*10 + NN) ex. 10.1.15.33 # passerelle / CIDR : voir la categorie # -# Contrainte : NN va de 01 a 09 par domaine (l'octet hote = service*10 + NN -# reste dans le bloc du service). Au-dela, ouvrir un nouveau domaine ou service. +# Contrainte : NN va de 01 a 09 par fonction (l'octet hote = service*10 + NN +# reste dans le bloc du service). Au-dela, ouvrir une nouvelle fonction ou service. supernet: "10.1.0.0/16" cidr_hote: 24 @@ -27,7 +27,7 @@ categories: 5: { libelle: "Applications", vlan: 15, sous_reseau: "10.1.15.0/24", passerelle: "10.1.15.1" } 9: { libelle: "Modeles / essais", vlan: 99, sous_reseau: "10.1.99.0/24", passerelle: "10.1.99.1" } -domaines: +fonctions: infra-pki: { categorie: 1, service: 1 } infra-edge: { categorie: 1, service: 2 } infra-mail: { categorie: 1, service: 3 } diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py index 4126aa3..c28e8d8 100644 --- a/scripts/inventory_gui.py +++ b/scripts/inventory_gui.py @@ -1072,7 +1072,7 @@ HTML = r""" } const index = selection, h = hotes[index]; const actif = h.etat === 'actif'; - const info = infoDomaine(domaineDe(h.nom).domaine); + const info = infoFonction(fonctionDe(h.nom).fonction); const zoneHint = info ? `${echapper(info.libelle)} · VLAN ${info.vlan}` : ''; const st = statutHote(h); const libelle = actif ? (hoteBloque(h) ? 'prérequis manquant' : 'déployable') : 'planifié'; @@ -1097,7 +1097,7 @@ HTML = r""" cible.innerHTML = `
-
${zoneHint}
+
${zoneHint}
@@ -1168,29 +1168,29 @@ HTML = r""" return lignes.join('\n'); } - function domaineDe(nom) { + function fonctionDe(nom) { const m = (nom || '').match(/^(.+)-(\d+)$/); - return m ? {domaine: m[1], seq: parseInt(m[2], 10)} : {domaine: nom || '', seq: null}; + return m ? {fonction: m[1], seq: parseInt(m[2], 10)} : {fonction: nom || '', seq: null}; } - function infoDomaine(domaine) { - const d = (nomenclature.domaines || {})[domaine]; + function infoFonction(fonction) { + const d = (nomenclature.fonctions || {})[fonction]; if (!d) return null; const c = (nomenclature.categories || {})[d.categorie]; if (!c) return null; return {categorie: d.categorie, service: d.service, libelle: c.libelle, vlan: c.vlan, sous_reseau: c.sous_reseau, passerelle: c.passerelle}; } - function prochainSeqLibre(domaine) { + function prochainSeqLibre(fonction) { const pris = new Set(); - hotes.forEach(h => { const x = domaineDe(h.nom); if (x.domaine === domaine && x.seq != null) pris.add(x.seq); }); + hotes.forEach(h => { const x = fonctionDe(h.nom); if (x.fonction === fonction && x.seq != null) pris.add(x.seq); }); let s = 1; while (pris.has(s)) s++; return s; } function proposer(index, silencieux=false) { const h = hotes[index]; - let {domaine, seq} = domaineDe(h.nom); - const info = infoDomaine(domaine); - if (!info) { if (!silencieux) message('Domaine inconnu de la nomenclature : ' + (domaine || '(vide)'), 'erreur'); return; } - if (seq == null) { seq = prochainSeqLibre(domaine); h.nom = domaine + '-' + String(seq).padStart(2, '0'); selectionNom = h.nom; } - if (seq > 9) { if (!silencieux) message('Séquence > 9 pour ' + domaine + ' : hors plage d\'adressage, à saisir à la main.', 'erreur'); return; } + let {fonction, seq} = fonctionDe(h.nom); + const info = infoFonction(fonction); + if (!info) { if (!silencieux) message('Fonction inconnue de la nomenclature : ' + (fonction || '(vide)'), 'erreur'); return; } + if (seq == null) { seq = prochainSeqLibre(fonction); h.nom = fonction + '-' + String(seq).padStart(2, '0'); selectionNom = h.nom; } + if (seq > 9) { if (!silencieux) message('Séquence > 9 pour ' + fonction + ' : hors plage d\'adressage, à saisir à la main.', 'erreur'); return; } const base3 = info.sous_reseau.split('.').slice(0, 3).join('.'); h.vmid = '9' + info.categorie + info.service + String(seq).padStart(2, '0'); h.vlan = String(info.vlan); @@ -1202,7 +1202,7 @@ HTML = r""" } function autoProposer(index) { const h = hotes[index]; - if (!String(h.vmid || '').trim() && infoDomaine(domaineDe(h.nom).domaine)) proposer(index, true); + if (!String(h.vmid || '').trim() && infoFonction(fonctionDe(h.nom).fonction)) proposer(index, true); } function echapper(valeur) { diff --git a/scripts/inventory_rules.py b/scripts/inventory_rules.py index 49705b4..37266ce 100644 --- a/scripts/inventory_rules.py +++ b/scripts/inventory_rules.py @@ -283,7 +283,7 @@ def expositions_du_groupe(registre: dict, groupe: str) -> list[dict]: def charger_nomenclature(path: Path | None) -> dict: - """Charge le registre de nomenclature (domaines, categories, adressage).""" + """Charge le registre de nomenclature (fonctions, categories, adressage).""" if not path or not path.exists(): return {} with path.open("r", encoding="utf-8") as fichier: