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

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

commit 7e6d00e3a50f3bbee9ec183307d0eb8224fe6dae
Author: Antonin Stefanutti <anto...@stefanutti.fr>
AuthorDate: Tue Nov 26 09:17:44 2019 +0100

    feat: Generic patching of integration resources in running phase
---
 pkg/controller/integration/monitor.go |  3 +-
 pkg/trait/affinity.go                 |  2 +-
 pkg/trait/classpath.go                |  3 +-
 pkg/trait/container.go                |  2 +-
 pkg/trait/debug.go                    |  2 +-
 pkg/trait/deployer.go                 | 97 ++++++++++++++++++++++++++++++++++-
 pkg/trait/deployment.go               |  5 +-
 pkg/trait/environment.go              |  2 +-
 pkg/trait/ingress.go                  |  2 +-
 pkg/trait/istio.go                    |  6 ++-
 pkg/trait/jolokia.go                  |  2 +-
 pkg/trait/jolokia_test.go             |  2 +-
 pkg/trait/knative.go                  |  2 +-
 pkg/trait/knative_service.go          |  2 -
 pkg/trait/owner.go                    |  2 +-
 pkg/trait/probes.go                   |  8 ++-
 pkg/trait/prometheus.go               |  2 +-
 pkg/trait/route.go                    |  2 +-
 pkg/trait/service.go                  |  4 +-
 pkg/trait/trait.go                    |  7 ---
 pkg/trait/trait_catalog.go            |  6 +--
 21 files changed, 127 insertions(+), 36 deletions(-)

diff --git a/pkg/controller/integration/monitor.go 
b/pkg/controller/integration/monitor.go
index 85d5a5a..1cad996 100644
--- a/pkg/controller/integration/monitor.go
+++ b/pkg/controller/integration/monitor.go
@@ -62,8 +62,7 @@ func (action *monitorAction) Handle(ctx context.Context, 
integration *v1alpha1.I
                return integration, nil
        }
 
-       // Run traits that are enabled for the running phase,
-       // such as the deployment, garbage collector and Knative service traits.
+       // Run traits that are enabled for the running phase
        _, err = trait.Apply(ctx, action.client, integration, nil)
        if err != nil {
                return nil, err
diff --git a/pkg/trait/affinity.go b/pkg/trait/affinity.go
index c285c6e..1c921e4 100644
--- a/pkg/trait/affinity.go
+++ b/pkg/trait/affinity.go
@@ -66,7 +66,7 @@ func (t *affinityTrait) Configure(e *Environment) (bool, 
error) {
                return false, fmt.Errorf("both pod affinity and pod 
anti-affinity can't be set simultaneously")
        }
 
-       return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
+       return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning), nil
 }
 
 func (t *affinityTrait) Apply(e *Environment) (err error) {
diff --git a/pkg/trait/classpath.go b/pkg/trait/classpath.go
index 14814f0..1a2a643 100644
--- a/pkg/trait/classpath.go
+++ b/pkg/trait/classpath.go
@@ -49,7 +49,8 @@ func (t *classpathTrait) Configure(e *Environment) (bool, 
error) {
                return false, nil
        }
 
-       return e.InPhase(v1alpha1.IntegrationKitPhaseReady, 
v1alpha1.IntegrationPhaseDeploying), nil
+       return e.InPhase(v1alpha1.IntegrationKitPhaseReady, 
v1alpha1.IntegrationPhaseDeploying) ||
+               e.InPhase(v1alpha1.IntegrationKitPhaseReady, 
v1alpha1.IntegrationPhaseRunning), nil
 }
 
 func (t *classpathTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index c37775c..6bd3ae6 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -82,7 +82,7 @@ func (t *containerTrait) Configure(e *Environment) (bool, 
error) {
                return false, nil
        }
 
-       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying) {
+       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning) {
                return false, nil
        }
 
