You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/06/23 10:17:49 UTC

[camel] 01/03: CAMEL-18171: camel-kubernetes - Add configmap property placeholder function

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

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

commit bd53c058d9f9d911ed6ddce88a6ebac3292af356
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Jun 23 10:52:38 2022 +0200

    CAMEL-18171: camel-kubernetes - Add configmap property placeholder function
---
 components/camel-kubernetes/README.md              |  38 ++++++++
 .../org/apache/camel/properties-function/configmap |   2 +
 .../properties/ConfigMapPropertiesFunction.java    | 104 +++++++++++++++++++++
 .../ConfigMapPropertiesFunctionRouteTest.java      |  81 ++++++++++++++++
 .../ConfigMapPropertiesFunctionTest.java           |  64 +++++++++++++
 5 files changed, 289 insertions(+)

diff --git a/components/camel-kubernetes/README.md b/components/camel-kubernetes/README.md
index bc14b34380a..59670dd2689 100644
--- a/components/camel-kubernetes/README.md
+++ b/components/camel-kubernetes/README.md
@@ -4,6 +4,8 @@
 
 This component contains unit and integration tests. Some of them - like the consumer ones - require a Kubernetes environment. 
 
+## Running using Kind
+
 It is possible to run the integration tests using Kind. To do so, follow these steps:
 
 1. Create a cluster:
