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 <noreply@anthropic.com>
This commit is contained in:
parent
27bb51d007
commit
113e78ee02
4 changed files with 21 additions and 20 deletions
|
|
@ -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é
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
---
|
||||
# Nomenclature Set-OPS : source unique pour hostnames, VMID, VLAN et adressage.
|
||||
#
|
||||
# Derivations (tout part du domaine de l'hote) :
|
||||
# hostname = <domaine>-<NN> ex. web-frontal-03
|
||||
# Derivations (tout part de la FONCTION de l'hote ; "domaine" est reserve au DNS) :
|
||||
# hostname = <fonction>-<NN> ex. web-frontal-03
|
||||
# VMID = 9 . categorie . service . NN ex. 9 5 3 03 -> 95303
|
||||
# VLAN = categorie.vlan ex. 15
|
||||
# IP = <prefixe_sous_reseau>.(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 }
|
||||
|
|
|
|||
|
|
@ -1072,7 +1072,7 @@ HTML = r"""<!doctype html>
|
|||
}
|
||||
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 ? `<span class="zone-hint" title="Dérivé de la nomenclature">${echapper(info.libelle)} · VLAN ${info.vlan}</span>` : '';
|
||||
const st = statutHote(h);
|
||||
const libelle = actif ? (hoteBloque(h) ? 'prérequis manquant' : 'déployable') : 'planifié';
|
||||
|
|
@ -1097,7 +1097,7 @@ HTML = r"""<!doctype html>
|
|||
cible.innerHTML = `
|
||||
<article class="detail ${hoteBloque(h) ? 'bloque' : ''}">
|
||||
<div class="detail-tete">
|
||||
<div class="detail-nom"><input value="${echapper(h.nom || '')}" placeholder="domaine-NN (ex. web-frontal-03)" oninput="definirNom(${index}, this.value)" onchange="autoProposer(${index})">${zoneHint}</div>
|
||||
<div class="detail-nom"><input value="${echapper(h.nom || '')}" placeholder="fonction-NN (ex. web-frontal-03)" oninput="definirNom(${index}, this.value)" onchange="autoProposer(${index})">${zoneHint}</div>
|
||||
<button type="button" class="fantome" title="Proposer VMID, VLAN, IP et passerelle depuis la nomenclature" onclick="proposer(${index})">✨ Proposer</button>
|
||||
<div class="etat-bascule">
|
||||
<button type="button" class="${actif ? 'on actif' : ''}" onclick="definirEtat(${index}, 'actif')">actif</button>
|
||||
|
|
@ -1168,29 +1168,29 @@ HTML = r"""<!doctype html>
|
|||
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"""<!doctype html>
|
|||
}
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Reference in a new issue