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

lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 3bbfaad7fbb88453bcd2e5bae7af18ebd2419c7e
Author: nferraro <[email protected]>
AuthorDate: Thu Oct 4 12:12:56 2018 +0200

    Moving logic to the trait area
---
 pkg/stub/action/integration/deploy.go              | 281 ++-------------------
 pkg/stub/action/integration/util.go                |  83 ------
 .../action/integration/deploy.go => trait/base.go} | 158 +++---------
 pkg/trait/{catalog => }/catalog.go                 |  64 +++--
 pkg/trait/{catalog => }/expose.go                  |   9 +-
 pkg/trait/{catalog => }/identity.go                |   9 +-
 pkg/trait/owner.go                                 |  48 ++++
 pkg/trait/trait.go                                 |  35 ++-
 pkg/{stub/action/integration => trait}/util.go     |  50 +---
 pkg/util/kubernetes/collection.go                  |  19 +-
 10 files changed, 213 insertions(+), 543 deletions(-)

diff --git a/pkg/stub/action/integration/deploy.go 
b/pkg/stub/action/integration/deploy.go
index 8067b3c..c9c7f4e 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/stub/action/integration/deploy.go
@@ -18,17 +18,14 @@ limitations under the License.
 package integration
 
 import (
-       "fmt"
-       "github.com/sirupsen/logrus"
-       "strings"
-
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/trait"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
        "github.com/operator-framework/operator-sdk/pkg/sdk"
        "github.com/pkg/errors"
-       appsv1 "k8s.io/api/apps/v1"
-       corev1 "k8s.io/api/core/v1"
+       "github.com/sirupsen/logrus"
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
 )
 
 // NewDeployAction create an action that handles integration deploy
@@ -48,15 +45,18 @@ func (action *deployAction) CanHandle(integration 
*v1alpha1.Integration) bool {
 }
 
 func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
-       ctx, err := LookupContextForIntegration(integration)
+       environment, err := trait.NewEnvironment(integration)
        if err != nil {
                return err
        }