@@ -30,3 +32,39 @@ export KUBE_HOST=https://localhost:$KIND_PORT
 mvn -Dkubernetes.test.auth="$KUBE_TOKEN" -Dkubernetes.test.host=$KUBE_HOST -Dkubernetes.test.host.k8s=true clean verify
 ```
 
+
+## Running using Minikube
+
+It is possible to run the integration tests using Minikube. To do so, follow these steps:
+
+1. Create a cluster:
+
+```
+minikube start
+```
+
+2. Get the auth token:
+
+```
+export KUBE_TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}"|base64 --decode)
+```
+
+4. Get the host:
+
+Find out the URL where the control plane is running:
+
+````
+kubectl cluster-info
+````
+
+And then set that as export, for example:
+
+```
+export KUBE_HOST=https://127.0.0.1:50179
+```
+
+5. Run the test:
+```
+mvn -Dkubernetes.test.auth="$KUBE_TOKEN" -Dkubernetes.test.host=$KUBE_HOST -Dkubernetes.test.host.k8s=true clean verify
+```
+
diff --git a/components/camel-kubernetes/src/generated/resources/META-INF/services/org/apache/camel/properties-function/configmap b/components/camel-kubernetes/src/generated/resources/META-INF/services/org/apache/camel/properties-function/configmap
new file mode 100644
index 00000000000..fd8e5d4f6d4
--- /dev/null
+++ b/components/camel-kubernetes/src/generated/resources/META-INF/services/org/apache/camel/properties-function/configmap
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.kubernetes.properties.ConfigMapPropertiesFunction
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunction.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunction.java
new file mode 100644
index 00000000000..d6bcb117730
--- /dev/null
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunction.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.kubernetes.properties;
+
+import java.util.Base64;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.spi.PropertiesFunction;
+import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+
+/**
+ * A {@link PropertiesFunction} that can lookup from Kubernetes configmaps.
+ */
+@org.apache.camel.spi.annotations.PropertiesFunction("configmap")
+public class ConfigMapPropertiesFunction extends ServiceSupport implements PropertiesFunction, CamelContextAware {
+
+    private CamelContext camelContext;
+    private KubernetesClient client;
+
+    @Override
+    protected void doInit() throws Exception {
+        if (client == null) {
+            client = CamelContextHelper.findSingleByType(camelContext, KubernetesClient.class);
+        }
+        ObjectHelper.notNull(client, "KubernetesClient must be configured");
+    }
+
+    @Override
+    public String getName() {
+        return "configmap";
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    public KubernetesClient getClient() {
+        return client;
+    }
+
+    public void setClient(KubernetesClient client) {
+        this.client = client;
+    }
+
+    @Override
+    public String apply(String remainder) {
+        String defaultValue = StringHelper.after(remainder, ":");
+
+        String name = StringHelper.before(remainder, "/");
+        String key = StringHelper.after(remainder, "/");
+
+        if (name == null || key == null) {
+            return defaultValue;
+        }
+
+        String answer = null;
+        ConfigMap cm = client.configMaps().withName(name).get();
+        if (cm != null) {
+            answer = cm.getData() != null ? cm.getData().get(key) : null;
+            if (answer == null) {
+                // maybe a binary data
+                answer = cm.getBinaryData() != null ? cm.getBinaryData().get(key) : null;
+                if (answer != null) {
+                    // need to decode base64
+                    byte[] data = Base64.getDecoder().decode(answer);
+                    if (data != null) {
+                        answer = new String(data);
+                    }
+                }
+            }
+        }
+        if (answer == null) {
+            return defaultValue;
+        }
+
+        return answer;
+    }
+}
diff --git a/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunctionRouteTest.java b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunctionRouteTest.java
new file mode 100644
index 00000000000..e4e65b806c8
--- /dev/null
+++ b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunctionRouteTest.java
@@ -0,0 +1,81 @@
+package org.apache.camel.component.kubernetes.properties;
+
+import java.util.Map;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.client.ConfigBuilder;
+import io.fabric8.kubernetes.client.DefaultKubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.kubernetes.KubernetesTestSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperties;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+
+@EnabledIfSystemProperties({
+        @EnabledIfSystemProperty(named = "kubernetes.test.auth", matches = ".*", disabledReason = "Requires kubernetes"),
+        @EnabledIfSystemProperty(named = "kubernetes.test.host", matches = ".*", disabledReason = "Requires kubernetes"),
+        @EnabledIfSystemProperty(named = "kubernetes.test.host.k8s", matches = "true", disabledReason = "Requires kubernetes"),
+})
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class ConfigMapPropertiesFunctionRouteTest extends KubernetesTestSupport {
+
+    private KubernetesClient client;
+    private ConfigMap cm;
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .transform().simple("Hello ${body} we are at {{configmap:myconfig/bar}}");
+            }
+        };
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+
+        ConfigBuilder builder = new ConfigBuilder();
+        builder.withOauthToken(authToken);
+        builder.withMasterUrl(host);
+        client = new DefaultKubernetesClient(builder.build());
+        context.getRegistry().bind("KubernetesClient", client);
+
+        Map<String, String> data = Map.of("foo", "123", "bar", "Moes Bar");
+        ConfigMap cm = new ConfigMapBuilder().editOrNewMetadata().withName("myconfig").endMetadata().withData(data).build();
+        this.cm = client.configMaps().createOrReplace(cm);
+
+        return context;
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (client != null && cm != null) {
+            try {
+                client.configMaps().delete(cm);
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+
+        super.tearDown();
+    }
+
+    @Test
+    @Order(1)
+    public void configMapPropertiesFunction() throws Exception {
+        String out = template.requestBody("direct:start", "Jack", String.class);
+        Assertions.assertEquals("Hello Jack we are at Moes Bar", out);
+    }
+
+}
diff --git a/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunctionTest.java b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunctionTest.java
new file mode 100644
index 00000000000..80cef7af3b2
--- /dev/null
+++ b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/properties/ConfigMapPropertiesFunctionTest.java
@@ -0,0 +1,64 @@
+package org.apache.camel.component.kubernetes.properties;
+
+import java.util.Map;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.client.ConfigBuilder;
+import io.fabric8.kubernetes.client.DefaultKubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import org.apache.camel.component.kubernetes.KubernetesTestSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperties;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+
+@EnabledIfSystemProperties({
+        @EnabledIfSystemProperty(named = "kubernetes.test.auth", matches = ".*", disabledReason = "Requires kubernetes"),
+        @EnabledIfSystemProperty(named = "kubernetes.test.host", matches = ".*", disabledReason = "Requires kubernetes"),
+        @EnabledIfSystemProperty(named = "kubernetes.test.host.k8s", matches = "true", disabledReason = "Requires kubernetes"),
+})
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class ConfigMapPropertiesFunctionTest extends KubernetesTestSupport {
+
+    @Test
+    @Order(1)
+    public void configMapPropertiesFunction() throws Exception {
+        ConfigBuilder builder = new ConfigBuilder();
+        builder.withOauthToken(authToken);
+        builder.withMasterUrl(host);
+
+        KubernetesClient client = new DefaultKubernetesClient(builder.build());
+
+        Map<String, String> data = Map.of("foo", "123", "bar", "Moes Bar");
+        ConfigMap cm = new ConfigMapBuilder().editOrNewMetadata().withName("myconfig").endMetadata().withData(data).build();
+        client.configMaps().createOrReplace(cm);
+
+        try {
+            ConfigMapPropertiesFunction cmf = new ConfigMapPropertiesFunction();
+            cmf.setClient(client);
+            cmf.setCamelContext(context);
+            cmf.start();
+
+            String out = cmf.apply("myconfig/foo");
+            Assertions.assertEquals("123", out);
+
+            out = cmf.apply("myconfig/unknown");
+            Assertions.assertNull(out);
+
+            out = cmf.apply("myconfig/unknown:444");
+            Assertions.assertEquals("444", out);
+
+            out = cmf.apply("myconfig/bar");
+            Assertions.assertEquals("Moes Bar", out);
+
+            cmf.stop();
+        } finally {
+            client.configMaps().delete(cm);
+        }
+    }
+
+}