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

nfilotto pushed a commit to branch 3002/properties-from-configmap
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit bbf97a99c8c0dc5d26ebfac5c43642f40d72b51e
Author: Nicolas Filotto <nfilo...@talend.com>
AuthorDate: Fri Sep 9 20:43:27 2022 +0200

    feat(cmd/run): secret/configmap as runtime/build-time properties
---
 .../pages/configuration/build-time-properties.adoc |  60 ++++++++++++
 .../pages/configuration/runtime-properties.adoc    |  60 ++++++++++++
 e2e/global/common/config/config_test.go            | 102 ++++++++++++++++++++-
 pkg/cmd/run.go                                     |  61 +++++++++---
 pkg/cmd/run_help.go                                |  66 +++++++------
 pkg/cmd/run_help_test.go                           |  63 -------------
 pkg/cmd/run_test.go                                |  69 +++++++++++++-
 7 files changed, 374 insertions(+), 107 deletions(-)

diff --git a/docs/modules/ROOT/pages/configuration/build-time-properties.adoc 
b/docs/modules/ROOT/pages/configuration/build-time-properties.adoc
index 713c3f182..e02d330dd 100644
--- a/docs/modules/ROOT/pages/configuration/build-time-properties.adoc
+++ b/docs/modules/ROOT/pages/configuration/build-time-properties.adoc
@@ -50,6 +50,66 @@ kamel run --build-property=file:quarkus.properties 
build-property-route.groovy
 
 The property file is parsed and its properties configured on the 
`Integration`. As soon as the application starts, you will see the log with the 
expected configuration.
 
+[[build-time-configmap]]
+== Property from ConfigMap/Secret
+
+In case some build-time properties are stored into a `Configmap` or a 
`Secret`, you can use the `--build-property` flag with a value of type 
respectively _configmap:name-of-configmap_ or _secret:name-of-secret_ to refer 
to the specific resource to use as build-time properties.
+
+As an example, let's create a `Configmap` named _my-cm-bp_ containing the 
build-time properties to load. You can alternatively use any `Configmap` you've 
already stored in your cluster:
+
+----
+kubectl create configmap my-cm-bp 
--from-literal=quarkus.application.name="my-great-application" 
--from-literal=quarkus.banner.enabled="true"
+----
+
+Here, as an example we have create a configmap with 2 `Quarkus` properties.
+
+[source,groovy]
+.build-property-route.groovy
+----
+from('timer:build-property')
+    .log('The application name: {{quarkus.application.name}}')
+----
+
+The `quarkus.banner.enabled` is configured to show the banner during the 
`Integration` startup. Let's use `--build-property` flag in conjunction with 
file:
+
+----
+kamel run --build-property=configmap:my-cm-bp build-property-route.groovy
+----
+
+The key-value pairs of the `ConfigMap` are loaded and used as build-time 
properties of the `Integration`. As soon as the application starts, you will 
see the log with the expected configuration.
+
+[[build-time-configmap-as-file]]
+== Property from ConfigMap/Secret as file
+
+When you have a lot of key-value pairs to store into a given 
`ConfigMap`/`Secret`, you may consider storing some build-time properties as a 
file into a specific key-value pair for the sake of simplicity. 
+
+The only constraint is to use `.properties` as a suffix of the key to indicate 
that the value is actually a property file, not a simple value.
+
+As an example, let's use the same `Integration` as the previous section but 
with a `ConfigMap` that contains all the properties into the same key-value 
pair.
+
+For this we need a properties file as next:
+
+[source,properties]
+.quarkus.properties
+----
+quarkus.application.name = my-super-application
+quarkus.banner.enabled = true
+----
+
+That we will load into a specific `ConfigMap` using the following command:
+
+----
+kubectl create configmap my-cm-bps --from-file=quarkus.properties
+----
+
+Then we launch the `run` command with the `--build-property` flag whose value 
matches with the appropriate syntax to refer to `my-cm-bps`:
+
+----
+kamel run --build-property configmap:my-cm-bps build-property-route.groovy
+----
+
+The value of the key-value of the `ConfigMap` is loaded as a property file and 
used as build-time properties of the `Integration`. you will see the log with 
the expected configuration.
+
 [[build-time-props-file-precedence]]
 == Property collision priority
 
