Skip to content

Commit d347ea3

Browse files
author
wlanboy
committed
split of http and k8s client
1 parent 34a1b1a commit d347ea3

File tree

3 files changed

+273
-50
lines changed

3 files changed

+273
-50
lines changed

src/main/resources/static/js/http-client.js

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => {
1010
const statusBadge = document.getElementById('statusBadge');
1111
const responseTimeText = document.getElementById('responseTime');
1212
const stacktraceArea = document.getElementById('stacktraceArea');
13+
const toggleStackBtn = document.getElementById('toggleStackBtn');
1314

1415
// Historie Elemente
1516
const historyList = document.getElementById('historyList');
@@ -24,10 +25,15 @@ document.addEventListener('DOMContentLoaded', () => {
2425

2526
// --- EVENT LISTENER ---
2627
addHeaderBtn.addEventListener('click', () => addHeaderRow());
27-
28-
document.getElementById('toggleStackBtn').addEventListener('click', () => {
29-
stacktraceArea.style.display = stacktraceArea.style.display === 'none' ? 'block' : 'none';
30-
});
28+
29+
// KORREKTUR: Robuster Toggle-Mechanismus
30+
if (toggleStackBtn) {
31+
toggleStackBtn.addEventListener('click', () => {
32+
const isHidden = stacktraceArea.style.display === 'none' || stacktraceArea.style.display === '';
33+
stacktraceArea.style.display = isHidden ? 'block' : 'none';
34+
toggleStackBtn.textContent = isHidden ? 'Stacktrace ausblenden' : 'Stacktrace Details';
35+
});
36+
}
3137

3238
clearHistoryBtn.addEventListener('click', () => {
3339
requestHistory = [];
@@ -65,7 +71,7 @@ document.addEventListener('DOMContentLoaded', () => {
6571

6672
const duration = Date.now() - startTime;
6773
const data = await response.text();
68-
74+
6975
updateResponseMetadata(response.status, duration);
7076
addToHistory(payload, response.status, duration, data);
7177

@@ -114,6 +120,7 @@ document.addEventListener('DOMContentLoaded', () => {
114120
responseOutput.style.display = 'block';
115121
responseOutput.innerText = "Sende Request an Cluster...";
116122
stacktraceArea.style.display = 'none';
123+
if (toggleStackBtn) toggleStackBtn.textContent = 'Stacktrace Details';
117124
}
118125

119126
function updateResponseMetadata(status, duration) {
@@ -129,7 +136,10 @@ document.addEventListener('DOMContentLoaded', () => {
129136
responseOutput.style.display = 'none';
130137
document.getElementById('errorSummary').innerText = lines[0];
131138
document.getElementById('errorDetail').innerText = lines[1] || "";
139+
132140
stacktraceArea.innerText = stack.trim();
141+
// Sicherstellen, dass er beim Laden des Fehlers erstmal zu ist
142+
stacktraceArea.style.display = 'none';
133143
}
134144

135145
function handleSuccess(data) {
@@ -183,12 +193,16 @@ document.addEventListener('DOMContentLoaded', () => {
183193
document.getElementById('method').value = entry.payload.method;
184194
document.getElementById('body').value = entry.payload.body;
185195
document.getElementById('copyHeaders').checked = entry.payload.copyHeaders;
186-
196+
187197
headerContainer.innerHTML = '';
188198
Object.entries(entry.payload.customHeaders).forEach(([k, v]) => addHeaderRow(k, v));
189199

190200
resultArea.style.display = 'block';
191201
updateResponseMetadata(entry.status, entry.duration);
202+
203+
const istioPanel = document.getElementById('istioPanel');
204+
if (istioPanel) istioPanel.style.display = 'none';
205+
192206
if (entry.status === 502 && entry.responseData.includes("---STACKTRACE---")) {
193207
handleDetailedError(entry.responseData);
194208
} else {
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/**
2+
* k8s-client.js
3+
* Zuständig für Kubernetes Kontext-Informationen und Istio-Netzwerkdiagnose.
4+
*/
5+
const K8sClient = (() => {
6+
7+
// Private Hilfsfunktion für API-Anfragen an den DiagnosticController
8+
async function apiFetch(endpoint) {
9+
const response = await fetch(endpoint);
10+
if (!response.ok) {
11+
throw new Error(`Fehler beim Abrufen der K8s-Daten (Status: ${response.status})`);
12+
}
13+
return await response.json();
14+
}
15+
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+
60+
return {
61+
// Lädt die Pod- und Namespace-Informationen für die Navbar
62+
loadContext: async () => {
63+
try {
64+
return await apiFetch('/api/k8s/context');
65+
} catch (err) {
66+
console.error("K8s Context Error:", err);
67+
return { error: err.message };
68+
}
69+
},
70+
71+
// Führt eine Tiefen-Diagnose für eine Ziel-URL durch
72+
runFullDiagnostics: async (targetUrl) => {
73+
const contentDiv = document.getElementById('istioContent');
74+
if (!contentDiv) return;
75+
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>`;
81+
82+
try {
83+
// Namespace aus URL extrahieren (Erwartet Format: http://service.namespace.svc...)
84+
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';
91+
92+
const [vs, dr] = await Promise.all([
93+
apiFetch(`/api/k8s/istio/virtualservice?namespace=${namespace}`),
94+
apiFetch(`/api/k8s/istio/destinationrule?namespace=${namespace}`)
95+
]);
96+
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]));
100+
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.
108+
</div>`;
109+
}
110+
}
111+
};
112+
})();
113+
114+
// Initialisierung bei DOM-Ready
115+
document.addEventListener('DOMContentLoaded', async () => {
116+
const contextEl = document.getElementById('k8sContext');
117+
const diagnoseBtn = document.getElementById('k8sDiagnoseBtn');
118+
const istioPanel = document.getElementById('istioPanel');
119+
120+
// 1. Kontext laden (Navbar)
121+
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+
}
135+
}
136+
137+
// 2. Event Listener für den Diagnose-Button
138+
if (diagnoseBtn) {
139+
diagnoseBtn.addEventListener('click', () => {
140+
const urlInput = document.getElementById('url').value;
141+
if (!urlInput) {
142+
alert("Bitte geben Sie erst eine Ziel-URL ein.");
143+
return;
144+
}
145+
if (istioPanel) istioPanel.style.display = 'block';
146+
K8sClient.runFullDiagnostics(urlInput);
147+
});
148+
}
149+
});

0 commit comments

Comments
 (0)