codehaus


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GitHub] nicolaferraro closed pull request #291: refactor: consistent env var management in traits


nicolaferraro closed pull request #291: refactor: consistent env var management in traits
URL: https://github.com/apache/camel-k/pull/291
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/pkg/client/cmd/install.go b/pkg/client/cmd/install.go
index 2bafe94c..0de2ed21 100644
--- a/pkg/client/cmd/install.go
+++ b/pkg/client/cmd/install.go
@@ -19,10 +19,10 @@ package cmd
 
 import (
 	"fmt"
-	"github.com/operator-framework/operator-sdk/pkg/k8sclient"
 	"time"
 
 	"github.com/apache/camel-k/pkg/install"
+	"github.com/operator-framework/operator-sdk/pkg/k8sclient"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/pkg/client/cmd/root.go b/pkg/client/cmd/root.go
index ed02838c..203876a1 100644
--- a/pkg/client/cmd/root.go
+++ b/pkg/client/cmd/root.go
@@ -19,6 +19,7 @@ package cmd
 
 import (
 	"context"
+
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go
index fd11fa2f..0cb22fcb 100644
--- a/pkg/trait/builder.go
+++ b/pkg/trait/builder.go
@@ -18,12 +18,13 @@ limitations under the License.
 package trait
 
 import (
+	"regexp"
+
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/builder"
 	"github.com/apache/camel-k/pkg/builder/kaniko"
 	"github.com/apache/camel-k/pkg/builder/s2i"
 	"github.com/apache/camel-k/pkg/platform"
-	"regexp"
 )
 
 const (
@@ -103,5 +104,4 @@ func (t *builderTrait) ReplaceHost(ctx *builder.Context) error {
 func getImageWithOpenShiftHost(image string) string {
 	pattern := regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+([:/].*)`)
 	return pattern.ReplaceAllString(image, openshiftDockerRegistryHost+"$1")
-	return image
 }
diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go
index cb9147f0..bf863301 100644
--- a/pkg/trait/builder_test.go
+++ b/pkg/trait/builder_test.go
@@ -20,6 +20,8 @@ package trait
 import (
 	"testing"
 
+	"k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/pkg/builder"
 
 	"github.com/apache/camel-k/pkg/util/kubernetes"
@@ -136,7 +138,7 @@ func createBuilderTestEnv(cluster v1alpha1.IntegrationPlatformCluster, strategy
 				},
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]v1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
@@ -150,4 +152,4 @@ func TestIPReplacement(t *testing.T) {
 	assert.Equal(t, "10.0.2.3.4/camel-k", getImageWithOpenShiftHost("10.0.2.3.4/camel-k"))
 	assert.Equal(t, "gcr.io/camel-k/camel-k:latest", getImageWithOpenShiftHost("gcr.io/camel-k/camel-k:latest"))
 	assert.Equal(t, "docker.io/camel-k:latest", getImageWithOpenShiftHost("docker.io/camel-k:latest"))
-}
\ No newline at end of file
+}
diff --git a/pkg/trait/catalog.go b/pkg/trait/catalog.go
index 6ab0ae23..0fd56689 100644
--- a/pkg/trait/catalog.go
+++ b/pkg/trait/catalog.go
@@ -86,8 +86,8 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 			c.tDependencies,
 			c.tBuilder,
 			c.tSpringBoot,
-			c.tDeployment,
 			c.tEnvironment,
+			c.tDeployment,
 			c.tService,
 			c.tRoute,
 			c.tOwner,
@@ -98,8 +98,8 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 			c.tDependencies,
 			c.tBuilder,
 			c.tSpringBoot,
-			c.tDeployment,
 			c.tEnvironment,
+			c.tDeployment,
 			c.tService,
 			c.tIngress,
 			c.tOwner,
@@ -110,9 +110,9 @@ func (c *Catalog) traitsFor(environment *Environment) []Trait {
 			c.tDependencies,
 			c.tBuilder,
 			c.tSpringBoot,
+			c.tEnvironment,
 			c.tKnative,
 			c.tDeployment,
-			c.tEnvironment,
 			c.tIstio,
 			c.tOwner,
 		}
diff --git a/pkg/trait/debug.go b/pkg/trait/debug.go
index b78bcc6e..51f5161f 100644
--- a/pkg/trait/debug.go
+++ b/pkg/trait/debug.go
@@ -19,6 +19,7 @@ package trait
 
 import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/util/envvar"
 )
 
 type debugTrait struct {
@@ -43,7 +44,7 @@ func (t *debugTrait) Configure(e *Environment) (bool, error) {
 
 func (t *debugTrait) Apply(e *Environment) error {
 	// this is all that's needed as long as the base image is `fabric8/s2i-java` look into builder/builder.go
-	e.EnvVars["JAVA_DEBUG"] = True
+	envvar.SetVal(&e.EnvVars, "JAVA_DEBUG", True)
 
 	return nil
 }
diff --git a/pkg/trait/debug_test.go b/pkg/trait/debug_test.go
index 6c24d82d..8283c08e 100644
--- a/pkg/trait/debug_test.go
+++ b/pkg/trait/debug_test.go
@@ -20,6 +20,10 @@ package trait
 import (
 	"testing"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
+	"k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/stretchr/testify/assert"
 )
@@ -40,7 +44,8 @@ func TestDebugTraitApplicability(t *testing.T) {
 				},
 			},
 		},
-		EnvVars: make(map[string]string)}
+		EnvVars: make([]v1.EnvVar, 0),
+	}
 
 	trait := newDebugTrait()
 
@@ -56,7 +61,7 @@ func TestDebugTraitApplicability(t *testing.T) {
 }
 
 func TestApplyDebugTrait(t *testing.T) {
-	env := Environment{
+	environment := Environment{
 		Integration: &v1alpha1.Integration{
 			Status: v1alpha1.IntegrationStatus{
 				Phase: v1alpha1.IntegrationPhaseDeploying,
@@ -71,10 +76,12 @@ func TestApplyDebugTrait(t *testing.T) {
 				},
 			},
 		},
-		EnvVars: make(map[string]string)}
+		EnvVars: make([]v1.EnvVar, 0),
+	}
 
 	trait := newDebugTrait()
 
-	assert.Nil(t, trait.Apply(&env))
-	assert.Equal(t, True, env.EnvVars["JAVA_DEBUG"])
+	assert.Nil(t, trait.Apply(&environment))
+	assert.NotNil(t, envvar.Get(environment.EnvVars, "JAVA_DEBUG"))
+	assert.Equal(t, True, envvar.Get(environment.EnvVars, "JAVA_DEBUG").Value)
 }
diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go
index 7e8d01fe..6b334852 100644
--- a/pkg/trait/deployment.go
+++ b/pkg/trait/deployment.go
@@ -23,6 +23,8 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -96,7 +98,11 @@ func (t *deploymentTrait) getConfigMapsFor(e *Environment) []runtime.Object {
 
 	// combine properties of integration with context, integration
 	// properties have the priority
-	properties := CombineConfigurationAsMap("property", e.Context, e.Integration)
+	properties := ""
+
+	VisitKeyValConfigurations("property", e.Context, e.Integration, func(key string, val string) {
+		properties += fmt.Sprintf("%s=%s\n", key, val)
+	})
 
 	maps = append(
 		maps,
@@ -113,7 +119,7 @@ func (t *deploymentTrait) getConfigMapsFor(e *Environment) []runtime.Object {
 				},
 			},
 			Data: map[string]string{
-				"properties": PropertiesString(properties),
+				"properties": properties,
 			},
 		},
 	)
@@ -194,28 +200,32 @@ func (t *deploymentTrait) getSources(e *Environment) []string {
 func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 	sources := t.getSources(e)
 
+	environment := make([]corev1.EnvVar, 0)
+
 	// combine Environment of integration with context, integration
 	// Environment has the priority
-	environment := CombineConfigurationAsMap("env", e.Context, e.Integration)
+	VisitKeyValConfigurations("env", e.Context, e.Integration, func(key string, value string) {
+		envvar.SetVal(&environment, key, value)
+	})
 
 	// set env vars needed by the runtime
-	environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
+	envvar.SetVal(&environment, "JAVA_MAIN_CLASS", "org.apache.camel.k.jvm.Application")
 
 	// camel-k runtime
-	environment["CAMEL_K_ROUTES"] = strings.Join(sources, ",")
-	environment["CAMEL_K_CONF"] = "/etc/camel/conf/application.properties"
-	environment["CAMEL_K_CONF_D"] = "/etc/camel/conf.d"
+	envvar.SetVal(&environment, "CAMEL_K_ROUTES", strings.Join(sources, ","))
+	envvar.SetVal(&environment, "CAMEL_K_CONF", "/etc/camel/conf/application.properties")
+	envvar.SetVal(&environment, "CAMEL_K_CONF_D", "/etc/camel/conf.d")
 
 	// add a dummy env var to trigger deployment if everything but the code
 	// has been changed
-	environment["CAMEL_K_DIGEST"] = e.Integration.Status.Digest
+	envvar.SetVal(&environment, "CAMEL_K_DIGEST", e.Integration.Status.Digest)
 
 	// optimizations
-	environment["AB_JOLOKIA_OFF"] = True
+	envvar.SetVal(&environment, "AB_JOLOKIA_OFF", True)
 
 	// add env vars from traits
-	for k, v := range e.EnvVars {
-		environment[k] = v
+	for _, envVar := range e.EnvVars {
+		envvar.SetVar(&environment, envVar)
 	}
 
 	labels := map[string]string{
@@ -248,7 +258,7 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 						{
 							Name:  e.Integration.Name,
 							Image: e.Integration.Status.Image,
-							Env:   EnvironmentAsEnvVarSlice(environment),
+							Env:   environment,
 						},
 					},
 				},
@@ -329,8 +339,7 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 	// Volumes :: Additional ConfigMaps
 	//
 
-	cmList := CombineConfigurationAsSlice("configmap", e.Context, e.Integration)
-	for _, cmName := range cmList {
+	VisitConfigurations("configmap", e.Context, e.Integration, func(cmName string) {
 		cnt++
 
 		vols = append(vols, corev1.Volume{
@@ -348,14 +357,13 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 			Name:      "integration-cm-" + cmName,
 			MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", cnt, cmName),
 		})
-	}
+	})
 
 	//
 	// Volumes :: Additional Secrets
 	//
 
-	secretList := CombineConfigurationAsSlice("secret", e.Context, e.Integration)
-	for _, secretName := range secretList {
+	VisitConfigurations("secret", e.Context, e.Integration, func(secretName string) {
 		cnt++
 
 		vols = append(vols, corev1.Volume{
@@ -371,7 +379,7 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 			Name:      "integration-secret-" + secretName,
 			MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", cnt, secretName),
 		})
-	}
+	})
 
 	//
 	// Volumes
diff --git a/pkg/trait/environment.go b/pkg/trait/environment.go
index 9e05d451..67fd522e 100644
--- a/pkg/trait/environment.go
+++ b/pkg/trait/environment.go
@@ -19,9 +19,8 @@ package trait
 
 import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/util/envvar"
 	"github.com/apache/camel-k/version"
-	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/api/core/v1"
 )
 
 type environmentTrait struct {
@@ -53,35 +52,12 @@ func (t *environmentTrait) Configure(e *Environment) (bool, error) {
 }
 
 func (t *environmentTrait) Apply(e *Environment) error {
-	e.Resources.VisitDeployment(func(deployment *appsv1.Deployment) {
-		for i := 0; i < len(deployment.Spec.Template.Spec.Containers); i++ {
-			c := &deployment.Spec.Template.Spec.Containers[i]
+	envvar.SetVal(&e.EnvVars, envVarCamelKVersion, version.Version)
 
-			c.Env = append(c.Env, v1.EnvVar{
-				Name:  envVarCamelKVersion,
-				Value: version.Version,
-			})
-
-			if t.ContainerMeta {
-				c.Env = append(c.Env, v1.EnvVar{
-					Name: envVarNamespace,
-					ValueFrom: &v1.EnvVarSource{
-						FieldRef: &v1.ObjectFieldSelector{
-							FieldPath: "metadata.namespace",
-						},
-					},
-				})
-				c.Env = append(c.Env, v1.EnvVar{
-					Name: envVarPodName,
-					ValueFrom: &v1.EnvVarSource{
-						FieldRef: &v1.ObjectFieldSelector{
-							FieldPath: "metadata.name",
-						},
-					},
-				})
-			}
-		}
-	})
+	if t.ContainerMeta {
+		envvar.SetValFrom(&e.EnvVars, envVarNamespace, "metadata.namespace")
+		envvar.SetValFrom(&e.EnvVars, envVarPodName, "metadata.name")
+	}
 
 	return nil
 }
diff --git a/pkg/trait/environment_test.go b/pkg/trait/environment_test.go
index 4707a968..430bef2a 100644
--- a/pkg/trait/environment_test.go
+++ b/pkg/trait/environment_test.go
@@ -20,6 +20,8 @@ package trait
 import (
 	"testing"
 
+	corev1 "k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 
 	"k8s.io/api/apps/v1"
@@ -44,7 +46,7 @@ func TestDefaultEnvironment(t *testing.T) {
 				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]corev1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
@@ -99,7 +101,7 @@ func TestEnabledContainerMetaDataEnvVars(t *testing.T) {
 				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]corev1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
@@ -154,7 +156,7 @@ func TestDisabledContainerMetaDataEnvVars(t *testing.T) {
 				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]corev1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go
index 93e16a0a..b31ef07c 100644
--- a/pkg/trait/knative.go
+++ b/pkg/trait/knative.go
@@ -21,6 +21,8 @@ import (
 	"encoding/json"
 	"fmt"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
 	"strconv"
 	"strings"
 
@@ -110,23 +112,33 @@ func (t *knativeTrait) prepareEnvVars(e *Environment) error {
 	if err != nil {
 		return err
 	}
-	e.EnvVars["CAMEL_KNATIVE_CONFIGURATION"] = conf
+
+	envvar.SetVal(&e.EnvVars, "CAMEL_KNATIVE_CONFIGURATION", conf)
+
 	return nil
 }
 
 func (t *knativeTrait) getServiceFor(e *Environment) *serving.Service {
 	// combine properties of integration with context, integration
 	// properties have the priority
-	properties := CombineConfigurationAsMap("property", e.Context, e.Integration)
+	properties := ""
+
+	VisitKeyValConfigurations("property", e.Context, e.Integration, func(key string, val string) {
+		properties += fmt.Sprintf("%s=%s\n", key, val)
+	})
+
+	environment := make([]corev1.EnvVar, 0)
 
 	// combine Environment of integration with context, integration
 	// Environment has the priority
-	environment := CombineConfigurationAsMap("env", e.Context, e.Integration)
+	VisitKeyValConfigurations("env", e.Context, e.Integration, func(key string, value string) {
+		envvar.SetVal(&environment, key, value)
+	})
 
 	sources := make([]string, 0, len(e.Integration.Spec.Sources))
 	for i, s := range e.Integration.Spec.Sources {
-		envName := fmt.Sprintf("KAMEL_K_ROUTE_%03d", i)
-		environment[envName] = s.Content
+		envName := fmt.Sprintf("CAMEL_K_ROUTE_%03d", i)
+		envvar.SetVal(&environment, envName, s.Content)
 
 		params := make([]string, 0)
 		if s.Language != "" {
@@ -145,23 +157,23 @@ func (t *knativeTrait) getServiceFor(e *Environment) *serving.Service {
 	}
 
 	// set env vars needed by the runtime
-	environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
+	envvar.SetVal(&environment, "JAVA_MAIN_CLASS", "org.apache.camel.k.jvm.Application")
 
 	// camel-k runtime
-	environment["CAMEL_K_ROUTES"] = strings.Join(sources, ",")
-	environment["CAMEL_K_CONF"] = "env:CAMEL_K_PROPERTIES"
-	environment["CAMEL_K_PROPERTIES"] = PropertiesString(properties)
+	envvar.SetVal(&environment, "CAMEL_K_ROUTES", strings.Join(sources, ","))
+	envvar.SetVal(&environment, "CAMEL_K_CONF", "env:CAMEL_K_PROPERTIES")
+	envvar.SetVal(&environment, "CAMEL_K_PROPERTIES", properties)
 
 	// add a dummy env var to trigger deployment if everything but the code
 	// has been changed
-	environment["CAMEL_K_DIGEST"] = e.Integration.Status.Digest
+	envvar.SetVal(&environment, "CAMEL_K_DIGEST", e.Integration.Status.Digest)
 
 	// optimizations
-	environment["AB_JOLOKIA_OFF"] = True
+	envvar.SetVal(&environment, "AB_JOLOKIA_OFF", True)
 
 	// add env vars from traits
-	for k, v := range e.EnvVars {
-		environment[k] = v
+	for _, envVar := range e.EnvVars {
+		envvar.SetVar(&environment, envVar)
 	}
 
 	labels := map[string]string{
@@ -200,7 +212,7 @@ func (t *knativeTrait) getServiceFor(e *Environment) *serving.Service {
 						Spec: serving.RevisionSpec{
 							Container: corev1.Container{
 								Image: e.Integration.Status.Image,
-								Env:   EnvironmentAsEnvVarSlice(environment),
+								Env:   environment,
 							},
 						},
 					},
diff --git a/pkg/trait/knative_test.go b/pkg/trait/knative_test.go
index f701c88f..4fd5c40d 100644
--- a/pkg/trait/knative_test.go
+++ b/pkg/trait/knative_test.go
@@ -20,6 +20,10 @@ package trait
 import (
 	"testing"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
+	"k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/pkg/util"
 
 	"github.com/apache/camel-k/pkg/util/kubernetes"
@@ -33,7 +37,7 @@ import (
 func TestKnativeTraitWithCompressedSources(t *testing.T) {
 	content := "H4sIAAAAAAAA/+JKK8rP1VAvycxNLbIqyUzOVtfkUlBQUNAryddQz8lPt8rMS8tX1+QCAAAA//8BAAD//3wZ4pUoAAAA"
 
-	env := Environment{
+	environment := Environment{
 		Integration: &v1alpha1.Integration{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      "test",
@@ -63,33 +67,33 @@ func TestKnativeTraitWithCompressedSources(t *testing.T) {
 				},
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]v1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
 
-	err := NewCatalog().apply(&env)
+	err := NewCatalog().apply(&environment)
 
 	assert.Nil(t, err)
-	assert.NotEmpty(t, env.ExecutedTraits)
-	assert.NotNil(t, env.GetTrait(ID("knative")))
-	assert.NotNil(t, env.EnvVars["KAMEL_KNATIVE_CONFIGURATION"])
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.NotNil(t, environment.GetTrait(ID("knative")))
+	assert.NotNil(t, envvar.Get(environment.EnvVars, "CAMEL_KNATIVE_CONFIGURATION"))
 
 	services := 0
-	env.Resources.VisitKnativeService(func(service *serving.Service) {
+	environment.Resources.VisitKnativeService(func(service *serving.Service) {
 		services++
 
 		vars := service.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Container.Env
 
 		routes := util.LookupEnvVar(vars, "CAMEL_K_ROUTES")
 		assert.NotNil(t, routes)
-		assert.Equal(t, "env:KAMEL_K_ROUTE_000?language=js&compression=true", routes.Value)
+		assert.Equal(t, "env:CAMEL_K_ROUTE_000?language=js&compression=true", routes.Value)
 
-		route := util.LookupEnvVar(vars, "KAMEL_K_ROUTE_000")
+		route := util.LookupEnvVar(vars, "CAMEL_K_ROUTE_000")
 		assert.NotNil(t, route)
 		assert.Equal(t, content, route.Value)
 	})
 
 	assert.True(t, services > 0)
-	assert.True(t, env.Resources.Size() > 0)
+	assert.True(t, environment.Resources.Size() > 0)
 }
diff --git a/pkg/trait/springboot.go b/pkg/trait/springboot.go
index 116c6844..f8d87b91 100644
--- a/pkg/trait/springboot.go
+++ b/pkg/trait/springboot.go
@@ -21,6 +21,8 @@ import (
 	"sort"
 	"strings"
 
+	"github.com/apache/camel-k/pkg/util/envvar"
+
 	"github.com/operator-framework/operator-sdk/pkg/sdk"
 	"github.com/pkg/errors"
 
@@ -75,8 +77,8 @@ func (t *springBootTrait) Apply(e *Environment) error {
 
 	if e.Integration != nil && e.Integration.Status.Phase == v1alpha1.IntegrationPhaseDeploying {
 		// Override env vars
-		e.EnvVars["JAVA_MAIN_CLASS"] = "org.springframework.boot.loader.PropertiesLauncher"
-		e.EnvVars["LOADER_PATH"] = "/deployments/dependencies/"
+		envvar.SetVal(&e.EnvVars, "JAVA_MAIN_CLASS", "org.springframework.boot.loader.PropertiesLauncher")
+		envvar.SetVal(&e.EnvVars, "LOADER_PATH", "/deployments/dependencies/")
 
 		if e.Integration.Spec.Context != "" {
 			name := e.Integration.Spec.Context
@@ -96,8 +98,8 @@ func (t *springBootTrait) Apply(e *Environment) error {
 				deps = append(deps, artifact.Target)
 			}
 
-			e.EnvVars["LOADER_HOME"] = "/deployments"
-			e.EnvVars["LOADER_PATH"] = strings.Join(deps, ",")
+			envvar.SetVal(&e.EnvVars, "LOADER_HOME", "/deployments")
+			envvar.SetVal(&e.EnvVars, "LOADER_PATH", strings.Join(deps, ","))
 		}
 	}
 
diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go
index 6684319f..fdc54285 100644
--- a/pkg/trait/trait.go
+++ b/pkg/trait/trait.go
@@ -22,6 +22,7 @@ import (
 	"github.com/apache/camel-k/pkg/platform"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 	"github.com/pkg/errors"
+	"k8s.io/api/core/v1"
 )
 
 // True --
@@ -75,6 +76,6 @@ func newEnvironment(integration *v1alpha1.Integration, ctx *v1alpha1.Integration
 		Integration:    integration,
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]v1.EnvVar, 0),
 	}, nil
 }
diff --git a/pkg/trait/trait_test.go b/pkg/trait/trait_test.go
index b48bd374..6c9b89af 100644
--- a/pkg/trait/trait_test.go
+++ b/pkg/trait/trait_test.go
@@ -192,7 +192,7 @@ func createTestEnv(cluster v1alpha1.IntegrationPlatformCluster, script string) *
 				Cluster: cluster,
 			},
 		},
-		EnvVars:        make(map[string]string),
+		EnvVars:        make([]corev1.EnvVar, 0),
 		ExecutedTraits: make([]Trait, 0),
 		Resources:      kubernetes.NewCollection(),
 	}
diff --git a/pkg/trait/types.go b/pkg/trait/types.go
index a81f2f40..bbba5acc 100644
--- a/pkg/trait/types.go
+++ b/pkg/trait/types.go
@@ -22,6 +22,7 @@ import (
 	"github.com/apache/camel-k/pkg/builder"
 	"github.com/apache/camel-k/pkg/platform"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
+	"k8s.io/api/core/v1"
 )
 
 // Identifiable represent an identifiable type
@@ -67,7 +68,7 @@ type Environment struct {
 	Steps          []builder.Step
 	BuildDir       string
 	ExecutedTraits []Trait
-	EnvVars        map[string]string
+	EnvVars        []v1.EnvVar
 }
 
 // GetTrait --
diff --git a/pkg/trait/util.go b/pkg/trait/util.go
index afb8f239..ad6e1d32 100644
--- a/pkg/trait/util.go
+++ b/pkg/trait/util.go
@@ -18,12 +18,10 @@ limitations under the License.
 package trait
 
 import (
-	"fmt"
 	"strings"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/operator-framework/operator-sdk/pkg/sdk"
-	"k8s.io/api/core/v1"
 )
 
 // GetIntegrationContext retrieves the context set on the integration
@@ -38,39 +36,19 @@ func GetIntegrationContext(integration *v1alpha1.Integration) (*v1alpha1.Integra
 	return &ctx, err
 }
 
-// PropertiesString --
-func PropertiesString(m map[string]string) string {
-	properties := ""
-	for k, v := range m {
-		properties += fmt.Sprintf("%s=%s\n", k, v)
-	}
-
-	return properties
-}
-
-// EnvironmentAsEnvVarSlice --
-func EnvironmentAsEnvVarSlice(m map[string]string) []v1.EnvVar {
-	env := make([]v1.EnvVar, 0, len(m))
-
-	for k, v := range m {
-		env = append(env, v1.EnvVar{Name: k, Value: v})
-	}
-
-	return env
-}
+// VisitConfigurations --
+func VisitConfigurations(
+	configurationType string,
+	context *v1alpha1.IntegrationContext,
+	integration *v1alpha1.Integration,
+	consumer func(string)) {
 
-// CombineConfigurationAsMap --
-func CombineConfigurationAsMap(configurationType string, context *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) map[string]string {
-	result := make(map[string]string)
 	if context != nil {
 		// Add context properties first so integrations can
 		// override it
 		for _, c := range context.Spec.Configuration {
 			if c.Type == configurationType {
-				pair := strings.Split(c.Value, "=")
-				if len(pair) == 2 {
-					result[pair[0]] = pair[1]
-				}
+				consumer(c.Value)
 			}
 		}
 	}
@@ -78,40 +56,40 @@ func CombineConfigurationAsMap(configurationType string, context *v1alpha1.Integ
 	if integration != nil {
 		for _, c := range integration.Spec.Configuration {
 			if c.Type == configurationType {
-				pair := strings.Split(c.Value, "=")
-				if len(pair) == 2 {
-					result[pair[0]] = pair[1]
-				}
+				consumer(c.Value)
 			}
 		}
 	}
-
-	return result
 }
 
-// CombineConfigurationAsSlice --
-func CombineConfigurationAsSlice(configurationType string, context *v1alpha1.IntegrationContext, integration *v1alpha1.Integration) []string {
-	result := make(map[string]bool)
+// VisitKeyValConfigurations --
+func VisitKeyValConfigurations(
+	configurationType string,
+	context *v1alpha1.IntegrationContext,
+	integration *v1alpha1.Integration,
+	consumer func(string, string)) {
+
 	if context != nil {
 		// Add context properties first so integrations can
 		// override it
 		for _, c := range context.Spec.Configuration {
 			if c.Type == configurationType {
-				result[c.Value] = true
+				pair := strings.Split(c.Value, "=")
+				if len(pair) == 2 {
+					consumer(pair[0], pair[1])
+				}
 			}
 		}
 	}
 
-	for _, c := range integration.Spec.Configuration {
-		if c.Type == configurationType {
-			result[c.Value] = true
+	if integration != nil {
+		for _, c := range integration.Spec.Configuration {
+			if c.Type == configurationType {
+				pair := strings.Split(c.Value, "=")
+				if len(pair) == 2 {
+					consumer(pair[0], pair[1])
+				}
+			}
 		}
 	}
-
-	keys := make([]string, 0, len(result))
-	for k := range result {
-		keys = append(keys, k)
-	}
-
-	return keys
 }
diff --git a/pkg/util/envvar/envvar.go b/pkg/util/envvar/envvar.go
new file mode 100644
index 00000000..68f6ba7e
--- /dev/null
+++ b/pkg/util/envvar/envvar.go
@@ -0,0 +1,87 @@
+/*
+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 envvar
+
+import "k8s.io/api/core/v1"
+
+// Get --
+func Get(vars []v1.EnvVar, name string) *v1.EnvVar {
+	for i := 0; i < len(vars); i++ {
+		if vars[i].Name == name {
+			return &vars[i]
+		}
+	}
+
+	return nil
+}
+
+// SetVal --
+func SetVal(vars *[]v1.EnvVar, name string, value string) {
+	envVar := Get(*vars, name)
+
+	if envVar != nil {
+		envVar.Value = value
+		envVar.ValueFrom = nil
+	} else {
+		*vars = append(*vars, v1.EnvVar{
+			Name:  name,
+			Value: value,
+		})
+	}
+}
+
+// SetVar --
+func SetVar(vars *[]v1.EnvVar, newEnvVar v1.EnvVar) {
+	envVar := Get(*vars, newEnvVar.Name)
+
+	if envVar != nil {
+		envVar.Value = newEnvVar.Value
+		envVar.ValueFrom = nil
+
+		if newEnvVar.ValueFrom != nil {
+			from := *newEnvVar.ValueFrom
+			envVar.ValueFrom = &from
+		}
+
+	} else {
+		*vars = append(*vars, newEnvVar)
+	}
+}
+
+// SetValFrom --
+func SetValFrom(vars *[]v1.EnvVar, name string, path string) {
+	envVar := Get(*vars, name)
+
+	if envVar != nil {
+		envVar.Value = ""
+		envVar.ValueFrom = &v1.EnvVarSource{
+			FieldRef: &v1.ObjectFieldSelector{
+				FieldPath: path,
+			},
+		}
+	} else {
+		*vars = append(*vars, v1.EnvVar{
+			Name: name,
+			ValueFrom: &v1.EnvVarSource{
+				FieldRef: &v1.ObjectFieldSelector{
+					FieldPath: path,
+				},
+			},
+		})
+	}
+}
diff --git a/pkg/util/envvar/envvar_test.go b/pkg/util/envvar/envvar_test.go
new file mode 100644
index 00000000..8d98c493
--- /dev/null
+++ b/pkg/util/envvar/envvar_test.go
@@ -0,0 +1,103 @@
+/*
+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 envvar
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"k8s.io/api/core/v1"
+)
+
+func TestGetEnvVar(t *testing.T) {
+	vars := []v1.EnvVar{
+		{
+			Name:  "MyEnv",
+			Value: "MyValue",
+		},
+	}
+
+	ev := Get(vars, "MyEnv")
+
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	assert.Nil(t, Get(vars, "NotMyEnv"))
+}
+
+func TestModifyEnvVar(t *testing.T) {
+	vars := []v1.EnvVar{
+		{
+			Name:  "MyEnv",
+			Value: "MyValue",
+		},
+	}
+
+	ev := Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyValue", ev.Value)
+
+	ev.Value = "MyNewValue"
+
+	ev = Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyNewValue", ev.Value)
+}
+
+func TestSetEnvVar(t *testing.T) {
+	vars := []v1.EnvVar{
+		{
+			Name:  "MyEnv",
+			Value: "MyValue",
+		},
+	}
+
+	ev := Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	SetVal(&vars, "MyEnv", "MyNewValue")
+
+	ev = Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyNewValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	SetVal(&vars, "MyNewEnv", "MyNewNewValue")
+
+	ev = Get(vars, "MyEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyNewValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	ev = Get(vars, "MyNewEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "MyNewNewValue", ev.Value)
+	assert.Nil(t, ev.ValueFrom)
+
+	SetValFrom(&vars, "MyNewEnv", "metadata.namespace")
+
+	ev = Get(vars, "MyNewEnv")
+	assert.NotNil(t, ev)
+	assert.Equal(t, "", ev.Value)
+	assert.NotNil(t, ev.ValueFrom)
+	assert.Equal(t, "metadata.namespace", ev.ValueFrom.FieldRef.FieldPath)
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@xxxxxxxxxxxxxxxx


With regards,
Apache Git Services