You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2018/11/05 19:46:35 UTC

[camel-k] 06/06: Moved dependencies to a proper trait

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 27e03854c670f01804cd7023db54afdcd0b40514
Author: nferraro <ni...@gmail.com>
AuthorDate: Mon Nov 5 18:33:35 2018 +0100

    Moved dependencies to a proper trait
---
 deploy/cr-example.yaml                           |  2 -
 deploy/resources.go                              |  2 -
 docs/traits.adoc                                 |  7 +++
 pkg/apis/camel/v1alpha1/types.go                 | 13 +++--
 pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go |  5 --
 pkg/client/cmd/run.go                            | 53 +++++++-----------
 pkg/stub/action/integration/deploy.go            |  2 +-
 pkg/stub/action/integration/initialize.go        | 41 +++-----------
 pkg/trait/catalog.go                             | 61 ++++++++++++++-------
 pkg/trait/dependencies.go                        | 69 ++++++++++++++++++++++++
 pkg/trait/deployment.go                          |  2 +-
 pkg/trait/ingress.go                             |  2 +-
 pkg/trait/owner.go                               |  2 +-
 pkg/trait/route.go                               |  2 +-
 pkg/trait/service.go                             |  2 +-
 pkg/trait/trait.go                               | 23 ++++++--
 pkg/trait/trait_test.go                          |  2 +-
 pkg/trait/types.go                               | 16 ++++--
 pkg/trait/util.go                                |  3 +-
 19 files changed, 186 insertions(+), 123 deletions(-)

diff --git a/deploy/cr-example.yaml b/deploy/cr-example.yaml
index c2851c7..253c402 100644
--- a/deploy/cr-example.yaml
+++ b/deploy/cr-example.yaml
@@ -3,8 +3,6 @@ kind: Integration
 metadata:
   name: example
 spec:
-  dependencies:
-    - camel:groovy
   source:
     content: |-
       // This is Camel K Groovy example route
diff --git a/deploy/resources.go b/deploy/resources.go
index b3e753e..de96acf 100644
--- a/deploy/resources.go
+++ b/deploy/resources.go
@@ -2188,8 +2188,6 @@ kind: Integration
 metadata:
   name: example
 spec:
-  dependencies:
-    - camel:groovy
   source:
     content: |-
       // This is Camel K Groovy example route
diff --git a/docs/traits.adoc b/docs/traits.adoc
index ff2ec93..27f90b2 100644
--- a/docs/traits.adoc
+++ b/docs/traits.adoc
@@ -55,6 +55,13 @@ The following is a list of common traits that can be configured by the end users
 |=======================
 | Trait      | Profiles 				| Description
 
+| dependencies
+| Kubernetes, OpenShift
+| Automatically adds dependencies required by the Camel routes by inspecting the user code.
+  +
+  +
+  It's enabled by default.
+
 | service
 | Kubernetes, OpenShift
 | Exposes the integration with a Service resource so that it can be accessed by other applications (or integrations) in the same namespace.
diff --git a/pkg/apis/camel/v1alpha1/types.go b/pkg/apis/camel/v1alpha1/types.go
index 06cccce..b79a0c5 100644
--- a/pkg/apis/camel/v1alpha1/types.go
+++ b/pkg/apis/camel/v1alpha1/types.go
@@ -49,13 +49,12 @@ type Integration struct {
 
 // IntegrationSpec --
 type IntegrationSpec struct {
-	Replicas                  *int32                          `json:"replicas,omitempty"`
-	Source                    SourceSpec                      `json:"source,omitempty"`
-	Context                   string                          `json:"context,omitempty"`
-	Dependencies              []string                        `json:"dependencies,omitempty"`
-	Traits                    map[string]IntegrationTraitSpec `json:"traits,omitempty"`
-	DependenciesAutoDiscovery *bool                           `json:"dependenciesAutoDiscovery,omitempty"`
-	Configuration             []ConfigurationSpec             `json:"configuration,omitempty"`
+	Replicas      *int32                          `json:"replicas,omitempty"`
+	Source        SourceSpec                      `json:"source,omitempty"`
+	Context       string                          `json:"context,omitempty"`
+	Dependencies  []string                        `json:"dependencies,omitempty"`
+	Traits        map[string]IntegrationTraitSpec `json:"traits,omitempty"`
+	Configuration []ConfigurationSpec             `json:"configuration,omitempty"`
 }
 
 // SourceSpec --
diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
index 1c13379..af2406c 100644
--- a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go
@@ -341,11 +341,6 @@ func (in *IntegrationSpec) DeepCopyInto(out *IntegrationSpec) {
 			(*out)[key] = *val.DeepCopy()
 		}
 	}
