@@ -20,6 +20,8 @@ public class K8sDiagnosticService {
2020
2121 private static final Logger logger = LoggerFactory .getLogger (K8sDiagnosticService .class );
2222 private static final String ENVOY_ADMIN_URL = "http://127.0.0.1:15000" ;
23+ private static final String ISTIO_GROUP = "networking.istio.io" ;
24+ private static final String ISTIO_VERSION = "v1alpha3" ;
2325
2426 private final ApiClient apiClient ;
2527 private final CustomObjectsApi customObjectsApi ;
@@ -28,8 +30,8 @@ public class K8sDiagnosticService {
2830 public K8sDiagnosticService () throws IOException {
2931 this .apiClient = Config .defaultClient ();
3032 this .customObjectsApi = new CustomObjectsApi (apiClient );
31- this .restTemplate = new RestTemplate (); // Für Envoy Admin API Calls
32- logger .info ("K8s ApiClient und Diagnose- Service initialisiert." );
33+ this .restTemplate = new RestTemplate ();
34+ logger .info ("K8s Diagnostic Service erfolgreich initialisiert." );
3335 }
3436
3537 public Map <String , Object > getContext () {
@@ -47,76 +49,56 @@ public Map<String, Object> getContext() {
4749 return details ;
4850 }
4951
50- /**
51- * Fragt den lokalen Envoy Proxy nach netzwerkrelevanten Infos
52- */
53-
5452 public Map <String , Object > getFullSidecarDetails () {
55- Map <String , Object > report = new LinkedHashMap <>(); // LinkedHashMap für stabile Reihenfolge im JSON
53+ Map <String , Object > report = new LinkedHashMap <>();
5654
5755 if (!checkIstioSidecar ()) {
58- report .put ("error" , "Istio Sidecar nicht aktiv. Port 15021 reagiert nicht." );
56+ report .put ("error" , "Istio Sidecar Proxy ist nicht aktiv ( Port 15021 nicht erreichbar) ." );
5957 return report ;
6058 }
6159
6260 try {
63- // --- SEKTION A: KONFIGURATION & ERREICHBARKEIT ---
61+ // Sektion A: Erreichbarkeit
6462 Map <String , Object > reachability = new HashMap <>();
6563
66- // Der Config Dump zeigt, was Envoy theoretisch tun sollte
6764 reachability .put ("envoyConfig" , restTemplate .getForObject (ENVOY_ADMIN_URL + "/config_dump" , Map .class ));
68-
69- // Der Cluster-Status zeigt, was Envoy real sieht (inkl. IP-Adressen der Pods)
7065 String clusters = restTemplate .getForObject (ENVOY_ADMIN_URL + "/clusters" , String .class );
7166 reachability .put ("activeEndpoints" , clusters );
7267 reachability .put ("summary" , summarizeClusters (clusters ));
73-
68+ reachability . put ( "envoyConfig" , restTemplate . getForObject ( ENVOY_ADMIN_URL + "/config_dump" , Map . class ));
7469 report .put ("reachability" , reachability );
7570
76- // --- SEKTION B: FEHLER & ANOMALIEN ---
71+ // Sektion B: Gesundheit & Fehler
7772 Map <String , Object > health = new HashMap <>();
78-
79- // 1. Hole alle Statistiken, die auf Fehler hindeuten
8073 String rawStats = restTemplate .getForObject (
8174 ENVOY_ADMIN_URL + "/stats?filter=.*(errors|5xx|timeout|retry|failed|reset|refused|overflow).*" ,
8275 String .class );
83-
84- // 2. Filtere nur die Statistiken, die wirklich Fehler zählen (Wert > 0)
8576 Map <String , String > activeErrors = parseErrorStatsOnly (rawStats );
86- health .put ("activeErrorMetrics" , activeErrors );
77+ health .put ("activeErrorMetrics" , parseErrorStatsOnly ( rawStats ) );
8778 health .put ("errorCount" , activeErrors .size ());
88-
8979 report .put ("healthDiagnostics" , health );
90- report .put ("timestamp" , new Date ());
9180
81+ report .put ("timestamp" , new Date ());
9282 } catch (Exception e ) {
93- logger .error ("Diagnose fehlgeschlagen " , e );
94- report .put ("error" , "Kritischer Diagnosefehler : " + e .getMessage ());
83+ logger .error ("Fehler beim Abruf der Envoy-Details: {} " , e . getMessage () );
84+ report .put ("error" , "Envoy Admin API Fehler : " + e .getMessage ());
9585 }
9686 return report ;
9787 }
9888
99- /**
100- * Filtert Statistiken: Nimmt nur Zeilen mit Werten > 0 auf,
101- * um die "Nadel im Heuhaufen" zu finden.
102- */
103- private Map <String , String > parseErrorStatsOnly (String rawStats ) {
104- Map <String , String > errorMap = new TreeMap <>(); // TreeMap sortiert alphabetisch
89+ private Map <String , String > parseErrorStatsOnly (String rawStats ) {
90+ Map <String , String > errorMap = new TreeMap <>();
10591 if (rawStats != null ) {
10692 rawStats .lines ()
10793 .filter (line -> line .contains (":" ))
10894 .forEach (line -> {
10995 String [] parts = line .split (":" );
110- String key = parts [0 ].trim ();
111- String value = parts [1 ].trim ();
96+ String val = parts [1 ].trim ();
11297 try {
113- // Wir nehmen nur Metriken auf, die einen Wert ungleich 0 haben
114- if (Long .parseLong (value ) > 0 ) {
115- errorMap .put (key , value );
98+ if (Long .parseLong (val ) > 0 ) {
99+ errorMap .put (parts [0 ].trim (), val );
116100 }
117- } catch (NumberFormatException e ) {
118- // Falls es kein Long ist (z.B. Text-Status), nehmen wir es trotzdem auf
119- errorMap .put (key , value );
101+ } catch (Exception ignored ) {
120102 }
121103 });
122104 }
@@ -148,22 +130,33 @@ private Map<String, Object> getEnvoyDetails() {
148130 @ SuppressWarnings ("unchecked" )
149131 public List <Object > getIstioResources (String namespace , String type ) {
150132 try {
151- String plural = type .toLowerCase ().endsWith ("s" ) ? type .toLowerCase () : type .toLowerCase () + "s" ;
152- Object result = customObjectsApi .listNamespacedCustomObject (
153- "networking.istio.io" , "v1alpha3" , namespace , plural ).execute ();
154-
155- return (result instanceof Map ) ? (List <Object >) ((Map <String , Object >) result ).get ("items" )
156- : Collections .emptyList ();
133+ // Normalisierung des Typs (z.B. "gateway" -> "gateways")
134+ String plural = type .toLowerCase ();
135+ if (!plural .endsWith ("s" )) {
136+ plural += "s" ;
137+ }
138+
139+ // Neuer Fluent-API Stil (ab SDK v12)
140+ // Wir übergeben nur die 4 erforderlichen Parameter
141+ Object result = customObjectsApi
142+ .listNamespacedCustomObject (ISTIO_GROUP , ISTIO_VERSION , namespace , plural )
143+ .execute ();
144+
145+ if (result instanceof Map ) {
146+ Map <String , Object > resultMap = (Map <String , Object >) result ;
147+ return (List <Object >) resultMap .get ("items" );
148+ }
157149 } catch (Exception e ) {
158- logger .error ("Fehler beim Abrufen der Istio-Ressourcen ({}): {}" , type , e .getMessage ());
159- return Collections .singletonList (Map .of ("error" , e .getMessage ()));
150+ logger .warn ("Fehler beim Laden von {} in {}: {}" , type , namespace , e .getMessage ());
160151 }
161- }
152+ return Collections .emptyList ();
153+ }
162154
163155 private String summarizeClusters (String rawClusters ) {
164- if (rawClusters == null )
165- return "Keine Daten" ;
166- return (long ) rawClusters .split ("\n " ).length + " bekannte Upstream-Endpunkte" ;
156+ if (rawClusters == null || rawClusters .isBlank ())
157+ return "Keine Upstream-Daten" ;
158+ long count = rawClusters .lines ().count ();
159+ return count + " aktive Upstream-Cluster-Einträge" ;
167160 }
168161
169162 private Map <String , String > parseStats (String rawStats ) {
@@ -189,7 +182,7 @@ private String getCurrentNamespace() {
189182
190183 private boolean checkIstioSidecar () {
191184 try (Socket socket = new Socket ()) {
192- socket .connect (new InetSocketAddress ("127.0.0.1" , 15021 ), 150 );
185+ socket .connect (new InetSocketAddress ("127.0.0.1" , 15021 ), 200 );
193186 return true ;
194187 } catch (Exception e ) {
195188 return false ;
0 commit comments