GUI : le panneau présente les deux devis, et son aide n'est plus périmée
La vue Réseau n'affichait que le devis des commutateurs. Le devis frontière était totalement absent de l'interface, alors qu'il porte les règles de la bordure et ses avertissements — dont celui sur « Block private networks », invisible dans les règles elles-mêmes. Ajouté `/api/devis-opnsense` et son bloc d'affichage avec bouton de copie. Vérifié par HTTP que les deux points d'API servent exactement ce que le CLI produit : 181 et 125 lignes, identiques au caractère près. Import paresseux et gardé — ce module lit l'underlay et les inventaires de tous les tenants, une erreur aurait sinon vidé la vue entière. Aide corrigée sur trois points périmés : les VLAN tenants annoncés « uniques sur le trunk » (faux en SDN, aucun n'y circule) ; le dialecte renvoyé à une variable d'environnement alors que c'est un intrant de la section Fabric ; et la route par défaut dite « à adapter » alors que la section 5 l'émet. Elle dit maintenant ce qui reste à nommer à la main : les ports physiques et, en SDN, le nœud de sortie EVPN. Preuves : 24 OK, 0 échec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
940e319285
commit
a85255dc35
2 changed files with 52 additions and 5 deletions
23
CHANGELOG.md
23
CHANGELOG.md
|
|
@ -1,5 +1,28 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-08-03 (suite 2) — le panneau présente les deux devis
|
||||
|
||||
La vue *Réseau* n'affichait que le devis des commutateurs : **le devis frontière était
|
||||
totalement absent de l'interface**, alors qu'il porte les règles de la bordure et ses
|
||||
avertissements — dont celui sur « Block private networks », invisible dans les règles
|
||||
elles-mêmes.
|
||||
|
||||
Ajouté : `/api/devis-opnsense` et son bloc d'affichage, avec bouton de copie. Vérifié **par
|
||||
HTTP** que les deux points d'API servent exactement ce que le CLI produit — 181 et 125 lignes,
|
||||
identiques au caractère près.
|
||||
|
||||
L'import est paresseux et gardé : ce module lit l'underlay et les inventaires de tous les
|
||||
tenants, et une erreur y aurait sinon empêché l'affichage du reste de la vue.
|
||||
|
||||
### Corrigé — le texte d'aide était périmé sur trois points
|
||||
Il annonçait les VLAN tenants « uniques **sur le trunk** » — faux en SDN, où aucun ne circule ;
|
||||
renvoyait le dialecte à `SETOPS_DIALECTE` alors que c'est un **intrant** de la section
|
||||
*Fabric* ; et disait que « la route par défaut vers OPNsense reste à adapter » alors que la
|
||||
section 5 l'émet depuis hier.
|
||||
|
||||
Il dit maintenant ce qui reste réellement à nommer à la main : les **ports physiques** et, en
|
||||
SDN, le **nœud de sortie EVPN**. Rien d'autre — adresses, VLAN et routes se dérivent.
|
||||
|
||||
## 2026-08-03 (suite) — le devis frontière rattrape la bascule SDN
|
||||
|
||||
Trois affirmations du devis frontière étaient devenues fausses, dont une qui cassait le
|
||||
|
|
|
|||
|
|
@ -1403,8 +1403,9 @@ HTML = r"""<!doctype html>
|
|||
<div class="hint-dep" style="margin-top:10px">Lecture seule. Éditer les <code>meta/flux.yml</code> des rôles, puis <code>make flux</code>.</div></div>`;
|
||||
} else if (vuePrincipale === 'reseau') {
|
||||
d.innerHTML = `<div class="detail"><div class="section-tete">Réseau & fédération</div>
|
||||
<div class="hint-dep">Chaque instance fédérée dérive son adressage de son seed <code>index</code> (VLAN = 1000 + index×10 + zone, unique sur le trunk). La vue liste la flotte, signale toute collision d'index, et génère le devis des switches.</div>
|
||||
<div class="hint-dep" style="margin-top:10px">Lecture seule, régénéré du plan — <code>make instances</code> / <code>make devis-reseau</code>. Masques d'ACL selon le dialecte (<code>SETOPS_DIALECTE=cisco|binardat</code> ou <code>make devis-reseau DIALECTE=binardat</code>). Le reste (HSRP, route par défaut vers OPNsense, port de trunk) reste à adapter à ta plateforme.</div></div>`;
|
||||
<div class="hint-dep">Chaque instance fédérée dérive son adressage de son seed <code>index</code> (VLAN/VNI = 1000 + index×10 + zone, unique dans la fédération). La vue liste la flotte, signale toute collision d'index, et génère les <strong>deux devis</strong> : commutateurs et frontière nord/sud.</div>
|
||||
<div class="hint-dep" style="margin-top:10px">Lecture seule, régénérés du plan — <code>make devis-reseau</code> / <code>make devis-opnsense</code>. Le <strong>dialecte de CLI</strong> et le <strong>mode de routage</strong> (commutateur ou SDN EVPN) se règlent dans la section <em>Fabric</em> du panneau « Intrants de base ». En mode SDN, les commutateurs ne portent ni VLAN tenant, ni SVI, ni ACL : le routage et le filtrage inter-zone vivent sur les hyperviseurs.</div>
|
||||
<div class="hint-dep" style="margin-top:10px">Ce qui reste à nommer à la main : les <strong>ports physiques</strong> (<code><PORT-VERS-…></code>) et, en SDN, le <strong>nœud de sortie EVPN</strong>. Rien d'autre — adresses, VLAN et routes se dérivent.</div></div>`;
|
||||
} else {
|
||||
d.innerHTML = `<div class="detail"><div class="section-tete">Reconstruction</div>
|
||||
<div class="hint-dep">L'ordre part du socle et remonte : chaque couche suppose la précédente debout. Le tri intra-couche vient du graphe des dépendances.</div>
|
||||
|
|
@ -1430,6 +1431,7 @@ HTML = r"""<!doctype html>
|
|||
}
|
||||
|
||||
let devisReseauTexte = '';
|
||||
let devisFrontiereTexte = '';
|
||||
function tableauFlotte(inst, coll, fmodeles, findexPris) {
|
||||
if (!inst.length) return '<div class="vide" style="padding:14px">Aucune instance découverte (dépôts frères avec plan/nomenclature.yml).</div>';
|
||||
const banniere = Object.keys(coll || {}).length
|
||||
|
|
@ -1498,11 +1500,12 @@ HTML = r"""<!doctype html>
|
|||
const cible = document.getElementById('grilles');
|
||||
cible.innerHTML = '<div class="vide" style="padding:14px">Lecture de la fédération…</div>';
|
||||
try {
|
||||
const [ri, rd] = await Promise.all([
|
||||
const [ri, rd, rf] = await Promise.all([
|
||||
fetch('/api/instances', {headers: {'X-Jeton': JETON}}),
|
||||
fetch('/api/devis-reseau', {headers: {'X-Jeton': JETON}}),
|
||||
fetch('/api/devis-opnsense', {headers: {'X-Jeton': JETON}}),
|
||||
]);
|
||||
const di = await ri.json(), data = await rd.json();
|
||||
const di = await ri.json(), data = await rd.json(), dfr = await rf.json();
|
||||
if (!rd.ok) { cible.innerHTML = '<div class="vide" style="padding:14px">' + echapper(data.erreur || 'Indisponible.') + '</div>'; return; }
|
||||
devisReseauTexte = data.config || '';
|
||||
const flotte = `<div class="section-grille"><div class="section-tete">Flotte d'instances <span class="compte">${(di.instances || []).length}</span></div>${tableauFlotte(di.instances || [], di.collisions || {}, di.modeles || [], di.index_pris || [])}</div>`;
|
||||
|
|
@ -1511,7 +1514,13 @@ HTML = r"""<!doctype html>
|
|||
<button type="button" class="fantome" style="margin-left:auto" onclick="copierDevis()">Copier</button></div>
|
||||
<pre class="devis-reseau">${echapper(devisReseauTexte)}</pre></div>`
|
||||
: '<div class="hint-dep" style="margin-top:12px">Aucune instance fédérée : pas de devis convergé à générer.</div>';
|
||||
cible.innerHTML = flotte + devis;
|
||||
devisFrontiereTexte = dfr.config || '';
|
||||
const frontiere = devisFrontiereTexte
|
||||
? `<div class="section-grille" style="margin-top:12px"><div class="section-tete">Devis config réseau — frontière nord/sud (OPNsense)
|
||||
<button type="button" class="fantome" style="margin-left:auto" onclick="copierDevisFrontiere()">Copier</button></div>
|
||||
<pre class="devis-reseau">${echapper(devisFrontiereTexte)}</pre></div>`
|
||||
: `<div class="hint-dep" style="margin-top:12px">Devis frontière indisponible${dfr.erreur ? ' : ' + echapper(dfr.erreur) : ''}.</div>`;
|
||||
cible.innerHTML = flotte + devis + frontiere;
|
||||
} catch (e) {
|
||||
cible.innerHTML = '<div class="vide" style="padding:14px">Erreur : ' + echapper(e.message) + '</div>';
|
||||
}
|
||||
|
|
@ -1520,6 +1529,10 @@ HTML = r"""<!doctype html>
|
|||
if (navigator.clipboard) navigator.clipboard.writeText(devisReseauTexte)
|
||||
.then(() => message('Devis réseau copié — prêt à coller sur le switch.', 'ok'), () => {});
|
||||
}
|
||||
function copierDevisFrontiere() {
|
||||
if (navigator.clipboard) navigator.clipboard.writeText(devisFrontiereTexte)
|
||||
.then(() => message('Devis frontière copié.', 'ok'), () => {});
|
||||
}
|
||||
|
||||
function dessinerCouches() {
|
||||
const cible = document.getElementById('grilles');
|
||||
|
|
@ -2740,6 +2753,17 @@ class Gestionnaire(BaseHTTPRequestHandler):
|
|||
"config": devis_reseau.generer(tenants) if tenants else "",
|
||||
"tenants": [{"nom": nom, "index": n["index"]} for nom, _, n in tenants],
|
||||
})
|
||||
elif chemin == "/api/devis-opnsense":
|
||||
# Import paresseux : ce module lit l'underlay et les inventaires de tous
|
||||
# les tenants ; une erreur ici ne doit pas empecher le reste du panneau.
|
||||
try:
|
||||
import devis_opnsense as _dop
|
||||
tenants = _dop.decouvrir()
|
||||
self.repondre_json(200, {
|
||||
"config": _dop.rendre(_dop.construire(tenants)) if tenants else "",
|
||||
})
|
||||
except Exception as exc:
|
||||
self.repondre_json(200, {"config": "", "erreur": str(exc)})
|
||||
elif chemin == "/api/instances":
|
||||
import instances as _inst
|
||||
import instance_creer as _ic
|
||||
|
|
|
|||
Loading…
Reference in a new issue