-	if in.DependenciesAutoDiscovery != nil {
-		in, out := &in.DependenciesAutoDiscovery, &out.DependenciesAutoDiscovery
-		*out = new(bool)
-		**out = **in
-	}
 	if in.Configuration != nil {
 		in, out := &in.Configuration, &out.Configuration
 		*out = make([]ConfigurationSpec, len(*in))
diff --git a/pkg/client/cmd/run.go b/pkg/client/cmd/run.go
index 3c59c84..6a52e03 100644
--- a/pkg/client/cmd/run.go
+++ b/pkg/client/cmd/run.go
@@ -63,7 +63,7 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd.Flags().StringVarP(&options.Language, "language", "l", "", "Programming Language used to write the file")
-	cmd.Flags().StringVarP(&options.Runtime, "runtime", "r", "jvm", "Runtime used by the integration")
+	cmd.Flags().StringVarP(&options.Runtime, "runtime", "r", "", "Runtime used by the integration")
 	cmd.Flags().StringVar(&options.IntegrationName, "name", "", "The integration name")
 	cmd.Flags().StringSliceVarP(&options.Dependencies, "dependency", "d", nil, "The integration dependency")
 	cmd.Flags().BoolVarP(&options.Wait, "wait", "w", false, "Waits for the integration to be running")
@@ -74,7 +74,6 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	cmd.Flags().BoolVar(&options.Logs, "logs", false, "Print integration logs")
 	cmd.Flags().BoolVar(&options.Sync, "sync", false, "Synchronize the local source file with the cluster, republishing at each change")
 	cmd.Flags().BoolVar(&options.Dev, "dev", false, "Enable Dev mode (equivalent to \"-w --logs --sync\")")
-	cmd.Flags().BoolVar(&options.DependenciesAutoDiscovery, "auto-discovery", true, "Automatically discover Camel modules by analyzing user code")
 	cmd.Flags().StringSliceVarP(&options.Traits, "trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
 	cmd.Flags().StringSliceVar(&options.LoggingLevels, "logging-level", nil, "Configure the logging level. E.g. \"--logging-level org.apache.camel=DEBUG\"")
 
@@ -86,21 +85,20 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
 
 type runCmdOptions struct {
 	*RootCmdOptions
-	IntegrationContext        string
-	Language                  string
-	Runtime                   string
-	IntegrationName           string
-	Dependencies              []string
-	Properties                []string
-	ConfigMaps                []string
-	Secrets                   []string
-	Wait                      bool
-	Logs                      bool
-	Sync                      bool
-	Dev                       bool
-	DependenciesAutoDiscovery bool
-	Traits                    []string
-	LoggingLevels             []string
+	IntegrationContext string
+	Language           string
+	Runtime            string
+	IntegrationName    string
+	Dependencies       []string
+	Properties         []string
+	ConfigMaps         []string
+	Secrets            []string
+	Wait               bool
+	Logs               bool
+	Sync               bool
+	Dev                bool
+	Traits             []string
+	LoggingLevels      []string
 }
 
 func (o *runCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
@@ -273,10 +271,9 @@ func (o *runCmdOptions) updateIntegrationCode(filename string) (*v1alpha1.Integr
 				Content:  code,
 				Language: v1alpha1.Language(o.Language),
 			},
-			Dependencies:              make([]string, 0, len(o.Dependencies)),
-			DependenciesAutoDiscovery: &o.DependenciesAutoDiscovery,
-			Context:                   o.IntegrationContext,
-			Configuration:             make([]v1alpha1.ConfigurationSpec, 0),
+			Dependencies:  make([]string, 0, len(o.Dependencies)),
+			Context:       o.IntegrationContext,
+			Configuration: make([]v1alpha1.ConfigurationSpec, 0),
 		},
 	}
 
@@ -290,24 +287,10 @@ func (o *runCmdOptions) updateIntegrationCode(filename string) (*v1alpha1.Integr
 		}
 	}
 
-	if o.Language == "groovy" || strings.HasSuffix(filename, ".groovy") {
-		util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:groovy")
-	}
-	if o.Language == "kotlin" || strings.HasSuffix(filename, ".kts") {
-		util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:kotlin")
-	}
-
-	// jvm runtime required by default
-	util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:jvm")
-
 	if o.Runtime != "" {
 		util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:"+o.Runtime)
 	}
 
