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,