You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2021/09/20 09:51:42 UTC

[camel-k] 01/03: fix: Unify post-build integration phases reconciliation

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

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

commit 8017be01fc04b102b1a2acbd134342a13b179db1
Author: Antonin Stefanutti <an...@stefanutti.fr>
AuthorDate: Fri Sep 17 11:49:01 2021 +0200

    fix: Unify post-build integration phases reconciliation
---
 pkg/controller/integration/deploy.go               |  64 ----------
 pkg/controller/integration/error.go                |  97 ---------------
 .../integration/integration_controller.go          |   2 -
 pkg/controller/integration/monitor.go              |  88 ++++++++++----
 pkg/trait/affinity.go                              |   2 +-
 pkg/trait/container.go                             |  16 +--
 pkg/trait/cron.go                                  |  23 ++--
 pkg/trait/deployer.go                              |  10 +-
 pkg/trait/deployer_test.go                         |   2 +-
 pkg/trait/deployment.go                            |  49 ++++----
 pkg/trait/environment.go                           |   3 +-
 pkg/trait/error_handler.go                         |   7 +-
 pkg/trait/gc.go                                    |   7 +-
 pkg/trait/ingress.go                               |   2 +-
 pkg/trait/ingress_test.go                          |   2 +-
 pkg/trait/init.go                                  |  72 +++++------
 pkg/trait/istio.go                                 |   6 +-
 pkg/trait/jolokia.go                               |  10 +-
 pkg/trait/jvm.go                                   |   3 +-
 pkg/trait/jvm_test.go                              |   2 +-
 pkg/trait/kamelets.go                              |  13 +-
 pkg/trait/knative.go                               |   4 +-
 pkg/trait/knative_service.go                       | 134 ++++++++++-----------
 pkg/trait/logging.go                               |   3 +-
 pkg/trait/owner.go                                 |   3 +-
 pkg/trait/pdb.go                                   |   5 +-
 pkg/trait/platform.go                              |   3 +-
 pkg/trait/pod.go                                   |   2 +-
 pkg/trait/prometheus.go                            |  10 +-
 pkg/trait/pull_secret.go                           |  18 +--
 pkg/trait/quarkus.go                               |   5 +-
 pkg/trait/route.go                                 |   6 +-
 pkg/trait/service.go                               |   2 +-
 pkg/trait/service_binding.go                       |  16 +--
 pkg/trait/toleration.go                            |   3 +-
 pkg/trait/trait_types.go                           |   4 +
 36 files changed, 269 insertions(+), 429 deletions(-)

diff --git a/pkg/controller/integration/deploy.go b/pkg/controller/integration/deploy.go
deleted file mode 100644
index fee22ae..0000000
--- a/pkg/controller/integration/deploy.go
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-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 integration
-
-import (
-	"context"
-
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
-	"github.com/apache/camel-k/pkg/trait"
-	"github.com/apache/camel-k/pkg/util/kubernetes"
-	"github.com/pkg/errors"
-)
-
-// NewDeployAction create an action that handles integration deploy
-func NewDeployAction() Action {
-	return &deployAction{}
-}
-
-type deployAction struct {
-	baseAction
-}
-
-func (action *deployAction) Name() string {
-	return "deploy"
-}
-
-func (action *deployAction) CanHandle(integration *v1.Integration) bool {
-	return integration.Status.Phase == v1.IntegrationPhaseDeploying
-}
-
-func (action *deployAction) Handle(ctx context.Context, integration *v1.Integration) (*v1.Integration, error) {
-	if integration.Status.IntegrationKit == nil {
-		return nil, errors.Errorf("no kit set on integration %s", integration.Name)
-	}
-
-	kit, err := kubernetes.GetIntegrationKit(ctx, action.client, integration.Status.IntegrationKit.Name, integration.Status.IntegrationKit.Namespace)
-	if err != nil {
-		return nil, errors.Wrapf(err, "unable to find integration kit %s/%s, %s", integration.Status.IntegrationKit.Namespace, integration.Status.IntegrationKit.Name, err)
-	}
-
-	_, err = trait.Apply(ctx, action.client, integration, kit)
-	if err != nil {
-		return nil, err
-	}
-
-	integration.Status.Phase = v1.IntegrationPhaseRunning
-
-	return integration, nil
-}
diff --git a/pkg/controller/integration/error.go b/pkg/controller/integration/error.go
deleted file mode 100644
index a7f490c..0000000
--- a/pkg/controller/integration/error.go
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-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 integration
-
-import (
-	"context"
-
-	appsv1 "k8s.io/api/apps/v1"
-	corev1 "k8s.io/api/core/v1"
-
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
-	"github.com/apache/camel-k/pkg/util/digest"
-	"github.com/apache/camel-k/pkg/util/kubernetes"
-	k8serrors "k8s.io/apimachinery/pkg/api/errors"
-)
-
-// NewErrorAction creates a new error action for an integration
-func NewErrorAction() Action {
-	return &errorAction{}
-}
-
-type errorAction struct {
-	baseAction
-}
-
-func (action *errorAction) Name() string {
-	return "error"
-}
-
-func (action *errorAction) CanHandle(integration *v1.Integration) bool {
-	return integration.Status.Phase == v1.IntegrationPhaseError
-}
-
-func (action *errorAction) Handle(ctx context.Context, integration *v1.Integration) (*v1.Integration, error) {
-	hash, err := digest.ComputeForIntegration(integration)
-	if err != nil {
-		return nil, err
-	}
-
-	if hash != integration.Status.Digest {
-		action.L.Info("Integration needs a rebuild")
-
-		integration.Initialize()
-		integration.Status.Digest = hash
-
-		return integration, nil
-	}
-
-	if kubernetes.IsConditionTrue(integration, v1.IntegrationConditionDeploymentAvailable) {
-		deployment, err := kubernetes.GetDeployment(ctx, action.client, integration.Name, integration.Namespace)
-		if err != nil && k8serrors.IsNotFound(err) {
-			return nil, err
-		}
-
-		// if the integration is in error phase, check if the corresponding pod is running ok, the user may have updated the integration.
-		deployAvailable := false
-		progressingOk := false
-		for _, c := range deployment.Status.Conditions {
-			// first, check if the container is in available state
-			if c.Type == appsv1.DeploymentAvailable {
-				deployAvailable = c.Status == corev1.ConditionTrue
-			}
-			// second, check the progressing and the reasons
-			if c.Type == appsv1.DeploymentProgressing {
-				progressingOk = c.Status == corev1.ConditionTrue && (c.Reason == "NewReplicaSetAvailable" || c.Reason == "ReplicaSetUpdated")
-			}
-		}
-		if deployAvailable && progressingOk {
-			availableCondition := v1.IntegrationCondition{
-				Type:   v1.IntegrationConditionReady, 
-				Status: corev1.ConditionTrue,
-				Reason: v1.IntegrationConditionReplicaSetReadyReason,
-			}
-			integration.Status.SetConditions(availableCondition)
-			integration.Status.Phase = v1.IntegrationPhaseRunning
-			return integration, nil
-		}
-	}
-
-	// TODO check also if deployment matches (e.g. replicas)
-	return nil, nil
-}
diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index 55bf2ec..8b9c745 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -311,9 +311,7 @@ func (r *reconcileIntegration) Reconcile(ctx context.Context, request reconcile.
 		NewPlatformSetupAction(),
 		NewInitializeAction(),
 		newBuildKitAction(),
-		NewDeployAction(),
 		NewMonitorAction(),
-		NewErrorAction(),
 	}
 
 	for _, a := range actions {
diff --git a/pkg/controller/integration/monitor.go b/pkg/controller/integration/monitor.go
index 532ad8f..a475abe 100644
--- a/pkg/controller/integration/monitor.go
+++ b/pkg/controller/integration/monitor.go
@@ -50,11 +50,18 @@ func (action *monitorAction) Name() string {
 }
 
 func (action *monitorAction) CanHandle(integration *v1.Integration) bool {
-	return integration.Status.Phase == v1.IntegrationPhaseRunning
+	return integration.Status.Phase == v1.IntegrationPhaseDeploying ||
+		integration.Status.Phase == v1.IntegrationPhaseRunning ||
+		integration.Status.Phase == v1.IntegrationPhaseError
 }
 
 func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integration) (*v1.Integration, error) {
-	// Check if the Integration has changed
+	// At that staged the Integration must have a Kit
+	if integration.Status.IntegrationKit == nil {
+		return nil, errors.Errorf("no kit set on integration %s", integration.Name)
+	}
+
+	// Check if the Integration requires a rebuild
 	hash, err := digest.ComputeForIntegration(integration)
 	if err != nil {
 		return nil, err
@@ -97,7 +104,7 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
 		integration.SetIntegrationKit(priorityReadyKit)
 	}
 
-	// Run traits that are enabled for the running phase
+	// Run traits that are enabled for the phase
 	_, err = trait.Apply(ctx, action.client, integration, kit)
 	if err != nil {
 		return nil, err
@@ -128,7 +135,12 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
 		}
 	}
 
