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

pcongiusti 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 2e652dd2e48 feat(core): auto cloud native properties
2e652dd2e48 is described below

commit 2e652dd2e48c287dc65487683714f120da9d7683
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Thu Aug 8 14:41:23 2024 +0200

    feat(core): auto cloud native properties
    
    Introduced camel.main.cloudPropertiesLocation which, if exists, would look 
into the related csv directories to find properties as
    possibly set in cloud native environments such as Kubernetes.
    
    Closes CAMEL-21036
---
 .../main/camel-main-configuration-metadata.json    |  1 +
 .../MainConfigurationPropertiesConfigurer.java     |  6 +++
 .../camel-main-configuration-metadata.json         |  1 +
 core/camel-main/src/main/docs/main.adoc            |  3 +-
 .../org/apache/camel/main/BaseMainSupport.java     | 52 ++++++++++++++++++++++
 .../camel/main/DefaultConfigurationProperties.java | 21 +++++++++
 .../java/org/apache/camel/main/MainConstants.java  |  1 +
 .../camel/main/MainPropertyPlaceholderTest.java    | 29 ++++++++++++
 .../camel-main/src/test/resources/cloud.properties | 17 +++++++
 .../k8s/etc/camel/conf.d/_configmaps/my-prop-1.txt |  1 +
 .../k8s/etc/camel/conf.d/_secrets/my-prop-2.txt    |  1 +
 11 files changed, 132 insertions(+), 1 deletion(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index a6b95b6a6e7..8185a3cf983 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -34,6 +34,7 @@
     { "name": "camel.main.beanPostProcessorEnabled", "description": "Can be 
used to turn off bean post processing. Be careful to turn this off, as this 
means that beans that use Camel annotations such as 
org.apache.camel.EndpointInject , org.apache.camel.ProducerTemplate , 
org.apache.camel.Produce , org.apache.camel.Consume etc will not be injected 
and in use. Turning this off should only be done if you are sure you do not use 
any of these Camel features. Not all runtimes allow turning t [...]
     { "name": "camel.main.camelEventsTimestampEnabled", "description": 
"Whether to include timestamps for all emitted Camel Events. Enabling this 
allows to know fine-grained at what time each event was emitted, which can be 
used for reporting to report exactly the time of the events. This is by default 
false to avoid the overhead of including this information.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": [...]
     { "name": "camel.main.caseInsensitiveHeaders", "description": "Whether to 
use case sensitive or insensitive headers. Important: When using case sensitive 
(this is set to false). Then the map is case sensitive which means headers such 
as content-type and Content-Type are two different keys which can be a problem 
for some protocols such as HTTP based, which rely on case insensitive headers. 
However case sensitive implementations can yield faster performance. Therefore 
use case sensitiv [...]
+    { "name": "camel.main.cloudPropertiesLocation", "description": "Sets the 
locations (comma separated values) where to find properties configuration as 
defined for cloud native environments such as Kubernetes. You should only scan 
text based mounted configuration.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "string", 
"javaType": "java.lang.String" },
     { "name": "camel.main.compileWorkDir", "description": "Work directory for 
compiler. Can be used to write compiled classes or other resources.", 
"sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": 
"string", "javaType": "java.lang.String" },
     { "name": "camel.main.configurationClasses", "description": "Sets classes 
names that will be used to configure the camel context as example by providing 
custom beans through org.apache.camel.BindToRegistry annotation.", 
"sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": 
"string", "javaType": "java.lang.String" },
     { "name": "camel.main.configurations", "description": "Sets the 
configuration objects used to configure the camel context.", "sourceType": 
"org.apache.camel.main.MainConfigurationProperties", "type": "object", 
"javaType": "java.util.List" },
diff --git 
a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
 
b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
index fab9993930d..9e1a410fd6b 100644
--- 
a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
+++ 
b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
@@ -53,6 +53,8 @@ public class MainConfigurationPropertiesConfigurer extends 
org.apache.camel.supp
         case "camelEventsTimestampEnabled": 
target.setCamelEventsTimestampEnabled(property(camelContext, boolean.class, 
value)); return true;
         case "caseinsensitiveheaders":
         case "caseInsensitiveHeaders": 
target.setCaseInsensitiveHeaders(property(camelContext, boolean.class, value)); 
return true;
+        case "cloudpropertieslocation":
+        case "cloudPropertiesLocation": 
target.setCloudPropertiesLocation(property(camelContext, 
java.lang.String.class, value)); return true;
         case "compileworkdir":
         case "compileWorkDir": target.setCompileWorkDir(property(camelContext, 
java.lang.String.class, value)); return true;
         case "configurationclasses":
@@ -293,6 +295,8 @@ public class MainConfigurationPropertiesConfigurer extends 
org.apache.camel.supp
         case "camelEventsTimestampEnabled": return boolean.class;
         case "caseinsensitiveheaders":
         case "caseInsensitiveHeaders": return boolean.class;
+        case "cloudpropertieslocation":
+        case "cloudPropertiesLocation": return java.lang.String.class;
         case "compileworkdir":
         case "compileWorkDir": return java.lang.String.class;
         case "configurationclasses":
@@ -534,6 +538,8 @@ public class MainConfigurationPropertiesConfigurer extends 
org.apache.camel.supp
         case "camelEventsTimestampEnabled": return 
target.isCamelEventsTimestampEnabled();
         case "caseinsensitiveheaders":
         case "caseInsensitiveHeaders": return 
target.isCaseInsensitiveHeaders();
+        case "cloudpropertieslocation":
+        case "cloudPropertiesLocation": return 
target.getCloudPropertiesLocation();
         case "compileworkdir":
         case "compileWorkDir": return target.getCompileWorkDir();
         case "configurationclasses":
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index a6b95b6a6e7..8185a3cf983 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -34,6 +34,7 @@
     { "name": "camel.main.beanPostProcessorEnabled", "description": "Can be 
used to turn off bean post processing. Be careful to turn this off, as this 
means that beans that use Camel annotations such as 
org.apache.camel.EndpointInject , org.apache.camel.ProducerTemplate , 
org.apache.camel.Produce , org.apache.camel.Consume etc will not be injected 
and in use. Turning this off should only be done if you are sure you do not use 
any of these Camel features. Not all runtimes allow turning t [...]
     { "name": "camel.main.camelEventsTimestampEnabled", "description": 
"Whether to include timestamps for all emitted Camel Events. Enabling this 
allows to know fine-grained at what time each event was emitted, which can be 
used for reporting to report exactly the time of the events. This is by default 
false to avoid the overhead of including this information.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": [...]
     { "name": "camel.main.caseInsensitiveHeaders", "description": "Whether to 
use case sensitive or insensitive headers. Important: When using case sensitive 
(this is set to false). Then the map is case sensitive which means headers such 
as content-type and Content-Type are two different keys which can be a problem 
for some protocols such as HTTP based, which rely on case insensitive headers. 
However case sensitive implementations can yield faster performance. Therefore 
use case sensitiv [...]
+    { "name": "camel.main.cloudPropertiesLocation", "description": "Sets the 
locations (comma separated values) where to find properties configuration as 
defined for cloud native environments such as Kubernetes. You should only scan 
text based mounted configuration.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "string", 
"javaType": "java.lang.String" },
     { "name": "camel.main.compileWorkDir", "description": "Work directory for 
compiler. Can be used to write compiled classes or other resources.", 
"sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": 
"string", "javaType": "java.lang.String" },
     { "name": "camel.main.configurationClasses", "description": "Sets classes 
names that will be used to configure the camel context as example by providing 
custom beans through org.apache.camel.BindToRegistry annotation.", 
"sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": 
"string", "javaType": "java.lang.String" },
     { "name": "camel.main.configurations", "description": "Sets the 
configuration objects used to configure the camel context.", "sourceType": 
"org.apache.camel.main.MainConfigurationProperties", "type": "object", 
"javaType": "java.util.List" },
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index d4f92574b94..69712f305d9 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -19,7 +19,7 @@ The following tables lists all the options:
 
 // main options: START
 === Camel Main configurations
-The camel.main supports 120 options, which are listed below.
+The camel.main supports 121 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -39,6 +39,7 @@ The camel.main supports 120 options, which are listed below.
 | *camel.main.beanPostProcessor{zwsp}Enabled* | Can be used to turn off bean 
post processing. Be careful to turn this off, as this means that beans that use 
Camel annotations such as org.apache.camel.EndpointInject , 
org.apache.camel.ProducerTemplate , org.apache.camel.Produce , 
org.apache.camel.Consume etc will not be injected and in use. Turning this off 
should only be done if you are sure you do not use any of these Camel features. 
Not all runtimes allow turning this off. The default  [...]
 | *camel.main.camelEvents{zwsp}TimestampEnabled* | Whether to include 
timestamps for all emitted Camel Events. Enabling this allows to know 
fine-grained at what time each event was emitted, which can be used for 
reporting to report exactly the time of the events. This is by default false to 
avoid the overhead of including this information. | false | boolean
 | *camel.main.caseInsensitive{zwsp}Headers* | Whether to use case sensitive or 
insensitive headers. Important: When using case sensitive (this is set to 
false). Then the map is case sensitive which means headers such as content-type 
and Content-Type are two different keys which can be a problem for some 
protocols such as HTTP based, which rely on case insensitive headers. However 
case sensitive implementations can yield faster performance. Therefore use case 
sensitive implementation with [...]
+| *camel.main.cloudProperties{zwsp}Location* | Sets the locations (comma 
separated values) where to find properties configuration as defined for cloud 
native environments such as Kubernetes. You should only scan text based mounted 
configuration. |  | String
 | *camel.main.compileWorkDir* | Work directory for compiler. Can be used to 
write compiled classes or other resources. |  | String
 | *camel.main.configuration{zwsp}Classes* | Sets classes names that will be 
used to configure the camel context as example by providing custom beans 
through org.apache.camel.BindToRegistry annotation. |  | String
 | *camel.main.configurations* | Sets the configuration objects used to 
configure the camel context. |  | List
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index c8505586f73..b3df528b469 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -20,6 +20,12 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -415,6 +421,15 @@ public abstract class BaseMainSupport extends BaseService {
         if (op != null) {
             pc.setOverrideProperties(op);
         }
+
+        Optional<String> cloudLocations = 
pc.resolveProperty(MainConstants.CLOUD_PROPERTIES_LOCATION);
+        if (cloudLocations.isPresent()) {
+            LOG.info("Cloud properties location: {}", cloudLocations);
+            final Properties kp = tryLoadCloudProperties(op, 
cloudLocations.get());
+            if (kp != null) {
+                pc.setOverrideProperties(kp);
+            }
+        }
     }
 
     private Properties tryLoadProperties(
@@ -433,6 +448,43 @@ public abstract class BaseMainSupport extends BaseService {
         return ip;
     }
 
+    private static Properties tryLoadCloudProperties(
+            Properties overridProperties, String cloudPropertiesLocations)
+            throws IOException {
+        final OrderedLocationProperties cp = new OrderedLocationProperties();
+        try {
+            String[] locations = cloudPropertiesLocations.split(",");
+            for (String loc : locations) {
+                Path confPath = Paths.get(loc);
+                if (Files.exists(confPath) && Files.isDirectory(confPath)) {
+                    Files.walkFileTree(confPath, new SimpleFileVisitor<Path>() 
{
+                        @Override
+                        public FileVisitResult visitFile(Path file, 
BasicFileAttributes attrs) {
+                            if (!Files.isDirectory(file)) {
+                                try {
+                                    String val = new 
String(Files.readAllBytes(file));
+                                    cp.put(loc, file.getFileName().toString(), 
val);
+                                } catch (IOException e) {
+                                    LOG.warn("Some error happened while 
reading property from cloud configuration file {}",
+                                            file, e);
+                                }
+                            }
+                            return FileVisitResult.CONTINUE;
+                        }
+                    });
+                }
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        if (overridProperties == null) {
+            return cp;
+        }
+        Properties mergedProperties = new Properties(overridProperties);
+        mergedProperties.putAll(cp);
+        return mergedProperties;
+    }
+
     protected void configureLifecycle(CamelContext camelContext) throws 
Exception {
     }
 
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
index e81123dbe7d..fc151aa0584 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
@@ -149,6 +149,7 @@ public abstract class DefaultConfigurationProperties<T> {
     private String startupRecorderProfile = "default";
     private long startupRecorderDuration;
     private String startupRecorderDir;
+    private String cloudPropertiesLocation;
 
     // getter and setters
     // --------------------------------------------------------------
@@ -2727,4 +2728,24 @@ public abstract class DefaultConfigurationProperties<T> {
         return (T) this;
     }
 
+    public String getCloudPropertiesLocation() {
+        return cloudPropertiesLocation;
+    }
+
+    /**
+     * Sets the locations (comma separated values) where to find properties 
configuration as defined for cloud native
+     * environments such as Kubernetes. You should only scan text based 
mounted configuration.
+     */
+    public void setCloudPropertiesLocation(String cloudPropertiesLocation) {
+        this.cloudPropertiesLocation = cloudPropertiesLocation;
+    }
+
+    /**
+     * Whether to use cloud properties location setting. Default is none.
+     */
+    public T withCloudPropertiesLocation(boolean 
dumpRoutesResolvePlaceholders) {
+        this.cloudPropertiesLocation = cloudPropertiesLocation;
+        return (T) this;
+    }
+
 }
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java 
b/core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java
index 2a0302161e5..0304faa0ace 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java
@@ -21,6 +21,7 @@ public final class MainConstants {
     public static final String DEFAULT_PROPERTY_PLACEHOLDER_LOCATION = 
"classpath:application.properties;optional=true";
     public static final String INITIAL_PROPERTIES_LOCATION = 
"camel.main.initial-properties-location";
     public static final String OVERRIDE_PROPERTIES_LOCATION = 
"camel.main.override-properties-location";
+    public static final String CLOUD_PROPERTIES_LOCATION = 
"camel.main.cloud-properties-location";
     public static final String PROPERTY_PLACEHOLDER_LOCATION = 
"camel.main.property-placeholder-location";
     public static final String PLATFORM_HTTP_SERVER = "platform-http-server";
     public static final String PROFILE = "camel.main.profile";
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MainPropertyPlaceholderTest.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/MainPropertyPlaceholderTest.java
index 3a01d77fd30..0a3194facd8 100644
--- 
a/core/camel-main/src/test/java/org/apache/camel/main/MainPropertyPlaceholderTest.java
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/MainPropertyPlaceholderTest.java
@@ -91,4 +91,33 @@ public class MainPropertyPlaceholderTest {
             main.stop();
         }
     }
+
+    @Test
+    public void testCloudPropertyPlaceholderLocationEnabled() {
+        Main main = new Main();
+        try {
+            
main.setDefaultPropertyPlaceholderLocation("classpath:cloud.properties");
+            main.start();
+            assertEquals("My configmap value", 
main.getCamelContext().resolvePropertyPlaceholders("{{my-prop-1.txt}}"));
+            assertEquals("My secret value", 
main.getCamelContext().resolvePropertyPlaceholders("{{my-prop-2.txt}}"));
+        } finally {
+            main.stop();
+        }
+    }
+
+    @Test
+    public void testCloudPropertyPlaceholderOverride() {
+        Main main = new Main();
+        try {
+            main.setInitialProperties(
+                    mapOf("my-prop-1.txt", "val-init"));
+            main.setOverrideProperties(
+                    mapOf("my-prop-1.txt", "val-override"));
+            
main.setDefaultPropertyPlaceholderLocation("classpath:cloud.properties");
+            main.start();
+            assertEquals("My configmap value", 
main.getCamelContext().resolvePropertyPlaceholders("{{my-prop-1.txt}}"));
+        } finally {
+            main.stop();
+        }
+    }
 }
diff --git a/core/camel-main/src/test/resources/cloud.properties 
b/core/camel-main/src/test/resources/cloud.properties
new file mode 100644
index 00000000000..dd6ef9663b8
--- /dev/null
+++ b/core/camel-main/src/test/resources/cloud.properties
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+camel.main.cloud-properties-location = 
src/test/resources/k8s/etc/camel/conf.d/_configmaps,src/test/resources/k8s/etc/camel/conf.d/_secrets
diff --git 
a/core/camel-main/src/test/resources/k8s/etc/camel/conf.d/_configmaps/my-prop-1.txt
 
b/core/camel-main/src/test/resources/k8s/etc/camel/conf.d/_configmaps/my-prop-1.txt
new file mode 100644
index 00000000000..fa4ef639073
--- /dev/null
+++ 
b/core/camel-main/src/test/resources/k8s/etc/camel/conf.d/_configmaps/my-prop-1.txt
@@ -0,0 +1 @@
+My configmap value
\ No newline at end of file
diff --git 
a/core/camel-main/src/test/resources/k8s/etc/camel/conf.d/_secrets/my-prop-2.txt
 
b/core/camel-main/src/test/resources/k8s/etc/camel/conf.d/_secrets/my-prop-2.txt
new file mode 100644
index 00000000000..859650292ad
--- /dev/null
+++ 
b/core/camel-main/src/test/resources/k8s/etc/camel/conf.d/_secrets/my-prop-2.txt
@@ -0,0 +1 @@
+My secret value
\ No newline at end of file

Reply via email to