1- /**
2- * k8s-client.js
3- * Umfassende Diagnose für Envoy-Sidecars und Istio-Netzwerkressourcen.
4- */
51const K8sClient = ( ( ) => {
62
73 async function apiFetch ( endpoint ) {
@@ -10,9 +6,7 @@ const K8sClient = (() => {
106 return await response . json ( ) ;
117 }
128
13- /**
14- * Hilfsfunktion zum Rendern einer Ressourcen-Gruppe (VS, DR, oder GW)
15- */
9+ // Zeigt einfach alle Items an, die übergeben werden
1610 function renderResourceGroup ( title , items , icon , colorClass ) {
1711 return `
1812 <div class="mb-3">
@@ -43,61 +37,56 @@ const K8sClient = (() => {
4337 const resourceDiv = document . getElementById ( 'resourceDisplay' ) ;
4438
4539 const spinner = '<div class="text-center p-4"><div class="spinner-border text-info"></div></div>' ;
46- [ configDiv , errorDiv , resourceDiv ] . forEach ( el => { if ( el ) el . innerHTML = spinner ; } ) ;
40+ [ configDiv , errorDiv , resourceDiv ] . forEach ( el => { if ( el ) el . innerHTML = spinner ; } ) ;
4741
4842 try {
43+ // Namespace-Logik: Wir nutzen primär den Namespace, in dem die App selbst läuft,
44+ // außer die URL ist voll qualifiziert (z.B. service.other-ns.svc).
4945 const urlObj = new URL ( targetUrl ) ;
5046 const hostParts = urlObj . hostname . split ( '.' ) ;
51- const targetNamespace = ( hostParts . length > 1 && hostParts [ 1 ] !== 'svc' ) ? hostParts [ 1 ] : 'default' ;
5247
53- // 1. Alle Daten parallel abrufen
48+ // Wir holen uns erst den eigenen Namespace der App aus dem Context
49+ const context = await apiFetch ( '/api/k8s/context' ) ;
50+ const currentNs = context . namespace || 'default' ;
51+
52+ // Wenn die URL einen Namespace enthält (part[1]), nutze diesen, sonst den aktuellen.
53+ const targetNamespace = ( hostParts . length > 1 && hostParts [ 1 ] !== 'svc' && hostParts [ 1 ] !== 'cluster' )
54+ ? hostParts [ 1 ] : currentNs ;
55+
5456 const [ report , vs , dr , gw ] = await Promise . all ( [
5557 apiFetch ( '/api/k8s/istio/full-report' ) ,
5658 apiFetch ( `/api/k8s/istio/virtualservice?namespace=${ targetNamespace } ` ) ,
5759 apiFetch ( `/api/k8s/istio/destinationrule?namespace=${ targetNamespace } ` ) ,
5860 apiFetch ( `/api/k8s/istio/gateway?namespace=${ targetNamespace } ` )
5961 ] ) ;
6062
61- if ( report . error ) throw new Error ( report . error ) ;
62-
63- // --- TAB A: ENVOY CONFIG ---
63+ // Render Sektionen
6464 configDiv . innerHTML = `
6565 <div class="mb-3">
66- <label class="fw-bold small text-muted">AKTIVE CLUSTER (UPSTREAM):</label>
67- <pre class="console x-small" style="max-height: 250px; overflow:auto; background: #1a1a1a; color: #00ff41; padding: 12px; border: 1px solid #333;">${ report . reachability . activeEndpoints } </pre>
68- <div class="badge bg-primary mt-1">${ report . reachability . summary } </div>
66+ <label class="fw-bold small text-muted">ENVOY CLUSTERS:</label>
67+ <pre class="console x-small" style="max-height: 250px; overflow:auto; background: #1a1a1a; color: #00ff41; padding: 12px;">${ report . reachability . activeEndpoints } </pre>
6968 </div>
70- <button class="btn btn-xs btn-outline-secondary" onclick="this.nextElementSibling.classList.toggle('d-none')">Raw JSON Config </button>
71- <pre class="console x-small d-none mt-2" style="max-height:300px; overflow:auto;" >${ JSON . stringify ( report . reachability . envoyConfig , null , 2 ) } </pre>` ;
69+ <button class="btn btn-xs btn-outline-secondary" onclick="this.nextElementSibling.classList.toggle('d-none')">Raw JSON</button>
70+ <pre class="console x-small d-none mt-2">${ JSON . stringify ( report . reachability . envoyConfig , null , 2 ) } </pre>` ;
7271
73- // --- TAB B: FEHLER ---
7472 const errorEntries = Object . entries ( report . healthDiagnostics . activeErrorMetrics ) ;
75- if ( errorEntries . length === 0 ) {
76- errorDiv . innerHTML = `<div class="alert alert-success mt-2 small"><i class="bi bi-check-circle me-2"></i>Keine aktiven Fehlermetriken im Sidecar.</div>` ;
77- } else {
78- errorDiv . innerHTML = `
79- <table class="table table-sm table-hover border small mt-2">
80- <thead class="table-dark"><tr><th>Envoy Metrik</th><th class="text-end">Wert</th></tr></thead>
81- <tbody>
82- ${ errorEntries . map ( ( [ k , v ] ) => `<tr><td class="x-small font-monospace">${ k } </td><td class="text-end text-danger fw-bold">${ v } </td></tr>` ) . join ( '' ) }
83- </tbody>
84- </table>` ;
85- }
86-
87- // --- TAB C: ALLE K8S/ISTIO RESSOURCEN ---
88- // Filtern auf Relevanz zum Hostname
89- const filterHost = ( list ) => list . filter ( item => JSON . stringify ( item ) . toLowerCase ( ) . includes ( hostParts [ 0 ] . toLowerCase ( ) ) ) ;
90-
73+ errorDiv . innerHTML = errorEntries . length === 0 ?
74+ `<div class="alert alert-success mt-2 small">Keine Fehler-Metriken > 0.</div>` :
75+ `<table class="table table-sm table-hover small mt-2">
76+ <thead class="table-dark"><tr><th>Metrik</th><th class="text-end">Wert</th></tr></thead>
77+ <tbody>${ errorEntries . map ( ( [ k , v ] ) => `<tr><td class="x-small">${ k } </td><td class="text-end fw-bold text-danger">${ v } </td></tr>` ) . join ( '' ) } </tbody>
78+ </table>` ;
79+
80+ // Ressourcen ohne Filter anzeigen
9181 resourceDiv . innerHTML = `
92- <div class="p-1">
93- ${ renderResourceGroup ( "Virtual Services" , filterHost ( vs ) , "bi-shuffle" , "border-primary" ) }
94- ${ renderResourceGroup ( "Destination Rules" , filterHost ( dr ) , "bi-shield-shaded" , "border-success" ) }
95- ${ renderResourceGroup ( "Gateways" , gw , "bi-door-open" , "border-warning" ) }
96- </div>` ;
82+ <div class="alert alert-info py-1 px-2 x-small mb-3">Zeige Ressourcen im Namespace: <strong>${ targetNamespace } </strong></div>
83+ ${ renderResourceGroup ( "Virtual Services" , vs , "bi-shuffle" , "border-primary" ) }
84+ ${ renderResourceGroup ( "Destination Rules" , dr , "bi-shield-shaded" , "border-success" ) }
85+ ${ renderResourceGroup ( "Gateways" , gw , "bi-door-open" , "border-warning" ) } ` ;
9786
9887 } catch ( err ) {
99- const msg = `<div class="alert alert-danger m-2 small">Diagnose fehlgeschlagen : ${ err . message } </div>` ;
100- [ configDiv , errorDiv , resourceDiv ] . forEach ( el => { if ( el ) el . innerHTML = msg ; } ) ;
88+ const msg = `<div class="alert alert-danger m-2 small">Fehler : ${ err . message } </div>` ;
89+ [ configDiv , errorDiv , resourceDiv ] . forEach ( el => { if ( el ) el . innerHTML = msg ; } ) ;
10190 }
10291 }
10392 } ;
@@ -119,15 +108,12 @@ document.addEventListener('DOMContentLoaded', async () => {
119108
120109 if ( diagnoseBtn ) {
121110 diagnoseBtn . addEventListener ( 'click' , ( ) => {
122- const urlVal = document . getElementById ( 'url' ) . value ;
123- if ( ! urlVal ) return alert ( "Bitte URL eingeben" ) ;
124111
125112 document . getElementById ( 'resultArea' ) . style . display = 'block' ;
126113 document . getElementById ( 'istioPanel' ) . style . display = 'block' ;
127114
128- // Sicherer Tab-Wechsel ohne 'bootstrap is not defined' Risiko
129115 const firstTab = document . querySelector ( '#config-tab' ) ;
130- if ( firstTab ) firstTab . click ( ) ;
116+ if ( firstTab ) firstTab . click ( ) ;
131117
132118 K8sClient . runFullDiagnostics ( urlVal ) ;
133119 } ) ;
0 commit comments