-	switch o.Runtime {
-
-	}
-
 	for _, item := range o.Properties {
 		integration.Spec.Configuration = append(integration.Spec.Configuration, v1alpha1.ConfigurationSpec{
 			Type:  "property",
diff --git a/pkg/stub/action/integration/deploy.go b/pkg/stub/action/integration/deploy.go
index 2c814bc..d666a7b 100644
--- a/pkg/stub/action/integration/deploy.go
+++ b/pkg/stub/action/integration/deploy.go
@@ -42,7 +42,7 @@ func (action *deployAction) CanHandle(integration *v1alpha1.Integration) bool {
 }
 
 func (action *deployAction) Handle(integration *v1alpha1.Integration) error {
-	resources, err := trait.ComputeDeployment(integration)
+	resources, err := trait.BeforeDeployment(integration)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/stub/action/integration/initialize.go b/pkg/stub/action/integration/initialize.go
index 3abf51f..949df34 100644
--- a/pkg/stub/action/integration/initialize.go
+++ b/pkg/stub/action/integration/initialize.go
@@ -18,16 +18,13 @@ limitations under the License.
 package integration
 
 import (
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/metadata"
 	"github.com/apache/camel-k/pkg/platform"
-	"github.com/sirupsen/logrus"
-	"sort"
-
-	"github.com/apache/camel-k/pkg/util"
-
-	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/trait"
 	"github.com/apache/camel-k/pkg/util/digest"
 	"github.com/operator-framework/operator-sdk/pkg/sdk"
+	"github.com/sirupsen/logrus"
 )
 
 // NewInitializeAction creates a new inititialize action
@@ -64,42 +61,16 @@ func (action *initializeAction) Handle(integration *v1alpha1.Integration) error
 	}
 	// extract metadata
 	meta := metadata.Extract(target.Spec.Source)
-
-	// set the correct language
 	target.Spec.Source.Language = meta.Language
 
-	if !util.StringSliceExists(target.Spec.Dependencies, "camel:core") {
-		target.Spec.Dependencies = append(target.Spec.Dependencies, "camel:core")
+	// execute custom initialization
+	if err := trait.BeforeInit(target); err != nil {
+		return err
 	}
 
-	// discover dependencies
-	if target.Spec.DependenciesAutoDiscovery == nil {
-		var autoDiscoveryDependencies = true
-		target.Spec.DependenciesAutoDiscovery = &autoDiscoveryDependencies
-	}
-	if *target.Spec.DependenciesAutoDiscovery {
-		target.Spec.Dependencies = action.mergeDependencies(target.Spec.Dependencies, meta.Dependencies)
-	}
-	// sort the dependencies to get always the same list if they don't change
-	sort.Strings(target.Spec.Dependencies)
 	// update the status
 	logrus.Info("Integration ", target.Name, " transitioning to state ", v1alpha1.IntegrationPhaseBuilding)
 	target.Status.Phase = v1alpha1.IntegrationPhaseBuilding
 	target.Status.Digest = digest.ComputeForIntegration(integration)
 	return sdk.Update(target)
 }
-
-func (action *initializeAction) mergeDependencies(list1 []string, list2 []string) []string {
-	set := make(map[string]bool, 0)
-	for _, d := range list1 {
-		set[d] = true
-	}
-	for _, d := range list2 {
-		set[d] = true
-	}
-	ret := make([]string, 0, len(set))
-	for d := range set {
-		ret = append(ret, d)
-	}
-	return ret
-}
diff --git a/pkg/trait/catalog.go b/pkg/trait/catalog.go
index d5cf865..956ed7e 100644
--- a/pkg/trait/catalog.go
+++ b/pkg/trait/catalog.go
@@ -27,26 +27,29 @@ import (
 
 // Catalog collects all information about traits in one place
 type Catalog struct {
-	tDeployment ITrait
-	tService    ITrait
-	tRoute      ITrait
-	tIngress    ITrait
-	tOwner      ITrait
+	tDependencies Trait
+	tDeployment   Trait
+	tService      Trait
+	tRoute        Trait
+	tIngress      Trait
+	tOwner        Trait
 }
 
 // NewCatalog creates a new trait Catalog
 func NewCatalog() *Catalog {
 	return &Catalog{
-		tDeployment: newDeploymentTrait(),
-		tService:    newServiceTrait(),
-		tRoute:      newRouteTrait(),
-		tIngress:    newIngressTrait(),
-		tOwner:      newOwnerTrait(),
+		tDependencies: newDependenciesTrait(),
+		tDeployment:   newDeploymentTrait(),
+		tService:      newServiceTrait(),
+		tRoute:        newRouteTrait(),
+		tIngress:      newIngressTrait(),
+		tOwner:        newOwnerTrait(),
 	}
 }
 
-func (c *Catalog) allTraits() []ITrait {
-	return []ITrait{
+func (c *Catalog) allTraits() []Trait {
+	return []Trait{
+		c.tDependencies,
 		c.tDeployment,
 		c.tService,
 		c.tRoute,
@@ -55,17 +58,19 @@ func (c *Catalog) allTraits() []ITrait {
 	}
 }
 
-func (c *Catalog) traitsFor(environment *environment) []ITrait {
+func (c *Catalog) traitsFor(environment *environment) []Trait {
 	switch environment.Platform.Spec.Cluster {
 	case v1alpha1.IntegrationPlatformClusterOpenShift:
-		return []ITrait{
+		return []Trait{
+			c.tDependencies,
 			c.tDeployment,
 			c.tService,
 			c.tRoute,
 			c.tOwner,
 		}
 	case v1alpha1.IntegrationPlatformClusterKubernetes:
-		return []ITrait{
+		return []Trait{
+			c.tDependencies,
 			c.tDeployment,
 			c.tService,
 			c.tIngress,
@@ -76,7 +81,7 @@ func (c *Catalog) traitsFor(environment *environment) []ITrait {
 	return nil
 }
 
-func (c *Catalog) customize(environment *environment, resources *kubernetes.Collection) error {
+func (c *Catalog) executeBeforeDeployment(environment *environment, resources *kubernetes.Collection) error {
 	c.configure(environment)
 	traits := c.traitsFor(environment)
 	for _, trait := range traits {
@@ -86,7 +91,27 @@ func (c *Catalog) customize(environment *environment, resources *kubernetes.Coll
 			}
 		}
 		if trait.IsEnabled() {
-			if err := trait.customize(environment, resources); err != nil {
+			if err := trait.beforeDeploy(environment, resources); err != nil {
+				return err
+			}
+			environment.ExecutedTraits = append(environment.ExecutedTraits, trait.ID())
+		}
+	}
+	return nil
+}
+
+func (c *Catalog) executeBeforeInit(environment *environment, integration *v1alpha1.Integration) error {
+	c.configure(environment)
+	traits := c.traitsFor(environment)
+	resources := kubernetes.NewCollection()
+	for _, trait := range traits {
+		if trait.IsAuto() {
+			if err := trait.autoconfigure(environment, resources); err != nil {
+				return err
+			}
+		}
+		if trait.IsEnabled() {
+			if err := trait.beforeInit(environment, integration); err != nil {
 				return err
 			}
 			environment.ExecutedTraits = append(environment.ExecutedTraits, trait.ID())
@@ -96,7 +121,7 @@ func (c *Catalog) customize(environment *environment, resources *kubernetes.Coll
 }
 
 // GetTrait returns the trait with the given ID
-func (c *Catalog) GetTrait(id string) ITrait {
+func (c *Catalog) GetTrait(id string) Trait {
 	for _, t := range c.allTraits() {
 		if t.ID() == ID(id) {
 			return t
diff --git a/pkg/trait/dependencies.go b/pkg/trait/dependencies.go
new file mode 100644
index 0000000..5bdb82d
--- /dev/null
+++ b/pkg/trait/dependencies.go
@@ -0,0 +1,69 @@
+/*
+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/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/metadata"
+	"github.com/apache/camel-k/pkg/util"
+	"sort"
+)
+
+type dependenciesTrait struct {
+	BaseTrait `property:",squash"`
+}
+
+func newDependenciesTrait() *dependenciesTrait {
+	return &dependenciesTrait{
+		BaseTrait: newBaseTrait("dependencies"),
+	}
+}
+
+func (d *dependenciesTrait) beforeInit(environment *environment, integration *v1alpha1.Integration) error {
+	meta := metadata.Extract(integration.Spec.Source)
+
+	if meta.Language == v1alpha1.LanguageGroovy {
+		util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:groovy")
+	} else if meta.Language == v1alpha1.LanguageKotlin {
+		util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:kotlin")
+	}
+
+	// jvm runtime and camel-core required by default
+	util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "runtime:jvm")
+	util.StringSliceUniqueAdd(&integration.Spec.Dependencies, "camel:core")
+
+	integration.Spec.Dependencies = d.mergeDependencies(integration.Spec.Dependencies, meta.Dependencies)
+	// sort the dependencies to get always the same list if they don't change
+	sort.Strings(integration.Spec.Dependencies)
+	return nil
+}
+
+func (d *dependenciesTrait) mergeDependencies(list1 []string, list2 []string) []string {
+	set := make(map[string]bool, 0)
+	for _, d := range list1 {
+		set[d] = true
+	}
+	for _, d := range list2 {
+		set[d] = true
+	}
+	ret := make([]string, 0, len(set))
+	for d := range set {
+		ret = append(ret, d)
+	}
+	return ret
+}
diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go
index 4225b99..41f5e93 100644
--- a/pkg/trait/deployment.go
+++ b/pkg/trait/deployment.go
@@ -38,7 +38,7 @@ func newDeploymentTrait() *deploymentTrait {
 	}
 }
 
-func (d *deploymentTrait) customize(environment *environment, resources *kubernetes.Collection) error {
+func (d *deploymentTrait) beforeDeploy(environment *environment, resources *kubernetes.Collection) error {
 	resources.Add(d.getConfigMapFor(environment))
 	resources.Add(d.getDeploymentFor(environment))
 	return nil
diff --git a/pkg/trait/ingress.go b/pkg/trait/ingress.go
index bbd7017..c166c43 100644
--- a/pkg/trait/ingress.go
+++ b/pkg/trait/ingress.go
@@ -48,7 +48,7 @@ func (e *ingressTrait) autoconfigure(environment *environment, resources *kubern
 	return nil
 }
 
-func (e *ingressTrait) customize(environment *environment, resources *kubernetes.Collection) error {
+func (e *ingressTrait) beforeDeploy(environment *environment, resources *kubernetes.Collection) error {
 	if e.Host == "" {
 		return errors.New("cannot apply ingress trait: no host defined")
 	}
diff --git a/pkg/trait/owner.go b/pkg/trait/owner.go
index 701b219..c0a732f 100644
--- a/pkg/trait/owner.go
+++ b/pkg/trait/owner.go
@@ -33,7 +33,7 @@ func newOwnerTrait() *ownerTrait {
 	}
 }
 
-func (*ownerTrait) customize(e *environment, resources *kubernetes.Collection) error {
+func (*ownerTrait) beforeDeploy(e *environment, resources *kubernetes.Collection) error {
 	controller := true
 	blockOwnerDeletion := true
 	resources.VisitMetaObject(func(res metav1.Object) {
diff --git a/pkg/trait/route.go b/pkg/trait/route.go
index 02299b1..fef1786 100644
--- a/pkg/trait/route.go
+++ b/pkg/trait/route.go
@@ -45,7 +45,7 @@ func (e *routeTrait) autoconfigure(environment *environment, resources *kubernet
 	return nil
 }
 
-func (e *routeTrait) customize(environment *environment, resources *kubernetes.Collection) error {
+func (e *routeTrait) beforeDeploy(environment *environment, resources *kubernetes.Collection) error {
 	service := e.getTargetService(environment, resources)
 	if service == nil {
 		return errors.New("cannot apply route trait: no target service")
diff --git a/pkg/trait/service.go b/pkg/trait/service.go
index 619226b..dcb77df 100644
--- a/pkg/trait/service.go
+++ b/pkg/trait/service.go
@@ -55,7 +55,7 @@ func (s *serviceTrait) autoconfigure(environment *environment, resources *kubern
 	return nil
 }
 
-func (s *serviceTrait) customize(environment *environment, resources *kubernetes.Collection) (err error) {
+func (s *serviceTrait) beforeDeploy(environment *environment, resources *kubernetes.Collection) (err error) {
 	var svc *corev1.Service
 	if svc, err = s.getServiceFor(environment); err != nil {
 		return err
diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go
index bdb5b0e..9239b3a 100644
--- a/pkg/trait/trait.go
+++ b/pkg/trait/trait.go
@@ -25,8 +25,8 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 )
 
-// ComputeDeployment generates all required resources for deploying the given integration
-func ComputeDeployment(integration *v1alpha1.Integration) ([]runtime.Object, error) {
+// BeforeDeployment generates all required resources for deploying the given integration
+func BeforeDeployment(integration *v1alpha1.Integration) ([]runtime.Object, error) {
 	environment, err := newEnvironment(integration)
 	if err != nil {
 		return nil, err
@@ -34,12 +34,26 @@ func ComputeDeployment(integration *v1alpha1.Integration) ([]runtime.Object, err
 	resources := kubernetes.NewCollection()
 	catalog := NewCatalog()
 	// invoke the trait framework to determine the needed resources
-	if err := catalog.customize(environment, resources); err != nil {
-		return nil, errors.Wrap(err, "error during trait customization")
+	if err := catalog.executeBeforeDeployment(environment, resources); err != nil {
+		return nil, errors.Wrap(err, "error during trait customization before deployment")
 	}
 	return resources.Items(), nil
 }
 
+// BeforeInit executes custom initializazion of the integration
+func BeforeInit(integration *v1alpha1.Integration) error {
+	environment, err := newEnvironment(integration)
+	if err != nil {
+		return err
+	}
+	catalog := NewCatalog()
+	// invoke the trait framework to determine the needed resources
+	if err := catalog.executeBeforeInit(environment, integration); err != nil {
+		return errors.Wrap(err, "error during trait customization before init")
+	}
+	return nil
+}
+
 // newEnvironment creates a environment from the given data
 func newEnvironment(integration *v1alpha1.Integration) (*environment, error) {
 	pl, err := platform.GetCurrentPlatform(integration.Namespace)
@@ -58,4 +72,3 @@ func newEnvironment(integration *v1alpha1.Integration) (*environment, error) {
 		ExecutedTraits: make([]ID, 0),
 	}, nil
 }
-
diff --git a/pkg/trait/trait_test.go b/pkg/trait/trait_test.go
index 6631c8c..d6f11aa 100644
--- a/pkg/trait/trait_test.go
+++ b/pkg/trait/trait_test.go
@@ -155,7 +155,7 @@ func TestTraitDecode(t *testing.T) {
 func processTestEnv(t *testing.T, env *environment) *kubernetes.Collection {
 	resources := kubernetes.NewCollection()
 	catalog := NewCatalog()
-	err := catalog.customize(env, resources)
+	err := catalog.executeBeforeDeployment(env, resources)
 	assert.Nil(t, err)
 	return resources
 }
diff --git a/pkg/trait/types.go b/pkg/trait/types.go
index 23aa6a2..3cb6cf5 100644
--- a/pkg/trait/types.go
+++ b/pkg/trait/types.go
@@ -30,8 +30,8 @@ type Identifiable interface {
 // ID uniquely identifies a trait
 type ID string
 
-// ITrait TODO rename
-type ITrait interface {
+// Trait is the interface of all traits
+type Trait interface {
 	Identifiable
 	// enabled tells if the trait is enabled
 	IsEnabled() bool
@@ -39,8 +39,10 @@ type ITrait interface {
 	IsAuto() bool
 	// autoconfigure is called before any customization to ensure the trait is fully configured
 	autoconfigure(environment *environment, resources *kubernetes.Collection) error
-	// customize executes the trait customization on the resources and return true if the resources have been changed
-	customize(environment *environment, resources *kubernetes.Collection) error
+	// beforeInit executes a customization of the integration before it's built
+	beforeInit(environment *environment, integration *v1alpha1.Integration) error
+	// beforeDeploy executes a customization of the gerenated resources before they are created
+	beforeDeploy(environment *environment, resources *kubernetes.Collection) error
 }
 
 /* Base trait */
@@ -83,7 +85,11 @@ func (trait *BaseTrait) autoconfigure(environment *environment, resources *kuber
 	return nil
 }
 
-func (trait *BaseTrait) customize(environment *environment, resources *kubernetes.Collection) error {
+func (trait *BaseTrait) beforeInit(environment *environment, integration *v1alpha1.Integration) error {
+	return nil
+}
+
+func (trait *BaseTrait) beforeDeploy(environment *environment, resources *kubernetes.Collection) error {
 	return nil
 }
 
diff --git a/pkg/trait/util.go b/pkg/trait/util.go
index 5b280a9..c6194b8 100644
--- a/pkg/trait/util.go
+++ b/pkg/trait/util.go
@@ -23,14 +23,13 @@ import (
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/operator-framework/operator-sdk/pkg/sdk"
-	"github.com/pkg/errors"
 	"k8s.io/api/core/v1"
 )
 
 // 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