-       err = createOrUpdateConfigMap(ctx, integration)
-       if err != nil {
-               return err
+       resources := kubernetes.NewCollection()
+       customizers := trait.CustomizersFor(*environment)
+       // invoke the trait framework to determine the needed resources
+       if _, err = customizers.Customize(*environment, resources); err != nil {
+               return errors.Wrap(err, "error during trait customization")
        }
-       err = createOrUpdateDeployment(ctx, integration)
+       // TODO we should look for objects that are no longer present in the 
collection and remove them
+       err = action.createOrUpdateObjects(resources.Items(), integration)
        if err != nil {
                return err
        }
@@ -68,254 +68,15 @@ func (action *deployAction) Handle(integration 
*v1alpha1.Integration) error {
        return sdk.Update(target)
 }
 
-// **********************************
-//
-// ConfigMap
-//
-// **********************************
-
-func getConfigMapFor(ctx *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) (*corev1.ConfigMap, error) {
-       controller := true
-       blockOwnerDeletion := true
-
-       // combine properties of integration with context, integration
-       // properties have the priority
-       properties := CombineConfigurationAsMap("property", ctx, integration)
-
-       cm := corev1.ConfigMap{
-               TypeMeta: metav1.TypeMeta{
-                       Kind:       "ConfigMap",
-                       APIVersion: "v1",
-               },
-               ObjectMeta: metav1.ObjectMeta{
-                       Name:      integration.Name,
-                       Namespace: integration.Namespace,
-                       Labels:    integration.Labels,
-                       Annotations: map[string]string{
-                               "camel.apache.org/source.language": 
string(integration.Spec.Source.Language),
-                               "camel.apache.org/source.name":     
integration.Spec.Source.Name,
-                       },
-                       OwnerReferences: []metav1.OwnerReference{
-                               {
-                                       APIVersion:         
integration.APIVersion,
-                                       Kind:               integration.Kind,
-                                       Name:               integration.Name,
-                                       UID:                integration.UID,
-                                       Controller:         &controller,
-                                       BlockOwnerDeletion: &blockOwnerDeletion,
-                               },
-                       },
-               },
-               Data: map[string]string{
-                       "integration": integration.Spec.Source.Content,
-                       "properties":  PropertiesString(properties),
-               },
-       }
-
-       return &cm, nil
-}
-
-func createOrUpdateConfigMap(ctx *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) error {
-       cm, err := getConfigMapFor(ctx, integration)
-       if err != nil {
-               return err
-       }
-
-       err = sdk.Create(cm)
-       if err != nil && k8serrors.IsAlreadyExists(err) {
-               err = sdk.Update(cm)
-       }
-       if err != nil {
-               return errors.Wrap(err, "could not create or replace configmap 
for integration "+integration.Name)
-       }
-
-       return err
-}
-
-// **********************************
-//
-// Deployment
-//
-// **********************************
-
-func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) (*appsv1.Deployment, error) {
-       controller := true
-       blockOwnerDeletion := true
-       sourceName := strings.TrimPrefix(integration.Spec.Source.Name, "/")
-
-       // combine environment of integration with context, integration
-       // environment has the priority
-       environment := CombineConfigurationAsMap("env", ctx, integration)
-
-       // set env vars needed by the runtime
-       environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
-
-       // camel-k runtime
-       environment["CAMEL_K_ROUTES_URI"] = "file:/etc/camel/conf/" + sourceName
-       environment["CAMEL_K_ROUTES_LANGUAGE"] = 
string(integration.Spec.Source.Language)
-       environment["CAMEL_K_CONF"] = "/etc/camel/conf/application.properties"
-       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"] = integration.Status.Digest
-
-       // optimizations
-       environment["AB_JOLOKIA_OFF"] = "true"
-
-       labels := map[string]string{
-               "camel.apache.org/integration": integration.Name,
-       }
-       deployment := appsv1.Deployment{
-               TypeMeta: metav1.TypeMeta{
-                       Kind:       "Deployment",
-                       APIVersion: appsv1.SchemeGroupVersion.String(),
-               },
-               ObjectMeta: metav1.ObjectMeta{
-                       Name:        integration.Name,
-                       Namespace:   integration.Namespace,
-                       Labels:      integration.Labels,
-                       Annotations: integration.Annotations,
-                       OwnerReferences: []metav1.OwnerReference{
-                               {
-                                       APIVersion:         
integration.APIVersion,
-                                       Kind:               integration.Kind,
-                                       Name:               integration.Name,
-                                       Controller:         &controller,
-                                       BlockOwnerDeletion: &blockOwnerDeletion,
-                                       UID:                integration.UID,
-                               },
-                       },
-               },
-               Spec: appsv1.DeploymentSpec{
-                       Replicas: integration.Spec.Replicas,
-                       Selector: &metav1.LabelSelector{
-                               MatchLabels: labels,
-                       },
-                       Template: corev1.PodTemplateSpec{
-                               ObjectMeta: metav1.ObjectMeta{
-                                       Labels: labels,
-                               },
-                               Spec: corev1.PodSpec{
-                                       Containers: []corev1.Container{
-                                               {
-                                                       Name:  integration.Name,
-                                                       Image: 
integration.Status.Image,
-                                                       Env:   
EnvironmentAsEnvVarSlice(environment),
-                                               },
-                                       },
-                               },
-                       },
-               },
-       }
-
-       //
-       // Volumes :: Setup
-       //
-
-       vols := make([]corev1.Volume, 0)
-       mnts := make([]corev1.VolumeMount, 0)
-       cnt := 0
-
-       //
-       // Volumes :: Defaults
-       //
-
-       vols = append(vols, corev1.Volume{
-               Name: "integration",
-               VolumeSource: corev1.VolumeSource{
-                       ConfigMap: &corev1.ConfigMapVolumeSource{
-                               LocalObjectReference: 
corev1.LocalObjectReference{
-                                       Name: integration.Name,
-                               },
-                               Items: []corev1.KeyToPath{
-                                       {
-                                               Key:  "integration",
-                                               Path: sourceName,
-                                       }, {
-                                               Key:  "properties",
-                                               Path: "application.properties",
-                                       },
-                               },
-                       },
-               },
-       })
-
-       mnts = append(mnts, corev1.VolumeMount{
-               Name:      "integration",
-               MountPath: "/etc/camel/conf",
-       })
-
-       //
-       // Volumes :: Additional ConfigMaps
-       //
-
-       cmList := CombineConfigurationAsSlice("configmap", ctx, integration)
-       for _, cmName := range cmList {
-               cnt++
-
-               vols = append(vols, corev1.Volume{
-                       Name: "integration-cm-" + cmName,
-                       VolumeSource: corev1.VolumeSource{
-                               ConfigMap: &corev1.ConfigMapVolumeSource{
-                                       LocalObjectReference: 
corev1.LocalObjectReference{
-                                               Name: cmName,
-                                       },
-                               },
-                       },
-               })
-
-               mnts = append(mnts, corev1.VolumeMount{
-                       Name:      "integration-cm-" + cmName,
-                       MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", 
cnt, cmName),
-               })
-       }
-
-       //
-       // Volumes :: Additional Secrets
-       //
-
-       secretList := CombineConfigurationAsSlice("secret", ctx, integration)
-       for _, secretName := range secretList {
-               cnt++
-
-               vols = append(vols, corev1.Volume{
-                       Name: "integration-secret-" + secretName,
-                       VolumeSource: corev1.VolumeSource{
-                               Secret: &corev1.SecretVolumeSource{
-                                       SecretName: secretName,
-                               },
-                       },
-               })
-
-               mnts = append(mnts, corev1.VolumeMount{
-                       Name:      "integration-secret-" + secretName,
-                       MountPath: fmt.Sprintf("/etc/camel/conf.d/%03d_%s", 
cnt, secretName),
-               })
-       }
-
-       //
-       // Volumes
-       //
-
-       deployment.Spec.Template.Spec.Volumes = vols
-       deployment.Spec.Template.Spec.Containers[0].VolumeMounts = mnts
-
-       return &deployment, nil
-}
-
-func createOrUpdateDeployment(ctx *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) error {
-       deployment, err := getDeploymentFor(ctx, integration)
-       if err != nil {
-               return err
-       }
-
-       err = sdk.Create(deployment)
-       if err != nil && k8serrors.IsAlreadyExists(err) {
-               err = sdk.Update(deployment)
-       }
-       if err != nil {
-               return errors.Wrap(err, "could not create or replace deployment 
for integration "+integration.Name)
+func (action *deployAction) createOrUpdateObjects(objects []runtime.Object, 
integration *v1alpha1.Integration) error {
+       for _, object := range objects {
+               err := sdk.Create(object)
+               if err != nil && k8serrors.IsAlreadyExists(err) {
+                       err = sdk.Update(object)
+               }
+               if err != nil {
+                       return errors.Wrap(err, "could not create or replace 
resource for integration "+integration.Name)
+               }
        }
 
        return nil
diff --git a/pkg/stub/action/integration/util.go 
b/pkg/stub/action/integration/util.go
index ab9cf79..27bfb29 100644
--- a/pkg/stub/action/integration/util.go
+++ b/pkg/stub/action/integration/util.go
@@ -18,15 +18,10 @@ limitations under the License.
 package integration
 
 import (
-       "fmt"
-       "strings"
-
        "github.com/apache/camel-k/pkg/util"
 
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        "github.com/operator-framework/operator-sdk/pkg/sdk"
-       "k8s.io/api/core/v1"
-
        "github.com/pkg/errors"
 )
 
@@ -65,81 +60,3 @@ func LookupContextForIntegration(integration 
*v1alpha1.Integration) (*v1alpha1.I
 
        return nil, nil
 }
-
-// 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
-}
-
-// 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]
-                               }
-                       }
-               }
-       }
-
-       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]
-                               }
-                       }
-               }
-       }
-
-       return result
-}
-
-// CombineConfigurationAsSlice --
-func CombineConfigurationAsSlice(configurationType string, context 
*v1alpha1.IntegrationContext, integration *v1alpha1.Integration) []string {
-       result := make(map[string]bool, 0)
-       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
-                       }
-               }
-       }
-
-       for _, c := range integration.Spec.Configuration {
-               if c.Type == configurationType {
-                       result[c.Value] = true
-               }
-       }
-
-       keys := make([]string, 0, len(result))
-       for k := range result {
-               keys = append(keys, k)
-       }
-
-       return keys
-}
diff --git a/pkg/stub/action/integration/deploy.go b/pkg/trait/base.go
similarity index 51%
copy from pkg/stub/action/integration/deploy.go
copy to pkg/trait/base.go
index 8067b3c..69a46b9 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/trait/base.go
@@ -15,57 +15,38 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package integration
+package trait
 
 import (
        "fmt"
-       "github.com/sirupsen/logrus"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
        "strings"
 
-       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
-       "github.com/operator-framework/operator-sdk/pkg/sdk"
-       "github.com/pkg/errors"
        appsv1 "k8s.io/api/apps/v1"
        corev1 "k8s.io/api/core/v1"
-       k8serrors "k8s.io/apimachinery/pkg/api/errors"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-// NewDeployAction create an action that handles integration deploy
-func NewDeployAction() Action {
-       return &deployAction{}
+type baseTrait struct {
 }
 
-type deployAction struct {
+func (*baseTrait) ID() ID {
+       return ID("base")
 }
 
-func (action *deployAction) Name() string {
-       return "deploy"
-}
-
-func (action *deployAction) CanHandle(integration *v1alpha1.Integration) bool {
-       return integration.Status.Phase == v1alpha1.IntegrationPhaseDeploying
-}
-
-func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
-       ctx, err := LookupContextForIntegration(integration)
-       if err != nil {
-               return err
+func (d *baseTrait) Customize(environment Environment, resources 
*kubernetes.Collection) (bool, error) {
+       var cm *corev1.ConfigMap
+       var err error
+       if cm, err = d.getConfigMapFor(environment); err != nil {
+               return false, err
        }
-       err = createOrUpdateConfigMap(ctx, integration)
-       if err != nil {
-               return err
+       resources.Add(cm)
+       var depl *appsv1.Deployment
+       if depl, err = d.getDeploymentFor(environment); err != nil {
+               return false, err
        }
-       err = createOrUpdateDeployment(ctx, integration)
-       if err != nil {
-               return err
-       }
-
-       target := integration.DeepCopy()
-       logrus.Info("Integration ", target.Name, " transitioning to state ", 
v1alpha1.IntegrationPhaseRunning)
-       target.Status.Phase = v1alpha1.IntegrationPhaseRunning
-
-       return sdk.Update(target)
+       resources.Add(depl)
+       return true, nil
 }
 
 // **********************************
@@ -74,13 +55,10 @@ func (action *deployAction) Handle(integration 
*v1alpha1.Integration) error {
 //
 // **********************************
 
-func getConfigMapFor(ctx *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) (*corev1.ConfigMap, error) {
-       controller := true
-       blockOwnerDeletion := true
-
+func (*baseTrait) getConfigMapFor(e Environment) (*corev1.ConfigMap, error) {
        // combine properties of integration with context, integration
        // properties have the priority
-       properties := CombineConfigurationAsMap("property", ctx, integration)
+       properties := CombineConfigurationAsMap("property", e.Context, 
e.Integration)
 
        cm := corev1.ConfigMap{
                TypeMeta: metav1.TypeMeta{
@@ -88,26 +66,16 @@ func getConfigMapFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.Int
                        APIVersion: "v1",
                },
                ObjectMeta: metav1.ObjectMeta{
-                       Name:      integration.Name,
-                       Namespace: integration.Namespace,
-                       Labels:    integration.Labels,
+                       Name:      e.Integration.Name,
+                       Namespace: e.Integration.Namespace,
+                       Labels:    e.Integration.Labels,
                        Annotations: map[string]string{
-                               "camel.apache.org/source.language": 
string(integration.Spec.Source.Language),
-                               "camel.apache.org/source.name":     
integration.Spec.Source.Name,
-                       },
-                       OwnerReferences: []metav1.OwnerReference{
-                               {
-                                       APIVersion:         
integration.APIVersion,
-                                       Kind:               integration.Kind,
-                                       Name:               integration.Name,
-                                       UID:                integration.UID,
-                                       Controller:         &controller,
-                                       BlockOwnerDeletion: &blockOwnerDeletion,
-                               },
+                               "camel.apache.org/source.language": 
string(e.Integration.Spec.Source.Language),
+                               "camel.apache.org/source.name":     
e.Integration.Spec.Source.Name,
                        },
                },
                Data: map[string]string{
-                       "integration": integration.Spec.Source.Content,
+                       "integration": e.Integration.Spec.Source.Content,
                        "properties":  PropertiesString(properties),
                },
        }
@@ -115,56 +83,37 @@ func getConfigMapFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.Int
        return &cm, nil
 }
 
-func createOrUpdateConfigMap(ctx *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) error {
-       cm, err := getConfigMapFor(ctx, integration)
-       if err != nil {
-               return err
-       }
-
-       err = sdk.Create(cm)
-       if err != nil && k8serrors.IsAlreadyExists(err) {
-               err = sdk.Update(cm)
-       }
-       if err != nil {
-               return errors.Wrap(err, "could not create or replace configmap 
for integration "+integration.Name)
-       }
-
-       return err
-}
-
 // **********************************
 //
 // Deployment
 //
 // **********************************
 
-func getDeploymentFor(ctx *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) (*appsv1.Deployment, error) {
-       controller := true
-       blockOwnerDeletion := true
-       sourceName := strings.TrimPrefix(integration.Spec.Source.Name, "/")
+func (*baseTrait) getDeploymentFor(e Environment) (*appsv1.Deployment, error) {
+       sourceName := strings.TrimPrefix(e.Integration.Spec.Source.Name, "/")
 
        // combine environment of integration with context, integration
        // environment has the priority
-       environment := CombineConfigurationAsMap("env", ctx, integration)
+       environment := CombineConfigurationAsMap("env", e.Context, 
e.Integration)
 
        // set env vars needed by the runtime
        environment["JAVA_MAIN_CLASS"] = "org.apache.camel.k.jvm.Application"
 
        // camel-k runtime
        environment["CAMEL_K_ROUTES_URI"] = "file:/etc/camel/conf/" + sourceName
-       environment["CAMEL_K_ROUTES_LANGUAGE"] = 
string(integration.Spec.Source.Language)
+       environment["CAMEL_K_ROUTES_LANGUAGE"] = 
string(e.Integration.Spec.Source.Language)
        environment["CAMEL_K_CONF"] = "/etc/camel/conf/application.properties"
        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"] = integration.Status.Digest
+       environment["CAMEL_K_DIGEST"] = e.Integration.Status.Digest
 
        // optimizations
        environment["AB_JOLOKIA_OFF"] = "true"
 
        labels := map[string]string{
-               "camel.apache.org/integration": integration.Name,
+               "camel.apache.org/integration": e.Integration.Name,
        }
        deployment := appsv1.Deployment{
                TypeMeta: metav1.TypeMeta{
@@ -172,23 +121,13 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.In
                        APIVersion: appsv1.SchemeGroupVersion.String(),
                },
                ObjectMeta: metav1.ObjectMeta{
-                       Name:        integration.Name,
-                       Namespace:   integration.Namespace,
-                       Labels:      integration.Labels,
-                       Annotations: integration.Annotations,
-                       OwnerReferences: []metav1.OwnerReference{
-                               {
-                                       APIVersion:         
integration.APIVersion,
-                                       Kind:               integration.Kind,
-                                       Name:               integration.Name,
-                                       Controller:         &controller,
-                                       BlockOwnerDeletion: &blockOwnerDeletion,
-                                       UID:                integration.UID,
-                               },
-                       },
+                       Name:        e.Integration.Name,
+                       Namespace:   e.Integration.Namespace,
+                       Labels:      e.Integration.Labels,
+                       Annotations: e.Integration.Annotations,
                },
                Spec: appsv1.DeploymentSpec{
-                       Replicas: integration.Spec.Replicas,
+                       Replicas: e.Integration.Spec.Replicas,
                        Selector: &metav1.LabelSelector{
                                MatchLabels: labels,
                        },
@@ -199,8 +138,8 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.In
                                Spec: corev1.PodSpec{
                                        Containers: []corev1.Container{
                                                {
-                                                       Name:  integration.Name,
-                                                       Image: 
integration.Status.Image,
+                                                       Name:  
e.Integration.Name,
+                                                       Image: 
e.Integration.Status.Image,
                                                        Env:   
EnvironmentAsEnvVarSlice(environment),
                                                },
                                        },
@@ -226,7 +165,7 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.In
                VolumeSource: corev1.VolumeSource{
                        ConfigMap: &corev1.ConfigMapVolumeSource{
                                LocalObjectReference: 
corev1.LocalObjectReference{
-                                       Name: integration.Name,
+                                       Name: e.Integration.Name,
                                },
                                Items: []corev1.KeyToPath{
                                        {
@@ -250,7 +189,7 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.In
        // Volumes :: Additional ConfigMaps
        //
 
-       cmList := CombineConfigurationAsSlice("configmap", ctx, integration)
+       cmList := CombineConfigurationAsSlice("configmap", e.Context, 
e.Integration)
        for _, cmName := range cmList {
                cnt++
 
@@ -275,7 +214,7 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.In
        // Volumes :: Additional Secrets
        //
 
-       secretList := CombineConfigurationAsSlice("secret", ctx, integration)
+       secretList := CombineConfigurationAsSlice("secret", e.Context, 
e.Integration)
        for _, secretName := range secretList {
                cnt++
 
@@ -303,20 +242,3 @@ func getDeploymentFor(ctx *v1alpha1.IntegrationContext, 
integration *v1alpha1.In
 
        return &deployment, nil
 }
-
-func createOrUpdateDeployment(ctx *v1alpha1.IntegrationContext, integration 
*v1alpha1.Integration) error {
-       deployment, err := getDeploymentFor(ctx, integration)
-       if err != nil {
-               return err
-       }
-
-       err = sdk.Create(deployment)
-       if err != nil && k8serrors.IsAlreadyExists(err) {
-               err = sdk.Update(deployment)
-       }
-       if err != nil {
-               return errors.Wrap(err, "could not create or replace deployment 
for integration "+integration.Name)
-       }
-
-       return nil
-}
diff --git a/pkg/trait/catalog/catalog.go b/pkg/trait/catalog.go
similarity index 58%
rename from pkg/trait/catalog/catalog.go
rename to pkg/trait/catalog.go
index 924ed37..3325860 100644
--- a/pkg/trait/catalog/catalog.go
+++ b/pkg/trait/catalog.go
@@ -15,39 +15,48 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package catalog
+package trait
 
 import (
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
-       "github.com/apache/camel-k/pkg/trait"
        "github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
-// TraitID uniquely identifies a trait
-type TraitID string
-
-const (
-       // Expose exposes a integration to the external world
-       Expose TraitID = "expose"
+var (
+       tExpose = &exposeTrait{}
+       tBase = &baseTrait{}
+       tOwner = &ownerTrait{}
 )
 
-// A Catalog is just a DeploymentCustomizer that applies multiple traits
-type Catalog trait.DeploymentCustomizer
-
-// For returns a Catalog for the given integration details
-func For(environment trait.Environment) Catalog {
-
+// CustomizersFor returns a Catalog for the given integration details
+func CustomizersFor(environment Environment) Customizer {
+       switch environment.Platform.Spec.Cluster {
+       case v1alpha1.IntegrationPlatformClusterOpenShift:
+               return compose(
+                       tBase,
+                       tExpose,
+                       tOwner,
+               )
+       case v1alpha1.IntegrationPlatformClusterKubernetes:
+               return compose(
+                       tBase,
+                       tExpose,
+                       tOwner,
+               )
+               // case Knative: ...
+       }
+       return nil
 }
 
-func compose(traits ...trait.DeploymentCustomizer) trait.DeploymentCustomizer {
+func compose(traits ...Customizer) Customizer {
        if len(traits) == 0 {
                return &identityTrait{}
        } else if len(traits) == 1 {
                return traits[0]
        }
-       var composite trait.DeploymentCustomizer = &identityTrait{}
+       var composite Customizer = &identityTrait{}
        for _, t := range traits {
-               composite = &catalogCustomizer{
+               composite = &chainedCustomizer{
                        t1: composite,
                        t2: t,
                }
@@ -57,29 +66,28 @@ func compose(traits ...trait.DeploymentCustomizer) 
trait.DeploymentCustomizer {
 
 // -------------------------------------------
 
-type catalogCustomizer struct {
-       t1 trait.DeploymentCustomizer
-       t2 trait.DeploymentCustomizer
+type chainedCustomizer struct {
+       t1 Customizer
+       t2 Customizer
 }
 
-func (c *catalogCustomizer) Name() string {
-       return ""
+func (c *chainedCustomizer) ID() ID {
+       return ID("")
 }
 
-func (c *catalogCustomizer) Customize(environment trait.Environment, resources 
*kubernetes.Collection) (bool, error) {
+func (c *chainedCustomizer) Customize(environment Environment, resources 
*kubernetes.Collection) (bool, error) {
        atLeastOnce := false
        var done bool
        var err error
        if done, err = c.t1.Customize(environment, resources); err != nil {
                return false, err
-       } else if done && c.t1.Name() != "" {
-               environment.ExecutedCustomizers = 
append(environment.ExecutedCustomizers, c.t1.Name())
+       } else if done && c.t1.ID() != "" {
+               environment.ExecutedCustomizers = 
append(environment.ExecutedCustomizers, c.t1.ID())
        }
        atLeastOnce = atLeastOnce || done
        done2, err := c.t2.Customize(environment, resources)
-       if done2 && c.t2.Name() != "" {
-               environment.ExecutedCustomizers = 
append(environment.ExecutedCustomizers, c.t2.Name())
+       if done2 && c.t2.ID() != "" {
+               environment.ExecutedCustomizers = 
append(environment.ExecutedCustomizers, c.t2.ID())
        }
-       environment.ExecutedCustomizers = 
append(environment.ExecutedCustomizers, c.t1.Name())
        return atLeastOnce || done2, err
 }
diff --git a/pkg/trait/catalog/expose.go b/pkg/trait/expose.go
similarity index 80%
rename from pkg/trait/catalog/expose.go
rename to pkg/trait/expose.go
index 91890eb..2dac116 100644
--- a/pkg/trait/catalog/expose.go
+++ b/pkg/trait/expose.go
@@ -15,20 +15,19 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package catalog
+package trait
 
 import (
-       "github.com/apache/camel-k/pkg/trait"
        "github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
 type exposeTrait struct {
 }
 
-func (*exposeTrait) Name() string {
-       return "expose"
+func (*exposeTrait) ID() ID {
+       return ID("expose")
 }
 
-func (*exposeTrait) Customize(environment trait.Environment, resources 
*kubernetes.Collection) (bool, error) {
+func (*exposeTrait) Customize(environment Environment, resources 
*kubernetes.Collection) (bool, error) {
        return false, nil
 }
diff --git a/pkg/trait/catalog/identity.go b/pkg/trait/identity.go
similarity index 79%
rename from pkg/trait/catalog/identity.go
rename to pkg/trait/identity.go
index cddd0f4..eda9d3a 100644
--- a/pkg/trait/catalog/identity.go
+++ b/pkg/trait/identity.go
@@ -15,20 +15,19 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package catalog
+package trait
 
 import (
-       "github.com/apache/camel-k/pkg/trait"
        "github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
 type identityTrait struct {
 }
 
-func (*identityTrait) Name() string {
-       return "identity"
+func (*identityTrait) ID() ID {
+       return ID("identity")
 }
 
-func (*identityTrait) Customize(environment trait.Environment, resources 
*kubernetes.Collection) (bool, error) {
+func (*identityTrait) Customize(environment Environment, resources 
*kubernetes.Collection) (bool, error) {
        return false, nil
 }
diff --git a/pkg/trait/owner.go b/pkg/trait/owner.go
new file mode 100644
index 0000000..905800b
--- /dev/null
+++ b/pkg/trait/owner.go
@@ -0,0 +1,48 @@
+/*
+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 trait
+
+import "github.com/apache/camel-k/pkg/util/kubernetes"
+import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+// ownerTrait ensures that all created resources belong to the integration 
being created
+type ownerTrait struct {
+}
+
+func (*ownerTrait) ID() ID {
+       return ID("identity")
+}
+
+func (*ownerTrait) Customize(e Environment, resources *kubernetes.Collection) 
(bool, error) {
+       controller := true
+       blockOwnerDeletion := true
+       resources.VisitMetaObject(func(res metav1.Object) {
+               references := []metav1.OwnerReference{
+                       {
+                               APIVersion:         e.Integration.APIVersion,
+                               Kind:               e.Integration.Kind,
+                               Name:               e.Integration.Name,
+                               UID:                e.Integration.UID,
+                               Controller:         &controller,
+                               BlockOwnerDeletion: &blockOwnerDeletion,
+                       },
+               }
+               res.SetOwnerReferences(references)
+       })
+       return true, nil
+}
diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go
index e0bb7ef..90e4d29 100644
--- a/pkg/trait/trait.go
+++ b/pkg/trait/trait.go
@@ -19,6 +19,8 @@ package trait
 
 import (
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/discover"
+       "github.com/apache/camel-k/pkg/platform"
        "github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
@@ -27,13 +29,38 @@ type Environment struct {
        Platform            *v1alpha1.IntegrationPlatform
        Context             *v1alpha1.IntegrationContext
        Integration         *v1alpha1.Integration
-       ExecutedCustomizers []string
+       Dependencies        []string
+       ExecutedCustomizers []ID
 }
 
-// A DeploymentCustomizer performs customization of the deployed objects
-type DeploymentCustomizer interface {
+// NewEnvironment creates a Environment from the given data
+func NewEnvironment(integration *v1alpha1.Integration) (*Environment, error) {
+       pl, err := platform.GetCurrentPlatform(integration.Namespace)
+       if err != nil {
+               return nil, err
+       }
+       ctx, err := GetIntegrationContext(integration)
+       if err != nil {
+               return nil, err
+       }
+       dependencies := discover.Dependencies(integration.Spec.Source)
+
+       return &Environment{
+               Platform:            pl,
+               Context:             ctx,
+               Integration:         integration,
+               Dependencies:        dependencies,
+               ExecutedCustomizers: make([]ID, 0),
+       }, nil
+}
+
+// ID uniquely identifies a trait
+type ID string
+
+// A Customizer performs customization of the deployed objects
+type Customizer interface {
        // The Name of the customizer
-       Name() string
+       ID() ID
        // Customize executes the trait customization on the resources and 
return true if the resources have been changed
        Customize(environment Environment, resources *kubernetes.Collection) 
(bool, error)
 }
diff --git a/pkg/stub/action/integration/util.go b/pkg/trait/util.go
similarity index 73%
copy from pkg/stub/action/integration/util.go
copy to pkg/trait/util.go
index ab9cf79..0e5da55 100644
--- a/pkg/stub/action/integration/util.go
+++ b/pkg/trait/util.go
@@ -15,55 +15,27 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package integration
+package trait
 
 import (
        "fmt"
-       "strings"
-
-       "github.com/apache/camel-k/pkg/util"
-
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        "github.com/operator-framework/operator-sdk/pkg/sdk"
-       "k8s.io/api/core/v1"
-
        "github.com/pkg/errors"
+       "k8s.io/api/core/v1"
+       "strings"
 )
 
-// LookupContextForIntegration --
-func LookupContextForIntegration(integration *v1alpha1.Integration) 
(*v1alpha1.IntegrationContext, error) {
-       if integration.Spec.Context != "" {
-               name := integration.Spec.Context
-               ctx := v1alpha1.NewIntegrationContext(integration.Namespace, 
name)
-
-               if err := sdk.Get(&ctx); err != nil {
-                       return nil, errors.Wrapf(err, "unable to find 
integration context %s, %s", ctx.Name, err)
-               }
-
-               return &ctx, nil
-       }
-
-       ctxList := v1alpha1.NewIntegrationContextList()
-       if err := sdk.List(integration.Namespace, &ctxList); err != nil {
-               return nil, err
-       }
-
-       for _, ctx := range ctxList.Items {
-               if ctx.Labels["camel.apache.org/context.type"] == "platform" {
-                       ideps := len(integration.Spec.Dependencies)
-                       cdeps := len(ctx.Spec.Dependencies)
-
-                       if ideps != cdeps {
-                               continue
-                       }
-
-                       if util.StringSliceContains(ctx.Spec.Dependencies, 
integration.Spec.Dependencies) {
-                               return &ctx, nil
-                       }
-               }
+// GetIntegrationContext retrieves the context set on the integration
+func GetIntegrationContext(integration *v1alpha1.Integration) 
(*v1alpha1.IntegrationContext, error) {
+       if integration.Spec.Context == "" {
+               return nil, errors.New("no context set on the integration")
        }
 
-       return nil, nil
+       name := integration.Spec.Context
+       ctx := v1alpha1.NewIntegrationContext(integration.Namespace, name)
+       err := sdk.Get(&ctx)
+       return &ctx, err
 }
 
 // PropertiesString --
diff --git a/pkg/util/kubernetes/collection.go 
b/pkg/util/kubernetes/collection.go
index a3ff2b7..91cb7ee 100644
--- a/pkg/util/kubernetes/collection.go
+++ b/pkg/util/kubernetes/collection.go
@@ -20,6 +20,7 @@ package kubernetes
 import (
        appsv1 "k8s.io/api/apps/v1"
        corev1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/runtime"
 )
 
@@ -28,6 +29,13 @@ type Collection struct {
        items []runtime.Object
 }
 
+// NewCollection creates a new empty collection
+func NewCollection() *Collection {
+       return &Collection{
+               items: make([]runtime.Object, 0),
+       }
+}
+
 // Items returns all resources belonging to the collection
 func (c *Collection) Items() []runtime.Object {
        return c.items
@@ -48,7 +56,7 @@ func (c *Collection) VisitDeployment(visitor 
func(*appsv1.Deployment)) {
 }
 
 // VisitConfigMap executes the visitor function on all ConfigMap resources
-func (c *Collection) VisitConfigMap(visitor func(configMap *corev1.ConfigMap)) 
{
+func (c *Collection) VisitConfigMap(visitor func(*corev1.ConfigMap)) {
        c.Visit(func(res runtime.Object) {
                if conv, ok := res.(*corev1.ConfigMap); ok {
                        visitor(conv)
@@ -56,6 +64,15 @@ func (c *Collection) VisitConfigMap(visitor func(configMap 
*corev1.ConfigMap)) {
        })
 }
 
+// VisitMetaObject executes the visitor function on all meta.Object resources
+func (c *Collection) VisitMetaObject(visitor func(metav1.Object)) {
+       c.Visit(func(res runtime.Object) {
+               if conv, ok := res.(metav1.Object); ok {
+                       visitor(conv)
+               }
+       })
+}
+
 // Visit executes the visitor function on all resources
 func (c *Collection) Visit(visitor func(runtime.Object)) {
        for _, res := range c.items {

Reply via email to