This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new fe14ff190185 CAMEL-25384: handle unconfigured Kubernetes vault 
consoles (#27493)
fe14ff190185 is described below

commit fe14ff190185dfb021b4132d5c86589f30d6dbed
Author: Andrea Cosentino <[email protected]>
AuthorDate: Wed Oct 7 15:02:54 2026 +0200

    CAMEL-25384: handle unconfigured Kubernetes vault consoles (#27493)
    
    When camel-kubernetes is present without configured vault resource names, 
its developer consoles threw while Camel JBang collected status, so the 
integration did not show in camel ps and camel get.
    
    Handle missing vault configurations and null or empty resource-name lists 
in both JSON and text output. Read ConfigMaps names and refresh settings from 
the ConfigMaps vault, and handle its absent client in local mode. Configured 
names stay sorted. The corrected ConfigMaps output is documented in the 4.23 
upgrade guide.
    
    Co-authored-by: Codex <[email protected]>
    Signed-off-by: Andrea Cosentino <[email protected]>
---
 .../config_maps/vault/ConfigmapsDevConsole.java    | 40 ++++++----
 .../secrets/vault/SecretsDevConsole.java           | 15 ++--
 .../vault/ConfigmapsDevConsoleTest.java            | 89 ++++++++++++++++++++--
 .../secrets/vault/SecretsDevConsoleTest.java       | 89 ++++++++++++++++++++--
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  7 ++
 5 files changed, 209 insertions(+), 31 deletions(-)

diff --git 
a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/config_maps/vault/ConfigmapsDevConsole.java
 
b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/config_maps/vault/ConfigmapsDevConsole.java
index 1c072f5938bf..11966ebfbd50 100644
--- 
a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/config_maps/vault/ConfigmapsDevConsole.java
+++ 
b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/config_maps/vault/ConfigmapsDevConsole.java
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import io.fabric8.kubernetes.client.KubernetesClient;
 import 
org.apache.camel.component.kubernetes.properties.ConfigMapPropertiesFunction;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.PeriodTaskScheduler;
@@ -32,7 +33,6 @@ import org.apache.camel.support.console.AbstractDevConsole;
 import org.apache.camel.util.TimeUtils;
 import org.apache.camel.util.json.JsonRecordSupport;
 import org.apache.camel.vault.KubernetesConfigMapVaultConfiguration;
-import org.apache.camel.vault.KubernetesVaultConfiguration;
 
 @DevConsole(name = "kubernetes-configmaps", displayName = "Kubernetes Config 
Maps",
             description = "Kubernetes Cluster Config Maps")
@@ -80,10 +80,13 @@ public class ConfigmapsDevConsole extends 
AbstractDevConsole {
 
         if (propertiesFunction != null) {
             sb.append("Kubernetes Config maps Cluster:");
-            sb.append(String.format("%n    Master Url: %s", 
propertiesFunction.getClient().getMasterUrl()));
-            sb.append("\n    Login: OAuth Token");
-            KubernetesVaultConfiguration kubernetes
-                    = 
getCamelContext().getVaultConfiguration().getKubernetesVaultConfiguration();
+            KubernetesClient client = propertiesFunction.getClient();
+            if (client != null && client.getMasterUrl() != null) {
+                sb.append(String.format("%n    Master Url: %s", 
client.getMasterUrl().toString()));
+                sb.append("\n    Login: OAuth Token");
+            }
+            KubernetesConfigMapVaultConfiguration kubernetes
+                    = 
getCamelContext().getVaultConfiguration().getKubernetesConfigMapVaultConfiguration();
             if (kubernetes != null) {
                 sb.append(String.format("%n    Refresh Enabled: %s", 
kubernetes.isRefreshEnabled()));
             }
@@ -94,10 +97,12 @@ public class ConfigmapsDevConsole extends 
AbstractDevConsole {
             }
             List<String> sorted = new ArrayList<>();
             if (kubernetes != null) {
-                sb.append("\n\nSecrets in use:");
+                sb.append("\n\nConfig maps in use:");
 
-                sorted = new 
ArrayList<>(List.of(kubernetes.getSecrets().split(",")));
-                Collections.sort(sorted);
+                if (kubernetes.getConfigmaps() != null && 
!kubernetes.getConfigmaps().isEmpty()) {
+                    sorted = new 
ArrayList<>(List.of(kubernetes.getConfigmaps().split(",")));
+                    Collections.sort(sorted);
+                }
             }
 
             for (String sec : sorted) {
@@ -113,11 +118,15 @@ public class ConfigmapsDevConsole extends 
AbstractDevConsole {
         String masterUrl = null;
         String login = null;
         if (propertiesFunction != null) {
-            masterUrl = 
propertiesFunction.getClient().getMasterUrl().toString();
-            login = "OAuth Token";
+            KubernetesClient client = propertiesFunction.getClient();
+            if (client != null && client.getMasterUrl() != null) {
+                masterUrl = client.getMasterUrl().toString();
+                login = "OAuth Token";
+            }
         }
 
-        KubernetesVaultConfiguration kubernetes = 
getCamelContext().getVaultConfiguration().getKubernetesVaultConfiguration();
+        KubernetesConfigMapVaultConfiguration kubernetes
+                = 
getCamelContext().getVaultConfiguration().getKubernetesConfigMapVaultConfiguration();
         Boolean refreshEnabled = kubernetes != null ? 
kubernetes.isRefreshEnabled() : null;
 
         Long startCheckTimestamp = null;
@@ -128,10 +137,11 @@ public class ConfigmapsDevConsole extends 
AbstractDevConsole {
             }
         }
 
-        // NOTE: kubernetes is dereferenced unconditionally here, same as the 
original code -
-        // preserved as-is rather than fixed, since this migration is about 
the response contract
-        List<String> sorted = new 
ArrayList<>(List.of(kubernetes.getSecrets().split(",")));
-        Collections.sort(sorted);
+        List<String> sorted = new ArrayList<>();
+        if (kubernetes != null && kubernetes.getConfigmaps() != null && 
!kubernetes.getConfigmaps().isEmpty()) {
+            sorted.addAll(List.of(kubernetes.getConfigmaps().split(",")));
+            Collections.sort(sorted);
+        }
 
         List<ConfigMapEntry> configmaps = new ArrayList<>();
         for (String sec : sorted) {
diff --git 
a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/secrets/vault/SecretsDevConsole.java
 
b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/secrets/vault/SecretsDevConsole.java
index 82b6d408cfa0..fc8fc8bde7a2 100644
--- 
a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/secrets/vault/SecretsDevConsole.java
+++ 
b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/secrets/vault/SecretsDevConsole.java
@@ -97,8 +97,10 @@ public class SecretsDevConsole extends AbstractDevConsole {
             if (kubernetes != null) {
                 sb.append("\n\nSecrets in use:");
 
-                sorted = new 
ArrayList<>(List.of(kubernetes.getSecrets().split(",")));
-                Collections.sort(sorted);
+                if (kubernetes.getSecrets() != null && 
!kubernetes.getSecrets().isEmpty()) {
+                    sorted = new 
ArrayList<>(List.of(kubernetes.getSecrets().split(",")));
+                    Collections.sort(sorted);
+                }
             }
 
             for (String sec : sorted) {
@@ -133,10 +135,11 @@ public class SecretsDevConsole extends AbstractDevConsole 
{
             }
         }
 
-        // NOTE: kubernetes is dereferenced unconditionally here, same as the 
original code - preserved
-        // as-is rather than fixed, since this migration is about the response 
contract
-        List<String> sorted = new 
ArrayList<>(List.of(kubernetes.getSecrets().split(",")));
-        Collections.sort(sorted);
+        List<String> sorted = new ArrayList<>();
+        if (kubernetes != null && kubernetes.getSecrets() != null && 
!kubernetes.getSecrets().isEmpty()) {
+            sorted.addAll(List.of(kubernetes.getSecrets().split(",")));
+            Collections.sort(sorted);
+        }
 
         List<SecretEntry> secrets = new ArrayList<>();
         for (String sec : sorted) {
diff --git 
a/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/config_maps/vault/ConfigmapsDevConsoleTest.java
 
b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/config_maps/vault/ConfigmapsDevConsoleTest.java
index 1bedf7ef554f..dafda618a0c5 100644
--- 
a/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/config_maps/vault/ConfigmapsDevConsoleTest.java
+++ 
b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/config_maps/vault/ConfigmapsDevConsoleTest.java
@@ -16,19 +16,24 @@
  */
 package org.apache.camel.component.kubernetes.config_maps.vault;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import 
org.apache.camel.component.kubernetes.properties.ConfigMapPropertiesFunction;
 import org.apache.camel.console.DevConsole;
 import org.apache.camel.support.PluginHelper;
+import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.test.junit6.CamelTestSupport;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
-/**
- * ConfigmapsDevConsole unconditionally dereferences the Kubernetes vault 
configuration's secrets list (a pre-existing
- * bug, preserved as-is by this migration), so calling it without a real 
Kubernetes vault configuration would NPE; this
- * test is limited to verifying the console registers correctly.
- */
 public class ConfigmapsDevConsoleTest extends CamelTestSupport {
 
     @Test
@@ -38,4 +43,78 @@ public class ConfigmapsDevConsoleTest extends 
CamelTestSupport {
         assertEquals("camel", con.getGroup());
         assertEquals("kubernetes-configmaps", con.getId());
     }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    public void testJsonWithoutConfiguredNames(String names) throws Exception {
+        
context.getVaultConfiguration().kubernetesConfigmaps().setConfigmaps(names);
+        DevConsole con = startConsole();
+        Map<?, ?> out = (Map<?, ?>) con.call(DevConsole.MediaType.JSON);
+        assertEquals(List.of(), out.get("configmaps"));
+        assertFalse(out.containsKey("masterUrl"));
+        assertFalse(out.containsKey("login"));
+    }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    public void testTextWithoutConfiguredNames(String names) throws Exception {
+        
context.getVaultConfiguration().kubernetesConfigmaps().setConfigmaps(names);
+        DevConsole con = startConsole();
+        String out = (String) con.call(DevConsole.MediaType.TEXT);
+        assertTrue(out.contains("Config maps in use:"));
+        assertFalse(out.contains("Master Url:"));
+        assertFalse(out.contains("Login:"));
+    }
+
+    @Test
+    public void testConfiguredNamesJson() throws Exception {
+        
context.getVaultConfiguration().kubernetesConfigmaps().setConfigmaps("zulu,alpha");
+        context.getVaultConfiguration().kubernetes().setSecrets("unrelated");
+        
context.getVaultConfiguration().kubernetesConfigmaps().setRefreshEnabled(true);
+        context.getVaultConfiguration().kubernetes().setRefreshEnabled(false);
+        DevConsole con = startConsole();
+        Map<?, ?> out = (Map<?, ?>) con.call(DevConsole.MediaType.JSON);
+        assertEquals(true, out.get("refreshEnabled"));
+        assertEquals(List.of(Map.of("name", "alpha"), Map.of("name", "zulu")), 
out.get("configmaps"));
+    }
+
+    @Test
+    public void testConfiguredNamesText() throws Exception {
+        
context.getVaultConfiguration().kubernetesConfigmaps().setConfigmaps("zulu,alpha");
+        context.getVaultConfiguration().kubernetes().setSecrets("unrelated");
+        DevConsole con = startConsole();
+        String out = (String) con.call(DevConsole.MediaType.TEXT);
+        assertTrue(out.contains("Config maps in use:"));
+        assertTrue(out.contains("alpha"));
+        assertTrue(out.contains("zulu"));
+        assertTrue(out.indexOf("alpha") < out.indexOf("zulu"));
+        assertFalse(out.contains("unrelated"));
+    }
+
+    @Test
+    public void testJsonWithoutVaultConfiguration() throws Exception {
+        
context.getVaultConfiguration().setKubernetesConfigMapVaultConfiguration(null);
+        DevConsole con = startConsole();
+        Map<?, ?> out = (Map<?, ?>) con.call(DevConsole.MediaType.JSON);
+        assertEquals(List.of(), out.get("configmaps"));
+        assertFalse(out.containsKey("refreshEnabled"));
+    }
+
+    @Test
+    public void testTextWithoutVaultConfiguration() throws Exception {
+        
context.getVaultConfiguration().setKubernetesConfigMapVaultConfiguration(null);
+        DevConsole con = startConsole();
+        String out = (String) con.call(DevConsole.MediaType.TEXT);
+        assertFalse(out.contains("Refresh Enabled:"));
+    }
+
+    private DevConsole startConsole() throws Exception {
+        Properties properties = new Properties();
+        properties.setProperty("camel.kubernetes-config.local-mode", "true");
+        context.getPropertiesComponent().setInitialProperties(properties);
+        context.getPropertiesComponent().addPropertiesFunction(new 
ConfigMapPropertiesFunction());
+        DevConsole con = 
PluginHelper.getDevConsoleResolver(context).resolveDevConsole("kubernetes-configmaps");
+        ServiceHelper.startService(con);
+        return con;
+    }
 }
diff --git 
a/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/secrets/vault/SecretsDevConsoleTest.java
 
b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/secrets/vault/SecretsDevConsoleTest.java
index 35688482ee46..4b2b06280145 100644
--- 
a/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/secrets/vault/SecretsDevConsoleTest.java
+++ 
b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/secrets/vault/SecretsDevConsoleTest.java
@@ -16,19 +16,24 @@
  */
 package org.apache.camel.component.kubernetes.secrets.vault;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import 
org.apache.camel.component.kubernetes.properties.SecretPropertiesFunction;
 import org.apache.camel.console.DevConsole;
 import org.apache.camel.support.PluginHelper;
+import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.test.junit6.CamelTestSupport;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
-/**
- * SecretsDevConsole unconditionally dereferences the Kubernetes vault 
configuration's secrets list (a pre-existing bug,
- * preserved as-is by this migration), so calling it without a real Kubernetes 
vault configuration would NPE; this test
- * is limited to verifying the console registers correctly.
- */
 public class SecretsDevConsoleTest extends CamelTestSupport {
 
     @Test
@@ -38,4 +43,78 @@ public class SecretsDevConsoleTest extends CamelTestSupport {
         assertEquals("camel", con.getGroup());
         assertEquals("kubernetes-secrets", con.getId());
     }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    public void testJsonWithoutConfiguredNames(String names) throws Exception {
+        context.getVaultConfiguration().kubernetes().setSecrets(names);
+        DevConsole con = startConsole();
+        Map<?, ?> out = (Map<?, ?>) con.call(DevConsole.MediaType.JSON);
+        assertEquals(List.of(), out.get("secrets"));
+        assertFalse(out.containsKey("masterUrl"));
+        assertFalse(out.containsKey("login"));
+    }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    public void testTextWithoutConfiguredNames(String names) throws Exception {
+        context.getVaultConfiguration().kubernetes().setSecrets(names);
+        DevConsole con = startConsole();
+        String out = (String) con.call(DevConsole.MediaType.TEXT);
+        assertTrue(out.contains("Secrets in use:"));
+        assertFalse(out.contains("Master Url:"));
+        assertFalse(out.contains("Login:"));
+    }
+
+    @Test
+    public void testConfiguredNamesJson() throws Exception {
+        context.getVaultConfiguration().kubernetes().setSecrets("zulu,alpha");
+        
context.getVaultConfiguration().kubernetesConfigmaps().setConfigmaps("unrelated");
+        context.getVaultConfiguration().kubernetes().setRefreshEnabled(true);
+        
context.getVaultConfiguration().kubernetesConfigmaps().setRefreshEnabled(false);
+        DevConsole con = startConsole();
+        Map<?, ?> out = (Map<?, ?>) con.call(DevConsole.MediaType.JSON);
+        assertEquals(true, out.get("refreshEnabled"));
+        assertEquals(List.of(Map.of("name", "alpha"), Map.of("name", "zulu")), 
out.get("secrets"));
+    }
+
+    @Test
+    public void testConfiguredNamesText() throws Exception {
+        context.getVaultConfiguration().kubernetes().setSecrets("zulu,alpha");
+        
context.getVaultConfiguration().kubernetesConfigmaps().setConfigmaps("unrelated");
+        DevConsole con = startConsole();
+        String out = (String) con.call(DevConsole.MediaType.TEXT);
+        assertTrue(out.contains("Secrets in use:"));
+        assertTrue(out.contains("alpha"));
+        assertTrue(out.contains("zulu"));
+        assertTrue(out.indexOf("alpha") < out.indexOf("zulu"));
+        assertFalse(out.contains("unrelated"));
+    }
+
+    @Test
+    public void testJsonWithoutVaultConfiguration() throws Exception {
+        context.getVaultConfiguration().setKubernetesVaultConfiguration(null);
+        DevConsole con = startConsole();
+        Map<?, ?> out = (Map<?, ?>) con.call(DevConsole.MediaType.JSON);
+        assertEquals(List.of(), out.get("secrets"));
+        assertFalse(out.containsKey("refreshEnabled"));
+    }
+
+    @Test
+    public void testTextWithoutVaultConfiguration() throws Exception {
+        context.getVaultConfiguration().setKubernetesVaultConfiguration(null);
+        DevConsole con = startConsole();
+        String out = (String) con.call(DevConsole.MediaType.TEXT);
+        assertFalse(out.contains("Refresh Enabled:"));
+    }
+
+    private DevConsole startConsole() throws Exception {
+        Properties properties = new Properties();
+        properties.setProperty("camel.kubernetes-config.local-mode", "true");
+        context.getPropertiesComponent().setInitialProperties(properties);
+        context.getPropertiesComponent().addPropertiesFunction(new 
SecretPropertiesFunction());
+        DevConsole con = 
PluginHelper.getDevConsoleResolver(context).resolveDevConsole("kubernetes-secrets");
+        ServiceHelper.startService(con);
+        return con;
+    }
 }
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 529fd7067b5a..443976a4fa07 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -4775,3 +4775,10 @@ consumes `AiToolResult` and handles its variants 
exhaustively — for example an
 `AiToolResult.ExecutionError` — must add a branch for `AuthorizationDenied` 
and relay its `message()` to the model as
 a refusal (do not rethrow). The in-tree adapters (camel-openai, 
camel-spring-ai-chat, camel-langchain4j-agent and the
 MCP server bridge) already handle it.
+
+=== camel-kubernetes
+
+The `kubernetes-configmaps` developer console now reports the config map names 
and refresh settings from
+`camel.vault.kubernetescm` instead of reading the Kubernetes secrets vault 
configuration.
+Its text output labels the list `Config maps in use:` instead of `Secrets in 
use:`.
+Both Kubernetes vault consoles return empty lists when no resource names are 
configured.

Reply via email to