-	// Mirror ready condition from the owned resource (e.g.ReplicaSet, Deployment, CronJob, ...)
+	// Reconcile Integration phase
+	if integration.Status.Phase == v1.IntegrationPhaseDeploying {
+		integration.Status.Phase = v1.IntegrationPhaseRunning
+	}
+
+	// Mirror ready condition from the owned resource (e.g., Deployment, CronJob, KnativeService ...)
 	// into the owning integration
 	previous := integration.Status.GetCondition(v1.IntegrationConditionReady)
 	kubernetes.MirrorReadyCondition(ctx, action.client, integration)
@@ -149,29 +161,57 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
 			return nil, err
 		}
 
-		deployUnavailable := false
-		progressingFailing := false
-		for _, c := range deployment.Status.Conditions {
-			// first, check if the container status is not available
-			if c.Type == appsv1.DeploymentAvailable {
-				deployUnavailable = c.Status == corev1.ConditionFalse
+		switch integration.Status.Phase {
+		case v1.IntegrationPhaseRunning:
+			deployUnavailable := false
+			progressingFailing := false
+			for _, c := range deployment.Status.Conditions {
+				// first, check if the container status is not available
+				if c.Type == appsv1.DeploymentAvailable {
+					deployUnavailable = c.Status == corev1.ConditionFalse
+				}
+				// second, check when it is progressing and reason is the replicas are available but the number of replicas are zero
+				// in this case, the container integration is failing
+				if c.Type == appsv1.DeploymentProgressing {
+					progressingFailing = c.Status == corev1.ConditionTrue && c.Reason == "NewReplicaSetAvailable" && deployment.Status.AvailableReplicas < 1
+				}
 			}
-			// second, check when it is progressing and reason is the replicas are available but the number of replicas are zero
-			// in this case, the container integration is failing
-			if c.Type == appsv1.DeploymentProgressing {
-				progressingFailing = c.Status == corev1.ConditionTrue && c.Reason == "NewReplicaSetAvailable" && deployment.Status.AvailableReplicas < 1
+			if deployUnavailable && progressingFailing {
+				notAvailableCondition := v1.IntegrationCondition{
+					Type:    v1.IntegrationConditionReady,
+					Status:  corev1.ConditionFalse,
+					Reason:  v1.IntegrationConditionErrorReason,
+					Message: "The corresponding pod(s) may be in error state, look at the pod status or log for errors",
+				}
+				integration.Status.SetConditions(notAvailableCondition)
+				integration.Status.Phase = v1.IntegrationPhaseError
+				return integration, nil
 			}
-		}
-		if deployUnavailable && progressingFailing {
-			notAvailableCondition := v1.IntegrationCondition{
-				Type:    v1.IntegrationConditionReady,
-				Status:  corev1.ConditionFalse,
-				Reason:  v1.IntegrationConditionErrorReason,
-				Message: "The corresponding pod(s) may be in error state, look at the pod status or log for errors",
+
+		case v1.IntegrationPhaseError:
+			// if the integration is in error phase, check if the corresponding pod is running ok, the user may have updated the integration.
+			deployAvailable := false
+			progressingOk := false
+			for _, c := range deployment.Status.Conditions {
+				// first, check if the container is in available state
+				if c.Type == appsv1.DeploymentAvailable {
+					deployAvailable = c.Status == corev1.ConditionTrue
+				}
+				// second, check the progressing and the reasons
+				if c.Type == appsv1.DeploymentProgressing {
+					progressingOk = c.Status == corev1.ConditionTrue && (c.Reason == "NewReplicaSetAvailable" || c.Reason == "ReplicaSetUpdated")
+				}
+			}
+			if deployAvailable && progressingOk {
+				availableCondition := v1.IntegrationCondition{
+					Type:   v1.IntegrationConditionReady,
+					Status: corev1.ConditionTrue,
+					Reason: v1.IntegrationConditionReplicaSetReadyReason,
+				}
+				integration.Status.SetConditions(availableCondition)
+				integration.Status.Phase = v1.IntegrationPhaseRunning
+				return integration, nil
 			}
-			integration.Status.SetConditions(notAvailableCondition)
-			integration.Status.Phase = v1.IntegrationPhaseError
-			return integration, nil
 		}
 	}
 
diff --git a/pkg/trait/affinity.go b/pkg/trait/affinity.go
index 330bd58..bd27846 100644
--- a/pkg/trait/affinity.go
+++ b/pkg/trait/affinity.go
@@ -68,7 +68,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(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning), nil
+	return e.IntegrationInRunningPhases(), nil
 }
 
 func (t *affinityTrait) Apply(e *Environment) (err error) {
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index 5ef07aa..9685e17 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -22,7 +22,6 @@ import (
 	"path"
 	"sort"
 
-	"github.com/apache/camel-k/pkg/util/kubernetes"
 	appsv1 "k8s.io/api/apps/v1"
 	"k8s.io/api/batch/v1beta1"
 	corev1 "k8s.io/api/core/v1"
@@ -34,6 +33,7 @@ import (
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/util"
 	"github.com/apache/camel-k/pkg/util/envvar"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
 const (
@@ -130,7 +130,7 @@ func (t *containerTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
@@ -157,16 +157,12 @@ func (t *containerTrait) Apply(e *Environment) error {
 		if err := t.configureDependencies(e); err != nil {
 			return err
 		}
+	} else {
+		return t.configureContainer(e)
 	}
 
-	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
-		if err := t.configureImageIntegrationKit(e); err != nil {
-			return err
-		}
-	}
-
-	if e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
-		return t.configureContainer(e)
+	if err := t.configureImageIntegrationKit(e); err != nil {
+		return err
 	}
 
 	return nil
diff --git a/pkg/trait/cron.go b/pkg/trait/cron.go
index 191fcaa..c82fe39 100644
--- a/pkg/trait/cron.go
+++ b/pkg/trait/cron.go
@@ -125,7 +125,7 @@ func (t *cronTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying) {
+	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
@@ -234,7 +234,7 @@ func (t *cronTrait) Apply(e *Environment) error {
 		}
 	}
 
-	if IsNilOrFalse(t.Fallback) && e.IntegrationInPhase(v1.IntegrationPhaseDeploying) {
+	if IsNilOrFalse(t.Fallback) && e.IntegrationInRunningPhases() {
 		if e.ApplicationProperties == nil {
 			e.ApplicationProperties = make(map[string]string)
 		}
@@ -260,13 +260,8 @@ func (t *cronTrait) Apply(e *Environment) error {
 }
 
 func (t *cronTrait) getCronJobFor(e *Environment) *v1beta1.CronJob {
-	labels := map[string]string{
-		v1.IntegrationLabel: e.Integration.Name,
-	}
-
-	annotations := make(map[string]string)
-
 	// Copy annotations from the integration resource
+	annotations := make(map[string]string)
 	if e.Integration.Annotations != nil {
 		for k, v := range filterTransferableAnnotations(e.Integration.Annotations) {
 			annotations[k] = v
@@ -279,9 +274,11 @@ func (t *cronTrait) getCronJobFor(e *Environment) *v1beta1.CronJob {
 			APIVersion: v1beta1.SchemeGroupVersion.String(),
 		},
 		ObjectMeta: metav1.ObjectMeta{
-			Name:        e.Integration.Name,
-			Namespace:   e.Integration.Namespace,
-			Labels:      labels,
+			Name:      e.Integration.Name,
+			Namespace: e.Integration.Namespace,
+			Labels: map[string]string{
+				v1.IntegrationLabel: e.Integration.Name,
+			},
 			Annotations: e.Integration.Annotations,
 		},
 		Spec: v1beta1.CronJobSpec{
@@ -292,7 +289,9 @@ func (t *cronTrait) getCronJobFor(e *Environment) *v1beta1.CronJob {
 				Spec: batchv1.JobSpec{
 					Template: corev1.PodTemplateSpec{
 						ObjectMeta: metav1.ObjectMeta{
-							Labels:      labels,
+							Labels: map[string]string{
+								v1.IntegrationLabel: e.Integration.Name,
+							},
 							Annotations: annotations,
 						},
 						Spec: corev1.PodSpec{
diff --git a/pkg/trait/deployer.go b/pkg/trait/deployer.go
index dcc71eb..56f148a 100644
--- a/pkg/trait/deployer.go
+++ b/pkg/trait/deployer.go
@@ -29,7 +29,6 @@ import (
 
 	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
 
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/util/patch"
 )
 
@@ -54,14 +53,7 @@ func newDeployerTrait() Trait {
 }
 
 func (t *deployerTrait) Configure(e *Environment) (bool, error) {
-	return e.IntegrationInPhase(
-		v1.IntegrationPhaseNone,
-		v1.IntegrationPhaseWaitingForBindings,
-		v1.IntegrationPhaseWaitingForPlatform,
-		v1.IntegrationPhaseInitialization,
-		v1.IntegrationPhaseDeploying,
-		v1.IntegrationPhaseRunning,
-	), nil
+	return e.Integration != nil && IsNilOrTrue(t.Enabled), nil
 }
 
 func (t *deployerTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/deployer_test.go b/pkg/trait/deployer_test.go
index 6b43c2b..3c44160 100644
--- a/pkg/trait/deployer_test.go
+++ b/pkg/trait/deployer_test.go
@@ -41,7 +41,7 @@ func TestConfigureDeployerTraitInWrongPhaseDoesNotSucceed(t *testing.T) {
 
 	configured, err := deployerTrait.Configure(environment)
 
-	assert.False(t, configured)
+	assert.True(t, configured)
 	assert.Nil(t, err)
 }
 
diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go
index cf788e7..34369fb 100644
--- a/pkg/trait/deployment.go
+++ b/pkg/trait/deployment.go
@@ -55,7 +55,7 @@ func (t *deploymentTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if e.IntegrationInPhase(v1.IntegrationPhaseRunning) {
+	if e.IntegrationInPhase(v1.IntegrationPhaseRunning, v1.IntegrationPhaseError) {
 		condition := e.Integration.Status.GetCondition(v1.IntegrationConditionDeploymentAvailable)
 		return condition != nil && condition.Status == corev1.ConditionTrue, nil
 	}
@@ -98,34 +98,18 @@ func (t *deploymentTrait) ControllerStrategySelectorOrder() int {
 }
 
 func (t *deploymentTrait) Apply(e *Environment) error {
-	if e.InPhase(v1.IntegrationKitPhaseReady, v1.IntegrationPhaseDeploying) ||
-		e.InPhase(v1.IntegrationKitPhaseReady, v1.IntegrationPhaseRunning) {
-		maps := e.computeConfigMaps()
-		deployment := t.getDeploymentFor(e)
+	maps := e.computeConfigMaps()
+	deployment := t.getDeploymentFor(e)
 
-		e.Resources.AddAll(maps)
-		e.Resources.Add(deployment)
+	e.Resources.AddAll(maps)
+	e.Resources.Add(deployment)
 
-		e.Integration.Status.SetCondition(
-			v1.IntegrationConditionDeploymentAvailable,
-			corev1.ConditionTrue,
-			v1.IntegrationConditionDeploymentAvailableReason,
-			fmt.Sprintf("deployment name is %s", deployment.Name),
-		)
-
-		if e.IntegrationInPhase(v1.IntegrationPhaseRunning) {
-			// Reconcile the deployment replicas
-			replicas := e.Integration.Spec.Replicas
-			// Deployment replicas defaults to 1, so we avoid forcing
-			// an update to nil that will result to another update cycle
-			// back to that default value by the Deployment controller.
-			if replicas == nil {
-				one := int32(1)
-				replicas = &one
-			}
-			deployment.Spec.Replicas = replicas
-		}
-	}
+	e.Integration.Status.SetCondition(
+		v1.IntegrationConditionDeploymentAvailable,
+		corev1.ConditionTrue,
+		v1.IntegrationConditionDeploymentAvailableReason,
+		fmt.Sprintf("deployment name is %s", deployment.Name),
+	)
 
 	return nil
 }
@@ -178,5 +162,16 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 		},
 	}
 
+	// Reconcile the deployment replicas
+	replicas := e.Integration.Spec.Replicas
+	// Deployment replicas defaults to 1, so we avoid forcing
+	// an update to nil that will result to another update cycle
+	// back to that default value by the Deployment controller.
+	if replicas == nil {
+		one := int32(1)
+		replicas = &one
+	}
+	deployment.Spec.Replicas = replicas
+
 	return &deployment
 }
diff --git a/pkg/trait/environment.go b/pkg/trait/environment.go
index 6ea9e9b..ed5ee41 100644
--- a/pkg/trait/environment.go
+++ b/pkg/trait/environment.go
@@ -18,7 +18,6 @@ limitations under the License.
 package trait
 
 import (
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/util/defaults"
 	"github.com/apache/camel-k/pkg/util/envvar"
 )
@@ -59,7 +58,7 @@ func newEnvironmentTrait() Trait {
 
 func (t *environmentTrait) Configure(e *Environment) (bool, error) {
 	if IsNilOrTrue(t.Enabled) {
-		return e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning), nil
+		return e.IntegrationInRunningPhases(), nil
 	}
 
 	return false, nil
diff --git a/pkg/trait/error_handler.go b/pkg/trait/error_handler.go
index dfb4799..571e4ec 100644
--- a/pkg/trait/error_handler.go
+++ b/pkg/trait/error_handler.go
@@ -21,9 +21,10 @@ import (
 	"fmt"
 	"strings"
 
+	"gopkg.in/yaml.v2"
+
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
-	"gopkg.in/yaml.v2"
 )
 
 // The error-handler is a platform trait used to inject Error Handler source into the integration runtime.
@@ -52,7 +53,7 @@ func (t *errorHandlerTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
@@ -65,7 +66,7 @@ func (t *errorHandlerTrait) Configure(e *Environment) (bool, error) {
 
 func (t *errorHandlerTrait) Apply(e *Environment) error {
 	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
-		// If the user configure directly the URI, we need to autodiscover the underlying component
+		// If the user configure directly the URI, we need to auto-discover the underlying component
 		// and add the related dependency
 		defaultErrorHandlerURI := e.Integration.Spec.GetConfigurationProperty(
 			fmt.Sprintf("%s.deadLetterUri", v1alpha1.ErrorHandlerAppPropertiesPrefix))
diff --git a/pkg/trait/gc.go b/pkg/trait/gc.go
index aec1008..a798a58 100644
--- a/pkg/trait/gc.go
+++ b/pkg/trait/gc.go
@@ -81,17 +81,14 @@ func (t *garbageCollectorTrait) Configure(e *Environment) (bool, error) {
 		t.DiscoveryCache = &s
 	}
 
-	return e.IntegrationInPhase(
-			v1.IntegrationPhaseInitialization,
-			v1.IntegrationPhaseDeploying,
-			v1.IntegrationPhaseRunning),
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(),
 		nil
 }
 
 func (t *garbageCollectorTrait) Apply(e *Environment) error {
 	switch e.Integration.Status.Phase {
 
-	case v1.IntegrationPhaseRunning:
+	case v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning, v1.IntegrationPhaseError:
 		// Register a post action that deletes the existing resources that are labelled
 		// with the previous integration generations.
 		// TODO: this should be refined so that it's run when all the replicas for the newer generation
diff --git a/pkg/trait/ingress.go b/pkg/trait/ingress.go
index dd0d565..24115fa 100644
--- a/pkg/trait/ingress.go
+++ b/pkg/trait/ingress.go
@@ -65,7 +65,7 @@ func (t *ingressTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
diff --git a/pkg/trait/ingress_test.go b/pkg/trait/ingress_test.go
index 84c3a06..e35cdff 100644
--- a/pkg/trait/ingress_test.go
+++ b/pkg/trait/ingress_test.go
@@ -59,7 +59,7 @@ func TestConfigureIngressTraitInWrongPhaseDoesNotSucceed(t *testing.T) {
 
 	configured, err := ingressTrait.Configure(environment)
 
-	assert.False(t, configured)
+	assert.True(t, configured)
 	assert.Nil(t, err)
 	assert.Len(t, environment.Integration.Status.Conditions, 0)
 }
diff --git a/pkg/trait/init.go b/pkg/trait/init.go
index 466c24e..3cf8472 100644
--- a/pkg/trait/init.go
+++ b/pkg/trait/init.go
@@ -29,7 +29,6 @@ import (
 
 const flowsInternalSourceName = "camel-k-embedded-flow.yaml"
 
-// Internal trait
 type initTrait struct {
 	BaseTrait `property:",squash"`
 }
@@ -45,54 +44,47 @@ func (t *initTrait) Configure(e *Environment) (bool, error) {
 		return false, errors.New("trait init cannot be disabled")
 	}
 
-	return true, nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil
 }
 
 func (t *initTrait) Apply(e *Environment) error {
-	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
-
-		// Flows need to be turned into a generated source
-		if len(e.Integration.Spec.Flows) > 0 {
-			content, err := dsl.ToYamlDSL(e.Integration.Spec.Flows)
-			if err != nil {
-				return err
-			}
-			e.Integration.Status.AddOrReplaceGeneratedSources(v1.SourceSpec{
-				DataSpec: v1.DataSpec{
-					Name:    flowsInternalSourceName,
-					Content: string(content),
-				},
-			})
+	// Flows need to be turned into a generated source
+	if len(e.Integration.Spec.Flows) > 0 {
+		content, err := dsl.ToYamlDSL(e.Integration.Spec.Flows)
+		if err != nil {
+			return err
 		}
+		e.Integration.Status.AddOrReplaceGeneratedSources(v1.SourceSpec{
+			DataSpec: v1.DataSpec{
+				Name:    flowsInternalSourceName,
+				Content: string(content),
+			},
+		})
+	}
 
-		//
-		// Dependencies need to be recomputed in case of a trait declares a capability but as
-		// the dependencies trait runs earlier than some task such as the cron one, we need to
-		// register a post step processor that recompute the dependencies based on the declared
-		// capabilities
-		//
-		e.PostStepProcessors = append(e.PostStepProcessors, func(environment *Environment) error {
-			//
-			// The camel catalog is set-up by the camel trait so it may not be available for
-			// traits executed before that one
-			//
-			if e.CamelCatalog != nil {
-				// add runtime specific dependencies
-				for _, capability := range e.Integration.Status.Capabilities {
-					for _, dependency := range e.CamelCatalog.Runtime.CapabilityDependencies(capability) {
-						util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, dependency.GetDependencyID())
-					}
+	// Dependencies need to be recomputed in case of a trait declares a capability but as
+	// the dependencies trait runs earlier than some task such as the cron one, we need to
+	// register a post step processor that recompute the dependencies based on the declared
+	// capabilities.
+	e.PostStepProcessors = append(e.PostStepProcessors, func(environment *Environment) error {
+		// The camel catalog is set up by the camel trait, so it may not be available for
+		// traits executed before that one.
+		if e.CamelCatalog != nil {
+			// add runtime specific dependencies
+			for _, capability := range e.Integration.Status.Capabilities {
+				for _, dependency := range e.CamelCatalog.Runtime.CapabilityDependencies(capability) {
+					util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, dependency.GetDependencyID())
 				}
 			}
+		}
 
-			if e.Integration.Status.Dependencies != nil {
-				// sort the dependencies to get always the same list if they don't change
-				sort.Strings(e.Integration.Status.Dependencies)
-			}
+		if e.Integration.Status.Dependencies != nil {
+			// sort the dependencies to get always the same list if they don't change
+			sort.Strings(e.Integration.Status.Dependencies)
+		}
 
-			return nil
-		})
-	}
+		return nil
+	})
 
 	return nil
 }
diff --git a/pkg/trait/istio.go b/pkg/trait/istio.go
index f6fc951..fd48559 100644
--- a/pkg/trait/istio.go
+++ b/pkg/trait/istio.go
@@ -23,11 +23,9 @@ import (
 	appsv1 "k8s.io/api/apps/v1"
 
 	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
-
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 )
 
-// The Istio trait allows to configure properties related to the Istio service mesh,
+// The Istio trait allows configuring properties related to the Istio service mesh,
 // such as sidecar injection and outbound IP ranges.
 //
 // +camel-k:trait=istio
@@ -53,7 +51,7 @@ func newIstioTrait() Trait {
 
 func (t *istioTrait) Configure(e *Environment) (bool, error) {
 	if IsTrue(t.Enabled) {
-		return e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning), nil
+		return e.IntegrationInRunningPhases(), nil
 	}
 
 	return false, nil
diff --git a/pkg/trait/jolokia.go b/pkg/trait/jolokia.go
index 9579d7c..ebfbb46 100644
--- a/pkg/trait/jolokia.go
+++ b/pkg/trait/jolokia.go
@@ -75,11 +75,11 @@ func newJolokiaTrait() Trait {
 }
 
 func (t *jolokiaTrait) Configure(e *Environment) (bool, error) {
-	return IsTrue(t.Enabled) && e.IntegrationInPhase(
-		v1.IntegrationPhaseInitialization,
-		v1.IntegrationPhaseDeploying,
-		v1.IntegrationPhaseRunning,
-	), nil
+	if IsNilOrFalse(t.Enabled) {
+		return false, nil
+	}
+
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil
 }
 
 func (t *jolokiaTrait) Apply(e *Environment) (err error) {
diff --git a/pkg/trait/jvm.go b/pkg/trait/jvm.go
index 60e853b..f327929 100644
--- a/pkg/trait/jvm.go
+++ b/pkg/trait/jvm.go
@@ -71,8 +71,7 @@ func (t *jvmTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.InPhase(v1.IntegrationKitPhaseReady, v1.IntegrationPhaseDeploying) &&
-		!e.InPhase(v1.IntegrationKitPhaseReady, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationKitInPhase(v1.IntegrationKitPhaseReady) || !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
diff --git a/pkg/trait/jvm_test.go b/pkg/trait/jvm_test.go
index a6360a7..6fe05d4 100644
--- a/pkg/trait/jvm_test.go
+++ b/pkg/trait/jvm_test.go
@@ -53,7 +53,7 @@ func TestConfigureJvmTraitInWrongIntegrationPhaseDoesNotSucceed(t *testing.T) {
 
 	configured, err := trait.Configure(environment)
 	assert.Nil(t, err)
-	assert.False(t, configured)
+	assert.True(t, configured)
 }
 
 func TestConfigureJvmTraitInWrongIntegrationKitPhaseDoesNotSucceed(t *testing.T) {
diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index cee7ac3..87f9c22 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -25,7 +25,8 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/apache/camel-k/pkg/util/source"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
@@ -37,8 +38,7 @@ import (
 	"github.com/apache/camel-k/pkg/util/digest"
 	"github.com/apache/camel-k/pkg/util/dsl"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"github.com/apache/camel-k/pkg/util/source"
 )
 
 // The kamelets trait is a platform trait used to inject Kamelets into the integration runtime.
@@ -92,7 +92,7 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
@@ -126,15 +126,14 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 }
 
 func (t *kameletsTrait) Apply(e *Environment) error {
-	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseRunning) {
+	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases() {
 		if err := t.addKamelets(e); err != nil {
 			return err
 		}
 	}
-
 	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
 		return t.addConfigurationSecrets(e)
-	} else if e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	} else if e.IntegrationInRunningPhases() {
 		return t.configureApplicationProperties(e)
 	}
 
diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go
index fa6591e..03ecfb3 100644
--- a/pkg/trait/knative.go
+++ b/pkg/trait/knative.go
@@ -108,7 +108,7 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
@@ -216,7 +216,7 @@ func (t *knativeTrait) Apply(e *Environment) error {
 		util.StringSliceUniqueAdd(&e.Integration.Status.Capabilities, v1.CapabilityPlatformHTTP)
 	}
 
-	if e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if e.IntegrationInRunningPhases() {
 		env := knativeapi.NewCamelEnvironment()
 		if t.Configuration != "" {
 			if err := env.Deserialize(t.Configuration); err != nil {
diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go
index 5bf9e5c..be620e1 100644
--- a/pkg/trait/knative_service.go
+++ b/pkg/trait/knative_service.go
@@ -102,7 +102,7 @@ func (t *knativeServiceTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.InPhase(v1.IntegrationKitPhaseReady, v1.IntegrationPhaseDeploying) && !e.IntegrationInPhase(v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
@@ -161,7 +161,7 @@ func (t *knativeServiceTrait) Configure(e *Environment) (bool, error) {
 		}
 	}
 
-	if e.IntegrationInPhase(v1.IntegrationPhaseRunning) {
+	if e.IntegrationInPhase(v1.IntegrationPhaseRunning, v1.IntegrationPhaseError) {
 		condition := e.Integration.Status.GetCondition(v1.IntegrationConditionKnativeServiceAvailable)
 		return condition != nil && condition.Status == corev1.ConditionTrue, nil
 	}
@@ -170,7 +170,10 @@ func (t *knativeServiceTrait) Configure(e *Environment) (bool, error) {
 }
 
 func (t *knativeServiceTrait) Apply(e *Environment) error {
-	ksvc := t.getServiceFor(e)
+	ksvc, err := t.getServiceFor(e)
+	if err != nil {
+		return err
+	}
 	maps := e.computeConfigMaps()
 
 	e.Resources.AddAll(maps)
@@ -183,56 +186,6 @@ func (t *knativeServiceTrait) Apply(e *Environment) error {
 		fmt.Sprintf("Knative service name is %s", ksvc.Name),
 	)
 
-	if e.IntegrationInPhase(v1.IntegrationPhaseRunning) {
-		replicas := e.Integration.Spec.Replicas
-
-		isUpdateRequired := false
-		minScale, ok := ksvc.Spec.Template.Annotations[knativeServingMinScaleAnnotation]
-		if ok {
-			min, err := strconv.Atoi(minScale)
-			if err != nil {
-				return err
-			}
-			if replicas == nil || min != int(*replicas) {
-				isUpdateRequired = true
-			}
-		} else if replicas != nil {
-			isUpdateRequired = true
-		}
-
-		maxScale, ok := ksvc.Spec.Template.Annotations[knativeServingMaxScaleAnnotation]
-		if ok {
-			max, err := strconv.Atoi(maxScale)
-			if err != nil {
-				return err
-			}
-			if replicas == nil || max != int(*replicas) {
-				isUpdateRequired = true
-			}
-		} else if replicas != nil {
-			isUpdateRequired = true
-		}
-
-		if isUpdateRequired {
-			if replicas == nil {
-				if t.MinScale != nil && *t.MinScale > 0 {
-					ksvc.Spec.Template.Annotations[knativeServingMinScaleAnnotation] = strconv.Itoa(*t.MinScale)
-				} else {
-					delete(ksvc.Spec.Template.Annotations, knativeServingMinScaleAnnotation)
-				}
-				if t.MaxScale != nil && *t.MaxScale > 0 {
-					ksvc.Spec.Template.Annotations[knativeServingMaxScaleAnnotation] = strconv.Itoa(*t.MaxScale)
-				} else {
-					delete(ksvc.Spec.Template.Annotations, knativeServingMaxScaleAnnotation)
-				}
-			} else {
-				scale := strconv.Itoa(int(*replicas))
-				ksvc.Spec.Template.Annotations[knativeServingMinScaleAnnotation] = scale
-				ksvc.Spec.Template.Annotations[knativeServingMaxScaleAnnotation] = scale
-			}
-		}
-	}
-
 	return nil
 }
 
@@ -262,23 +215,16 @@ func (t *knativeServiceTrait) ControllerStrategySelectorOrder() int {
 	return 100
 }
 
-func (t *knativeServiceTrait) getServiceFor(e *Environment) *serving.Service {
-	labels := map[string]string{
-		v1.IntegrationLabel: e.Integration.Name,
-	}
-
-	annotations := make(map[string]string)
-
+func (t *knativeServiceTrait) getServiceFor(e *Environment) (*serving.Service, error) {
 	// Copy annotations from the integration resource
+	annotations := make(map[string]string)
 	if e.Integration.Annotations != nil {
 		for k, v := range filterTransferableAnnotations(e.Integration.Annotations) {
 			annotations[k] = v
 		}
 	}
 
-	//
-	// Set Knative Scaling behavior
-	//
+	// Set Knative auto-scaling behavior
 	if t.Class != "" {
 		annotations[knativeServingClassAnnotation] = t.Class
 	}
@@ -301,16 +247,20 @@ func (t *knativeServiceTrait) getServiceFor(e *Environment) *serving.Service {
 			APIVersion: serving.SchemeGroupVersion.String(),
 		},
 		ObjectMeta: metav1.ObjectMeta{
-			Name:        e.Integration.Name,
-			Namespace:   e.Integration.Namespace,
-			Labels:      labels,
+			Name:      e.Integration.Name,
+			Namespace: e.Integration.Namespace,
+			Labels: map[string]string{
+				v1.IntegrationLabel: e.Integration.Name,
+			},
 			Annotations: e.Integration.Annotations,
 		},
 		Spec: serving.ServiceSpec{
 			ConfigurationSpec: serving.ConfigurationSpec{
 				Template: serving.RevisionTemplateSpec{
 					ObjectMeta: metav1.ObjectMeta{
-						Labels:      labels,
+						Labels: map[string]string{
+							v1.IntegrationLabel: e.Integration.Name,
+						},
 						Annotations: annotations,
 					},
 					Spec: serving.RevisionSpec{
@@ -323,5 +273,53 @@ func (t *knativeServiceTrait) getServiceFor(e *Environment) *serving.Service {
 		},
 	}
 
-	return &svc
+	replicas := e.Integration.Spec.Replicas
+
+	isUpdateRequired := false
+	minScale, ok := svc.Spec.Template.Annotations[knativeServingMinScaleAnnotation]
+	if ok {
+		min, err := strconv.Atoi(minScale)
+		if err != nil {
+			return nil, err
+		}
+		if replicas == nil || min != int(*replicas) {
+			isUpdateRequired = true
+		}
+	} else if replicas != nil {
+		isUpdateRequired = true
+	}
+
+	maxScale, ok := svc.Spec.Template.Annotations[knativeServingMaxScaleAnnotation]
+	if ok {
+		max, err := strconv.Atoi(maxScale)
+		if err != nil {
+			return nil, err
+		}
+		if replicas == nil || max != int(*replicas) {
+			isUpdateRequired = true
+		}
+	} else if replicas != nil {
+		isUpdateRequired = true
+	}
+
+	if isUpdateRequired {
+		if replicas == nil {
+			if t.MinScale != nil && *t.MinScale > 0 {
+				svc.Spec.Template.Annotations[knativeServingMinScaleAnnotation] = strconv.Itoa(*t.MinScale)
+			} else {
+				delete(svc.Spec.Template.Annotations, knativeServingMinScaleAnnotation)
+			}
+			if t.MaxScale != nil && *t.MaxScale > 0 {
+				svc.Spec.Template.Annotations[knativeServingMaxScaleAnnotation] = strconv.Itoa(*t.MaxScale)
+			} else {
+				delete(svc.Spec.Template.Annotations, knativeServingMaxScaleAnnotation)
+			}
+		} else {
+			scale := strconv.Itoa(int(*replicas))
+			svc.Spec.Template.Annotations[knativeServingMinScaleAnnotation] = scale
+			svc.Spec.Template.Annotations[knativeServingMaxScaleAnnotation] = scale
+		}
+	}
+
+	return &svc, nil
 }
diff --git a/pkg/trait/logging.go b/pkg/trait/logging.go
index 0c97dcc..1f14e2c 100644
--- a/pkg/trait/logging.go
+++ b/pkg/trait/logging.go
@@ -18,7 +18,6 @@ limitations under the License.
 package trait
 
 import (
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/util/envvar"
 )
 
@@ -61,7 +60,7 @@ func (l loggingTrait) Configure(environment *Environment) (bool, error) {
 		return false, nil
 	}
 
-	return environment.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning), nil
+	return environment.IntegrationInRunningPhases(), nil
 }
 
 func (l loggingTrait) Apply(environment *Environment) error {
diff --git a/pkg/trait/owner.go b/pkg/trait/owner.go
index baf3b45..3a95b77 100644
--- a/pkg/trait/owner.go
+++ b/pkg/trait/owner.go
@@ -20,6 +20,7 @@ package trait
 import (
 	appsv1 "k8s.io/api/apps/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
 	serving "knative.dev/serving/pkg/apis/serving/v1"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
@@ -52,7 +53,7 @@ func (t *ownerTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil
 }
 
 func (t *ownerTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/pdb.go b/pkg/trait/pdb.go
index f862dae..4a334c5 100644
--- a/pkg/trait/pdb.go
+++ b/pkg/trait/pdb.go
@@ -66,10 +66,7 @@ func (t *pdbTrait) Configure(e *Environment) (bool, error) {
 		return false, fmt.Errorf("both minAvailable and maxUnavailable can't be set simultaneously")
 	}
 
-	return e.IntegrationInPhase(
-		v1.IntegrationPhaseDeploying,
-		v1.IntegrationPhaseRunning,
-	), nil
+	return e.IntegrationInRunningPhases(), nil
 }
 
 func (t *pdbTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/platform.go b/pkg/trait/platform.go
index e91dea1..d0d9b23 100644
--- a/pkg/trait/platform.go
+++ b/pkg/trait/platform.go
@@ -18,10 +18,11 @@ limitations under the License.
 package trait
 
 import (
+	k8serrors "k8s.io/apimachinery/pkg/api/errors"
+
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/platform"
 	"github.com/apache/camel-k/pkg/util/openshift"
-	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 )
 
 // The platform trait is a base trait that is used to assign an integration platform to an integration.
diff --git a/pkg/trait/pod.go b/pkg/trait/pod.go
index e45edc0..8ce9aed 100644
--- a/pkg/trait/pod.go
+++ b/pkg/trait/pod.go
@@ -58,7 +58,7 @@ func (t *podTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning), nil
+	return e.IntegrationInRunningPhases(), nil
 }
 
 func (t *podTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/prometheus.go b/pkg/trait/prometheus.go
index bf192f6..6db5c51 100644
--- a/pkg/trait/prometheus.go
+++ b/pkg/trait/prometheus.go
@@ -57,11 +57,11 @@ func newPrometheusTrait() Trait {
 }
 
 func (t *prometheusTrait) Configure(e *Environment) (bool, error) {
-	return IsTrue(t.Enabled) && e.IntegrationInPhase(
-		v1.IntegrationPhaseInitialization,
-		v1.IntegrationPhaseDeploying,
-		v1.IntegrationPhaseRunning,
-	), nil
+	if IsNilOrFalse(t.Enabled) {
+		return false, nil
+	}
+
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil
 }
 
 func (t *prometheusTrait) Apply(e *Environment) (err error) {
diff --git a/pkg/trait/pull_secret.go b/pkg/trait/pull_secret.go
index 20d4722..10779e3 100644
--- a/pkg/trait/pull_secret.go
+++ b/pkg/trait/pull_secret.go
@@ -20,15 +20,17 @@ package trait
 import (
 	"fmt"
 
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
-	"github.com/apache/camel-k/pkg/platform"
-	"github.com/apache/camel-k/pkg/util/kubernetes"
-	"github.com/apache/camel-k/pkg/util/openshift"
 	"github.com/pkg/errors"
+
 	corev1 "k8s.io/api/core/v1"
 	rbacv1 "k8s.io/api/rbac/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+
+	"github.com/apache/camel-k/pkg/platform"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
+	"github.com/apache/camel-k/pkg/util/openshift"
 )
 
 // The Pull Secret trait sets a pull secret on the pod,
@@ -64,7 +66,7 @@ func (t *pullSecretTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
@@ -72,7 +74,7 @@ func (t *pullSecretTrait) Configure(e *Environment) (bool, error) {
 		if t.SecretName == "" {
 			secret := e.Platform.Status.Build.Registry.Secret
 			if secret != "" {
-				key := client.ObjectKey{Namespace: e.Platform.Namespace, Name: secret}
+				key := ctrl.ObjectKey{Namespace: e.Platform.Namespace, Name: secret}
 				obj := corev1.Secret{}
 				if err := t.Client.Get(e.Ctx, key, &obj); err != nil {
 					return false, err
@@ -119,7 +121,7 @@ func (t *pullSecretTrait) Apply(e *Environment) error {
 }
 
 func (t *pullSecretTrait) delegateImagePuller(e *Environment) error {
-	// Applying the rolebinding directly because it's a resource in the operator namespace
+	// Applying the RoleBinding directly because it's a resource in the operator namespace
 	// (different from the integration namespace when delegation is enabled).
 	rb := t.newImagePullerRoleBinding(e)
 	if err := kubernetes.ReplaceResource(e.Ctx, e.Client, rb); err != nil {
diff --git a/pkg/trait/quarkus.go b/pkg/trait/quarkus.go
index 0b76021..f10242d 100644
--- a/pkg/trait/quarkus.go
+++ b/pkg/trait/quarkus.go
@@ -121,8 +121,7 @@ func (t *quarkusTrait) Configure(e *Environment) (bool, error) {
 
 	return e.IntegrationInPhase(v1.IntegrationPhaseBuildingKit) ||
 			e.IntegrationKitInPhase(v1.IntegrationKitPhaseBuildSubmitted) ||
-			e.InPhase(v1.IntegrationKitPhaseReady, v1.IntegrationPhaseDeploying) ||
-			e.InPhase(v1.IntegrationKitPhaseReady, v1.IntegrationPhaseRunning),
+			e.IntegrationKitInPhase(v1.IntegrationKitPhaseReady) && e.IntegrationInRunningPhases(),
 		nil
 }
 
@@ -232,7 +231,7 @@ func (t *quarkusTrait) Apply(e *Environment) error {
 		build.Steps = builder.StepIDsFor(steps...)
 
 	case v1.IntegrationKitPhaseReady:
-		if e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) && t.isNativeIntegration(e) {
+		if e.IntegrationInRunningPhases() && t.isNativeIntegration(e) {
 			container := e.getIntegrationContainer()
 			if container == nil {
 				return fmt.Errorf("unable to find integration container: %s", e.Integration.Name)
diff --git a/pkg/trait/route.go b/pkg/trait/route.go
index bd573cf..944e81d 100644
--- a/pkg/trait/route.go
+++ b/pkg/trait/route.go
@@ -120,7 +120,7 @@ func (t *routeTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
@@ -278,9 +278,9 @@ func (t *routeTrait) readContentIfExists(e *Environment, secretName string) (str
 	if len(key) > 0 {
 		content := string(secret.Data[key])
 		if len(content) == 0 {
-			return "", fmt.Errorf("Could not find key %s in secret %s in namespace %s", key, secretName, t.service.Namespace)
+			return "", fmt.Errorf("could not find key %s in secret %s in namespace %s", key, secretName, t.service.Namespace)
 		}
 		return content, nil
 	}
 	return "", nil
-}
\ No newline at end of file
+}
diff --git a/pkg/trait/service.go b/pkg/trait/service.go
index d12d1c7..510a0bd 100644
--- a/pkg/trait/service.go
+++ b/pkg/trait/service.go
@@ -66,7 +66,7 @@ func (t *serviceTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	if !e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	if !e.IntegrationInRunningPhases() {
 		return false, nil
 	}
 
diff --git a/pkg/trait/service_binding.go b/pkg/trait/service_binding.go
index 7bb600c..62540b1 100644
--- a/pkg/trait/service_binding.go
+++ b/pkg/trait/service_binding.go
@@ -20,16 +20,16 @@ package trait
 import (
 	"fmt"
 
-	"github.com/apache/camel-k/pkg/util/reference"
 	corev1 "k8s.io/api/core/v1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
+	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
 
 	sb "github.com/redhat-developer/service-binding-operator/api/v1alpha1"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/util/reference"
 )
 
 // The Service Binding trait allows users to connect to Provisioned Services and ServiceBindings in Kubernetes:
@@ -57,12 +57,8 @@ func (t *serviceBindingTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
-	return e.IntegrationInPhase(
-		v1.IntegrationPhaseInitialization,
-		v1.IntegrationPhaseWaitingForBindings,
-		v1.IntegrationPhaseDeploying,
-		v1.IntegrationPhaseRunning,
-	), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseWaitingForBindings) ||
+		e.IntegrationInRunningPhases(), nil
 }
 
 func (t *serviceBindingTrait) Apply(e *Environment) error {
@@ -121,7 +117,7 @@ func (t *serviceBindingTrait) Apply(e *Environment) error {
 				e.Resources.Add(&request)
 			}
 		}
-	} else if e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning) {
+	} else if e.IntegrationInRunningPhases() {
 		e.ServiceBindings = make(map[string]string)
 		for _, name := range serviceBindings {
 			sb, err := t.getServiceBinding(e, name)
@@ -168,7 +164,7 @@ func isCollectionReady(sb sb.ServiceBinding) bool {
 
 func (t *serviceBindingTrait) getServiceBinding(e *Environment, name string) (sb.ServiceBinding, error) {
 	serviceBinding := sb.ServiceBinding{}
-	key := k8sclient.ObjectKey{
+	key := ctrl.ObjectKey{
 		Namespace: e.Integration.Namespace,
 		Name:      name,
 	}
diff --git a/pkg/trait/toleration.go b/pkg/trait/toleration.go
index add1428..dc5c1cb 100644
--- a/pkg/trait/toleration.go
+++ b/pkg/trait/toleration.go
@@ -22,7 +22,6 @@ import (
 
 	corev1 "k8s.io/api/core/v1"
 
-	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
@@ -61,7 +60,7 @@ func (t *tolerationTrait) Configure(e *Environment) (bool, error) {
 		return false, fmt.Errorf("no taint was provided")
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning), nil
+	return e.IntegrationInRunningPhases(), nil
 }
 
 func (t *tolerationTrait) Apply(e *Environment) (err error) {
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index 50fcb1a..47df0b8 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -248,6 +248,10 @@ func (e *Environment) IntegrationInPhase(phases ...v1.IntegrationPhase) bool {
 	return false
 }
 
+func (e *Environment) IntegrationInRunningPhases() bool {
+	return e.IntegrationInPhase(v1.IntegrationPhaseDeploying, v1.IntegrationPhaseRunning, v1.IntegrationPhaseError)
+}
+
 func (e *Environment) IntegrationKitInPhase(phases ...v1.IntegrationKitPhase) bool {
 	if e.IntegrationKit == nil {
 		return false