diff --git a/docs/modules/ROOT/pages/configuration/runtime-properties.adoc 
b/docs/modules/ROOT/pages/configuration/runtime-properties.adoc
index c65b5efb2..3c6cc36d7 100644
--- a/docs/modules/ROOT/pages/configuration/runtime-properties.adoc
+++ b/docs/modules/ROOT/pages/configuration/runtime-properties.adoc
@@ -67,6 +67,66 @@ kamel run --property file:my.properties property-route.groovy
 
 The property file is parsed and its properties configured on the 
`Integration`. As soon as the application starts, you will see the log with the 
expected configuration.
 
+[[runtime-configmap]]
+== Property from ConfigMap/Secret
+
+In case some runtime properties are stored into a `Configmap` or a `Secret`, 
you can use the `--property` flag with a value of type respectively 
_configmap:name-of-configmap_ or _secret:name-of-secret_ to refer to the 
specific resource to use as runtime properties.
+
+As an example, let's create a `Configmap` named _my-cm-rp_ containing the 
runtime properties to load. You can alternatively use any `Configmap` you've 
already stored in your cluster:
+
+----
+kubectl create configmap my-cm-rp --from-literal=name="Will Smith" 
--from-literal=period="2000"
+----
+
+In our `Integration` we can simply refer to the properties defined in the 
`ConfigMap` as we'd do with any other property:
+
+[source,groovy]
+.property-configmap-route.groovy
+----
+from('timer:property?period={{period}}')
+    .log('Hello {{name}}!')
+----
+
+Then we launch the `run` command with the `--property` flag whose value 
matches with the appropriate syntax to refer to `my-cm-rp`:
+
+----
+kamel run --property configmap:my-cm-rp property-configmap-route.groovy
+----
+
+The key-value pairs of the `ConfigMap` are loaded and used as runtime 
properties of the `Integration`. As soon as the application starts, you will 
see the log with the expected message.
+
+[[runtime-configmap-as-file]]
+== Property from ConfigMap/Secret as file
+
+When you have a lot of key-value pairs to store into a given 
`ConfigMap`/`Secret`, you may consider storing some runtime properties as a 
file into a specific key-value pair for the sake of simplicity. 
+
+The only constraint is to use `.properties` as a suffix of the key to indicate 
that the value is actually a property file, not a simple value.
+
+As an example, let's use the same `Integration` as the previous section but 
with a `ConfigMap` that contains all the properties into the same key-value 
pair.
+
+For this we need a properties file as next:
+
+[source,text]
+.some.properties
+----
+name=John Smith
+period=2000
+----
+
+That we will load into a specific `ConfigMap` using the following command:
+
+----
+kubectl create configmap my-cm-rps --from-file=some.properties
+----
+
+Then we launch the `run` command with the `--property` flag whose value 
matches with the appropriate syntax to refer to `my-cm-rps`:
+
+----
+kamel run --property configmap:my-cm-rps property-configmap-route.groovy
+----
+
+The value of the key-value of the `ConfigMap` is loaded as a property file and 
used as runtime properties of the `Integration`. As soon as the application 
starts, you will see the log with the expected message.
+
 [[runtime-props-file-precedence]]
 == Property collision priority
 