diff --git a/pkg/trait/debug.go b/pkg/trait/debug.go
index 7dcc430..d9d30bf 100644
--- a/pkg/trait/debug.go
+++ b/pkg/trait/debug.go
@@ -40,7 +40,7 @@ func newDebugTrait() *debugTrait {
 
 func (t *debugTrait) Configure(e *Environment) (bool, error) {
        if t.Enabled != nil && *t.Enabled {
-               return 
e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
+               return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning), nil
        }
 
        return false, nil
diff --git a/pkg/trait/deployer.go b/pkg/trait/deployer.go
index b5a8beb..1a9550f 100644
--- a/pkg/trait/deployer.go
+++ b/pkg/trait/deployer.go
@@ -17,6 +17,21 @@ limitations under the License.
 
 package trait
 
+import (
+       jsonpatch "github.com/evanphx/json-patch"
+
+       "github.com/pkg/errors"
+
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+       "k8s.io/apimachinery/pkg/util/json"
+
+       "sigs.k8s.io/controller-runtime/pkg/client"
+
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
+)
+
 // The deployer trait can be used to explicitly select the kind of high level 
resource that
 // will deploy the integration.
 //
@@ -34,10 +49,49 @@ func newDeployerTrait() *deployerTrait {
 }
 
 func (t *deployerTrait) Configure(e *Environment) (bool, error) {
-       return true, nil
+       return e.IntegrationInPhase(
+               v1alpha1.IntegrationPhaseInitialization,
+               v1alpha1.IntegrationPhaseDeploying,
+               v1alpha1.IntegrationPhaseRunning,
+       ), nil
 }
 
 func (t *deployerTrait) Apply(e *Environment) error {
+       switch e.Integration.Status.Phase {
+
+       case v1alpha1.IntegrationPhaseInitialization, 
v1alpha1.IntegrationPhaseDeploying:
+               // Register a post action that updates the resources generated 
by the traits
+               e.PostActions = append(e.PostActions, func(env *Environment) 
error {
+                       if err := kubernetes.ReplaceResources(env.C, 
env.Client, env.Resources.Items()); err != nil {
+                               return errors.Wrap(err, "error during replace 
resource")
+                       }
+                       return nil
+               })
+
+       case v1alpha1.IntegrationPhaseRunning:
+               // Register a post action that patches the resources generated 
by the traits
+               e.PostActions = append(e.PostActions, func(env *Environment) 
error {
+                       for _, resource := range env.Resources.Items() {
+                               key, err := client.ObjectKeyFromObject(resource)
+                               if err != nil {
+                                       return err
+                               }
+
+                               object := resource.DeepCopyObject()
+                               err = env.Client.Get(env.C, key, object)
+                               if err != nil {
+                                       return err
+                               }
+
+                               err = env.Client.Patch(env.C, resource, 
mergeFrom(object))
+                               if err != nil {
+                                       return errors.Wrap(err, "error during 
patch resource")
+                               }
+                       }
+                       return nil
+               })
+       }
+
        return nil
 }
 
@@ -45,3 +99,44 @@ func (t *deployerTrait) Apply(e *Environment) error {
 func (t *deployerTrait) IsPlatformTrait() bool {
        return true
 }
+
+type mergeFromPositivePatch struct {
+       from runtime.Object
+}
+
+func (s *mergeFromPositivePatch) Type() types.PatchType {
+       return types.MergePatchType
+}
+
+func (s *mergeFromPositivePatch) Data(obj runtime.Object) ([]byte, error) {
+       originalJSON, err := json.Marshal(s.from)
+       if err != nil {
+               return nil, err
+       }
+
+       modifiedJSON, err := json.Marshal(obj)
+       if err != nil {
+               return nil, err
+       }
+
+       patch, err := jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
+       if err != nil {
+               return nil, err
+       }
+
+       // The following is a work-around to remove null fields from the JSON 
merge patch
+       // so that values defaulted by controllers server-side are not deleted.
+       // It's generally acceptable as these values are orthogonal to the 
values managed
+       // by the traits.
+       out := obj.DeepCopyObject()
+       err = json.Unmarshal(patch, out)
+       if err != nil {
+               return nil, err
+       }
+
+       return json.Marshal(out)
+}
+
+func mergeFrom(obj runtime.Object) client.Patch {
+       return &mergeFromPositivePatch{obj}
+}
diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go
index 29f8b52..1375dfd 100644
--- a/pkg/trait/deployment.go
+++ b/pkg/trait/deployment.go
@@ -107,7 +107,8 @@ func (t *deploymentTrait) Apply(e *Environment) error {
                return nil
        }
 
-       if e.InPhase(v1alpha1.IntegrationKitPhaseReady, 
v1alpha1.IntegrationPhaseDeploying) {
+       if e.InPhase(v1alpha1.IntegrationKitPhaseReady, 
v1alpha1.IntegrationPhaseDeploying) ||
+               e.InPhase(v1alpha1.IntegrationKitPhaseReady, 
v1alpha1.IntegrationPhaseRunning) {
                maps := e.ComputeConfigMaps()
                depl := t.getDeploymentFor(e)
 
@@ -120,8 +121,6 @@ func (t *deploymentTrait) Apply(e *Environment) error {
                        v1alpha1.IntegrationConditionDeploymentAvailableReason,
                        depl.Name,
                )
-
-               return nil
        }
 
        if e.IntegrationInPhase(v1alpha1.IntegrationPhaseRunning) {
diff --git a/pkg/trait/environment.go b/pkg/trait/environment.go
index 137b3ff..04774f7 100644
--- a/pkg/trait/environment.go
+++ b/pkg/trait/environment.go
@@ -53,7 +53,7 @@ func newEnvironmentTrait() *environmentTrait {
 
 func (t *environmentTrait) Configure(e *Environment) (bool, error) {
        if t.Enabled == nil || *t.Enabled {
-               return 
e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
+               return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning), nil
        }
 
        return false, nil
diff --git a/pkg/trait/ingress.go b/pkg/trait/ingress.go
index 0b99cdd..75af6f9 100644
--- a/pkg/trait/ingress.go
+++ b/pkg/trait/ingress.go
@@ -62,7 +62,7 @@ func (t *ingressTrait) Configure(e *Environment) (bool, 
error) {
                return false, nil
        }
 
-       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying) {
+       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning) {
                return false, nil
        }
 
diff --git a/pkg/trait/istio.go b/pkg/trait/istio.go
index abe3f81..4b8a904 100644
--- a/pkg/trait/istio.go
+++ b/pkg/trait/istio.go
@@ -20,9 +20,11 @@ package trait
 import (
        "strconv"
 
-       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        appsv1 "k8s.io/api/apps/v1"
+
        servingv1 "knative.dev/serving/pkg/apis/serving/v1"
+
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 )
 
 // The Istio trait allows to configure properties related to the Istio service 
mesh,
@@ -51,7 +53,7 @@ func newIstioTrait() *istioTrait {
 
 func (t *istioTrait) Configure(e *Environment) (bool, error) {
        if t.Enabled != nil && *t.Enabled {
-               return 
e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
+               return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning), nil
        }
 
        return false, nil
diff --git a/pkg/trait/jolokia.go b/pkg/trait/jolokia.go
index 90c590d..8a8b80d 100644
--- a/pkg/trait/jolokia.go
+++ b/pkg/trait/jolokia.go
@@ -96,7 +96,7 @@ func (t *jolokiaTrait) Configure(e *Environment) (bool, 
error) {
                setDefaultJolokiaOption(options, &t.UseSslClientAuthentication, 
"useSslClientAuthentication", true)
        }
 
-       return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
+       return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning), nil
 }
 
 func (t *jolokiaTrait) Apply(e *Environment) (err error) {
diff --git a/pkg/trait/jolokia_test.go b/pkg/trait/jolokia_test.go
index 5474fde..abf43f9 100644
--- a/pkg/trait/jolokia_test.go
+++ b/pkg/trait/jolokia_test.go
@@ -55,7 +55,7 @@ func TestConfigureJolokiaTraitInWrongPhaseDoesNotSucceed(t 
*testing.T) {
        configured, err := trait.Configure(environment)
 
        assert.Nil(t, err)
-       assert.False(t, configured)
+       assert.True(t, configured)
 }
 
 func TestConfigureJolokiaTraitWithUnparseableOptionsDoesNotSucceed(t 
*testing.T) {
diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go
index 368d6f8..13f36ff 100644
--- a/pkg/trait/knative.go
+++ b/pkg/trait/knative.go
@@ -95,7 +95,7 @@ func (t *knativeTrait) Configure(e *Environment) (bool, 
error) {
                return false, nil
        }
 
-       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying) {
+       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning) {
                return false, nil
        }
 
diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go
index 9fa8089..d60e1b7 100644
--- a/pkg/trait/knative_service.go
+++ b/pkg/trait/knative_service.go
@@ -229,8 +229,6 @@ func (t *knativeServiceTrait) Apply(e *Environment) error {
                                return err
                        }
                }
-
-               return nil
        }
 
        ksvc := t.getServiceFor(e)
diff --git a/pkg/trait/owner.go b/pkg/trait/owner.go
index 37c7d64..3b1ff11 100644
--- a/pkg/trait/owner.go
+++ b/pkg/trait/owner.go
@@ -54,7 +54,7 @@ func (t *ownerTrait) Configure(e *Environment) (bool, error) {
                return false, nil
        }
 
-       return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
+       return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning), nil
 }
 
 func (t *ownerTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/probes.go b/pkg/trait/probes.go
index 5731d6f..8ab2ba3 100644
--- a/pkg/trait/probes.go
+++ b/pkg/trait/probes.go
@@ -73,7 +73,11 @@ func newProbesTrait() *probesTrait {
 
 func (t *probesTrait) Configure(e *Environment) (bool, error) {
        if t.Enabled != nil && *t.Enabled {
-               return 
e.IntegrationInPhase(v1alpha1.IntegrationPhaseInitialization) || 
e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
+               return e.IntegrationInPhase(
+                       v1alpha1.IntegrationPhaseInitialization,
+                       v1alpha1.IntegrationPhaseDeploying,
+                       v1alpha1.IntegrationPhaseRunning,
+               ), nil
        }
 
        return false, nil
@@ -100,7 +104,7 @@ func (t *probesTrait) Apply(e *Environment) error {
                )
        }
 
-       if e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying) {
+       if e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning) {
                e.Resources.VisitDeployment(func(deployment *appsv1.Deployment) 
{
                        if len(deployment.Spec.Template.Spec.Containers) != 1 {
                                return
diff --git a/pkg/trait/prometheus.go b/pkg/trait/prometheus.go
index 84a8a73..8cc6ad0 100644
--- a/pkg/trait/prometheus.go
+++ b/pkg/trait/prometheus.go
@@ -64,7 +64,7 @@ func newPrometheusTrait() *prometheusTrait {
 }
 
 func (t *prometheusTrait) Configure(e *Environment) (bool, error) {
-       return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying), nil
+       return e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning), nil
 }
 
 func (t *prometheusTrait) Apply(e *Environment) (err error) {
diff --git a/pkg/trait/route.go b/pkg/trait/route.go
index 6a0fd18..1109c02 100644
--- a/pkg/trait/route.go
+++ b/pkg/trait/route.go
@@ -87,7 +87,7 @@ func (t *routeTrait) Configure(e *Environment) (bool, error) {
                return false, nil
        }
 
-       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying) {
+       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning) {
                return false, nil
        }
 
diff --git a/pkg/trait/service.go b/pkg/trait/service.go
index e58ff68..8511dd9 100644
--- a/pkg/trait/service.go
+++ b/pkg/trait/service.go
@@ -64,7 +64,7 @@ func (t *serviceTrait) Configure(e *Environment) (bool, 
error) {
                return false, nil
        }
 
-       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying) {
+       if !e.IntegrationInPhase(v1alpha1.IntegrationPhaseDeploying, 
v1alpha1.IntegrationPhaseRunning) {
                return false, nil
        }
 
@@ -102,8 +102,8 @@ func (t *serviceTrait) Apply(e *Environment) error {
        // add a new service if not already created
        if svc == nil {
                svc = getServiceFor(e)
-               e.Resources.Add(svc)
        }
+       e.Resources.Add(svc)
        return nil
 }
 
diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go
index 8e50c2c..8d691bc 100644
--- a/pkg/trait/trait.go
+++ b/pkg/trait/trait.go
@@ -47,13 +47,6 @@ func Apply(ctx context.Context, c client.Client, integration 
*v1alpha1.Integrati
                return nil, errors.Wrap(err, "error during trait customization")
        }
 
-       // replace resources created by the trait
-       if environment.Resources != nil {
-               if err := kubernetes.ReplaceResources(ctx, c, 
environment.Resources.Items()); err != nil {
-                       return nil, errors.Wrap(err, "error during replace 
resource")
-               }
-       }
-
        // execute post actions registered by traits
        for _, postAction := range environment.PostActions {
                err := postAction(environment)
diff --git a/pkg/trait/trait_catalog.go b/pkg/trait/trait_catalog.go
index 1f3c1d1..3e627ae 100644
--- a/pkg/trait/trait_catalog.go
+++ b/pkg/trait/trait_catalog.go
@@ -143,7 +143,6 @@ func (c *Catalog) TraitsForProfile(profile 
v1alpha1.TraitProfile) []Trait {
        case v1alpha1.TraitProfileOpenShift:
                return []Trait{
                        c.tCamel,
-                       c.tGarbageCollector,
                        c.tDebug,
                        c.tRestDsl,
                        c.tDependencies,
@@ -152,6 +151,7 @@ func (c *Catalog) TraitsForProfile(profile 
v1alpha1.TraitProfile) []Trait {
                        c.tEnvironment,
                        c.tDeployer,
                        c.tDeployment,
+                       c.tGarbageCollector,
                        c.tAffinity,
                        c.tService,
                        c.tContainer,
@@ -167,7 +167,6 @@ func (c *Catalog) TraitsForProfile(profile 
v1alpha1.TraitProfile) []Trait {
        case v1alpha1.TraitProfileKubernetes:
                return []Trait{
                        c.tCamel,
-                       c.tGarbageCollector,
                        c.tDebug,
                        c.tRestDsl,
                        c.tDependencies,
@@ -176,6 +175,7 @@ func (c *Catalog) TraitsForProfile(profile 
v1alpha1.TraitProfile) []Trait {
                        c.tEnvironment,
                        c.tDeployer,
                        c.tDeployment,
+                       c.tGarbageCollector,
                        c.tAffinity,
                        c.tService,
                        c.tContainer,
@@ -191,7 +191,6 @@ func (c *Catalog) TraitsForProfile(profile 
v1alpha1.TraitProfile) []Trait {
        case v1alpha1.TraitProfileKnative:
                return []Trait{
                        c.tCamel,
-                       c.tGarbageCollector,
                        c.tDebug,
                        c.tRestDsl,
                        c.tKnative,
@@ -201,6 +200,7 @@ func (c *Catalog) TraitsForProfile(profile 
v1alpha1.TraitProfile) []Trait {
                        c.tEnvironment,
                        c.tDeployer,
                        c.tDeployment,
+                       c.tGarbageCollector,
                        c.tAffinity,
                        c.tKnativeService,
                        c.tContainer,

Reply via email to