Skip to content

Commit e7adf2c

Browse files
author
wlanboy
committed
added logic to call data
1 parent 4e25875 commit e7adf2c

File tree

2 files changed

+118
-102
lines changed

2 files changed

+118
-102
lines changed
Lines changed: 117 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,24 @@
11
/**
22
* k8s-client.js
3-
* Zuständig für Kubernetes Kontext-Informationen und Istio-Netzwerkdiagnose.
3+
* Verwaltet Kubernetes Kontext und tiefe Istio/Envoy Diagnose-Daten.
44
*/
55
const K8sClient = (() => {
66

7-
// Private Hilfsfunktion für API-Anfragen an den DiagnosticController
7+
/**
8+
* Private Hilfsfunktion für API-Calls
9+
*/
810
async function apiFetch(endpoint) {
911
const response = await fetch(endpoint);
1012
if (!response.ok) {
11-
throw new Error(`Fehler beim Abrufen der K8s-Daten (Status: ${response.status})`);
13+
throw new Error(`Server-Fehler: ${response.status}`);
1214
}
1315
return await response.json();
1416
}
1517

16-
/**
17-
* Erstellt das HTML für die Anzeige der Istio-Ressourcen
18-
*/
19-
function renderDiagnostics(container, data) {
20-
let html = `
21-
<div class="row g-3">
22-
<div class="col-md-6">
23-
<div class="p-2 border rounded bg-light h-100">
24-
<h6 class="fw-bold border-bottom pb-2">
25-
<i class="bi bi-shuffle me-2"></i>Virtual Services
26-
<span class="badge bg-secondary float-end">${data.virtualServices.length}</span>
27-
</h6>
28-
<div class="list-group list-group-flush shadow-sm mt-2">
29-
${data.virtualServices.map(v => `
30-
<div class="list-group-item p-2 small">
31-
<span class="text-primary fw-bold">${v.metadata.name}</span>
32-
</div>
33-
`).join('') || '<div class="text-muted small p-2 italic">Keine VirtualServices gefunden</div>'}
34-
</div>
35-
</div>
36-
</div>
37-
<div class="col-md-6">
38-
<div class="p-2 border rounded bg-light h-100">
39-
<h6 class="fw-bold border-bottom pb-2">
40-
<i class="bi bi-shield-check me-2"></i>Destination Rules
41-
<span class="badge bg-secondary float-end">${data.destinationRules.length}</span>
42-
</h6>
43-
<div class="list-group list-group-flush shadow-sm mt-2">
44-
${data.destinationRules.map(d => `
45-
<div class="list-group-item p-2 small">
46-
<span class="text-success fw-bold">${d.metadata.name}</span>
47-
</div>
48-
`).join('') || '<div class="text-muted small p-2 italic">Keine DestinationRules gefunden</div>'}
49-
</div>
50-
</div>
51-
</div>
52-
</div>
53-
<div class="mt-3 p-2 bg-dark text-white rounded x-small">
54-
<i class="bi bi-info-circle me-2"></i>Gefiltert nach Host: <strong>${data.host}</strong> im Namespace: <strong>${data.namespace}</strong>
55-
</div>
56-
`;
57-
container.innerHTML = html;
58-
}
59-
6018
return {
61-
// Lädt die Pod- und Namespace-Informationen für die Navbar
19+
/**
20+
* Lädt initialen Kontext für die Navbar (Namespace & Istio Status)
21+
*/
6222
loadContext: async () => {
6323
try {
6424
return await apiFetch('/api/k8s/context');
@@ -68,89 +28,144 @@ const K8sClient = (() => {
6828
}
6929
},
7030

71-
// Führt eine Tiefen-Diagnose für eine Ziel-URL durch
31+
/**
32+
* Hauptfunktion für die Deep-Dive Diagnose
33+
*/
7234
runFullDiagnostics: async (targetUrl) => {
73-
const contentDiv = document.getElementById('istioContent');
74-
if (!contentDiv) return;
35+
const configDiv = document.getElementById('configDisplay');
36+
const errorDiv = document.getElementById('errorDisplay');
37+
const resourceDiv = document.getElementById('resourceDisplay');
7538

76-
contentDiv.innerHTML = `
77-
<div class="text-center p-4">
78-
<div class="spinner-border text-info" role="status"></div>
79-
<div class="mt-2">Analysiere Routing-Regeln im Cluster...</div>
80-
</div>`;
39+
// 1. Loading State für alle Tabs setzen
40+
const spinner = '<div class="text-center p-3"><div class="spinner-border spinner-border-sm text-info"></div><div class="mt-2 x-small text-muted">Abfrage läuft...</div></div>';
41+
if (configDiv) configDiv.innerHTML = spinner;
42+
if (errorDiv) errorDiv.innerHTML = spinner;
43+
if (resourceDiv) resourceDiv.innerHTML = spinner;
8144

8245
try {
83-
// Namespace aus URL extrahieren (Erwartet Format: http://service.namespace.svc...)
46+
// 2. Daten parallel abfragen
47+
// A) Full Report vom Envoy Proxy (Backend getFullReport)
48+
// B) K8s Ressourcen (Backend getIstioResources)
49+
8450
const urlObj = new URL(targetUrl);
85-
const host = urlObj.hostname;
86-
const parts = host.split('.');
87-
88-
// Logik: service.namespace.svc -> namespace ist an Index 1
89-
// Bei "localhost" oder einfachen Namen nehmen wir "default"
90-
const namespace = (parts.length > 1 && parts[1] !== 'svc') ? parts[1] : 'default';
51+
const hostParts = urlObj.hostname.split('.');
52+
// Extrahiere Namespace aus URL (z.B. service.namespace.svc.cluster.local)
53+
const targetNamespace = (hostParts.length > 1 && hostParts[1] !== 'svc') ? hostParts[1] : 'default';
9154

92-
const [vs, dr] = await Promise.all([
93-
apiFetch(`/api/k8s/istio/virtualservice?namespace=${namespace}`),
94-
apiFetch(`/api/k8s/istio/destinationrule?namespace=${namespace}`)
55+
const [report, vsData] = await Promise.all([
56+
apiFetch('/api/k8s/istio/full-report'),
57+
apiFetch(`/api/k8s/istio/virtualservice?namespace=${targetNamespace}`)
9558
]);
9659

97-
// Filtern der Ressourcen, die den Host-Namen im Spec oder Metadaten enthalten
98-
const virtualServices = vs.filter(item => JSON.stringify(item).includes(parts[0]));
99-
const destinationRules = dr.filter(item => JSON.stringify(item).includes(parts[0]));
60+
if (report.error) throw new Error(report.error);
10061

101-
renderDiagnostics(contentDiv, { host, namespace, virtualServices, destinationRules });
102-
} catch (err) {
103-
contentDiv.innerHTML = `
104-
<div class="alert alert-warning">
105-
<i class="bi bi-exclamation-triangle me-2"></i>
106-
<strong>Diagnose eingeschränkt:</strong><br>
107-
${err.message}. Stellen Sie sicher, dass es sich um eine interne Cluster-URL handelt.
62+
// --- RENDERING TAB A: CONFIG & REACHABILITY ---
63+
configDiv.innerHTML = `
64+
<div class="mb-3">
65+
<label class="form-label fw-bold small text-uppercase text-muted">Aktive Upstream Endpunkte (Envoy Clusters):</label>
66+
<pre class="console x-small" style="max-height: 250px; overflow:auto; background: #1e1e1e; color: #4af626; padding: 12px; border-radius: 4px; border: 1px solid #333;">${report.reachability.activeEndpoints || 'Keine Daten verfügbar'}</pre>
67+
<div class="badge bg-primary mt-1">${report.reachability.summary}</div>
68+
</div>
69+
<div class="mt-3 border-top pt-2">
70+
<button class="btn btn-sm btn-outline-secondary" onclick="this.nextElementSibling.classList.toggle('d-none')">
71+
<i class="bi bi-code-slash me-1"></i>Raw Envoy Config Dump (JSON)
72+
</button>
73+
<pre class="console x-small d-none mt-2" style="max-height: 400px; overflow:auto; background: #f8f9fa; color: #333; border: 1px solid #ddd; padding: 10px;">${JSON.stringify(report.reachability.envoyConfig, null, 2)}</pre>
74+
</div>`;
75+
76+
// --- RENDERING TAB B: ACTIVE ERRORS ---
77+
const errorEntries = Object.entries(report.healthDiagnostics.activeErrorMetrics);
78+
if (errorEntries.length === 0) {
79+
errorDiv.innerHTML = `
80+
<div class="alert alert-success border-0 shadow-sm d-flex align-items-center mt-2">
81+
<i class="bi bi-check-circle-fill fs-4 me-3 text-success"></i>
82+
<div><strong>Alles okay!</strong> Keine aktiven Fehlermetriken im Sidecar Proxy für diesen Pod gefunden.</div>
83+
</div>`;
84+
} else {
85+
errorDiv.innerHTML = `
86+
<div class="table-responsive mt-2">
87+
<table class="table table-sm table-hover border small shadow-sm">
88+
<thead class="table-dark">
89+
<tr><th>Envoy Metrik Pfad</th><th class="text-end">Zählerstand</th></tr>
90+
</thead>
91+
<tbody>
92+
${errorEntries.map(([k, v]) => `
93+
<tr>
94+
<td class="font-monospace x-small text-muted">${k}</td>
95+
<td class="text-end fw-bold text-danger">${v}</td>
96+
</tr>
97+
`).join('')}
98+
</tbody>
99+
</table>
100+
<div class="p-2 x-small bg-light border rounded"><i class="bi bi-info-circle me-1"></i> Es werden nur Counter mit Werten > 0 angezeigt.</div>
101+
</div>`;
102+
}
103+
104+
// --- RENDERING TAB C: K8S RESOURCES ---
105+
const vsFiltered = vsData.filter(item => JSON.stringify(item).includes(hostParts[0]));
106+
resourceDiv.innerHTML = `
107+
<div class="p-2">
108+
<h6 class="small fw-bold text-uppercase text-muted mb-3 border-bottom pb-2">Gefundene VirtualServices in '${targetNamespace}'</h6>
109+
<div class="list-group list-group-flush shadow-sm">
110+
${vsFiltered.map(v => `
111+
<div class="list-group-item p-2 small border-start border-4 border-info mb-2 bg-light d-flex justify-content-between">
112+
<span><i class="bi bi-shuffle me-2 text-primary"></i>${v.metadata.name}</span>
113+
<span class="badge bg-white text-dark border">v1alpha3</span>
114+
</div>
115+
`).join('') || '<div class="alert alert-light small text-center">Keine spezifischen Istio-Regeln für diesen Host gefunden.</div>'}
116+
</div>
108117
</div>`;
118+
119+
} catch (err) {
120+
console.error("Diagnostic Error:", err);
121+
const errorMsg = `<div class="alert alert-danger m-3 small"><i class="bi bi-exclamation-triangle-fill me-2"></i>${err.message}</div>`;
122+
configDiv.innerHTML = errorMsg;
123+
errorDiv.innerHTML = errorMsg;
124+
resourceDiv.innerHTML = errorMsg;
109125
}
110126
}
111127
};
112128
})();
113129

114-
// Initialisierung bei DOM-Ready
130+
/**
131+
* Event Listener Initialisierung
132+
*/
115133
document.addEventListener('DOMContentLoaded', async () => {
116134
const contextEl = document.getElementById('k8sContext');
117135
const diagnoseBtn = document.getElementById('k8sDiagnoseBtn');
118-
const istioPanel = document.getElementById('istioPanel');
119136

120-
// 1. Kontext laden (Navbar)
137+
// 1. Initialer Context-Check für die UI
121138
const ctx = await K8sClient.loadContext();
122-
if (contextEl) {
123-
if (ctx.error) {
124-
contextEl.innerHTML = `<span class="badge bg-danger">K8s Offline</span>`;
125-
} else {
126-
contextEl.innerHTML = `
127-
<span class="badge bg-opacity-25 bg-light border me-2" title="Aktueller Namespace">
128-
<i class="bi bi-tags me-1"></i>${ctx.namespace}
129-
</span>
130-
<span class="badge ${ctx.istioSidecar ? 'bg-success' : 'bg-warning text-dark'}" title="Istio Sidecar Status">
131-
<i class="bi bi-shield-check me-1"></i>Istio: ${ctx.istioSidecar ? 'ON' : 'OFF'}
132-
</span>
133-
`;
134-
}
139+
if (contextEl && !ctx.error) {
140+
contextEl.innerHTML = `
141+
<span class="badge bg-dark border me-2" title="Namespace"><i class="bi bi-tags me-1"></i>${ctx.namespace}</span>
142+
<span class="badge ${ctx.istioSidecar ? 'bg-success' : 'bg-warning text-dark'}">
143+
<i class="bi bi-shield-check me-1"></i>Istio: ${ctx.istioSidecar ? 'ON' : 'OFF'}
144+
</span>`;
135145
}
136146

137-
// 2. Event Listener für den Diagnose-Button
147+
// 2. Diagnose Button Logik
138148
if (diagnoseBtn) {
139149
diagnoseBtn.addEventListener('click', () => {
140-
const urlInput = document.getElementById('url').value;
141-
if (!urlInput) {
142-
alert("Bitte geben Sie erst eine Ziel-URL ein, die analysiert werden soll.");
150+
const urlValue = document.getElementById('url').value;
151+
if (!urlValue) {
152+
alert("Bitte eine Ziel-URL eingeben!");
143153
return;
144154
}
145155

146-
// WICHTIG: Die ResultArea und das Panel sichtbar machen
147-
const resultArea = document.getElementById('resultArea');
148-
const istioPanel = document.getElementById('istioPanel');
156+
// UI-Bereiche einblenden
157+
document.getElementById('resultArea').style.display = 'block';
158+
document.getElementById('istioPanel').style.display = 'block';
149159

150-
if (resultArea) resultArea.style.display = 'block';
151-
if (istioPanel) istioPanel.style.display = 'block';
160+
// Automatisch zum ersten Tab wechseln (falls man im Fehler-Tab war)
161+
const firstTabEl = document.querySelector('#config-tab');
162+
if (firstTabEl) {
163+
const tabTrigger = new bootstrap.Tab(firstTabEl);
164+
tabTrigger.show();
165+
}
152166

153-
K8sClient.runFullDiagnostics(urlInput);
167+
// Diagnose starten
168+
K8sClient.runFullDiagnostics(urlValue);
154169
});
155170
}
156171
});

src/main/resources/templates/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ <h6 class="mb-0 fw-bold"><i class="bi bi-clock-history me-2"></i>Historie</h6>
243243
</div>
244244
</div>
245245

246+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
246247
<script src="/js/k8s-client.js"></script>
247248
<script src="/js/http-client.js"></script>
248249

0 commit comments

Comments
 (0)