diff --git a/e2e/global/common/config/config_test.go 
b/e2e/global/common/config/config_test.go
index 9363fb391..5b5dfe125 100644
--- a/e2e/global/common/config/config_test.go
+++ b/e2e/global/common/config/config_test.go
@@ -23,7 +23,6 @@ limitations under the License.
 package resources
 
 import (
-       "fmt"
        "io/ioutil"
        "testing"
 
@@ -39,8 +38,10 @@ import (
 
 func TestRunConfigExamples(t *testing.T) {
        WithNewTestNamespace(t, func(ns string) {
-               operatorID := fmt.Sprintf("camel-k-%s", ns)
-               Expect(KamelInstallWithID(operatorID, 
ns).Execute()).To(Succeed())
+               ns = "operator-test"
+               operatorID := "camel-k"
+               //operatorID := fmt.Sprintf("camel-k-%s", ns)
+               //Expect(KamelInstallWithID(operatorID, 
ns).Execute()).To(Succeed())
 
                // Properties
 
@@ -68,6 +69,54 @@ func TestRunConfigExamples(t *testing.T) {
                        Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
                })
 
+               t.Run("Property from ConfigMap", func(t *testing.T) {
+                       var cmData = make(map[string]string)
+                       cmData["my.message"] = "my-configmap-property-value"
+                       CreatePlainTextConfigmap(ns, "my-cm-test-property", 
cmData)
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"./files/property-route.groovy", "-p", 
"configmap:my-cm-test-property").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, "property-route"), 
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+                       Eventually(IntegrationConditionStatus(ns, 
"property-route", v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+                       Eventually(IntegrationLogs(ns, "property-route"), 
TestTimeoutShort).Should(ContainSubstring("my-configmap-property-value"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
+               })
+
+               t.Run("Property from ConfigMap as property file", func(t 
*testing.T) {
+                       var cmData = make(map[string]string)
+                       cmData["my.properties"] = 
"my.message=my-configmap-property-entry"
+                       CreatePlainTextConfigmap(ns, "my-cm-test-properties", 
cmData)
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"./files/property-route.groovy", "-p", 
"configmap:my-cm-test-properties").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, "property-route"), 
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+                       Eventually(IntegrationConditionStatus(ns, 
"property-route", v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+                       Eventually(IntegrationLogs(ns, "property-route"), 
TestTimeoutShort).Should(ContainSubstring("my-configmap-property-entry"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
+               })
+
+               t.Run("Property from Secret", func(t *testing.T) {
+                       var secData = make(map[string]string)
+                       secData["my.message"] = "my-secret-property-value"
+                       CreatePlainTextSecret(ns, "my-sec-test-property", 
secData)
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"./files/property-route.groovy", "-p", 
"secret:my-sec-test-property").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, "property-route"), 
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+                       Eventually(IntegrationConditionStatus(ns, 
"property-route", v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+                       Eventually(IntegrationLogs(ns, "property-route"), 
TestTimeoutShort).Should(ContainSubstring("my-secret-property-value"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
+               })
+
+               t.Run("Property from Secret as property file", func(t 
*testing.T) {
+                       var secData = make(map[string]string)
+                       secData["my.properties"] = 
"my.message=my-secret-property-entry"
+                       CreatePlainTextSecret(ns, "my-sec-test-properties", 
secData)
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"./files/property-route.groovy", "-p", 
"secret:my-sec-test-properties").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, "property-route"), 
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+                       Eventually(IntegrationConditionStatus(ns, 
"property-route", v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+                       Eventually(IntegrationLogs(ns, "property-route"), 
TestTimeoutShort).Should(ContainSubstring("my-secret-property-entry"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
+               })
+
                // Configmap
 
                // Store a configmap on the cluster
@@ -274,5 +323,52 @@ func TestRunConfigExamples(t *testing.T) {
                        Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
                })
 
+               t.Run("Build time property from ConfigMap", func(t *testing.T) {
+                       var cmData = make(map[string]string)
+                       cmData["quarkus.application.name"] = 
"my-cool-application"
+                       CreatePlainTextConfigmap(ns, 
"my-cm-test-build-property", cmData)
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"./files/build-property-file-route.groovy", "--build-property", 
"configmap:my-cm-test-build-property").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, 
"build-property-file-route"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+                       Eventually(IntegrationConditionStatus(ns, 
"build-property-file-route", v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+                       Eventually(IntegrationLogs(ns, 
"build-property-file-route"), 
TestTimeoutShort).Should(ContainSubstring("my-cool-application"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
+               })
+
+               t.Run("Build time property from ConfigMap as property file", 
func(t *testing.T) {
+                       var cmData = make(map[string]string)
+                       cmData["my.properties"] = 
"quarkus.application.name=my-super-cool-application"
+                       CreatePlainTextConfigmap(ns, 
"my-cm-test-build-properties", cmData)
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"./files/build-property-file-route.groovy", "--build-property", 
"configmap:my-cm-test-build-properties").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, 
"build-property-file-route"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+                       Eventually(IntegrationConditionStatus(ns, 
"build-property-file-route", v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+                       Eventually(IntegrationLogs(ns, 
"build-property-file-route"), 
TestTimeoutShort).Should(ContainSubstring("my-super-cool-application"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
+               })
+
+               t.Run("Build time property from Secret", func(t *testing.T) {
+                       var secData = make(map[string]string)
+                       secData["quarkus.application.name"] = 
"my-great-application"
+                       CreatePlainTextSecret(ns, "my-sec-test-build-property", 
secData)
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"./files/build-property-file-route.groovy", "--build-property", 
"secret:my-sec-test-build-property").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, 
"build-property-file-route"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+                       Eventually(IntegrationConditionStatus(ns, 
"build-property-file-route", v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+                       Eventually(IntegrationLogs(ns, 
"build-property-file-route"), 
TestTimeoutShort).Should(ContainSubstring("my-great-application"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
+               })
+
+               t.Run("Build time property from Secret as property file", 
func(t *testing.T) {
+                       var secData = make(map[string]string)
+                       secData["my.properties"] = 
"quarkus.application.name=my-awsome-application"
+                       CreatePlainTextSecret(ns, 
"my-sec-test-build-properties", secData)
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"./files/build-property-file-route.groovy", "--build-property", 
"secret:my-sec-test-build-properties").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, 
"build-property-file-route"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+                       Eventually(IntegrationConditionStatus(ns, 
"build-property-file-route", v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+                       Eventually(IntegrationLogs(ns, 
"build-property-file-route"), 
TestTimeoutShort).Should(ContainSubstring("my-awsome-application"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).To(Succeed())
+               })
        })
 }
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index ac4174ff4..301aa05b3 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -101,8 +101,8 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *runCmdOptions)
        cmd.Flags().StringArrayP("dependency", "d", nil, usageDependency)
        cmd.Flags().BoolP("wait", "w", false, "Wait for the integration to be 
running")
        cmd.Flags().StringP("kit", "k", "", "The kit used to run the 
integration")
-       cmd.Flags().StringArrayP("property", "p", nil, "Add a runtime property 
or properties file (syntax: 
[my-key=my-value|file:/path/to/my-conf.properties])")
-       cmd.Flags().StringArray("build-property", nil, "Add a build time 
property or properties file (syntax: 
[my-key=my-value|file:/path/to/my-conf.properties])")
+       cmd.Flags().StringArrayP("property", "p", nil, "Add a runtime property 
or properties file from a path, a config map or a secret (syntax: 
[my-key=my-value|file:/path/to/my-conf.properties|[configmap|secret]:name])")
+       cmd.Flags().StringArray("build-property", nil, "Add a build time 
property or properties file from a path, a config map or a secret (syntax: 
[my-key=my-value|file:/path/to/my-conf.properties|[configmap|secret]:name]])")
        cmd.Flags().StringArray("config", nil, "Add a runtime configuration 
from a Configmap, a Secret or a file (syntax: 
[configmap|secret|file]:name[/key], where name represents the local file path 
or the configmap/secret name and key optionally represents the configmap/secret 
key to be filtered)")
        cmd.Flags().StringArray("resource", nil, "Add a runtime resource from a 
Configmap, a Secret or a file (syntax: 
[configmap|secret|file]:name[/key][@path], where name represents the local file 
path or the configmap/secret name, key optionally represents the 
configmap/secret key to be filtered and path represents the destination path)")
        cmd.Flags().StringArray("maven-repository", nil, "Add a maven 
repository")
@@ -694,11 +694,11 @@ func (o *runCmdOptions) convertOptionsToTraits(cmd 
*cobra.Command, c client.Clie
                return err
        }
 
-       if err := o.applyProperties(); err != nil {
+       if err := o.applyProperties(c); err != nil {
                return err
        }
 
-       if err := o.applyBuildProperties(); err != nil {
+       if err := o.applyBuildProperties(c); err != nil {
                return err
        }
 
@@ -738,14 +738,14 @@ func convertToTrait(value, traitParameter string) string {
        return fmt.Sprintf("%s=%s", traitParameter, value)
 }
 
-func (o *runCmdOptions) applyProperties() error {
-       props, err := mergePropertiesWithPrecedence(o.Properties)
+func (o *runCmdOptions) applyProperties(c client.Client) error {
+       props, err := o.mergePropertiesWithPrecedence(c, o.Properties)
        if err != nil {
                return err
        }
        for _, key := range props.Keys() {
                kv := fmt.Sprintf("%s=%s", key, props.GetString(key, ""))
-               propsTraits, err := convertToTraitParameter(kv, 
"camel.properties")
+               propsTraits, err := o.convertToTraitParameter(c, kv, 
"camel.properties")
                if err != nil {
                        return err
                }
@@ -755,15 +755,15 @@ func (o *runCmdOptions) applyProperties() error {
        return nil
 }
 
-func (o *runCmdOptions) applyBuildProperties() error {
+func (o *runCmdOptions) applyBuildProperties(c client.Client) error {
        // convert each build configuration to a builder trait property
-       buildProps, err := mergePropertiesWithPrecedence(o.BuildProperties)
+       buildProps, err := o.mergePropertiesWithPrecedence(c, o.BuildProperties)
        if err != nil {
                return err
        }
        for _, key := range buildProps.Keys() {
                kv := fmt.Sprintf("%s=%s", key, buildProps.GetString(key, ""))
-               buildPropsTraits, err := convertToTraitParameter(kv, 
"builder.properties")
+               buildPropsTraits, err := o.convertToTraitParameter(c, kv, 
"builder.properties")
                if err != nil {
                        return err
                }
@@ -773,9 +773,9 @@ func (o *runCmdOptions) applyBuildProperties() error {
        return nil
 }
 
-func convertToTraitParameter(value, traitParameter string) ([]string, error) {
+func (o *runCmdOptions) convertToTraitParameter(c client.Client, value, 
traitParameter string) ([]string, error) {
        traits := make([]string, 0)
-       props, err := extractProperties(value)
+       props, err := o.extractProperties(c, value)
        if err != nil {
                return nil, err
        }
@@ -852,6 +852,43 @@ func (o *runCmdOptions) GetIntegrationName(sources 
[]string) string {
        return name
 }
 
+func (o *runCmdOptions) mergePropertiesWithPrecedence(c client.Client, items 
[]string) (*properties.Properties, error) {
+       loPrecedenceProps := properties.NewProperties()
+       hiPrecedenceProps := properties.NewProperties()
+       for _, item := range items {
+               prop, err := o.extractProperties(c, item)
+               if err != nil {
+                       return nil, err
+               }
+               // We consider file, secret and config map props to have a 
lower priority versus single properties
+               if strings.HasPrefix(item, "file:") || strings.HasPrefix(item, 
"secret:") || strings.HasPrefix(item, "configmap:") {
+                       loPrecedenceProps.Merge(prop)
+               } else {
+                       hiPrecedenceProps.Merge(prop)
+               }
+       }
+       // Any property contained in both collections will be merged
+       // giving precedence to the ones in hiPrecedenceProps
+       loPrecedenceProps.Merge(hiPrecedenceProps)
+       return loPrecedenceProps, nil
+}
+
+// The function parse the value and if it is a file (file:/path/), it will 
parse as property file
+// otherwise return a single property built from the item passed as 
`key=value`.
+func (o *runCmdOptions) extractProperties(c client.Client, value string) 
(*properties.Properties, error) {
+       switch {
+       case strings.HasPrefix(value, "file:"):
+               // we already validated the existence of files during validate()
+               return loadPropertyFile(strings.Replace(value, "file:", "", 1))
+       case strings.HasPrefix(value, "secret:"):
+               return loadPropertiesFromSecret(o.Context, c, o.Namespace, 
strings.Replace(value, "secret:", "", 1))
+       case strings.HasPrefix(value, "configmap:"):
+               return loadPropertiesFromConfigMap(o.Context, c, o.Namespace, 
strings.Replace(value, "configmap:", "", 1))
+       default:
+               return keyValueProps(value)
+       }
+}
+
 func loadPropertyFile(fileName string) (*properties.Properties, error) {
        file, err := util.ReadFile(fileName)
        if err != nil {
diff --git a/pkg/cmd/run_help.go b/pkg/cmd/run_help.go
index c885e4151..328e9be32 100644
--- a/pkg/cmd/run_help.go
+++ b/pkg/cmd/run_help.go
@@ -21,6 +21,7 @@ import (
        "context"
        "fmt"
        "path"
+       "reflect"
        "strings"
 
        v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
@@ -115,37 +116,48 @@ func filterFileLocation(maybeFileLocations []string) 
[]string {
        return filteredOptions
 }
 
-func mergePropertiesWithPrecedence(items []string) (*properties.Properties, 
error) {
-       loPrecedenceProps := properties.NewProperties()
-       hiPrecedenceProps := properties.NewProperties()
-       for _, item := range items {
-               prop, err := extractProperties(item)
-               if err != nil {
-                       return nil, err
-               }
-               // We consider file props to have a lower priority versus 
single properties
-               if strings.HasPrefix(item, "file:") {
-                       loPrecedenceProps.Merge(prop)
-               } else {
-                       hiPrecedenceProps.Merge(prop)
-               }
+func keyValueProps(value string) (*properties.Properties, error) {
+       return properties.Load([]byte(value), properties.UTF8)
+}
+
+func loadPropertiesFromSecret(ctx context.Context, c client.Client, ns string, 
name string) (*properties.Properties, error) {
+       secret := kubernetes.LookupSecret(ctx, c, ns, name)
+       if secret == nil {
+               return nil, fmt.Errorf("%s secret not found in %s namespace, 
make sure to provide it before the Integration can run", name, ns)
        }
-       // Any property contained in both collections will be merged
-       // giving precedence to the ones in hiPrecedenceProps
-       loPrecedenceProps.Merge(hiPrecedenceProps)
-       return loPrecedenceProps, nil
+       return fromMapToProperties(secret.Data,
+               func(v reflect.Value) string { return string(v.Bytes()) },
+               func(v reflect.Value) (*properties.Properties, error) {
+                       return properties.Load(v.Bytes(), properties.UTF8)
+               })
 }
 
-// The function parse the value and if it is a file (file:/path/), it will 
parse as property file
-// otherwise return a single property built from the item passed as 
`key=value`.
-func extractProperties(value string) (*properties.Properties, error) {
-       if !strings.HasPrefix(value, "file:") {
-               return keyValueProps(value)
+func loadPropertiesFromConfigMap(ctx context.Context, c client.Client, ns 
string, name string) (*properties.Properties, error) {
+       cm := kubernetes.LookupConfigmap(ctx, c, ns, name)
+       if cm == nil {
+               return nil, fmt.Errorf("%s configmap not found in %s namespace, 
make sure to provide it before the Integration can run", name, ns)
        }
-       // we already validated the existence of files during validate()
-       return loadPropertyFile(strings.Replace(value, "file:", "", 1))
+       return fromMapToProperties(cm.Data,
+               func(v reflect.Value) string { return v.String() },
+               func(v reflect.Value) (*properties.Properties, error) { return 
keyValueProps(v.String()) })
 }
 
-func keyValueProps(value string) (*properties.Properties, error) {
-       return properties.Load([]byte(value), properties.UTF8)
+func fromMapToProperties(data interface{}, toString func(reflect.Value) 
string, loadProperties func(reflect.Value) (*properties.Properties, error)) 
(*properties.Properties, error) {
+       result := properties.NewProperties()
+       m := reflect.ValueOf(data)
+       for _, k := range m.MapKeys() {
+               key := k.String()
+               value := m.MapIndex(k)
+               if strings.HasSuffix(key, ".properties") {
+                       p, err := loadProperties(value)
+                       if err == nil {
+                               result.Merge(p)
+                       } else if _, _, err = result.Set(key, toString(value)); 
err != nil {
+                               return nil, fmt.Errorf("cannot assign %s to 
%s", value, key)
+                       }
+               } else if _, _, err := result.Set(key, toString(value)); err != 
nil {
+                       return nil, fmt.Errorf("cannot assign %s to %s", value, 
key)
+               }
+       }
+       return result, nil
 }
diff --git a/pkg/cmd/run_help_test.go b/pkg/cmd/run_help_test.go
index 0fa7c9a96..175d4da93 100644
--- a/pkg/cmd/run_help_test.go
+++ b/pkg/cmd/run_help_test.go
@@ -18,8 +18,6 @@ limitations under the License.
 package cmd
 
 import (
-       "io/ioutil"
-       "os"
        "testing"
 
        "github.com/stretchr/testify/assert"
@@ -41,64 +39,3 @@ func TestFilterFileLocation(t *testing.T) {
        assert.Equal(t, "app.properties", filteredOptions[1])
        assert.Equal(t, "/validfile", filteredOptions[2])
 }
-
-func TestExtractProperties_SingleKeyValue(t *testing.T) {
-       correctValues := []string{"key=val", "key = val", "key= val", " key   = 
 val"}
-       for _, val := range correctValues {
-               prop, err := extractProperties(val)
-               assert.Nil(t, err)
-               value, ok := prop.Get("key")
-               assert.True(t, ok)
-               assert.Equal(t, "val", value)
-       }
-}
-
-func TestExtractProperties_FromFile(t *testing.T) {
-       var tmpFile1 *os.File
-       var err error
-       if tmpFile1, err = ioutil.TempFile("", "camel-k-*.properties"); err != 
nil {
-               t.Error(err)
-       }
-
-       assert.Nil(t, tmpFile1.Close())
-       assert.Nil(t, ioutil.WriteFile(tmpFile1.Name(), []byte(`
-       key=value
-       #key2=value2
-       my.key=value
-       `), 0o400))
-
-       props, err := extractProperties("file:" + tmpFile1.Name())
-       assert.Nil(t, err)
-       assert.Equal(t, 2, props.Len())
-       for _, prop := range props.Keys() {
-               value, ok := props.Get(prop)
-               assert.True(t, ok)
-               assert.Equal(t, "value", value)
-       }
-}
-
-func TestExtractPropertiesFromFileAndSingleValue(t *testing.T) {
-       var tmpFile1 *os.File
-       var err error
-       if tmpFile1, err = ioutil.TempFile("", "camel-k-*.properties"); err != 
nil {
-               t.Error(err)
-       }
-
-       assert.Nil(t, tmpFile1.Close())
-       assert.Nil(t, ioutil.WriteFile(tmpFile1.Name(), []byte(`
-       key=value
-       #key2=value2
-       my.key=value
-       `), 0o400))
-
-       properties := []string{"key=override", "file:" + tmpFile1.Name(), 
"my.key = override"}
-       props, err := mergePropertiesWithPrecedence(properties)
-       assert.Nil(t, err)
-       assert.Equal(t, 2, props.Len())
-       val, ok := props.Get("key")
-       assert.True(t, ok)
-       assert.Equal(t, "override", val)
-       val, ok = props.Get("my.key")
-       assert.True(t, ok)
-       assert.Equal(t, "override", val)
-}
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go
index b02f37698..2b7144071 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/run_test.go
@@ -274,6 +274,69 @@ f=g:h
 i=j\nk
 `
 
+func TestExtractProperties_SingleKeyValue(t *testing.T) {
+       correctValues := []string{"key=val", "key = val", "key= val", " key   = 
 val"}
+       runCmdOptions, _, _ := initializeRunCmdOptionsWithOutput(t)
+       for _, val := range correctValues {
+               prop, err := runCmdOptions.extractProperties(nil, val)
+               assert.Nil(t, err)
+               value, ok := prop.Get("key")
+               assert.True(t, ok)
+               assert.Equal(t, "val", value)
+       }
+}
+
+func TestExtractProperties_FromFile(t *testing.T) {
+       var tmpFile1 *os.File
+       var err error
+       if tmpFile1, err = ioutil.TempFile("", "camel-k-*.properties"); err != 
nil {
+               t.Error(err)
+       }
+
+       assert.Nil(t, tmpFile1.Close())
+       assert.Nil(t, ioutil.WriteFile(tmpFile1.Name(), []byte(`
+       key=value
+       #key2=value2
+       my.key=value
+       `), 0o400))
+       runCmdOptions, _, _ := initializeRunCmdOptionsWithOutput(t)
+       props, err := runCmdOptions.extractProperties(nil, 
"file:"+tmpFile1.Name())
+       assert.Nil(t, err)
+       assert.Equal(t, 2, props.Len())
+       for _, prop := range props.Keys() {
+               value, ok := props.Get(prop)
+               assert.True(t, ok)
+               assert.Equal(t, "value", value)
+       }
+}
+
+func TestExtractPropertiesFromFileAndSingleValue(t *testing.T) {
+       var tmpFile1 *os.File
+       var err error
+       if tmpFile1, err = ioutil.TempFile("", "camel-k-*.properties"); err != 
nil {
+               t.Error(err)
+       }
+
+       assert.Nil(t, tmpFile1.Close())
+       assert.Nil(t, ioutil.WriteFile(tmpFile1.Name(), []byte(`
+       key=value
+       #key2=value2
+       my.key=value
+       `), 0o400))
+
+       properties := []string{"key=override", "file:" + tmpFile1.Name(), 
"my.key = override"}
+       runCmdOptions, _, _ := initializeRunCmdOptionsWithOutput(t)
+       props, err := runCmdOptions.mergePropertiesWithPrecedence(nil, 
properties)
+       assert.Nil(t, err)
+       assert.Equal(t, 2, props.Len())
+       val, ok := props.Get("key")
+       assert.True(t, ok)
+       assert.Equal(t, "override", val)
+       val, ok = props.Get("my.key")
+       assert.True(t, ok)
+       assert.Equal(t, "override", val)
+}
+
 func TestAddPropertyFile(t *testing.T) {
        var tmpFile *os.File
        var err error
@@ -284,7 +347,8 @@ func TestAddPropertyFile(t *testing.T) {
        assert.Nil(t, tmpFile.Close())
        assert.Nil(t, ioutil.WriteFile(tmpFile.Name(), 
[]byte(TestPropertyFileContent), 0o400))
 
-       properties, err := convertToTraitParameter("file:"+tmpFile.Name(), 
"trait.properties")
+       runCmdOptions, _, _ := initializeRunCmdOptionsWithOutput(t)
+       properties, err := runCmdOptions.convertToTraitParameter(nil, 
"file:"+tmpFile.Name(), "trait.properties")
        assert.Nil(t, err)
        assert.Equal(t, 3, len(properties))
        assert.Equal(t, `trait.properties=a = b`, properties[0])
@@ -293,7 +357,8 @@ func TestAddPropertyFile(t *testing.T) {
 }
 
 func TestRunProperty(t *testing.T) {
-       properties, err := convertToTraitParameter(`key=value\nnewline`, 
"trait.properties")
+       runCmdOptions, _, _ := initializeRunCmdOptionsWithOutput(t)
+       properties, err := runCmdOptions.convertToTraitParameter(nil, 
`key=value\nnewline`, "trait.properties")
        assert.Nil(t, err)
        assert.Equal(t, 1, len(properties))
        assert.Equal(t, `trait.properties=key = value\nnewline`, properties[0])

Reply via email to