You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pc...@apache.org on 2023/10/24 16:22:30 UTC

[camel-k] 01/02: feat(trait): expose conditions

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

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

commit 93a78e6590267d79129f402e65cdd4a623f70591
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Tue Oct 24 13:19:18 2023 +0200

    feat(trait): expose conditions
    
    Add a TraitCondition to be returned by each trait configuration. With this we harmonize the way we collect and expose informations about traits configuration.
---
 addons/keda/keda.go                            | 11 ++--
 addons/keda/keda_test.go                       | 21 ++++---
 addons/master/master.go                        | 22 ++++---
 addons/resume/resume.go                        | 13 ++---
 addons/telemetry/telemetry.go                  | 17 ++++--
 addons/telemetry/telemetry_test.go             |  6 +-
 addons/threescale/3scale.go                    | 10 ++--
 addons/threescale/3scale_test.go               |  9 ++-
 addons/tracing/tracing.go                      |  8 +--
 addons/tracing/tracing_test.go                 |  3 +-
 addons/vault/aws/aws_secrets_manager.go        | 10 ++--
 addons/vault/aws/aws_secrets_manager_test.go   | 12 ++--
 addons/vault/azure/azure_key_vault.go          | 10 ++--
 addons/vault/azure/azure_key_vault_test.go     |  9 ++-
 addons/vault/gcp/gcp_secret_manager.go         | 10 ++--
 addons/vault/gcp/gcp_secret_manager_test.go    |  6 +-
 addons/vault/hashicorp/hashicorp_vault.go      | 10 ++--
 addons/vault/hashicorp/hashicorp_vault_test.go |  9 ++-
 pkg/apis/camel/v1/integration_types.go         |  3 +-
 pkg/apis/camel/v1/integrationkit_types.go      |  2 +
 pkg/trait/affinity.go                          |  8 +--
 pkg/trait/affinity_test.go                     |  9 ++-
 pkg/trait/builder.go                           | 50 ++++++++++++----
 pkg/trait/builder_test.go                      | 19 ++++--
 pkg/trait/camel.go                             |  4 +-
 pkg/trait/camel_test.go                        | 15 +++--
 pkg/trait/container.go                         | 19 +++---
 pkg/trait/container_probes_test.go             | 28 +++++++--
 pkg/trait/container_test.go                    | 35 ++++++-----
 pkg/trait/cron.go                              | 65 ++++++++-------------
 pkg/trait/cron_test.go                         | 31 +++++++---
 pkg/trait/dependencies.go                      |  6 +-
 pkg/trait/dependencies_test.go                 | 27 ++++++---
 pkg/trait/deployer.go                          |  4 +-
 pkg/trait/deployer_test.go                     |  8 +--
 pkg/trait/deployment.go                        | 22 ++++---
 pkg/trait/deployment_test.go                   | 30 +++++-----
 pkg/trait/environment.go                       |  6 +-
 pkg/trait/environment_test.go                  | 16 +++---
 pkg/trait/error_handler.go                     |  8 +--
 pkg/trait/error_handler_test.go                | 18 ++++--
 pkg/trait/gc.go                                | 11 ++--
 pkg/trait/gc_test.go                           | 16 +++++-
 pkg/trait/health.go                            |  9 ++-
 pkg/trait/ingress.go                           | 28 ++++-----
 pkg/trait/ingress_test.go                      | 38 ++++++------
 pkg/trait/init.go                              |  6 +-
 pkg/trait/istio.go                             |  6 +-
 pkg/trait/istio_test.go                        | 16 +++---
 pkg/trait/jolokia.go                           |  6 +-
 pkg/trait/jolokia_test.go                      |  3 +-
 pkg/trait/jvm.go                               | 11 ++--
 pkg/trait/jvm_test.go                          |  9 ++-
 pkg/trait/kamelets.go                          | 16 +++---
 pkg/trait/kamelets_test.go                     | 30 ++++++----
 pkg/trait/knative.go                           | 39 +++++++------
 pkg/trait/knative_service.go                   | 52 ++++++++---------
 pkg/trait/knative_service_test.go              | 17 +++---
 pkg/trait/knative_test.go                      | 16 +++---
 pkg/trait/logging.go                           | 12 ++--
 pkg/trait/logging_test.go                      |  6 +-
 pkg/trait/mount.go                             | 12 ++--
 pkg/trait/mount_test.go                        |  9 ++-
 pkg/trait/openapi.go                           | 10 ++--
 pkg/trait/openapi_test.go                      | 12 ++--
 pkg/trait/owner.go                             | 11 ++--
 pkg/trait/pdb.go                               | 12 ++--
 pkg/trait/pdb_test.go                          |  6 +-
 pkg/trait/platform.go                          | 12 ++--
 pkg/trait/platform_test.go                     |  9 ++-
 pkg/trait/pod.go                               | 14 +++--
 pkg/trait/pod_test.go                          |  9 ++-
 pkg/trait/prometheus.go                        |  6 +-
 pkg/trait/prometheus_test.go                   |  6 +-
 pkg/trait/pull_secret.go                       | 18 +++---
 pkg/trait/pull_secret_test.go                  | 12 ++--
 pkg/trait/quarkus.go                           | 14 +++--
 pkg/trait/quarkus_test.go                      |  9 ++-
 pkg/trait/registry.go                          |  6 +-
 pkg/trait/route.go                             | 39 +++++--------
 pkg/trait/route_test.go                        | 56 ++++++++++--------
 pkg/trait/service.go                           | 46 ++++++---------
 pkg/trait/service_binding.go                   | 14 +++--
 pkg/trait/service_test.go                      | 56 +++++++++++++++---
 pkg/trait/toleration.go                        |  8 +--
 pkg/trait/toleration_test.go                   |  3 +-
 pkg/trait/trait.go                             | 15 ++++-
 pkg/trait/trait_catalog.go                     | 23 +++++---
 pkg/trait/trait_condition_types.go             | 80 ++++++++++++++++++++++++++
 pkg/trait/trait_test.go                        |  2 +-
 pkg/trait/trait_types.go                       |  2 +-
 pkg/trait/util.go                              |  7 ---
 92 files changed, 905 insertions(+), 609 deletions(-)

diff --git a/addons/keda/keda.go b/addons/keda/keda.go
index 8fa069c72..ce4b56ab9 100644
--- a/addons/keda/keda.go
+++ b/addons/keda/keda.go
@@ -116,22 +116,21 @@ func NewKedaTrait() trait.Trait {
 	}
 }
 
-func (t *kedaTrait) Configure(e *trait.Environment) (bool, error) {
+func (t *kedaTrait) Configure(e *trait.Environment) (bool, *trait.TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
-
 	if !e.IntegrationInPhase(camelv1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if t.Auto == nil || *t.Auto {
 		if err := t.populateTriggersFromKamelets(e); err != nil {
-			return false, err
+			return false, nil, err
 		}
 	}
 
-	return len(t.Triggers) > 0, nil
+	return len(t.Triggers) > 0, nil, nil
 }
 
 func (t *kedaTrait) Apply(e *trait.Environment) error {
diff --git a/addons/keda/keda_test.go b/addons/keda/keda_test.go
index 73d60d4ea..d43ed1f63 100644
--- a/addons/keda/keda_test.go
+++ b/addons/keda/keda_test.go
@@ -52,9 +52,10 @@ func TestManualConfig(t *testing.T) {
 	})
 	env := createBasicTestEnvironment()
 
-	res, err := keda.Configure(env)
+	res, condition, err := keda.Configure(env)
 	assert.NoError(t, err)
 	assert.True(t, res)
+	assert.Nil(t, condition)
 	assert.NoError(t, keda.Apply(env))
 	so := getScaledObject(env)
 	assert.NotNil(t, so)
@@ -90,9 +91,10 @@ func TestConfigFromSecret(t *testing.T) {
 		},
 	})
 
-	res, err := keda.Configure(env)
+	res, condition, err := keda.Configure(env)
 	assert.NoError(t, err)
 	assert.True(t, res)
+	assert.Nil(t, condition)
 	assert.NoError(t, keda.Apply(env))
 	so := getScaledObject(env)
 	assert.NotNil(t, so)
@@ -177,9 +179,10 @@ func TestKameletAutoDetection(t *testing.T) {
 			},
 		})
 
-	res, err := keda.Configure(env)
+	res, condition, err := keda.Configure(env)
 	assert.NoError(t, err)
 	assert.True(t, res)
+	assert.Nil(t, condition)
 	assert.NoError(t, keda.Apply(env))
 	so := getScaledObject(env)
 	assert.NotNil(t, so)
@@ -284,15 +287,17 @@ func TestPipeAutoDetection(t *testing.T) {
 
 	it.Status.Phase = camelv1.IntegrationPhaseInitialization
 	init := trait.NewInitTrait()
-	ok, err := init.Configure(env)
+	ok, condition, err := init.Configure(env)
 	assert.NoError(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 	assert.NoError(t, init.Apply(env))
 
 	it.Status.Phase = camelv1.IntegrationPhaseDeploying
-	res, err := keda.Configure(env)
+	res, condition, err := keda.Configure(env)
 	assert.NoError(t, err)
 	assert.True(t, res)
+	assert.Nil(t, condition)
 	assert.NoError(t, keda.Apply(env))
 	so := getScaledObject(env)
 	assert.NotNil(t, so)
@@ -339,9 +344,10 @@ func TestHackReplicas(t *testing.T) {
 		},
 	)
 
-	res, err := keda.Configure(env)
+	res, condition, err := keda.Configure(env)
 	assert.NoError(t, err)
 	assert.True(t, res)
+	assert.Nil(t, condition)
 	assert.NoError(t, keda.Apply(env))
 	scalesClient, err := env.Client.ScalesClient()
 	assert.NoError(t, err)
@@ -386,9 +392,10 @@ func TestHackKLBReplicas(t *testing.T) {
 		},
 	)
 
-	res, err := keda.Configure(env)
+	res, condition, err := keda.Configure(env)
 	assert.NoError(t, err)
 	assert.True(t, res)
+	assert.Nil(t, condition)
 	assert.NoError(t, keda.Apply(env))
 	scalesClient, err := env.Client.ScalesClient()
 	assert.NoError(t, err)
diff --git a/addons/master/master.go b/addons/master/master.go
index aad5a8af5..c60733341 100644
--- a/addons/master/master.go
+++ b/addons/master/master.go
@@ -84,25 +84,27 @@ var (
 	configMapResourceType = "ConfigMap"
 )
 
-func (t *masterTrait) Configure(e *trait.Environment) (bool, error) {
+func (t *masterTrait) Configure(e *trait.Environment) (bool, *trait.TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+		return false, nil, nil
 	}
-
 	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, false) {
+		return false, trait.NewIntegrationConditionUserDisabled(), nil
 	}
 
 	if pointer.BoolDeref(t.Auto, true) {
 		// Check if the master component has been used
 		sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, t.Client, e.Integration, e.Resources)
 		if err != nil {
-			return false, err
+			return false, nil, err
 		}
 
 		meta, err := metadata.ExtractAll(e.CamelCatalog, sources)
 		if err != nil {
-			return false, err
+			return false, nil, err
 		}
 
 		if t.Enabled == nil {
@@ -114,10 +116,6 @@ func (t *masterTrait) Configure(e *trait.Environment) (bool, error) {
 			}
 		}
 
-		if !pointer.BoolDeref(t.Enabled, false) {
-			return false, nil
-		}
-
 		if t.IncludeDelegateDependencies == nil || *t.IncludeDelegateDependencies {
 			t.delegateDependencies = findAdditionalDependencies(e, meta)
 		}
@@ -130,7 +128,7 @@ func (t *masterTrait) Configure(e *trait.Environment) (bool, error) {
 		if t.ResourceType == nil {
 			canUseLeases, err := t.canUseLeases(e)
 			if err != nil {
-				return false, err
+				return false, nil, err
 			}
 			if canUseLeases {
 				t.ResourceType = &leaseResourceType
@@ -149,7 +147,7 @@ func (t *masterTrait) Configure(e *trait.Environment) (bool, error) {
 		}
 	}
 
-	return pointer.BoolDeref(t.Enabled, true), nil
+	return pointer.BoolDeref(t.Enabled, true), nil, nil
 }
 
 func (t *masterTrait) Apply(e *trait.Environment) error {
diff --git a/addons/resume/resume.go b/addons/resume/resume.go
index f593b9fc8..221ae0364 100644
--- a/addons/resume/resume.go
+++ b/addons/resume/resume.go
@@ -75,25 +75,24 @@ func NewResumeTrait() trait.Trait {
 	}
 }
 
-func (r *resumeTrait) Configure(environment *trait.Environment) (bool, error) {
+func (r *resumeTrait) Configure(environment *trait.Environment) (bool, *trait.TraitCondition, error) {
 	if !pointer.BoolDeref(r.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
-
 	if !environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !environment.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if pointer.BoolDeref(r.Auto, true) {
 		// Check which components have been used
 		sources, err := kubernetes.ResolveIntegrationSources(environment.Ctx, r.Client, environment.Integration, environment.Resources)
 		if err != nil {
-			return false, err
+			return false, nil, err
 		}
 
 		meta, err := metadata.ExtractAll(environment.CamelCatalog, sources)
 		if err != nil {
-			return false, err
+			return false, nil, err
 		}
 
 		for _, endpoint := range meta.FromURIs {
@@ -109,7 +108,7 @@ func (r *resumeTrait) Configure(environment *trait.Environment) (bool, error) {
 		}
 	}
 
-	return r.Enabled != nil && *r.Enabled, nil
+	return r.Enabled != nil && *r.Enabled, nil, nil
 }
 
 func (r *resumeTrait) Apply(environment *trait.Environment) error {
diff --git a/addons/telemetry/telemetry.go b/addons/telemetry/telemetry.go
index 0ad3035de..2d830d991 100644
--- a/addons/telemetry/telemetry.go
+++ b/addons/telemetry/telemetry.go
@@ -20,6 +20,8 @@ package telemetry
 import (
 	"k8s.io/utils/pointer"
 
+	corev1 "k8s.io/api/core/v1"
+
 	"github.com/apache/camel-k/v2/addons/telemetry/discovery"
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
 	traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
@@ -85,20 +87,27 @@ func NewTelemetryTrait() trait.Trait {
 	}
 }
 
-func (t *telemetryTrait) Configure(e *trait.Environment) (bool, error) {
+func (t *telemetryTrait) Configure(e *trait.Environment) (bool, *trait.TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
+	var condition *trait.TraitCondition
 	if pointer.BoolDeref(t.Auto, true) {
 		if t.Endpoint == "" {
 			for _, locator := range discovery.TelemetryLocators {
 				endpoint, err := locator.FindEndpoint(e.Ctx, t.Client, t.L, e)
 				if err != nil {
-					return false, err
+					return false, nil, err
 				}
 				if endpoint != "" {
 					t.L.Infof("Using tracing endpoint: %s", endpoint)
+					condition = trait.NewIntegrationCondition(
+						v1.IntegrationConditionTraitInfo,
+						corev1.ConditionTrue,
+						"Tracing endpoint",
+						endpoint,
+					)
 					t.Endpoint = endpoint
 					break
 				}
@@ -114,7 +123,7 @@ func (t *telemetryTrait) Configure(e *trait.Environment) (bool, error) {
 		}
 	}
 
-	return true, nil
+	return true, condition, nil
 }
 
 func (t *telemetryTrait) Apply(e *trait.Environment) error {
diff --git a/addons/telemetry/telemetry_test.go b/addons/telemetry/telemetry_test.go
index 76bea8696..c15af2894 100644
--- a/addons/telemetry/telemetry_test.go
+++ b/addons/telemetry/telemetry_test.go
@@ -36,9 +36,10 @@ func TestTelemetryTraitOnDefaultQuarkus(t *testing.T) {
 	tt, _ := telemetry.(*telemetryTrait)
 	tt.Enabled = pointer.Bool(true)
 	tt.Endpoint = "http://endpoint3"
-	ok, err := telemetry.Configure(e)
+	ok, condition, err := telemetry.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = telemetry.Apply(e)
 	assert.Nil(t, err)
@@ -61,9 +62,10 @@ func TestTelemetryTraitWithValues(t *testing.T) {
 	tt.Sampler = "ratio"
 	tt.SamplerRatio = "0.001"
 	tt.SamplerParentBased = pointer.Bool(false)
-	ok, err := telemetry.Configure(e)
+	ok, condition, err := telemetry.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = telemetry.Apply(e)
 	assert.Nil(t, err)
diff --git a/addons/threescale/3scale.go b/addons/threescale/3scale.go
index a75fa460f..2bab8ea21 100644
--- a/addons/threescale/3scale.go
+++ b/addons/threescale/3scale.go
@@ -87,14 +87,12 @@ func NewThreeScaleTrait() trait.Trait {
 	}
 }
 
-func (t *threeScaleTrait) Configure(e *trait.Environment) (bool, error) {
+func (t *threeScaleTrait) Configure(e *trait.Environment) (bool, *trait.TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		// disabled by default
-		return false, nil
+		return false, nil, nil
 	}
-
 	if !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if pointer.BoolDeref(t.Auto, true) {
@@ -113,7 +111,7 @@ func (t *threeScaleTrait) Configure(e *trait.Environment) (bool, error) {
 		}
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *threeScaleTrait) Apply(e *trait.Environment) error {
diff --git a/addons/threescale/3scale_test.go b/addons/threescale/3scale_test.go
index cfd802514..d7a3a35c2 100644
--- a/addons/threescale/3scale_test.go
+++ b/addons/threescale/3scale_test.go
@@ -39,9 +39,10 @@ func TestThreeScaleDisabled(t *testing.T) {
 	}
 
 	threeScale := NewThreeScaleTrait()
-	enabled, err := threeScale.Configure(e)
+	enabled, condition, err := threeScale.Configure(e)
 	assert.Nil(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 }
 
 func TestThreeScaleInjection(t *testing.T) {
@@ -49,9 +50,10 @@ func TestThreeScaleInjection(t *testing.T) {
 	threeScale := NewThreeScaleTrait()
 	tst, _ := threeScale.(*threeScaleTrait)
 	tst.Enabled = pointer.Bool(true)
-	ok, err := threeScale.Configure(e)
+	ok, condition, err := threeScale.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = threeScale.Apply(e)
 	assert.Nil(t, err)
@@ -69,9 +71,10 @@ func TestThreeScaleInjectionNoAPIPath(t *testing.T) {
 	tst, _ := threeScale.(*threeScaleTrait)
 	tst.Enabled = pointer.Bool(true)
 	tst.DescriptionPath = pointer.String("")
-	ok, err := threeScale.Configure(e)
+	ok, condition, err := threeScale.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = threeScale.Apply(e)
 	assert.Nil(t, err)
diff --git a/addons/tracing/tracing.go b/addons/tracing/tracing.go
index caca01841..0cf3852e0 100644
--- a/addons/tracing/tracing.go
+++ b/addons/tracing/tracing.go
@@ -86,9 +86,9 @@ func NewTracingTrait() trait.Trait {
 	}
 }
 
-func (t *tracingTrait) Configure(e *trait.Environment) (bool, error) {
+func (t *tracingTrait) Configure(e *trait.Environment) (bool, *trait.TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if pointer.BoolDeref(t.Auto, true) {
@@ -96,7 +96,7 @@ func (t *tracingTrait) Configure(e *trait.Environment) (bool, error) {
 			for _, locator := range discovery.TracingLocators {
 				endpoint, err := locator.FindEndpoint(e.Ctx, t.Client, t.L, e)
 				if err != nil {
-					return false, err
+					return false, nil, err
 				}
 				if endpoint != "" {
 					t.L.Infof("Using tracing endpoint: %s", endpoint)
@@ -119,7 +119,7 @@ func (t *tracingTrait) Configure(e *trait.Environment) (bool, error) {
 		}
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *tracingTrait) Apply(e *trait.Environment) error {
diff --git a/addons/tracing/tracing_test.go b/addons/tracing/tracing_test.go
index 0cdaef089..25865c02b 100644
--- a/addons/tracing/tracing_test.go
+++ b/addons/tracing/tracing_test.go
@@ -36,9 +36,10 @@ func TestTracingTraitOnQuarkus(t *testing.T) {
 	tt, _ := tracing.(*tracingTrait)
 	tt.Enabled = pointer.Bool(true)
 	tt.Endpoint = "http://endpoint3"
-	ok, err := tracing.Configure(e)
+	ok, condition, err := tracing.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = tracing.Apply(e)
 	assert.Nil(t, err)
diff --git a/addons/vault/aws/aws_secrets_manager.go b/addons/vault/aws/aws_secrets_manager.go
index 81aa15c1b..1a98e0324 100644
--- a/addons/vault/aws/aws_secrets_manager.go
+++ b/addons/vault/aws/aws_secrets_manager.go
@@ -82,13 +82,13 @@ func NewAwsSecretsManagerTrait() trait.Trait {
 	}
 }
 
-func (t *awsSecretsManagerTrait) Configure(environment *trait.Environment) (bool, error) {
-	if !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+func (t *awsSecretsManagerTrait) Configure(environment *trait.Environment) (bool, *trait.TraitCondition, error) {
+	if environment.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
+		return false, nil, nil
 	}
 
 	if !environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !environment.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if t.UseDefaultCredentialsProvider == nil {
@@ -101,7 +101,7 @@ func (t *awsSecretsManagerTrait) Configure(environment *trait.Environment) (bool
 		t.RefreshEnabled = pointer.Bool(false)
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *awsSecretsManagerTrait) Apply(environment *trait.Environment) error {
diff --git a/addons/vault/aws/aws_secrets_manager_test.go b/addons/vault/aws/aws_secrets_manager_test.go
index aeb1e86f4..ce48f5ab3 100644
--- a/addons/vault/aws/aws_secrets_manager_test.go
+++ b/addons/vault/aws/aws_secrets_manager_test.go
@@ -43,9 +43,10 @@ func TestAwsSecretsManagerTraitApply(t *testing.T) {
 	secrets.Region = "eu-west-1"
 	secrets.AccessKey = "access-key"
 	secrets.SecretKey = "secret-key"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
@@ -65,9 +66,10 @@ func TestAwsSecretsManagerTraitNoDefaultCreds(t *testing.T) {
 	secrets.Region = "eu-west-1"
 	secrets.AccessKey = "access-key"
 	secrets.SecretKey = "secret-key"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
@@ -104,9 +106,10 @@ func TestAwsSecretsManagerTraitWithSecrets(t *testing.T) {
 	secrets.Region = "eu-west-1"
 	secrets.AccessKey = "secret:my-secret2/aws-access-key"
 	secrets.SecretKey = "secret:my-secret1/aws-secret-key"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
@@ -143,9 +146,10 @@ func TestAwsSecretsManagerTraitWithConfigMap(t *testing.T) {
 	secrets.Region = "eu-west-1"
 	secrets.AccessKey = "configmap:my-configmap2/aws-access-key"
 	secrets.SecretKey = "configmap:my-configmap1/aws-secret-key"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
diff --git a/addons/vault/azure/azure_key_vault.go b/addons/vault/azure/azure_key_vault.go
index 5ab1ab0f6..04281fe04 100644
--- a/addons/vault/azure/azure_key_vault.go
+++ b/addons/vault/azure/azure_key_vault.go
@@ -90,13 +90,13 @@ func NewAzureKeyVaultTrait() trait.Trait {
 	}
 }
 
-func (t *azureKeyVaultTrait) Configure(environment *trait.Environment) (bool, error) {
-	if !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+func (t *azureKeyVaultTrait) Configure(environment *trait.Environment) (bool, *trait.TraitCondition, error) {
+	if environment.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
+		return false, nil, nil
 	}
 
 	if !environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !environment.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if t.ContextReloadEnabled == nil {
@@ -107,7 +107,7 @@ func (t *azureKeyVaultTrait) Configure(environment *trait.Environment) (bool, er
 		t.RefreshEnabled = pointer.Bool(false)
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *azureKeyVaultTrait) Apply(environment *trait.Environment) error {
diff --git a/addons/vault/azure/azure_key_vault_test.go b/addons/vault/azure/azure_key_vault_test.go
index 388643605..7f3299ba4 100644
--- a/addons/vault/azure/azure_key_vault_test.go
+++ b/addons/vault/azure/azure_key_vault_test.go
@@ -43,9 +43,10 @@ func TestAzureKeyVaultTraitApply(t *testing.T) {
 	secrets.ClientID = "client-id"
 	secrets.ClientSecret = "secret"
 	secrets.VaultName = "my-vault"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
@@ -85,9 +86,10 @@ func TestAzureKeyVaultTraitApplyWithConfigmapAndRefresh(t *testing.T) {
 	secrets.BlobAccessKey = "configmap:my-configmap2/azure-storage-blob-key"
 	secrets.BlobAccountName = "camel-k"
 	secrets.BlobContainerName = "camel-k-container"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
@@ -131,9 +133,10 @@ func TestAzureKeyVaultTraitApplyWithSecretAndRefresh(t *testing.T) {
 	secrets.BlobAccessKey = "secret:my-secret2/azure-storage-blob-key"
 	secrets.BlobAccountName = "camel-k"
 	secrets.BlobContainerName = "camel-k-container"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
diff --git a/addons/vault/gcp/gcp_secret_manager.go b/addons/vault/gcp/gcp_secret_manager.go
index b3784d89e..7f9810dbc 100644
--- a/addons/vault/gcp/gcp_secret_manager.go
+++ b/addons/vault/gcp/gcp_secret_manager.go
@@ -75,13 +75,13 @@ func NewGcpSecretManagerTrait() trait.Trait {
 	}
 }
 
-func (t *gcpSecretManagerTrait) Configure(environment *trait.Environment) (bool, error) {
-	if !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+func (t *gcpSecretManagerTrait) Configure(environment *trait.Environment) (bool, *trait.TraitCondition, error) {
+	if environment.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
+		return false, nil, nil
 	}
 
 	if !environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !environment.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if t.UseDefaultInstance == nil {
@@ -96,7 +96,7 @@ func (t *gcpSecretManagerTrait) Configure(environment *trait.Environment) (bool,
 		t.RefreshEnabled = pointer.Bool(false)
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *gcpSecretManagerTrait) Apply(environment *trait.Environment) error {
diff --git a/addons/vault/gcp/gcp_secret_manager_test.go b/addons/vault/gcp/gcp_secret_manager_test.go
index a7e88ad7c..2d01c57cb 100644
--- a/addons/vault/gcp/gcp_secret_manager_test.go
+++ b/addons/vault/gcp/gcp_secret_manager_test.go
@@ -38,9 +38,10 @@ func TestGcpSecretManagerTraitApply(t *testing.T) {
 	secrets.UseDefaultInstance = pointer.Bool(false)
 	secrets.ProjectID = "project-gcp"
 	secrets.ServiceAccountKey = "file:////usr/local/serviceaccount.json"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
@@ -58,9 +59,10 @@ func TestGcpSecretManagerTraitNoDefaultCreds(t *testing.T) {
 	secrets.UseDefaultInstance = pointer.Bool(false)
 	secrets.ProjectID = "project-gcp"
 	secrets.ServiceAccountKey = "file:////usr/local/serviceaccount.json"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
diff --git a/addons/vault/hashicorp/hashicorp_vault.go b/addons/vault/hashicorp/hashicorp_vault.go
index 058b18cc9..616409a17 100644
--- a/addons/vault/hashicorp/hashicorp_vault.go
+++ b/addons/vault/hashicorp/hashicorp_vault.go
@@ -68,16 +68,16 @@ func NewHashicorpVaultTrait() trait.Trait {
 	}
 }
 
-func (t *hashicorpVaultTrait) Configure(environment *trait.Environment) (bool, error) {
-	if !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+func (t *hashicorpVaultTrait) Configure(environment *trait.Environment) (bool, *trait.TraitCondition, error) {
+	if environment.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
+		return false, nil, nil
 	}
 
 	if !environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !environment.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *hashicorpVaultTrait) Apply(environment *trait.Environment) error {
diff --git a/addons/vault/hashicorp/hashicorp_vault_test.go b/addons/vault/hashicorp/hashicorp_vault_test.go
index 86cb70229..975cc3be1 100644
--- a/addons/vault/hashicorp/hashicorp_vault_test.go
+++ b/addons/vault/hashicorp/hashicorp_vault_test.go
@@ -44,9 +44,10 @@ func TestHashicorpVaultTraitApply(t *testing.T) {
 	secrets.Host = "localhost"
 	secrets.Port = "9091"
 	secrets.Scheme = "http"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
@@ -77,9 +78,10 @@ func TestHashicorpVaultTraitWithSecretApply(t *testing.T) {
 	secrets.Host = "localhost"
 	secrets.Port = "9091"
 	secrets.Scheme = "http"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
@@ -110,9 +112,10 @@ func TestHashicorpVaultTraitWithConfigMapApply(t *testing.T) {
 	secrets.Host = "localhost"
 	secrets.Port = "9091"
 	secrets.Scheme = "http"
-	ok, err := secrets.Configure(e)
+	ok, condition, err := secrets.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = secrets.Apply(e)
 	assert.Nil(t, err)
diff --git a/pkg/apis/camel/v1/integration_types.go b/pkg/apis/camel/v1/integration_types.go
index 86cf7a1ae..78dd40a8c 100644
--- a/pkg/apis/camel/v1/integration_types.go
+++ b/pkg/apis/camel/v1/integration_types.go
@@ -180,7 +180,8 @@ const (
 	IntegrationConditionProbesAvailable IntegrationConditionType = "ProbesAvailable"
 	// IntegrationConditionReady --.
 	IntegrationConditionReady IntegrationConditionType = "Ready"
-
+	// IntegrationConditionTraitInfo --.
+	IntegrationConditionTraitInfo IntegrationConditionType = "TraitInfo"
 	// IntegrationConditionKitAvailableReason --.
 	IntegrationConditionKitAvailableReason string = "IntegrationKitAvailable"
 	// IntegrationConditionPlatformAvailableReason --.
diff --git a/pkg/apis/camel/v1/integrationkit_types.go b/pkg/apis/camel/v1/integrationkit_types.go
index 2ddca5179..8ee233dee 100644
--- a/pkg/apis/camel/v1/integrationkit_types.go
+++ b/pkg/apis/camel/v1/integrationkit_types.go
@@ -187,6 +187,8 @@ const (
 	IntegrationKitConditionCatalogAvailable IntegrationKitConditionType = "CamelCatalogAvailable"
 	// IntegrationKitConditionPlatformAvailableReason --.
 	IntegrationKitConditionPlatformAvailableReason string = "IntegrationPlatformAvailable"
+	// IntegrationKitConditionTraitInfo --.
+	IntegrationKitConditionTraitInfo IntegrationKitConditionType = "TraitInfo"
 )
 
 // IntegrationKitCondition describes the state of a resource at a certain point.
diff --git a/pkg/trait/affinity.go b/pkg/trait/affinity.go
index 509d196c1..d3fad6cea 100644
--- a/pkg/trait/affinity.go
+++ b/pkg/trait/affinity.go
@@ -46,16 +46,16 @@ func newAffinityTrait() Trait {
 	}
 }
 
-func (t *affinityTrait) Configure(e *Environment) (bool, error) {
+func (t *affinityTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if pointer.BoolDeref(t.PodAffinity, false) && pointer.BoolDeref(t.PodAntiAffinity, false) {
-		return false, fmt.Errorf("both pod affinity and pod anti-affinity can't be set simultaneously")
+		return false, nil, fmt.Errorf("both pod affinity and pod anti-affinity can't be set simultaneously")
 	}
 
-	return e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *affinityTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/affinity_test.go b/pkg/trait/affinity_test.go
index 86eaa74d6..35a27e9bc 100644
--- a/pkg/trait/affinity_test.go
+++ b/pkg/trait/affinity_test.go
@@ -32,9 +32,10 @@ import (
 func TestConfigureAffinityTraitDoesSucceed(t *testing.T) {
 	affinityTrait := createNominalAffinityTest()
 	environment, _ := createNominalDeploymentTraitTest()
-	configured, err := affinityTrait.Configure(environment)
+	configured, condition, err := affinityTrait.Configure(environment)
 
 	assert.True(t, configured)
+	assert.Nil(t, condition)
 	assert.Nil(t, err)
 }
 
@@ -43,9 +44,10 @@ func TestConfigureAffinityTraitWithConflictingAffinitiesFails(t *testing.T) {
 	environment, _ := createNominalDeploymentTraitTest()
 	affinityTrait.PodAffinity = pointer.Bool(true)
 	affinityTrait.PodAntiAffinity = pointer.Bool(true)
-	configured, err := affinityTrait.Configure(environment)
+	configured, condition, err := affinityTrait.Configure(environment)
 
 	assert.False(t, configured)
+	assert.Nil(t, condition)
 	assert.NotNil(t, err)
 }
 
@@ -53,10 +55,11 @@ func TestConfigureDisabledAffinityTraitFails(t *testing.T) {
 	affinityTrait := createNominalAffinityTest()
 	affinityTrait.Enabled = pointer.Bool(false)
 	environment, _ := createNominalDeploymentTraitTest()
-	configured, err := affinityTrait.Configure(environment)
+	configured, condition, err := affinityTrait.Configure(environment)
 
 	assert.False(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestApplyAffinityMissingDeployment(t *testing.T) {
diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go
index 58d5790d5..64b3144cc 100644
--- a/pkg/trait/builder.go
+++ b/pkg/trait/builder.go
@@ -60,12 +60,12 @@ func (t *builderTrait) InfluencesBuild(this, prev map[string]interface{}) bool {
 	return true
 }
 
-func (t *builderTrait) Configure(e *Environment) (bool, error) {
+func (t *builderTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.IntegrationKit == nil {
-		return false, nil
+		return false, nil, nil
 	}
 
-	t.adaptDeprecatedFields()
+	condition := t.adaptDeprecatedFields()
 
 	if e.IntegrationKitInPhase(v1.IntegrationKitPhaseBuildSubmitted) {
 		if trait := e.Catalog.GetTrait(quarkusTraitID); trait != nil {
@@ -73,7 +73,7 @@ func (t *builderTrait) Configure(e *Environment) (bool, error) {
 			isNativeIntegration := quarkus.isNativeIntegration(e)
 			isNativeKit, err := quarkus.isNativeKit(e)
 			if err != nil {
-				return false, err
+				return false, condition, err
 			}
 			if ok && (isNativeIntegration || isNativeKit) {
 				// TODO expect maven repository in local repo (need to change builder pod accordingly!)
@@ -86,7 +86,9 @@ func (t *builderTrait) Configure(e *Environment) (bool, error) {
 				// it should be performed as the last custom task
 				t.Tasks = append(t.Tasks, fmt.Sprintf(`quarkus-native;%s;/bin/bash -c "%s"`, nativeBuilderImage, command))
 				// Force the build to run in a separate Pod and strictly sequential
-				t.L.Info("This is a Quarkus native build: setting build configuration with build Pod strategy, and native container with 1 CPU core and 4 GiB memory. Make sure your cluster can handle it.")
+				m := "This is a Quarkus native build: setting build configuration with build Pod strategy, and native container with 1 CPU core and 4 GiB memory. Make sure your cluster can handle it."
+				t.L.Info(m)
+				condition = newOrAppend(condition, m)
 				t.Strategy = string(v1.BuildStrategyPod)
 				t.OrderStrategy = string(v1.BuildOrderStrategySequential)
 				t.TasksRequestCPU = append(t.TasksRequestCPU, "quarkus-native:1000m")
@@ -94,29 +96,53 @@ func (t *builderTrait) Configure(e *Environment) (bool, error) {
 			}
 		}
 
-		return true, nil
+		return true, condition, nil
 	}
 
-	return false, nil
+	return false, condition, nil
 }
 
-func (t *builderTrait) adaptDeprecatedFields() {
+func (t *builderTrait) adaptDeprecatedFields() *TraitCondition {
+	var condition *TraitCondition
 	if t.RequestCPU != "" {
-		t.L.Info("The request-cpu parameter is deprecated and may be removed in future releases. Make sure to use tasks-request-cpu parameter instead.")
+		m := "The request-cpu parameter is deprecated and may be removed in future releases. Make sure to use tasks-request-cpu parameter instead."
+		t.L.Info(m)
+		condition = newOrAppend(condition, m)
 		t.TasksRequestCPU = append(t.TasksRequestCPU, fmt.Sprintf("builder:%s", t.RequestCPU))
 	}
 	if t.LimitCPU != "" {
-		t.L.Info("The limit-cpu parameter is deprecated and may be removed in future releases. Make sure to use tasks-limit-cpu parameter instead.")
+		m := "The limit-cpu parameter is deprecated and may be removed in future releases. Make sure to use tasks-limit-cpu parameter instead."
+		t.L.Info(m)
+		condition = newOrAppend(condition, m)
 		t.TasksLimitCPU = append(t.TasksLimitCPU, fmt.Sprintf("builder:%s", t.LimitCPU))
 	}
 	if t.RequestMemory != "" {
-		t.L.Info("The request-memory parameter is deprecated and may be removed in future releases. Make sure to use tasks-request-memory parameter instead.")
+		m := "The request-memory parameter is deprecated and may be removed in future releases. Make sure to use tasks-request-memory parameter instead."
+		t.L.Info(m)
+		condition = newOrAppend(condition, m)
 		t.TasksRequestMemory = append(t.TasksRequestMemory, fmt.Sprintf("builder:%s", t.RequestMemory))
 	}
 	if t.LimitMemory != "" {
-		t.L.Info("The limit-memory parameter is deprecated and may be removed in future releases. Make sure to use tasks-limit-memory parameter instead.")
+		m := "The limit-memory parameter is deprecated and may be removed in future releases. Make sure to use tasks-limit-memory parameter instead."
+		t.L.Info(m)
+		if condition == nil {
+			condition = NewIntegrationCondition(v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationMessage, "")
+		}
+		condition = newOrAppend(condition, m)
 		t.TasksLimitMemory = append(t.TasksLimitMemory, fmt.Sprintf("builder:%s", t.LimitMemory))
 	}
+
+	return condition
+}
+
+func newOrAppend(condition *TraitCondition, reason string) *TraitCondition {
+	if condition == nil {
+		condition = NewIntegrationCondition(v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationMessage, reason)
+	} else {
+		condition.reason += "; " + reason
+	}
+
+	return condition
 }
 
 func (t *builderTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go
index 66a5eab2a..21c7829d4 100644
--- a/pkg/trait/builder_test.go
+++ b/pkg/trait/builder_test.go
@@ -44,9 +44,10 @@ func TestBuilderTraitNotAppliedBecauseOfNilKit(t *testing.T) {
 		e.IntegrationKit = nil
 
 		t.Run(string(e.Platform.Status.Cluster), func(t *testing.T) {
-			err := NewBuilderTestCatalog().apply(e)
+			conditions, err := NewBuilderTestCatalog().apply(e)
 
 			assert.Nil(t, err)
+			assert.Empty(t, conditions)
 			assert.NotEmpty(t, e.ExecutedTraits)
 			assert.Nil(t, e.GetTrait("builder"))
 			assert.Empty(t, e.Pipeline)
@@ -65,9 +66,10 @@ func TestBuilderTraitNotAppliedBecauseOfNilPhase(t *testing.T) {
 		e.IntegrationKit.Status.Phase = v1.IntegrationKitPhaseInitialization
 
 		t.Run(string(e.Platform.Status.Cluster), func(t *testing.T) {
-			err := NewBuilderTestCatalog().apply(e)
+			conditions, err := NewBuilderTestCatalog().apply(e)
 
 			assert.Nil(t, err)
+			assert.Empty(t, conditions)
 			assert.NotEmpty(t, e.ExecutedTraits)
 			assert.Nil(t, e.GetTrait("builder"))
 			assert.Empty(t, e.Pipeline)
@@ -77,9 +79,10 @@ func TestBuilderTraitNotAppliedBecauseOfNilPhase(t *testing.T) {
 
 func TestS2IBuilderTrait(t *testing.T) {
 	env := createBuilderTestEnv(v1.IntegrationPlatformClusterOpenShift, v1.IntegrationPlatformBuildPublishStrategyS2I, v1.BuildStrategyRoutine)
-	err := NewBuilderTestCatalog().apply(env)
+	conditions, err := NewBuilderTestCatalog().apply(env)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, env.ExecutedTraits)
 	assert.NotNil(t, env.GetTrait("builder"))
 	assert.NotEmpty(t, env.Pipeline)
@@ -91,9 +94,10 @@ func TestS2IBuilderTrait(t *testing.T) {
 
 func TestKanikoBuilderTrait(t *testing.T) {
 	env := createBuilderTestEnv(v1.IntegrationPlatformClusterKubernetes, v1.IntegrationPlatformBuildPublishStrategyKaniko, v1.BuildStrategyRoutine)
-	err := NewBuilderTestCatalog().apply(env)
+	conditions, err := NewBuilderTestCatalog().apply(env)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, env.ExecutedTraits)
 	assert.NotNil(t, env.GetTrait("builder"))
 	assert.NotEmpty(t, env.Pipeline)
@@ -420,10 +424,15 @@ func TestBuilderDeprecatedParams(t *testing.T) {
 	builderTrait.LimitMemory = "100Mi"
 	builderTrait.RequestMemory = "100Mi"
 
-	active, err := builderTrait.Configure(env)
+	active, condition, err := builderTrait.Configure(env)
 
 	assert.Nil(t, err)
 	assert.True(t, active)
+	assert.NotNil(t, condition)
+	assert.Contains(t, condition.reason, "The request-cpu parameter is deprecated and may be removed in future releases")
+	assert.Contains(t, condition.reason, "The limit-cpu parameter is deprecated and may be removed in future releases")
+	assert.Contains(t, condition.reason, "The request-memory parameter is deprecated and may be removed in future releases")
+	assert.Contains(t, condition.reason, "The limit-memory parameter is deprecated and may be removed in future releases")
 	assert.Len(t, builderTrait.TasksLimitCPU, 1)
 	assert.Len(t, builderTrait.TasksRequestCPU, 1)
 	assert.Len(t, builderTrait.TasksLimitMemory, 1)
diff --git a/pkg/trait/camel.go b/pkg/trait/camel.go
index 36e3d74b4..9842ea934 100644
--- a/pkg/trait/camel.go
+++ b/pkg/trait/camel.go
@@ -59,12 +59,12 @@ func (t *camelTrait) InfluencesBuild(this, prev map[string]interface{}) bool {
 	return this["runtimeVersion"] != prev["runtimeVersion"]
 }
 
-func (t *camelTrait) Configure(e *Environment) (bool, error) {
+func (t *camelTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if t.RuntimeVersion == "" {
 		t.RuntimeVersion = determineRuntimeVersion(e)
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *camelTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/camel_test.go b/pkg/trait/camel_test.go
index 692c5df21..e300291da 100644
--- a/pkg/trait/camel_test.go
+++ b/pkg/trait/camel_test.go
@@ -35,16 +35,18 @@ import (
 func TestConfigureEnabledCamelTraitSucceeds(t *testing.T) {
 	trait, environment := createNominalCamelTest(false)
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, configured)
 }
 
 func TestApplyCamelTraitSucceeds(t *testing.T) {
 	trait, environment := createNominalCamelTest(false)
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, configured)
 
 	err = trait.Apply(environment)
@@ -65,8 +67,9 @@ func TestApplyCamelTraitWithoutEnvironmentCatalogAndUnmatchableVersionFails(t *t
 	environment.Integration.Status.RuntimeVersion = "Unmatchable version"
 	environment.Integration.Status.RuntimeProvider = v1.RuntimeProviderQuarkus
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, configured)
 
 	err = trait.Apply(environment)
@@ -167,8 +170,9 @@ func TestApplyCamelTraitWithProperties(t *testing.T) {
 	trait, environment := createNominalCamelTest(false)
 	trait.Properties = []string{"a=b", "c=d"}
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, configured)
 
 	err = trait.Apply(environment)
@@ -186,8 +190,9 @@ func TestApplyCamelTraitWithProperties(t *testing.T) {
 func TestApplyCamelTraitWithSources(t *testing.T) {
 	trait, environment := createNominalCamelTest(true)
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, configured)
 
 	err = trait.Apply(environment)
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index 62b905eb0..6f6bb462c 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -67,33 +67,32 @@ func newContainerTrait() Trait {
 	}
 }
 
-func (t *containerTrait) Configure(e *Environment) (bool, error) {
+func (t *containerTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	knativeInstalled, _ := knative.IsInstalled(e.Client)
 	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !knativeInstalled {
 		hasKnativeEndpoint, err := containsEndpoint("knative", e, t.Client)
 		if err != nil {
-			return false, err
+			return false, nil, err
 		}
 
 		if hasKnativeEndpoint {
 			// fail fast the integration as there is no knative installed in the cluster
 			t.L.ForIntegration(e.Integration).Infof("Integration %s/%s contains knative endpoint that cannot run, as knative is not installed in the cluster.", e.Integration.Namespace, e.Integration.Name)
 			err := errors.New("integration cannot run, as knative is not installed in the cluster")
-			e.Integration.Status.SetCondition(
+			return false, NewIntegrationCondition(
 				v1.IntegrationConditionKnativeAvailable,
 				corev1.ConditionFalse,
 				v1.IntegrationConditionKnativeNotInstalledReason,
-				err.Error())
-			e.Integration.Status.Phase = v1.IntegrationPhaseError
-			return false, err
+				err.Error(),
+			), err
 		}
 	}
 
@@ -105,10 +104,10 @@ func (t *containerTrait) Configure(e *Environment) (bool, error) {
 	}
 
 	if !isValidPullPolicy(t.ImagePullPolicy) {
-		return false, fmt.Errorf("unsupported pull policy %s", t.ImagePullPolicy)
+		return false, nil, fmt.Errorf("unsupported pull policy %s", t.ImagePullPolicy)
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func isValidPullPolicy(policy corev1.PullPolicy) bool {
diff --git a/pkg/trait/container_probes_test.go b/pkg/trait/container_probes_test.go
index f7d58a4f0..772dfd46c 100644
--- a/pkg/trait/container_probes_test.go
+++ b/pkg/trait/container_probes_test.go
@@ -78,9 +78,9 @@ func TestProbesDependencies(t *testing.T) {
 	env := newTestProbesEnv(t, integration)
 	env.Integration.Status.Phase = v1.IntegrationPhaseInitialization
 
-	err := env.Catalog.apply(&env)
+	conditions, err := env.Catalog.apply(&env)
 	assert.Nil(t, err)
-
+	assert.Empty(t, conditions)
 	assert.Contains(t, env.Integration.Status.Dependencies, "mvn:org.apache.camel.quarkus:camel-quarkus-microprofile-health")
 }
 
@@ -103,8 +103,9 @@ func TestProbesOnDeployment(t *testing.T) {
 	env := newTestProbesEnv(t, integration)
 	env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
 
-	err := env.Catalog.apply(&env)
+	conditions, err := env.Catalog.apply(&env)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	container := env.GetIntegrationContainer()
 
@@ -140,8 +141,9 @@ func TestProbesOnDeploymentWithCustomScheme(t *testing.T) {
 	env := newTestProbesEnv(t, integration)
 	env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
 
-	err := env.Catalog.apply(&env)
+	conditions, err := env.Catalog.apply(&env)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	container := env.GetIntegrationContainer()
 
@@ -181,8 +183,24 @@ func TestProbesOnKnativeService(t *testing.T) {
 	env := newTestProbesEnv(t, integration)
 	env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
 
-	err := env.Catalog.apply(&env)
+	serviceOverrideCondition := NewIntegrationCondition(
+		v1.IntegrationConditionTraitInfo,
+		corev1.ConditionTrue,
+		"service trait configuration",
+		"explicitly disabled by the platform: knative-service trait has priority over this trait",
+	)
+	ctrlStrategyCondition := NewIntegrationCondition(
+		v1.IntegrationConditionDeploymentAvailable,
+		corev1.ConditionFalse,
+		"deployment trait configuration",
+		"controller strategy: knative-service",
+	)
+
+	conditions, err := env.Catalog.apply(&env)
 	assert.Nil(t, err)
+	assert.Len(t, conditions, 2)
+	assert.Contains(t, conditions, ctrlStrategyCondition)
+	assert.Contains(t, conditions, serviceOverrideCondition)
 
 	container := env.GetIntegrationContainer()
 
diff --git a/pkg/trait/container_test.go b/pkg/trait/container_test.go
index 78abb84cd..c483eedaa 100644
--- a/pkg/trait/container_test.go
+++ b/pkg/trait/container_test.go
@@ -84,9 +84,10 @@ func TestContainerWithDefaults(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("deployment"))
 	assert.NotNil(t, environment.GetTrait("container"))
@@ -150,9 +151,10 @@ func TestContainerWithCustomName(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("deployment"))
 	assert.NotNil(t, environment.GetTrait("container"))
@@ -215,8 +217,10 @@ func TestContainerWithCustomImage(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
+
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	for _, postAction := range environment.PostActions {
 		assert.Nil(t, postAction(&environment))
@@ -294,8 +298,9 @@ func TestContainerWithCustomImageAndIntegrationKit(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
 	assert.NotNil(t, err)
+	assert.Empty(t, conditions)
 	assert.Contains(t, err.Error(), "unsupported configuration: a container image has been set in conjunction with an IntegrationKit")
 }
 
@@ -336,8 +341,10 @@ func TestContainerWithImagePullPolicy(t *testing.T) {
 	environment.Integration.Status.Phase = v1.IntegrationPhaseDeploying
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
+
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	container := environment.GetIntegrationContainer()
 
@@ -345,11 +352,8 @@ func TestContainerWithImagePullPolicy(t *testing.T) {
 }
 
 func TestRunKnativeEndpointWithKnativeNotInstalled(t *testing.T) {
-
 	environment := createEnvironment()
-
 	trait, _ := newContainerTrait().(*containerTrait)
-
 	environment.Integration.Spec.Sources = []v1.SourceSpec{
 		{
 			DataSpec: v1.DataSpec{
@@ -361,12 +365,16 @@ func TestRunKnativeEndpointWithKnativeNotInstalled(t *testing.T) {
 			Language: v1.LanguageJavaSource,
 		},
 	}
-	configured, err := trait.Configure(environment)
+	expectedCondition := NewIntegrationCondition(
+		v1.IntegrationConditionKnativeAvailable,
+		corev1.ConditionFalse,
+		v1.IntegrationConditionKnativeNotInstalledReason,
+		"integration cannot run, as knative is not installed in the cluster",
+	)
+	configured, condition, err := trait.Configure(environment)
 	assert.NotNil(t, err)
+	assert.Equal(t, expectedCondition, condition)
 	assert.False(t, configured)
-	conditions := environment.Integration.Status.Conditions
-	assert.Len(t, conditions, 1)
-	assert.Equal(t, v1.IntegrationConditionKnativeNotInstalledReason, conditions[0].Reason)
 }
 
 func TestRunNonKnativeEndpointWithKnativeNotInstalled(t *testing.T) {
@@ -385,8 +393,9 @@ func TestRunNonKnativeEndpointWithKnativeNotInstalled(t *testing.T) {
 		},
 	}
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, configured)
 	conditions := environment.Integration.Status.Conditions
 	assert.Len(t, conditions, 0)
diff --git a/pkg/trait/cron.go b/pkg/trait/cron.go
index a5926c50a..0a7a69cb0 100644
--- a/pkg/trait/cron.go
+++ b/pkg/trait/cron.go
@@ -73,44 +73,35 @@ func newCronTrait() Trait {
 	}
 }
 
-func (t *cronTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		if e.Integration != nil {
-			e.Integration.Status.SetCondition(
-				v1.IntegrationConditionCronJobAvailable,
-				corev1.ConditionFalse,
-				v1.IntegrationConditionCronJobNotAvailableReason,
-				"explicitly disabled",
-			)
-		}
-
-		return false, nil
+func (t *cronTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
-
 	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if _, ok := e.CamelCatalog.Runtime.Capabilities[v1.CapabilityCron]; !ok {
-		e.Integration.Status.SetCondition(
+		return false, NewIntegrationCondition(
 			v1.IntegrationConditionCronJobAvailable,
 			corev1.ConditionFalse,
 			v1.IntegrationConditionCronJobNotAvailableReason,
 			"the runtime provider %s does not declare 'cron' capability",
-		)
-
-		return false, nil
+		), nil
 	}
 
 	if pointer.BoolDeref(t.Auto, true) {
 		globalCron, err := t.getGlobalCron(e)
 		if err != nil {
-			e.Integration.Status.SetErrorCondition(
+			return false, NewIntegrationCondition(
 				v1.IntegrationConditionCronJobAvailable,
+				corev1.ConditionFalse,
 				v1.IntegrationConditionCronJobNotAvailableReason,
-				err,
-			)
-			return false, err
+				err.Error(),
+			), err
 		}
 
 		if t.Schedule == "" && globalCron != nil {
@@ -133,7 +124,7 @@ func (t *cronTrait) Configure(e *Environment) (bool, error) {
 			// If there's at least a `cron` endpoint, add a fallback implementation
 			fromURIs, err := t.getSourcesFromURIs(e)
 			if err != nil {
-				return false, err
+				return false, nil, err
 			}
 			for _, fromURI := range fromURIs {
 				if uri.GetComponent(fromURI) == genericCronComponent {
@@ -146,40 +137,33 @@ func (t *cronTrait) Configure(e *Environment) (bool, error) {
 
 	// Fallback strategy can be implemented in any other controller
 	if pointer.BoolDeref(t.Fallback, false) {
+		var condition *TraitCondition
 		if e.IntegrationInPhase(v1.IntegrationPhaseDeploying) {
-			e.Integration.Status.SetCondition(
+			condition = NewIntegrationCondition(
 				v1.IntegrationConditionCronJobAvailable,
 				corev1.ConditionFalse,
 				v1.IntegrationConditionCronJobNotAvailableReason,
 				"fallback strategy selected",
 			)
 		}
-		return true, nil
+		return true, condition, nil
 	}
 
 	// CronJob strategy requires common schedule
 	strategy, err := e.DetermineControllerStrategy()
 	if err != nil {
-		e.Integration.Status.SetErrorCondition(
+		return false, NewIntegrationCondition(
 			v1.IntegrationConditionCronJobAvailable,
+			corev1.ConditionFalse,
 			v1.IntegrationConditionCronJobNotAvailableReason,
-			err,
-		)
-		return false, err
+			err.Error(),
+		), err
 	}
 	if strategy != ControllerStrategyCronJob {
-		if e.IntegrationInPhase(v1.IntegrationPhaseDeploying) {
-			e.Integration.Status.SetCondition(
-				v1.IntegrationConditionCronJobAvailable,
-				corev1.ConditionFalse,
-				v1.IntegrationConditionCronJobNotAvailableReason,
-				fmt.Sprintf("different controller strategy used (%s)", string(strategy)),
-			)
-		}
-		return false, nil
+		return false, nil, nil
 	}
 
-	return t.Schedule != "", nil
+	return t.Schedule != "", nil, nil
 }
 
 func (t *cronTrait) Apply(e *Environment) error {
@@ -280,9 +264,6 @@ func (t *cronTrait) getCronJobFor(e *Environment) *batchv1.CronJob {
 // SelectControllerStrategy can be used to check if a CronJob can be generated given the integration and trait settings.
 func (t *cronTrait) SelectControllerStrategy(e *Environment) (*ControllerStrategy, error) {
 	cronStrategy := ControllerStrategyCronJob
-	if !pointer.BoolDeref(t.Enabled, true) {
-		return nil, nil
-	}
 	if pointer.BoolDeref(t.Fallback, false) {
 		return nil, nil
 	}
diff --git a/pkg/trait/cron_test.go b/pkg/trait/cron_test.go
index dc00b2032..78964e527 100644
--- a/pkg/trait/cron_test.go
+++ b/pkg/trait/cron_test.go
@@ -284,10 +284,10 @@ func TestCronDeps(t *testing.T) {
 	assert.Nil(t, err)
 
 	tc := NewCatalog(c)
-
-	err = tc.apply(&environment)
+	conditions, err := tc.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 
 	ct, _ := environment.GetTrait("cron").(*cronTrait)
@@ -364,9 +364,10 @@ func TestCronDepsFallback(t *testing.T) {
 
 	tc := NewCatalog(c)
 
-	err = tc.apply(&environment)
+	conditions, err := tc.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 
 	ct, _ := environment.GetTrait("cron").(*cronTrait)
@@ -397,7 +398,6 @@ func TestCronWithActiveDeadline(t *testing.T) {
 				Phase: v1.IntegrationPhaseDeploying,
 			},
 			Spec: v1.IntegrationSpec{
-				Profile: v1.TraitProfileKnative,
 				Sources: []v1.SourceSpec{
 					{
 						DataSpec: v1.DataSpec{
@@ -440,9 +440,16 @@ func TestCronWithActiveDeadline(t *testing.T) {
 
 	tc := NewCatalog(c)
 
-	err = tc.apply(&environment)
-
+	expectedCondition := NewIntegrationCondition(
+		v1.IntegrationConditionDeploymentAvailable,
+		corev1.ConditionFalse,
+		"deployment trait configuration",
+		"controller strategy: cron-job",
+	)
+	conditions, err := tc.apply(&environment)
 	assert.Nil(t, err)
+	assert.Len(t, conditions, 1)
+	assert.Contains(t, conditions, expectedCondition)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 
 	ct, _ := environment.GetTrait("cron").(*cronTrait)
@@ -480,7 +487,6 @@ func TestCronWithBackoffLimit(t *testing.T) {
 				Phase: v1.IntegrationPhaseDeploying,
 			},
 			Spec: v1.IntegrationSpec{
-				Profile: v1.TraitProfileKnative,
 				Sources: []v1.SourceSpec{
 					{
 						DataSpec: v1.DataSpec{
@@ -523,9 +529,16 @@ func TestCronWithBackoffLimit(t *testing.T) {
 
 	tc := NewCatalog(c)
 
-	err = tc.apply(&environment)
-
+	expectedCondition := NewIntegrationCondition(
+		v1.IntegrationConditionDeploymentAvailable,
+		corev1.ConditionFalse,
+		"deployment trait configuration",
+		"controller strategy: cron-job",
+	)
+	conditions, err := tc.apply(&environment)
 	assert.Nil(t, err)
+	assert.Len(t, conditions, 1)
+	assert.Contains(t, conditions, expectedCondition)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 
 	ct, _ := environment.GetTrait("cron").(*cronTrait)
diff --git a/pkg/trait/dependencies.go b/pkg/trait/dependencies.go
index 3aefec8bd..e8d6e5d0f 100644
--- a/pkg/trait/dependencies.go
+++ b/pkg/trait/dependencies.go
@@ -38,12 +38,12 @@ func newDependenciesTrait() Trait {
 	}
 }
 
-func (t *dependenciesTrait) Configure(e *Environment) (bool, error) {
+func (t *dependenciesTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil, nil
 }
 
 func (t *dependenciesTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/dependencies_test.go b/pkg/trait/dependencies_test.go
index 35ba5ea16..1f3920453 100644
--- a/pkg/trait/dependencies_test.go
+++ b/pkg/trait/dependencies_test.go
@@ -33,18 +33,21 @@ func TestDependenciesTraitApplicability(t *testing.T) {
 	}
 
 	trait := newDependenciesTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.False(t, enabled)
 
 	e.Integration.Status.Phase = v1.IntegrationPhaseNone
-	enabled, err = trait.Configure(e)
+	enabled, condition, err = trait.Configure(e)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.False(t, enabled)
 
 	e.Integration.Status.Phase = v1.IntegrationPhaseInitialization
-	enabled, err = trait.Configure(e)
+	enabled, condition, err = trait.Configure(e)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, enabled)
 }
 
@@ -74,8 +77,9 @@ func TestIntegrationDefaultDeps(t *testing.T) {
 	}
 
 	trait := newDependenciesTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, enabled)
 
 	err = trait.Apply(e)
@@ -122,8 +126,9 @@ func TestIntegrationCustomDeps(t *testing.T) {
 	}
 
 	trait := newDependenciesTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, enabled)
 
 	err = trait.Apply(e)
@@ -176,8 +181,9 @@ func TestIntegrationAutoGeneratedDeps(t *testing.T) {
 	}
 
 	for _, trait := range []Trait{NewInitTrait(), newDependenciesTrait()} {
-		enabled, err := trait.Configure(e)
+		enabled, condition, err := trait.Configure(e)
 		assert.Nil(t, err)
+		assert.Nil(t, condition)
 		assert.True(t, enabled)
 		assert.Nil(t, trait.Apply(e))
 	}
@@ -231,8 +237,9 @@ func TestIntegrationCustomLoader(t *testing.T) {
 	}
 
 	trait := newDependenciesTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, enabled)
 
 	err = trait.Apply(e)
@@ -274,8 +281,9 @@ func TestRestDeps(t *testing.T) {
 	}
 
 	trait := newDependenciesTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, enabled)
 
 	err = trait.Apply(e)
@@ -316,8 +324,9 @@ func TestRestDepsQuarkus(t *testing.T) {
 	}
 
 	trait := newDependenciesTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.True(t, enabled)
 
 	err = trait.Apply(e)
diff --git a/pkg/trait/deployer.go b/pkg/trait/deployer.go
index 6ec537b8d..6cab16078 100644
--- a/pkg/trait/deployer.go
+++ b/pkg/trait/deployer.go
@@ -50,8 +50,8 @@ func newDeployerTrait() Trait {
 	}
 }
 
-func (t *deployerTrait) Configure(e *Environment) (bool, error) {
-	return e.Integration != nil, nil
+func (t *deployerTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	return e.Integration != nil, nil, nil
 }
 
 func (t *deployerTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/deployer_test.go b/pkg/trait/deployer_test.go
index 91b05f7f5..5809e16ec 100644
--- a/pkg/trait/deployer_test.go
+++ b/pkg/trait/deployer_test.go
@@ -29,20 +29,20 @@ import (
 func TestConfigureDeployerTraitDoesSucceed(t *testing.T) {
 	deployerTrait, environment := createNominalDeployerTest()
 
-	configured, err := deployerTrait.Configure(environment)
-
+	configured, condition, err := deployerTrait.Configure(environment)
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestConfigureDeployerTraitInWrongPhaseDoesNotSucceed(t *testing.T) {
 	deployerTrait, environment := createNominalDeployerTest()
 	environment.Integration.Status.Phase = v1.IntegrationPhaseError
 
-	configured, err := deployerTrait.Configure(environment)
-
+	configured, condition, err := deployerTrait.Configure(environment)
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestApplyDeployerTraitDoesSucceed(t *testing.T) {
diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go
index 9424f4605..c11fff7fb 100644
--- a/pkg/trait/deployment.go
+++ b/pkg/trait/deployment.go
@@ -43,39 +43,37 @@ func newDeploymentTrait() Trait {
 	}
 }
 
-func (t *deploymentTrait) Configure(e *Environment) (bool, error) {
+func (t *deploymentTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if e.IntegrationInPhase(v1.IntegrationPhaseRunning, v1.IntegrationPhaseError) {
 		condition := e.Integration.Status.GetCondition(v1.IntegrationConditionDeploymentAvailable)
-		return condition != nil && condition.Status == corev1.ConditionTrue, nil
+		return condition != nil && condition.Status == corev1.ConditionTrue, nil, nil
 	}
 
 	// Don't deploy when a different strategy is needed (e.g. Knative, Cron)
 	strategy, err := e.DetermineControllerStrategy()
 	if err != nil {
-		e.Integration.Status.SetErrorCondition(
+		return false, NewIntegrationCondition(
 			v1.IntegrationConditionDeploymentAvailable,
+			corev1.ConditionFalse,
 			v1.IntegrationConditionDeploymentAvailableReason,
-			err,
-		)
-
-		return false, err
+			err.Error(),
+		), err
 	}
 
 	if strategy != ControllerStrategyDeployment {
-		e.Integration.Status.SetCondition(
+		return false, NewIntegrationCondition(
 			v1.IntegrationConditionDeploymentAvailable,
 			corev1.ConditionFalse,
 			v1.IntegrationConditionDeploymentAvailableReason,
 			"controller strategy: "+string(strategy),
-		)
-		return false, nil
+		), nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseDeploying), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseDeploying), nil, nil
 }
 
 func (t *deploymentTrait) SelectControllerStrategy(e *Environment) (*ControllerStrategy, error) {
diff --git a/pkg/trait/deployment_test.go b/pkg/trait/deployment_test.go
index 018db540d..9539cddec 100644
--- a/pkg/trait/deployment_test.go
+++ b/pkg/trait/deployment_test.go
@@ -42,29 +42,29 @@ func TestConfigureDeploymentTraitWhileIntegrationIsRunningDoesSucceed(t *testing
 	)
 	environment.Integration.Status.Phase = v1.IntegrationPhaseRunning
 
-	configured, err := deploymentTrait.Configure(environment)
-
-	assert.Nil(t, err)
+	configured, condition, err := deploymentTrait.Configure(environment)
 	assert.True(t, configured)
+	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestConfigureDeploymentTraitDoesSucceed(t *testing.T) {
 	deploymentTrait, environment := createNominalDeploymentTest()
 
-	configured, err := deploymentTrait.Configure(environment)
-
-	assert.Nil(t, err)
+	configured, condition, err := deploymentTrait.Configure(environment)
 	assert.True(t, configured)
+	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestConfigureDeploymentTraitWhileBuildingKitDoesNotSucceed(t *testing.T) {
 	deploymentTrait, environment := createNominalDeploymentTest()
 	environment.Integration.Status.Phase = v1.IntegrationPhaseBuildingKit
 
-	configured, err := deploymentTrait.Configure(environment)
-
-	assert.Nil(t, err)
+	configured, condition, err := deploymentTrait.Configure(environment)
 	assert.False(t, configured)
+	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestConfigureDeploymentTraitWhileWaitingPlatformDoesNotSucceed(t *testing.T) {
@@ -72,20 +72,20 @@ func TestConfigureDeploymentTraitWhileWaitingPlatformDoesNotSucceed(t *testing.T
 	environment.Integration.Status.Phase = v1.IntegrationPhaseBuildingKit
 	environment.IntegrationKit.Status.Phase = v1.IntegrationKitPhaseWaitingForPlatform
 
-	configured, err := deploymentTrait.Configure(environment)
-
-	assert.Nil(t, err)
+	configured, condition, err := deploymentTrait.Configure(environment)
 	assert.False(t, configured)
+	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestApplyDeploymentTraitWhileResolvingKitDoesNotSucceed(t *testing.T) {
 	deploymentTrait, environment := createNominalDeploymentTest()
 	environment.Integration.Status.Phase = v1.IntegrationPhaseBuildingKit
 
-	configured, err := deploymentTrait.Configure(environment)
-
-	assert.Nil(t, err)
+	configured, condition, err := deploymentTrait.Configure(environment)
 	assert.False(t, configured)
+	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestApplyDeploymentTraitWhileDeployingIntegrationDoesSucceed(t *testing.T) {
diff --git a/pkg/trait/environment.go b/pkg/trait/environment.go
index 4569c38a4..760f6e34e 100644
--- a/pkg/trait/environment.go
+++ b/pkg/trait/environment.go
@@ -61,12 +61,12 @@ func newEnvironmentTrait() Trait {
 	}
 }
 
-func (t *environmentTrait) Configure(e *Environment) (bool, error) {
+func (t *environmentTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *environmentTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/environment_test.go b/pkg/trait/environment_test.go
index 75f2d421d..63f72e38f 100644
--- a/pkg/trait/environment_test.go
+++ b/pkg/trait/environment_test.go
@@ -41,9 +41,9 @@ func TestDefaultEnvironment(t *testing.T) {
 	env := mockEnvironment(catalog)
 	env.Platform.ResyncStatusFullConfig()
 
-	err = NewEnvironmentTestCatalog().apply(&env)
-
+	conditions, err := NewEnvironmentTestCatalog().apply(&env)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	ns := false
 	name := false
@@ -90,9 +90,9 @@ func TestEnabledContainerMetaDataEnvVars(t *testing.T) {
 	}
 	env.Platform.ResyncStatusFullConfig()
 
-	err = NewEnvironmentTestCatalog().apply(&env)
-
+	conditions, err := NewEnvironmentTestCatalog().apply(&env)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	ns := false
 	name := false
@@ -130,9 +130,9 @@ func TestDisabledContainerMetaDataEnvVars(t *testing.T) {
 
 	env.Platform.ResyncStatusFullConfig()
 
-	err = NewEnvironmentTestCatalog().apply(&env)
-
+	conditions, err := NewEnvironmentTestCatalog().apply(&env)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	ns := false
 	name := false
@@ -169,9 +169,9 @@ func TestCustomEnvVars(t *testing.T) {
 	}
 	env.Platform.ResyncStatusFullConfig()
 
-	err = NewEnvironmentTestCatalog().apply(&env)
-
+	conditions, err := NewEnvironmentTestCatalog().apply(&env)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	userK1 := false
 	userK2 := false
diff --git a/pkg/trait/error_handler.go b/pkg/trait/error_handler.go
index 3da5efff1..116dd3883 100644
--- a/pkg/trait/error_handler.go
+++ b/pkg/trait/error_handler.go
@@ -41,20 +41,20 @@ func newErrorHandlerTrait() Trait {
 	}
 }
 
-func (t *errorHandlerTrait) Configure(e *Environment) (bool, error) {
+func (t *errorHandlerTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if t.ErrorHandlerRef == "" {
 		t.ErrorHandlerRef = e.Integration.Spec.GetConfigurationProperty(v1.ErrorHandlerRefName)
 	}
 
-	return t.ErrorHandlerRef != "", nil
+	return t.ErrorHandlerRef != "", nil, nil
 }
 
 func (t *errorHandlerTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/error_handler_test.go b/pkg/trait/error_handler_test.go
index d18fce211..6c9320682 100644
--- a/pkg/trait/error_handler_test.go
+++ b/pkg/trait/error_handler_test.go
@@ -36,19 +36,23 @@ func TestErrorHandlerConfigureFromIntegrationProperty(t *testing.T) {
 	e.Integration.Spec.AddConfiguration("property", fmt.Sprintf("%v = %s", v1.ErrorHandlerRefName, "defaultErrorHandler"))
 
 	trait := newErrorHandlerTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 
 	e.Integration.Status.Phase = v1.IntegrationPhaseNone
-	enabled, err = trait.Configure(e)
+	enabled, condition, err = trait.Configure(e)
 	assert.Nil(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 
 	e.Integration.Status.Phase = v1.IntegrationPhaseInitialization
-	enabled, err = trait.Configure(e)
+	enabled, condition, err = trait.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
+
 }
 
 func TestErrorHandlerApplySource(t *testing.T) {
@@ -60,9 +64,11 @@ func TestErrorHandlerApplySource(t *testing.T) {
 	e.Integration.Status.Phase = v1.IntegrationPhaseInitialization
 
 	trait := newErrorHandlerTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
+
 	err = trait.Apply(e)
 	assert.Nil(t, err)
 	assert.Equal(t, `- error-handler:
@@ -84,9 +90,11 @@ func TestErrorHandlerApplyDependency(t *testing.T) {
 	e.Integration.Status.Phase = v1.IntegrationPhaseInitialization
 
 	trait := newErrorHandlerTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
+
 	err = trait.Apply(e)
 	assert.Nil(t, err)
 	assert.Equal(t, "camel:log", e.Integration.Status.Dependencies[0])
diff --git a/pkg/trait/gc.go b/pkg/trait/gc.go
index 3beeb88d9..ef309c9eb 100644
--- a/pkg/trait/gc.go
+++ b/pkg/trait/gc.go
@@ -61,12 +61,15 @@ func newGCTrait() Trait {
 	}
 }
 
-func (t *gcTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+func (t *gcTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *gcTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/gc_test.go b/pkg/trait/gc_test.go
index aad15f1a2..463af2f5a 100644
--- a/pkg/trait/gc_test.go
+++ b/pkg/trait/gc_test.go
@@ -23,26 +23,36 @@ import (
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
 	"github.com/stretchr/testify/assert"
 
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
 )
 
 func TestConfigureGCTraitDoesSucceed(t *testing.T) {
 	gcTrait, environment := createNominalGCTest()
-	configured, err := gcTrait.Configure(environment)
+	configured, condition, err := gcTrait.Configure(environment)
 
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
+
 }
 
 func TestConfigureDisabledGCTraitDoesNotSucceed(t *testing.T) {
 	gcTrait, environment := createNominalGCTest()
 	gcTrait.Enabled = pointer.Bool(false)
 
-	configured, err := gcTrait.Configure(environment)
-
+	expectedCondition := NewIntegrationCondition(
+		v1.IntegrationConditionTraitInfo,
+		corev1.ConditionTrue,
+		"Trait configuration",
+		"explicitly disabled by the user",
+	)
+	configured, condition, err := gcTrait.Configure(environment)
 	assert.False(t, configured)
 	assert.Nil(t, err)
+	assert.NotNil(t, condition)
+	assert.Equal(t, expectedCondition, condition)
 }
 
 func TestApplyGarbageCollectorTraitFirstGenerationDoesSucceed(t *testing.T) {
diff --git a/pkg/trait/health.go b/pkg/trait/health.go
index bf8350e4b..cb357a39e 100644
--- a/pkg/trait/health.go
+++ b/pkg/trait/health.go
@@ -52,17 +52,16 @@ func newHealthTrait() Trait {
 	}
 }
 
-func (t *healthTrait) Configure(e *Environment) (bool, error) {
+func (t *healthTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil ||
 		!e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
-
 	if !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *healthTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/ingress.go b/pkg/trait/ingress.go
index f611e8667..f240f10d9 100644
--- a/pkg/trait/ingress.go
+++ b/pkg/trait/ingress.go
@@ -24,6 +24,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	networkingv1 "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/utils/pointer"
 
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
 	traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
@@ -51,34 +52,29 @@ func (t *ingressTrait) IsAllowedInProfile(profile v1.TraitProfile) bool {
 	return profile.Equal(v1.TraitProfileKubernetes)
 }
 
-func (t *ingressTrait) Configure(e *Environment) (bool, error) {
+func (t *ingressTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
 	if !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
-
-	if !ptrDerefOr(t.Enabled, true) {
-		e.Integration.Status.SetCondition(
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationCondition(
 			v1.IntegrationConditionExposureAvailable,
 			corev1.ConditionFalse,
 			v1.IntegrationConditionIngressNotAvailableReason,
 			"explicitly disabled",
-		)
-		return false, nil
+		), nil
 	}
 
-	if ptrDerefOr(t.Auto, true) {
+	if pointer.BoolDeref(t.Auto, true) {
 		if e.Resources.GetUserServiceForIntegration(e.Integration) == nil {
-			e.Integration.Status.SetCondition(
-				v1.IntegrationConditionExposureAvailable,
-				corev1.ConditionFalse,
-				v1.IntegrationConditionIngressNotAvailableReason,
-				"no service defined",
-			)
-			return false, nil
+			return false, nil, nil
 		}
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *ingressTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/ingress_test.go b/pkg/trait/ingress_test.go
index c19032376..b299f8f46 100644
--- a/pkg/trait/ingress_test.go
+++ b/pkg/trait/ingress_test.go
@@ -34,59 +34,55 @@ import (
 
 func TestConfigureIngressTraitDoesSucceed(t *testing.T) {
 	ingressTrait, environment := createNominalIngressTest()
-	configured, err := ingressTrait.Configure(environment)
+	configured, condition, err := ingressTrait.Configure(environment)
 
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.Len(t, environment.Integration.Status.Conditions, 0)
+	assert.Nil(t, condition)
+
 }
 
 func TestConfigureDisabledIngressTraitDoesNotSucceed(t *testing.T) {
 	ingressTrait, environment := createNominalIngressTest()
 	ingressTrait.Enabled = pointer.Bool(false)
 
-	configured, err := ingressTrait.Configure(environment)
+	expectedCondition := NewIntegrationCondition(
+		v1.IntegrationConditionExposureAvailable,
+		corev1.ConditionFalse,
+		v1.IntegrationConditionIngressNotAvailableReason,
+		"explicitly disabled",
+	)
+	configured, condition, err := ingressTrait.Configure(environment)
 
 	assert.False(t, configured)
 	assert.Nil(t, err)
-	conditions := environment.Integration.Status.Conditions
-	assert.Len(t, conditions, 1)
-	assert.Equal(t, "explicitly disabled", conditions[0].Message)
+	assert.NotNil(t, condition)
+	assert.Equal(t, expectedCondition, condition)
 }
 
 func TestConfigureIngressTraitInWrongPhaseDoesNotSucceed(t *testing.T) {
 	ingressTrait, environment := createNominalIngressTest()
 	environment.Integration.Status.Phase = v1.IntegrationPhaseError
 
-	configured, err := ingressTrait.Configure(environment)
+	configured, condition, err := ingressTrait.Configure(environment)
 
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.Len(t, environment.Integration.Status.Conditions, 0)
 }
 
-func TestConfigureAutoIngressTraitWithoutUserServiceDoesNotSucceed(t *testing.T) {
-	ingressTrait, environment := createNominalIngressTest()
-	ingressTrait.Auto = pointer.Bool(true)
-	environment.Resources = kubernetes.NewCollection()
-
-	configured, err := ingressTrait.Configure(environment)
-
-	assert.False(t, configured)
-	assert.Nil(t, err)
-	conditions := environment.Integration.Status.Conditions
-	assert.Len(t, conditions, 1)
-	assert.Equal(t, "no service defined", conditions[0].Message)
-}
-
 func TestConfigureAutoIngressTraitWithUserServiceDoesSucceed(t *testing.T) {
 	ingressTrait, environment := createNominalIngressTest()
 	ingressTrait.Auto = nil
 
-	configured, err := ingressTrait.Configure(environment)
+	configured, condition, err := ingressTrait.Configure(environment)
 
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 	assert.Len(t, environment.Integration.Status.Conditions, 0)
 }
 
diff --git a/pkg/trait/init.go b/pkg/trait/init.go
index d941af7c1..a365f344e 100644
--- a/pkg/trait/init.go
+++ b/pkg/trait/init.go
@@ -42,12 +42,12 @@ func NewInitTrait() Trait {
 	}
 }
 
-func (t *initTrait) Configure(e *Environment) (bool, error) {
+func (t *initTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if !pointer.BoolDeref(t.Enabled, true) {
-		return false, errors.New("trait init cannot be disabled")
+		return false, nil, errors.New("trait init cannot be disabled")
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil, nil
 }
 
 func (t *initTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/istio.go b/pkg/trait/istio.go
index 26e35540b..86d4ea268 100644
--- a/pkg/trait/istio.go
+++ b/pkg/trait/istio.go
@@ -47,12 +47,12 @@ func newIstioTrait() Trait {
 	}
 }
 
-func (t *istioTrait) Configure(e *Environment) (bool, error) {
+func (t *istioTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *istioTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/istio_test.go b/pkg/trait/istio_test.go
index d3cf638f4..6c7d5b69b 100644
--- a/pkg/trait/istio_test.go
+++ b/pkg/trait/istio_test.go
@@ -60,7 +60,6 @@ func NewIstioTestEnv(t *testing.T, d *appsv1.Deployment, s *serving.Service, ena
 			},
 			Spec: v1.IntegrationPlatformSpec{
 				Cluster: v1.IntegrationPlatformClusterOpenShift,
-				Profile: v1.TraitProfileKnative,
 				Build: v1.IntegrationPlatformBuildSpec{
 					RuntimeVersion: catalog.Runtime.Version,
 				},
@@ -100,9 +99,9 @@ func TestIstioInject(t *testing.T) {
 	}
 
 	env := NewIstioTestEnv(t, &d, &s, true)
-	err := env.Catalog.apply(&env)
+	conditions, err := env.Catalog.apply(&env)
 	assert.Nil(t, err)
-
+	assert.Empty(t, conditions)
 	assert.Empty(t, s.Spec.ConfigurationSpec.Template.Annotations[istioSidecarInjectAnnotation])
 	assert.NotEmpty(t, d.Spec.Template.Annotations[istioSidecarInjectAnnotation])
 }
@@ -125,9 +124,9 @@ func TestIstioForcedInjectTrue(t *testing.T) {
 	env.Integration.Spec.Traits.Istio.Enabled = pointer.Bool(true)
 	env.Integration.Spec.Traits.Istio.Inject = pointer.Bool(true)
 
-	err := env.Catalog.apply(&env)
+	conditions, err := env.Catalog.apply(&env)
 	assert.Nil(t, err)
-
+	assert.Empty(t, conditions)
 	assert.Equal(t, "true", s.Spec.ConfigurationSpec.Template.Annotations[istioSidecarInjectAnnotation])
 	assert.Equal(t, "true", d.Spec.Template.Annotations[istioSidecarInjectAnnotation])
 }
@@ -150,9 +149,9 @@ func TestIstioForcedInjectFalse(t *testing.T) {
 	env.Integration.Spec.Traits.Istio.Enabled = pointer.Bool(true)
 	env.Integration.Spec.Traits.Istio.Inject = pointer.Bool(false)
 
-	err := env.Catalog.apply(&env)
+	conditions, err := env.Catalog.apply(&env)
 	assert.Nil(t, err)
-
+	assert.Empty(t, conditions)
 	assert.Equal(t, "false", s.Spec.ConfigurationSpec.Template.Annotations[istioSidecarInjectAnnotation])
 	assert.Equal(t, "false", d.Spec.Template.Annotations[istioSidecarInjectAnnotation])
 }
@@ -173,7 +172,8 @@ func TestIstioDisabled(t *testing.T) {
 
 	env := NewIstioTestEnv(t, &d, &s, false)
 
-	err := env.Catalog.apply(&env)
+	conditions, err := env.Catalog.apply(&env)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotContains(t, env.ExecutedTraits, "istio")
 }
diff --git a/pkg/trait/jolokia.go b/pkg/trait/jolokia.go
index 871c257ee..057fa71e8 100644
--- a/pkg/trait/jolokia.go
+++ b/pkg/trait/jolokia.go
@@ -44,12 +44,12 @@ func newJolokiaTrait() Trait {
 	}
 }
 
-func (t *jolokiaTrait) Configure(e *Environment) (bool, error) {
+func (t *jolokiaTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *jolokiaTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/jolokia_test.go b/pkg/trait/jolokia_test.go
index 4b7bc9a8a..f0210e5d0 100644
--- a/pkg/trait/jolokia_test.go
+++ b/pkg/trait/jolokia_test.go
@@ -34,10 +34,11 @@ func TestConfigureJolokiaTraitInRunningPhaseDoesSucceed(t *testing.T) {
 	trait, environment := createNominalJolokiaTest()
 	environment.Integration.Status.Phase = v1.IntegrationPhaseRunning
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 
 	assert.Nil(t, err)
 	assert.True(t, configured)
+	assert.Nil(t, condition)
 }
 
 func TestApplyJolokiaTraitNominalShouldSucceed(t *testing.T) {
diff --git a/pkg/trait/jvm.go b/pkg/trait/jvm.go
index 8a6968736..9223cfef6 100644
--- a/pkg/trait/jvm.go
+++ b/pkg/trait/jvm.go
@@ -55,23 +55,22 @@ func newJvmTrait() Trait {
 	}
 }
 
-func (t *jvmTrait) Configure(e *Environment) (bool, error) {
+func (t *jvmTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
-
 	if !e.IntegrationKitInPhase(v1.IntegrationKitPhaseReady) || !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if trait := e.Catalog.GetTrait(quarkusTraitID); trait != nil {
 		// The JVM trait must be disabled in case the current IntegrationKit corresponds to a native build
 		if quarkus, ok := trait.(*quarkusTrait); ok && quarkus.isNativeIntegration(e) {
-			return false, nil
+			return false, newIntegrationConditionPlatformDisabledWithReason("Quarkus native build"), nil
 		}
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 // nolint: maintidx // TODO: refactor the code
diff --git a/pkg/trait/jvm_test.go b/pkg/trait/jvm_test.go
index 41c3d8280..610d5000b 100644
--- a/pkg/trait/jvm_test.go
+++ b/pkg/trait/jvm_test.go
@@ -49,27 +49,30 @@ var (
 func TestConfigureJvmTraitInRightPhasesDoesSucceed(t *testing.T) {
 	trait, environment := createNominalJvmTest(v1.IntegrationKitTypePlatform)
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
 	assert.True(t, configured)
+	assert.Nil(t, condition)
 }
 
 func TestConfigureJvmTraitInWrongIntegrationPhaseDoesNotSucceed(t *testing.T) {
 	trait, environment := createNominalJvmTest(v1.IntegrationKitTypePlatform)
 	environment.Integration.Status.Phase = v1.IntegrationPhaseError
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
 	assert.True(t, configured)
+	assert.Nil(t, condition)
 }
 
 func TestConfigureJvmTraitInWrongIntegrationKitPhaseDoesNotSucceed(t *testing.T) {
 	trait, environment := createNominalJvmTest(v1.IntegrationKitTypePlatform)
 	environment.IntegrationKit.Status.Phase = v1.IntegrationKitPhaseWaitingForPlatform
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
 	assert.False(t, configured)
+	assert.Nil(t, condition)
 }
 
 func TestApplyJvmTraitWithDeploymentResource(t *testing.T) {
diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index 012e17835..d54878b16 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -71,19 +71,21 @@ func newKameletsTrait() Trait {
 	}
 }
 
-func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+func (t *kameletsTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
-
 	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if pointer.BoolDeref(t.Auto, true) {
 		kamelets, err := kamelets.ExtractKameletFromSources(e.Ctx, e.Client, e.CamelCatalog, e.Resources, e.Integration)
 		if err != nil {
-			return false, err
+			return false, nil, err
 		}
 
 		if len(kamelets) > 0 {
@@ -96,7 +98,7 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 		}
 	}
 
-	return len(t.getKameletKeys()) > 0, nil
+	return len(t.getKameletKeys()) > 0, nil, nil
 }
 
 func (t *kameletsTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/kamelets_test.go b/pkg/trait/kamelets_test.go
index ea2bf5690..e3cf4fd09 100644
--- a/pkg/trait/kamelets_test.go
+++ b/pkg/trait/kamelets_test.go
@@ -40,9 +40,10 @@ func TestConfigurationNoKameletsUsed(t *testing.T) {
     steps:
     - to: log:info
 `)
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 	assert.Equal(t, "", trait.List)
 }
 
@@ -60,9 +61,10 @@ func TestConfigurationWithKamelets(t *testing.T) {
     - to: kamelet://complex-.-.-1b/a
     - to: kamelet://complex-.-.-1c/b
 `)
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 	assert.Equal(t, []string{"c0", "c1", "c2", "complex-.-.-1a", "complex-.-.-1b", "complex-.-.-1c"}, trait.getKameletKeys())
 	assert.Equal(t, []configurationKey{
 		newConfigurationKey("c0", ""),
@@ -99,9 +101,10 @@ func TestKameletLookup(t *testing.T) {
 			},
 		},
 	})
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 	assert.Equal(t, []string{"timer"}, trait.getKameletKeys())
 
 	err = trait.Apply(environment)
@@ -147,9 +150,10 @@ func TestKameletSecondarySourcesLookup(t *testing.T) {
 			},
 		},
 	})
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 	assert.Equal(t, []string{"timer"}, trait.getKameletKeys())
 
 	err = trait.Apply(environment)
@@ -197,9 +201,10 @@ func TestNonYAMLKameletLookup(t *testing.T) {
 			},
 		},
 	})
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 	assert.Equal(t, []string{"timer"}, trait.getKameletKeys())
 
 	err = trait.Apply(environment)
@@ -271,9 +276,10 @@ func TestMultipleKamelets(t *testing.T) {
 			},
 		},
 	})
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 	assert.Equal(t, []string{"logger", "timer"}, trait.getKameletKeys())
 
 	err = trait.Apply(environment)
@@ -357,9 +363,10 @@ func TestKameletConfigLookup(t *testing.T) {
 			},
 		},
 	})
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 	assert.Equal(t, []string{"timer"}, trait.getKameletKeys())
 	assert.Equal(t, []configurationKey{newConfigurationKey("timer", "")}, trait.getConfigurationKeys())
 
@@ -420,9 +427,10 @@ func TestKameletNamedConfigLookup(t *testing.T) {
 			},
 		},
 	})
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 	assert.Equal(t, []string{"timer"}, trait.getKameletKeys())
 	assert.Equal(t, []configurationKey{
 		newConfigurationKey("timer", ""),
@@ -460,9 +468,10 @@ func TestKameletConditionFalse(t *testing.T) {
 			},
 		})
 
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 
 	err = trait.Apply(environment)
 	assert.Error(t, err)
@@ -511,9 +520,10 @@ func TestKameletConditionTrue(t *testing.T) {
 			},
 		})
 
-	enabled, err := trait.Configure(environment)
+	enabled, condition, err := trait.Configure(environment)
 	require.NoError(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 
 	err = trait.Apply(environment)
 	require.NoError(t, err)
diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go
index 5e09bcd44..91bb7b7bc 100644
--- a/pkg/trait/knative.go
+++ b/pkg/trait/knative.go
@@ -66,27 +66,28 @@ func (t *knativeTrait) IsAllowedInProfile(profile v1.TraitProfile) bool {
 	return profile.Equal(v1.TraitProfileKnative)
 }
 
-func (t *knativeTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+func (t *knativeTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
-
 	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
-
 	if pointer.BoolDeref(t.Auto, true) {
 		if len(t.ChannelSources) == 0 {
 			items := make([]string, 0)
 			sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources)
 			if err != nil {
-				return false, err
+				return false, nil, err
 			}
 			if err := metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool {
 				items = append(items, knativeutil.FilterURIs(meta.FromURIs, knativeapi.CamelServiceTypeChannel)...)
 				return true
 			}); err != nil {
-				return false, err
+				return false, nil, err
 			}
 
 			t.ChannelSources = items
@@ -96,13 +97,13 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 			items := make([]string, 0)
 			sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources)
 			if err != nil {
-				return false, err
+				return false, nil, err
 			}
 			if err := metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool {
 				items = append(items, knativeutil.FilterURIs(meta.ToURIs, knativeapi.CamelServiceTypeChannel)...)
 				return true
 			}); err != nil {
-				return false, err
+				return false, nil, err
 			}
 
 			t.ChannelSinks = items
@@ -112,13 +113,13 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 			items := make([]string, 0)
 			sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources)
 			if err != nil {
-				return false, err
+				return false, nil, err
 			}
 			if err := metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool {
 				items = append(items, knativeutil.FilterURIs(meta.FromURIs, knativeapi.CamelServiceTypeEndpoint)...)
 				return true
 			}); err != nil {
-				return false, err
+				return false, nil, err
 			}
 
 			t.EndpointSources = items
@@ -128,13 +129,13 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 			items := make([]string, 0)
 			sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources)
 			if err != nil {
-				return false, err
+				return false, nil, err
 			}
 			if err := metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool {
 				items = append(items, knativeutil.FilterURIs(meta.ToURIs, knativeapi.CamelServiceTypeEndpoint)...)
 				return true
 			}); err != nil {
-				return false, err
+				return false, nil, err
 			}
 
 			t.EndpointSinks = items
@@ -144,13 +145,13 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 			items := make([]string, 0)
 			sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources)
 			if err != nil {
-				return false, err
+				return false, nil, err
 			}
 			if err := metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool {
 				items = append(items, knativeutil.FilterURIs(meta.FromURIs, knativeapi.CamelServiceTypeEvent)...)
 				return true
 			}); err != nil {
-				return false, err
+				return false, nil, err
 			}
 
 			t.EventSources = items
@@ -160,13 +161,13 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 			items := make([]string, 0)
 			sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources)
 			if err != nil {
-				return false, err
+				return false, nil, err
 			}
 			if err := metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool {
 				items = append(items, knativeutil.FilterURIs(meta.ToURIs, knativeapi.CamelServiceTypeEvent)...)
 				return true
 			}); err != nil {
-				return false, err
+				return false, nil, err
 			}
 
 			t.EventSinks = items
@@ -182,7 +183,7 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 		}
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *knativeTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go
index 63b8f231e..7d667881a 100644
--- a/pkg/trait/knative_service.go
+++ b/pkg/trait/knative_service.go
@@ -69,63 +69,57 @@ func (t *knativeServiceTrait) IsAllowedInProfile(profile v1.TraitProfile) bool {
 	return profile.Equal(v1.TraitProfileKnative)
 }
 
-func (t *knativeServiceTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		if e.Integration != nil {
-			e.Integration.Status.SetCondition(
-				v1.IntegrationConditionKnativeServiceAvailable,
-				corev1.ConditionFalse,
-				v1.IntegrationConditionKnativeServiceNotAvailableReason,
-				"explicitly disabled",
-			)
-		}
-
-		return false, nil
+func (t *knativeServiceTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationCondition(
+			v1.IntegrationConditionKnativeServiceAvailable,
+			corev1.ConditionFalse,
+			v1.IntegrationConditionKnativeServiceNotAvailableReason,
+			"explicitly disabled",
+		), nil
 	}
 
 	if !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if e.Resources.GetDeploymentForIntegration(e.Integration) != nil {
-		e.Integration.Status.SetCondition(
+		// A controller is already present for the integration
+		return false, NewIntegrationCondition(
 			v1.IntegrationConditionKnativeServiceAvailable,
 			corev1.ConditionFalse,
 			v1.IntegrationConditionKnativeServiceNotAvailableReason,
 			fmt.Sprintf("different controller strategy used (%s)", string(ControllerStrategyDeployment)),
-		)
-
-		// A controller is already present for the integration
-		return false, nil
+		), nil
 	}
 
 	strategy, err := e.DetermineControllerStrategy()
 	if err != nil {
-		e.Integration.Status.SetErrorCondition(
+		return false, NewIntegrationCondition(
 			v1.IntegrationConditionKnativeServiceAvailable,
+			corev1.ConditionFalse,
 			v1.IntegrationConditionKnativeServiceNotAvailableReason,
-			err,
-		)
-
-		return false, err
+			err.Error(),
+		), err
 	}
 	if strategy != ControllerStrategyKnativeService {
-		e.Integration.Status.SetCondition(
+		return false, NewIntegrationCondition(
 			v1.IntegrationConditionKnativeServiceAvailable,
 			corev1.ConditionFalse,
 			v1.IntegrationConditionKnativeServiceNotAvailableReason,
 			fmt.Sprintf("different controller strategy used (%s)", string(strategy)),
-		)
-
-		return false, nil
+		), nil
 	}
 
 	if e.IntegrationInPhase(v1.IntegrationPhaseRunning, v1.IntegrationPhaseError) {
 		condition := e.Integration.Status.GetCondition(v1.IntegrationConditionKnativeServiceAvailable)
-		return condition != nil && condition.Status == corev1.ConditionTrue, nil
+		return condition != nil && condition.Status == corev1.ConditionTrue, nil, nil
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *knativeServiceTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/knative_service_test.go b/pkg/trait/knative_service_test.go
index ccf49b3d8..6367c13f6 100644
--- a/pkg/trait/knative_service_test.go
+++ b/pkg/trait/knative_service_test.go
@@ -118,7 +118,8 @@ func TestKnativeService(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	// don't care about conditions in this unit test
+	_, err = traitCatalog.apply(&environment)
 
 	require.NoError(t, err)
 	assert.NotEmpty(t, environment.ExecutedTraits)
@@ -246,7 +247,8 @@ func TestKnativeServiceWithCustomContainerName(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	// don't care about conditions in this unit test
+	_, err = traitCatalog.apply(&environment)
 
 	require.NoError(t, err)
 	assert.NotEmpty(t, environment.ExecutedTraits)
@@ -330,7 +332,8 @@ func TestKnativeServiceWithRest(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	// don't care about conditions in this unit test
+	_, err = traitCatalog.apply(&environment)
 
 	require.NoError(t, err)
 	assert.NotEmpty(t, environment.ExecutedTraits)
@@ -397,7 +400,8 @@ func TestKnativeServiceNotApplicable(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	// don't care about conditions in this unit test
+	_, err = traitCatalog.apply(&environment)
 
 	require.NoError(t, err)
 	assert.NotEmpty(t, environment.ExecutedTraits)
@@ -507,8 +511,7 @@ func createKnativeServiceTestEnvironment(t *testing.T, trait *traitv1.KnativeSer
 
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(environment)
-
+	_, err = traitCatalog.apply(environment)
 	require.NoError(t, err)
 
 	return environment
@@ -521,7 +524,7 @@ func TestServiceAnnotation(t *testing.T) {
 	})
 
 	traitsCatalog := environment.Catalog
-	err := traitsCatalog.apply(environment)
+	_, err := traitsCatalog.apply(environment)
 
 	assert.Nil(t, err)
 
diff --git a/pkg/trait/knative_test.go b/pkg/trait/knative_test.go
index 134819436..0d5a339fb 100644
--- a/pkg/trait/knative_test.go
+++ b/pkg/trait/knative_test.go
@@ -109,9 +109,10 @@ func TestKnativeEnvConfigurationFromTrait(t *testing.T) {
 	assert.Nil(t, err)
 
 	tr, _ := tc.GetTrait("knative").(*knativeTrait)
-	ok, err := tr.Configure(&environment)
+	ok, condition, err := tr.Configure(&environment)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = tr.Apply(&environment)
 	assert.Nil(t, err)
@@ -230,9 +231,10 @@ func TestKnativeEnvConfigurationFromSource(t *testing.T) {
 
 	tr, _ := tc.GetTrait("knative").(*knativeTrait)
 
-	ok, err := tr.Configure(&environment)
+	ok, condition, err := tr.Configure(&environment)
 	assert.Nil(t, err)
 	assert.True(t, ok)
+	assert.Nil(t, condition)
 
 	err = tr.Apply(&environment)
 	assert.Nil(t, err)
@@ -296,9 +298,8 @@ func TestKnativePlatformHttpConfig(t *testing.T) {
 			err = tc.Configure(&environment)
 			assert.Nil(t, err)
 
-			err = tc.apply(&environment)
+			_, err = tc.apply(&environment)
 			assert.Nil(t, err)
-
 			assert.Contains(t, environment.Integration.Status.Capabilities, v1.CapabilityPlatformHTTP)
 		})
 	}
@@ -343,9 +344,9 @@ func TestKnativePlatformHttpDependencies(t *testing.T) {
 			err = tc.Configure(&environment)
 			assert.Nil(t, err)
 
-			err = tc.apply(&environment)
+			conditions, err := tc.apply(&environment)
 			assert.Nil(t, err)
-
+			assert.Empty(t, conditions)
 			assert.Contains(t, environment.Integration.Status.Capabilities, v1.CapabilityPlatformHTTP)
 			assert.Contains(t, environment.Integration.Status.Dependencies, "mvn:org.apache.camel.quarkus:camel-quarkus-platform-http")
 		})
@@ -394,7 +395,8 @@ func TestKnativeConfigurationSorting(t *testing.T) {
 	tc := NewCatalog(c)
 	err = tc.Configure(&environment)
 	assert.Nil(t, err)
-	_ = tc.apply(&environment)
+	conditions, _ := tc.apply(&environment)
+	assert.Empty(t, conditions)
 	// no matter if there is any other trait error
 	camelEnv := knativeapi.NewCamelEnvironment()
 	err = camelEnv.Deserialize(envvar.Get(environment.EnvVars, "CAMEL_KNATIVE_CONFIGURATION").Value)
diff --git a/pkg/trait/logging.go b/pkg/trait/logging.go
index 3e3590b78..dafd331a7 100644
--- a/pkg/trait/logging.go
+++ b/pkg/trait/logging.go
@@ -48,12 +48,16 @@ func newLoggingTraitTrait() Trait {
 	}
 }
 
-func (l loggingTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(l.Enabled, true) {
-		return false, nil
+func (l loggingTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
 	}
 
-	return e.IntegrationInRunningPhases(), nil
+	if !pointer.BoolDeref(l.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
+	}
+
+	return e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (l loggingTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/logging_test.go b/pkg/trait/logging_test.go
index 2dad88db3..6b2846e62 100644
--- a/pkg/trait/logging_test.go
+++ b/pkg/trait/logging_test.go
@@ -110,9 +110,10 @@ func NewLoggingTestCatalog() *Catalog {
 
 func TestEmptyLoggingTrait(t *testing.T) {
 	env := createDefaultLoggingTestEnv(t)
-	err := NewLoggingTestCatalog().apply(env)
+	conditions, err := NewLoggingTestCatalog().apply(env)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, env.ExecutedTraits)
 
 	quarkusConsoleColor := false
@@ -162,9 +163,10 @@ func TestEmptyLoggingTrait(t *testing.T) {
 func TestJsonLoggingTrait(t *testing.T) {
 	// When running, this log should look like "09:07:00 INFO  (main) Profile prod activated."
 	env := createLoggingTestEnv(t, true, true, false, "TRACE", "%d{HH:mm:ss} %-5p (%t) %s%e%n")
-	err := NewLoggingTestCatalog().apply(env)
+	conditions, err := NewLoggingTestCatalog().apply(env)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, env.ExecutedTraits)
 
 	quarkusConsoleColor := false
diff --git a/pkg/trait/mount.go b/pkg/trait/mount.go
index a99e3c9b0..ccb3b344b 100644
--- a/pkg/trait/mount.go
+++ b/pkg/trait/mount.go
@@ -46,29 +46,29 @@ func newMountTrait() Trait {
 	}
 }
 
-func (t *mountTrait) Configure(e *Environment) (bool, error) {
+func (t *mountTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) ||
 		(!e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases()) {
-		return false, nil
+		return false, nil, nil
 	}
 
 	// Validate resources and pvcs
 	for _, c := range t.Configs {
 		if !strings.HasPrefix(c, "configmap:") && !strings.HasPrefix(c, "secret:") {
-			return false, fmt.Errorf("unsupported config %s, must be a configmap or secret resource", c)
+			return false, nil, fmt.Errorf("unsupported config %s, must be a configmap or secret resource", c)
 		}
 	}
 	for _, r := range t.Resources {
 		if !strings.HasPrefix(r, "configmap:") && !strings.HasPrefix(r, "secret:") {
-			return false, fmt.Errorf("unsupported resource %s, must be a configmap or secret resource", r)
+			return false, nil, fmt.Errorf("unsupported resource %s, must be a configmap or secret resource", r)
 		}
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *mountTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/mount_test.go b/pkg/trait/mount_test.go
index 199597d9f..6191b2ae6 100644
--- a/pkg/trait/mount_test.go
+++ b/pkg/trait/mount_test.go
@@ -43,9 +43,10 @@ func TestMountVolumesEmpty(t *testing.T) {
 	environment.Integration.Spec.Traits = v1.Traits{} // empty traits
 	environment.Platform.ResyncStatusFullConfig()
 
-	err := traitCatalog.apply(environment)
+	conditions, err := traitCatalog.apply(environment)
 
 	require.NoError(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("mount"))
 
@@ -65,9 +66,10 @@ func TestMountVolumesIntegrationPhaseDeploying(t *testing.T) {
 	environment := getNominalEnv(t, traitCatalog)
 	environment.Platform.ResyncStatusFullConfig()
 
-	err := traitCatalog.apply(environment)
+	conditions, err := traitCatalog.apply(environment)
 
 	require.NoError(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("mount"))
 
@@ -113,9 +115,10 @@ func TestMountVolumesIntegrationPhaseInitialization(t *testing.T) {
 	environment.Integration.Status.Phase = v1.IntegrationPhaseInitialization
 	environment.Platform.ResyncStatusFullConfig()
 
-	err := traitCatalog.apply(environment)
+	conditions, err := traitCatalog.apply(environment)
 
 	require.NoError(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.Nil(t, environment.GetTrait("mount"))
 
diff --git a/pkg/trait/openapi.go b/pkg/trait/openapi.go
index 50ab972d5..0da314b96 100644
--- a/pkg/trait/openapi.go
+++ b/pkg/trait/openapi.go
@@ -55,21 +55,21 @@ func newOpenAPITrait() Trait {
 	}
 }
 
-func (t *openAPITrait) Configure(e *Environment) (bool, error) {
+func (t *openAPITrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
-		return false, nil
+		return false, nil, nil
 	}
 
 	// check if the runtime provides 'rest' capabilities
 	if _, ok := e.CamelCatalog.Runtime.Capabilities[v1.CapabilityRest]; !ok {
-		return false, fmt.Errorf("the runtime provider %s does not declare 'rest' capability", e.CamelCatalog.Runtime.Provider)
+		return false, nil, fmt.Errorf("the runtime provider %s does not declare 'rest' capability", e.CamelCatalog.Runtime.Provider)
 	}
 
 	if t.Configmaps != nil {
-		return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil
+		return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil, nil
 	}
 
-	return false, nil
+	return false, nil, nil
 }
 
 func (t *openAPITrait) Apply(e *Environment) error {
diff --git a/pkg/trait/openapi_test.go b/pkg/trait/openapi_test.go
index d90a27ac1..05e710dc7 100644
--- a/pkg/trait/openapi_test.go
+++ b/pkg/trait/openapi_test.go
@@ -36,27 +36,31 @@ func TestRestDslTraitApplicability(t *testing.T) {
 	}
 
 	trait, _ := newOpenAPITrait().(*openAPITrait)
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 
 	e.Integration = &v1.Integration{
 		Status: v1.IntegrationStatus{
 			Phase: v1.IntegrationPhaseNone,
 		},
 	}
-	enabled, err = trait.Configure(e)
+	enabled, condition, err = trait.Configure(e)
 	assert.Nil(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 
 	trait.Configmaps = []string{"my-configmap"}
 
-	enabled, err = trait.Configure(e)
+	enabled, condition, err = trait.Configure(e)
 	assert.Nil(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 
 	e.Integration.Status.Phase = v1.IntegrationPhaseInitialization
-	enabled, err = trait.Configure(e)
+	enabled, condition, err = trait.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 }
diff --git a/pkg/trait/owner.go b/pkg/trait/owner.go
index 31066f1a2..20bab1952 100644
--- a/pkg/trait/owner.go
+++ b/pkg/trait/owner.go
@@ -39,12 +39,15 @@ func newOwnerTrait() Trait {
 	}
 }
 
-func (t *ownerTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+func (t *ownerTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *ownerTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/pdb.go b/pkg/trait/pdb.go
index 50093faf1..94532a698 100644
--- a/pkg/trait/pdb.go
+++ b/pkg/trait/pdb.go
@@ -40,25 +40,25 @@ func newPdbTrait() Trait {
 	}
 }
 
-func (t *pdbTrait) Configure(e *Environment) (bool, error) {
+func (t *pdbTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
 	strategy, err := e.DetermineControllerStrategy()
 	if err != nil {
-		return false, fmt.Errorf("unable to determine the controller stratedy")
+		return false, nil, fmt.Errorf("unable to determine the controller strategy")
 	}
 
 	if strategy == ControllerStrategyCronJob {
-		return false, fmt.Errorf("poddisruptionbudget isn't supported with cron-job controller strategy")
+		return false, nil, fmt.Errorf("poddisruptionbudget isn't supported with cron-job controller strategy")
 	}
 
 	if t.MaxUnavailable != "" && t.MinAvailable != "" {
-		return false, fmt.Errorf("both minAvailable and maxUnavailable can't be set simultaneously")
+		return false, nil, fmt.Errorf("both minAvailable and maxUnavailable can't be set simultaneously")
 	}
 
-	return e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *pdbTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/pdb_test.go b/pkg/trait/pdb_test.go
index 65fec620b..17518c4f9 100644
--- a/pkg/trait/pdb_test.go
+++ b/pkg/trait/pdb_test.go
@@ -34,10 +34,11 @@ import (
 
 func TestConfigurePdbTraitDoesSucceed(t *testing.T) {
 	pdbTrait, environment, _ := createPdbTest()
-	configured, err := pdbTrait.Configure(environment)
+	configured, condition, err := pdbTrait.Configure(environment)
 
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestConfigurePdbTraitDoesNotSucceed(t *testing.T) {
@@ -45,9 +46,10 @@ func TestConfigurePdbTraitDoesNotSucceed(t *testing.T) {
 
 	pdbTrait.MinAvailable = "1"
 	pdbTrait.MaxUnavailable = "2"
-	configured, err := pdbTrait.Configure(environment)
+	configured, condition, err := pdbTrait.Configure(environment)
 	assert.NotNil(t, err)
 	assert.False(t, configured)
+	assert.Nil(t, condition)
 }
 
 func TestPdbIsCreatedWithoutParametersEnabled(t *testing.T) {
diff --git a/pkg/trait/platform.go b/pkg/trait/platform.go
index 3401d481a..58e545597 100644
--- a/pkg/trait/platform.go
+++ b/pkg/trait/platform.go
@@ -43,13 +43,13 @@ func newPlatformTrait() Trait {
 	}
 }
 
-func (t *platformTrait) Configure(e *Environment) (bool, error) {
+func (t *platformTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if !e.IntegrationInPhase(v1.IntegrationPhaseNone, v1.IntegrationPhaseWaitingForPlatform) {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if !pointer.BoolDeref(t.Auto, false) {
@@ -57,11 +57,11 @@ func (t *platformTrait) Configure(e *Environment) (bool, error) {
 			if t.CreateDefault == nil {
 				// Calculate if the platform should be automatically created when missing.
 				if ocp, err := openshift.IsOpenShift(t.Client); err != nil {
-					return false, err
+					return false, nil, err
 				} else if ocp {
 					t.CreateDefault = &ocp
 				} else if addr, err := image.GetRegistryAddress(e.Ctx, t.Client); err != nil {
-					return false, err
+					return false, nil, err
 				} else if addr != nil {
 					t.CreateDefault = pointer.Bool(true)
 				}
@@ -73,7 +73,7 @@ func (t *platformTrait) Configure(e *Environment) (bool, error) {
 		}
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *platformTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/platform_test.go b/pkg/trait/platform_test.go
index 2907680a4..7db06c3bd 100644
--- a/pkg/trait/platform_test.go
+++ b/pkg/trait/platform_test.go
@@ -65,9 +65,10 @@ func TestPlatformTraitChangeStatus(t *testing.T) {
 			trait.Client, err = test.NewFakeClient()
 			assert.Nil(t, err)
 
-			enabled, err := trait.Configure(&e)
+			enabled, condition, err := trait.Configure(&e)
 			assert.Nil(t, err)
 			assert.True(t, enabled)
+			assert.Nil(t, condition)
 
 			err = trait.Apply(&e)
 			assert.Nil(t, err)
@@ -99,9 +100,10 @@ func TestPlatformTraitCreatesDefaultPlatform(t *testing.T) {
 	trait.Client, err = test.NewFakeClient()
 	assert.Nil(t, err)
 
-	enabled, err := trait.Configure(&e)
+	enabled, condition, err := trait.Configure(&e)
 	assert.Nil(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 
 	err = trait.Apply(&e)
 	assert.Nil(t, err)
@@ -156,9 +158,10 @@ func TestPlatformTraitExisting(t *testing.T) {
 			trait.Client, err = test.NewFakeClient(&existingPlatform)
 			assert.Nil(t, err)
 
-			enabled, err := trait.Configure(&e)
+			enabled, condition, err := trait.Configure(&e)
 			assert.Nil(t, err)
 			assert.True(t, enabled)
+			assert.Nil(t, condition)
 
 			err = trait.Apply(&e)
 			assert.Nil(t, err)
diff --git a/pkg/trait/pod.go b/pkg/trait/pod.go
index aa440548d..5233bd513 100644
--- a/pkg/trait/pod.go
+++ b/pkg/trait/pod.go
@@ -44,16 +44,18 @@ func newPodTrait() Trait {
 	}
 }
 
-func (t *podTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+func (t *podTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
-
 	if e.Integration.Spec.PodTemplate == nil {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *podTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/pod_test.go b/pkg/trait/pod_test.go
index 0ecef59c3..5a994cb50 100755
--- a/pkg/trait/pod_test.go
+++ b/pkg/trait/pod_test.go
@@ -36,14 +36,16 @@ import (
 
 func TestConfigurePodTraitDoesSucceed(t *testing.T) {
 	trait, environment, _ := createPodTest("")
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 
 	assert.True(t, configured)
+	assert.Nil(t, condition)
 	assert.Nil(t, err)
 
-	configured, err = trait.Configure(environment)
+	configured, condition, err = trait.Configure(environment)
 
 	assert.True(t, configured)
+	assert.Nil(t, condition)
 	assert.Nil(t, err)
 }
 
@@ -203,8 +205,9 @@ func testPodTemplateSpec(t *testing.T, template string) corev1.PodTemplateSpec {
 
 	trait, environment, _ := createPodTest(template)
 
-	_, err := trait.Configure(environment)
+	_, condition, err := trait.Configure(environment)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 
 	err = trait.Apply(environment)
 	assert.Nil(t, err)
diff --git a/pkg/trait/prometheus.go b/pkg/trait/prometheus.go
index 620b32293..e0870a041 100644
--- a/pkg/trait/prometheus.go
+++ b/pkg/trait/prometheus.go
@@ -45,12 +45,12 @@ func newPrometheusTrait() Trait {
 	}
 }
 
-func (t *prometheusTrait) Configure(e *Environment) (bool, error) {
+func (t *prometheusTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *prometheusTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/prometheus_test.go b/pkg/trait/prometheus_test.go
index 8fe005233..71c097f3f 100644
--- a/pkg/trait/prometheus_test.go
+++ b/pkg/trait/prometheus_test.go
@@ -36,20 +36,22 @@ import (
 func TestConfigurePrometheusTraitInRightPhaseDoesSucceed(t *testing.T) {
 	trait, environment := createNominalPrometheusTest()
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 
 	assert.Nil(t, err)
 	assert.True(t, configured)
+	assert.Nil(t, condition)
 }
 
 func TestConfigurePrometheusTraitInWrongPhaseDoesNotSucceed(t *testing.T) {
 	trait, environment := createNominalPrometheusTest()
 	environment.Integration.Status.Phase = v1.IntegrationPhaseBuildingKit
 
-	configured, err := trait.Configure(environment)
+	configured, condition, err := trait.Configure(environment)
 
 	assert.Nil(t, err)
 	assert.False(t, configured)
+	assert.Nil(t, condition)
 }
 
 func TestApplyNominalPrometheusTraitDoesSucceed(t *testing.T) {
diff --git a/pkg/trait/pull_secret.go b/pkg/trait/pull_secret.go
index 640d9a341..829a7920f 100644
--- a/pkg/trait/pull_secret.go
+++ b/pkg/trait/pull_secret.go
@@ -44,13 +44,15 @@ func newPullSecretTrait() Trait {
 	}
 }
 
-func (t *pullSecretTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+func (t *pullSecretTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
-
 	if !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if pointer.BoolDeref(t.Auto, true) {
@@ -60,7 +62,7 @@ func (t *pullSecretTrait) Configure(e *Environment) (bool, error) {
 				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
+					return false, nil, err
 				}
 				if obj.Type == corev1.SecretTypeDockerConfigJson {
 					t.SecretName = secret
@@ -73,7 +75,7 @@ func (t *pullSecretTrait) Configure(e *Environment) (bool, error) {
 				var err error
 				isOpenShift, err = openshift.IsOpenShift(t.Client)
 				if err != nil {
-					return false, err
+					return false, nil, err
 				}
 			}
 			isOperatorGlobal := platform.IsCurrentOperatorGlobal()
@@ -83,7 +85,7 @@ func (t *pullSecretTrait) Configure(e *Environment) (bool, error) {
 		}
 	}
 
-	return t.SecretName != "" || pointer.BoolDeref(t.ImagePullerDelegation, false), nil
+	return t.SecretName != "" || pointer.BoolDeref(t.ImagePullerDelegation, false), nil, nil
 }
 
 func (t *pullSecretTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/pull_secret_test.go b/pkg/trait/pull_secret_test.go
index 4eddbbccb..ded0281d5 100644
--- a/pkg/trait/pull_secret_test.go
+++ b/pkg/trait/pull_secret_test.go
@@ -40,9 +40,10 @@ func TestPullSecret(t *testing.T) {
 
 	trait, _ := newPullSecretTrait().(*pullSecretTrait)
 	trait.SecretName = "xxxy"
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 
 	err = trait.Apply(e)
 	assert.Nil(t, err)
@@ -54,9 +55,10 @@ func TestPullSecretDoesNothingWhenNotSetOnPlatform(t *testing.T) {
 	e.Platform = &v1.IntegrationPlatform{}
 
 	trait := newPullSecretTrait()
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 }
 
 func TestPullSecretAuto(t *testing.T) {
@@ -64,9 +66,10 @@ func TestPullSecretAuto(t *testing.T) {
 
 	trait, _ := newPullSecretTrait().(*pullSecretTrait)
 	trait.Auto = pointer.Bool(false)
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
 	assert.False(t, enabled)
+	assert.Nil(t, condition)
 }
 
 func TestPullSecretImagePullerDelegation(t *testing.T) {
@@ -75,9 +78,10 @@ func TestPullSecretImagePullerDelegation(t *testing.T) {
 	trait, _ := newPullSecretTrait().(*pullSecretTrait)
 	trait.Auto = pointer.Bool(false)
 	trait.ImagePullerDelegation = pointer.Bool(true)
-	enabled, err := trait.Configure(e)
+	enabled, condition, err := trait.Configure(e)
 	assert.Nil(t, err)
 	assert.True(t, enabled)
+	assert.Nil(t, condition)
 	assert.True(t, *trait.ImagePullerDelegation)
 
 	err = trait.Apply(e)
diff --git a/pkg/trait/quarkus.go b/pkg/trait/quarkus.go
index fbe0618e1..3127c679f 100644
--- a/pkg/trait/quarkus.go
+++ b/pkg/trait/quarkus.go
@@ -140,18 +140,19 @@ func (t *quarkusTrait) Matches(trait Trait) bool {
 	return true
 }
 
-func (t *quarkusTrait) Configure(e *Environment) (bool, error) {
-	t.adaptDeprecatedFields()
+func (t *quarkusTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	condition := t.adaptDeprecatedFields()
 
 	return e.IntegrationInPhase(v1.IntegrationPhaseBuildingKit) ||
 			e.IntegrationKitInPhase(v1.IntegrationKitPhaseBuildSubmitted) ||
 			e.IntegrationKitInPhase(v1.IntegrationKitPhaseReady) && e.IntegrationInRunningPhases(),
-		nil
+		condition, nil
 }
 
-func (t *quarkusTrait) adaptDeprecatedFields() {
+func (t *quarkusTrait) adaptDeprecatedFields() *TraitCondition {
 	if t.PackageTypes != nil {
-		t.L.Info("The package-type parameter is deprecated and may be removed in future releases. Make sure to use mode parameter instead.")
+		message := "The package-type parameter is deprecated and may be removed in future releases. Make sure to use mode parameter instead."
+		t.L.Info(message)
 		for _, pt := range t.PackageTypes {
 			if pt == traitv1.NativePackageType {
 				t.Modes = append(t.Modes, traitv1.NativeQuarkusMode)
@@ -161,7 +162,10 @@ func (t *quarkusTrait) adaptDeprecatedFields() {
 				t.Modes = append(t.Modes, traitv1.JvmQuarkusMode)
 			}
 		}
+		return NewIntegrationCondition(v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationMessage, message)
 	}
+
+	return nil
 }
 
 func (t *quarkusTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/quarkus_test.go b/pkg/trait/quarkus_test.go
index e4a48d791..4b9312c0b 100644
--- a/pkg/trait/quarkus_test.go
+++ b/pkg/trait/quarkus_test.go
@@ -32,10 +32,11 @@ func TestConfigureQuarkusTraitBuildSubmitted(t *testing.T) {
 	quarkusTrait, environment := createNominalQuarkusTest()
 	environment.IntegrationKit.Status.Phase = v1.IntegrationKitPhaseBuildSubmitted
 
-	configured, err := quarkusTrait.Configure(environment)
+	configured, condition, err := quarkusTrait.Configure(environment)
 
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 
 	err = quarkusTrait.Apply(environment)
 	assert.Nil(t, err)
@@ -53,9 +54,10 @@ func TestApplyQuarkusTraitDefaultKitLayout(t *testing.T) {
 	quarkusTrait, environment := createNominalQuarkusTest()
 	environment.Integration.Status.Phase = v1.IntegrationPhaseBuildingKit
 
-	configured, err := quarkusTrait.Configure(environment)
+	configured, condition, err := quarkusTrait.Configure(environment)
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 
 	err = quarkusTrait.Apply(environment)
 	assert.Nil(t, err)
@@ -69,9 +71,10 @@ func TestApplyQuarkusTraitAnnotationKitConfiguration(t *testing.T) {
 
 	v1.SetAnnotation(&environment.Integration.ObjectMeta, v1.TraitAnnotationPrefix+"quarkus.foo", "camel-k")
 
-	configured, err := quarkusTrait.Configure(environment)
+	configured, condition, err := quarkusTrait.Configure(environment)
 	assert.True(t, configured)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 
 	err = quarkusTrait.Apply(environment)
 	assert.Nil(t, err)
diff --git a/pkg/trait/registry.go b/pkg/trait/registry.go
index 27aed1355..daa1bb8ff 100644
--- a/pkg/trait/registry.go
+++ b/pkg/trait/registry.go
@@ -58,13 +58,13 @@ func (t *registryTrait) InfluencesBuild(this, prev map[string]interface{}) bool
 	return true
 }
 
-func (t *registryTrait) Configure(e *Environment) (bool, error) {
+func (t *registryTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	// disabled by default
 	if e.IntegrationKit == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return e.IntegrationKitInPhase(v1.IntegrationKitPhaseBuildSubmitted), nil
+	return e.IntegrationKitInPhase(v1.IntegrationKitPhaseBuildSubmitted), nil, nil
 }
 
 func (t *registryTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/route.go b/pkg/trait/route.go
index 165e345b6..101f5c326 100644
--- a/pkg/trait/route.go
+++ b/pkg/trait/route.go
@@ -54,39 +54,28 @@ func (t *routeTrait) IsAllowedInProfile(profile v1.TraitProfile) bool {
 	return profile.Equal(v1.TraitProfileOpenShift)
 }
 
-func (t *routeTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		if e.Integration != nil {
-			e.Integration.Status.SetCondition(
-				v1.IntegrationConditionExposureAvailable,
-				corev1.ConditionFalse,
-				v1.IntegrationConditionRouteNotAvailableReason,
-				"explicitly disabled",
-			)
-		}
-
-		return false, nil
+func (t *routeTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationCondition(
+			v1.IntegrationConditionExposureAvailable,
+			corev1.ConditionFalse,
+			v1.IntegrationConditionRouteNotAvailableReason,
+			"explicitly disabled",
+		), nil
 	}
-
 	if !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	t.service = e.Resources.GetUserServiceForIntegration(e.Integration)
 	if t.service == nil {
-		if e.Integration != nil {
-			e.Integration.Status.SetCondition(
-				v1.IntegrationConditionExposureAvailable,
-				corev1.ConditionFalse,
-				v1.IntegrationConditionRouteNotAvailableReason,
-				"no target service found",
-			)
-		}
-
-		return false, nil
+		return false, nil, nil
 	}
 
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *routeTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/route_test.go b/pkg/trait/route_test.go
index ae8d335a9..a4ecdc2dd 100644
--- a/pkg/trait/route_test.go
+++ b/pkg/trait/route_test.go
@@ -205,9 +205,9 @@ func TestRoute_Default(t *testing.T) {
 	environment := createTestRouteEnvironment(t, name)
 	traitsCatalog := environment.Catalog
 
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("container"))
 	assert.NotNil(t, environment.GetTrait("route"))
@@ -233,10 +233,17 @@ func TestRoute_Disabled(t *testing.T) {
 		},
 	}
 
+	expectedCondition := NewIntegrationCondition(
+		v1.IntegrationConditionExposureAvailable,
+		corev1.ConditionFalse,
+		"route trait configuration",
+		"explicitly disabled",
+	)
 	traitsCatalog := environment.Catalog
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
 	assert.Nil(t, err)
+	assert.Len(t, conditions, 1)
+	assert.Contains(t, conditions, expectedCondition)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.Nil(t, environment.GetTrait("route"))
 
@@ -256,9 +263,10 @@ func TestRoute_Configure_IntegrationKitOnly(t *testing.T) {
 	enabled := false
 	routeTrait.Enabled = &enabled
 
-	result, err := routeTrait.Configure(environment)
+	result, condition, err := routeTrait.Configure(environment)
 	assert.False(t, result)
 	assert.Nil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestRoute_Host(t *testing.T) {
@@ -272,9 +280,10 @@ func TestRoute_Host(t *testing.T) {
 		},
 	}
 
-	err := traitsCatalog.apply(environment)
+	conditions, err := traitsCatalog.apply(environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("route"))
 
@@ -302,9 +311,10 @@ func TestRoute_TLS_From_Secret_reencrypt(t *testing.T) {
 			TLSDestinationCACertificateSecret: tlsMultipleSecretsName + "/" + tlsMultipleSecretsCert3Key,
 		},
 	}
-	err := traitsCatalog.apply(environment)
+	conditions, err := traitsCatalog.apply(environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("route"))
 
@@ -337,8 +347,8 @@ func TestRoute_TLS_wrong_secret(t *testing.T) {
 			TLSDestinationCACertificateSecret: "404",
 		},
 	}
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
+	assert.Empty(t, conditions)
 	// there must be errors as the trait has wrong configuration
 	assert.NotNil(t, err)
 	assert.Nil(t, environment.GetTrait("route"))
@@ -365,8 +375,8 @@ func TestRoute_TLS_secret_wrong_key(t *testing.T) {
 			TLSCACertificateSecret: tlsMultipleSecretsName + "/foo",
 		},
 	}
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
+	assert.Empty(t, conditions)
 	// there must be errors as the trait has wrong configuration
 	assert.NotNil(t, err)
 	assert.Nil(t, environment.GetTrait("route"))
@@ -393,8 +403,8 @@ func TestRoute_TLS_secret_missing_key(t *testing.T) {
 			TLSCACertificateSecret: tlsMultipleSecretsName,
 		},
 	}
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
+	assert.Empty(t, conditions)
 	// there must be errors as the trait has wrong configuration
 	assert.NotNil(t, err)
 	assert.Nil(t, environment.GetTrait("route"))
@@ -422,9 +432,9 @@ func TestRoute_TLS_reencrypt(t *testing.T) {
 			TLSDestinationCACertificate: destinationCaCert,
 		},
 	}
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("route"))
 
@@ -456,9 +466,9 @@ func TestRoute_TLS_edge(t *testing.T) {
 			TLSCACertificate: caCert,
 		},
 	}
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("route"))
 
@@ -488,9 +498,9 @@ func TestRoute_TLS_passthrough(t *testing.T) {
 			TLSInsecureEdgeTerminationPolicy: string(routev1.InsecureEdgeTerminationPolicyAllow),
 		},
 	}
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("route"))
 
@@ -518,9 +528,9 @@ func TestRoute_WithCustomServicePort(t *testing.T) {
 	}
 
 	traitsCatalog := environment.Catalog
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("container"))
 	assert.NotNil(t, environment.GetTrait("route"))
@@ -552,9 +562,9 @@ func TestRouteAnnotation(t *testing.T) {
 	}
 
 	traitsCatalog := environment.Catalog
-	err := traitsCatalog.apply(environment)
-
+	conditions, err := traitsCatalog.apply(environment)
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 
 	route := environment.Resources.GetRoute(func(r *routev1.Route) bool {
 		return r.ObjectMeta.Name == name
diff --git a/pkg/trait/service.go b/pkg/trait/service.go
index 2ae926a78..8f431f036 100644
--- a/pkg/trait/service.go
+++ b/pkg/trait/service.go
@@ -43,18 +43,17 @@ func newServiceTrait() Trait {
 	}
 }
 
-func (t *serviceTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		if e.Integration != nil {
-			e.Integration.Status.SetCondition(
-				v1.IntegrationConditionServiceAvailable,
-				corev1.ConditionFalse,
-				v1.IntegrationConditionServiceNotAvailableReason,
-				"explicitly disabled",
-			)
-		}
-
-		return false, nil
+func (t *serviceTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationCondition(
+			v1.IntegrationConditionServiceAvailable,
+			corev1.ConditionFalse,
+			v1.IntegrationConditionServiceNotAvailableReason,
+			"explicitly disabled",
+		), nil
 	}
 
 	// in case the knative-service and service trait are enabled, the knative-service has priority
@@ -62,43 +61,36 @@ func (t *serviceTrait) Configure(e *Environment) (bool, error) {
 	if e.GetTrait(knativeServiceTraitID) != nil {
 		knativeServiceTrait, _ := e.GetTrait(knativeServiceTraitID).(*knativeServiceTrait)
 		if pointer.BoolDeref(knativeServiceTrait.Enabled, true) {
-			return false, nil
+			return false, newIntegrationConditionPlatformDisabledWithReason("knative-service trait has priority over this trait"), nil
 		}
 	}
 
 	if !e.IntegrationInRunningPhases() {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if pointer.BoolDeref(t.Auto, true) {
 		sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, t.Client, e.Integration, e.Resources)
+		var condition *TraitCondition
 		if err != nil {
-			e.Integration.Status.SetCondition(
+			condition = NewIntegrationCondition(
 				v1.IntegrationConditionServiceAvailable,
 				corev1.ConditionFalse,
 				v1.IntegrationConditionServiceNotAvailableReason,
 				err.Error(),
 			)
-
-			return false, err
+			return false, condition, err
 		}
 
 		meta, err := metadata.ExtractAll(e.CamelCatalog, sources)
 		if err != nil {
-			return false, err
+			return false, nil, err
 		}
 		if !meta.ExposesHTTPServices {
-			e.Integration.Status.SetCondition(
-				v1.IntegrationConditionServiceAvailable,
-				corev1.ConditionFalse,
-				v1.IntegrationConditionServiceNotAvailableReason,
-				"no http service required",
-			)
-
-			return false, nil
+			return false, nil, nil
 		}
 	}
-	return true, nil
+	return true, nil, nil
 }
 
 func (t *serviceTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/service_binding.go b/pkg/trait/service_binding.go
index f58685166..dabea7481 100644
--- a/pkg/trait/service_binding.go
+++ b/pkg/trait/service_binding.go
@@ -48,16 +48,18 @@ func newServiceBindingTrait() Trait {
 	}
 }
 
-func (t *serviceBindingTrait) Configure(e *Environment) (bool, error) {
-	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
-		return false, nil
+func (t *serviceBindingTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
+	if e.Integration == nil {
+		return false, nil, nil
+	}
+	if !pointer.BoolDeref(t.Enabled, true) {
+		return false, NewIntegrationConditionUserDisabled(), nil
 	}
-
 	if len(t.Services) == 0 {
-		return false, nil
+		return false, nil, nil
 	}
 
-	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInPhase(v1.IntegrationPhaseInitialization) || e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *serviceBindingTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/service_test.go b/pkg/trait/service_test.go
index a1aefa779..cbb856856 100644
--- a/pkg/trait/service_test.go
+++ b/pkg/trait/service_test.go
@@ -108,9 +108,10 @@ func TestServiceWithDefaults(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("deployment"))
 	assert.NotNil(t, environment.GetTrait("service"))
@@ -215,9 +216,10 @@ func TestService(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("deployment"))
 	assert.NotNil(t, environment.GetTrait("service"))
@@ -302,9 +304,10 @@ func TestServiceWithCustomContainerName(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("deployment"))
 	assert.NotNil(t, environment.GetTrait("service"))
@@ -393,9 +396,10 @@ func TestServiceWithNodePort(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Empty(t, conditions)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait("deployment"))
 	assert.NotNil(t, environment.GetTrait("service"))
@@ -487,9 +491,24 @@ func TestServiceWithKnativeServiceEnabled(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	deploymentCondition := NewIntegrationCondition(
+		v1.IntegrationConditionDeploymentAvailable,
+		corev1.ConditionFalse,
+		"deployment trait configuration",
+		"controller strategy: knative-service",
+	)
+	serviceCondition := NewIntegrationCondition(
+		v1.IntegrationConditionTraitInfo,
+		corev1.ConditionTrue,
+		"service trait configuration",
+		"explicitly disabled by the platform: knative-service trait has priority over this trait",
+	)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Len(t, conditions, 2)
+	assert.Contains(t, conditions, deploymentCondition)
+	assert.Contains(t, conditions, serviceCondition)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.Nil(t, environment.GetTrait(serviceTraitID))
 	assert.NotNil(t, environment.GetTrait(knativeServiceTraitID))
@@ -550,9 +569,24 @@ func TestServicesWithKnativeProfile(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	deploymentCondition := NewIntegrationCondition(
+		v1.IntegrationConditionDeploymentAvailable,
+		corev1.ConditionFalse,
+		"deployment trait configuration",
+		"controller strategy: knative-service",
+	)
+	serviceCondition := NewIntegrationCondition(
+		v1.IntegrationConditionTraitInfo,
+		corev1.ConditionTrue,
+		"service trait configuration",
+		"explicitly disabled by the platform: knative-service trait has priority over this trait",
+	)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Len(t, conditions, 2)
+	assert.Contains(t, conditions, deploymentCondition)
+	assert.Contains(t, conditions, serviceCondition)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.Nil(t, environment.GetTrait(serviceTraitID))
 	assert.NotNil(t, environment.GetTrait(knativeServiceTraitID))
@@ -621,9 +655,17 @@ func TestServiceWithKnativeServiceDisabledInIntegrationPlatform(t *testing.T) {
 	}
 	environment.Platform.ResyncStatusFullConfig()
 
-	err = traitCatalog.apply(&environment)
+	expectedCondition := NewIntegrationCondition(
+		v1.IntegrationConditionKnativeServiceAvailable,
+		corev1.ConditionFalse,
+		"knative-service trait configuration",
+		"explicitly disabled",
+	)
+	conditions, err := traitCatalog.apply(&environment)
 
 	assert.Nil(t, err)
+	assert.Len(t, conditions, 1)
+	assert.Contains(t, conditions, expectedCondition)
 	assert.NotEmpty(t, environment.ExecutedTraits)
 	assert.NotNil(t, environment.GetTrait(serviceTraitID))
 	assert.Nil(t, environment.GetTrait(knativeServiceTraitID))
diff --git a/pkg/trait/toleration.go b/pkg/trait/toleration.go
index 73303a293..8d58e75ef 100644
--- a/pkg/trait/toleration.go
+++ b/pkg/trait/toleration.go
@@ -38,16 +38,16 @@ func newTolerationTrait() Trait {
 	}
 }
 
-func (t *tolerationTrait) Configure(e *Environment) (bool, error) {
+func (t *tolerationTrait) Configure(e *Environment) (bool, *TraitCondition, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, false) {
-		return false, nil
+		return false, nil, nil
 	}
 
 	if len(t.Taints) == 0 {
-		return false, fmt.Errorf("no taint was provided")
+		return false, nil, fmt.Errorf("no taint was provided")
 	}
 
-	return e.IntegrationInRunningPhases(), nil
+	return e.IntegrationInRunningPhases(), nil, nil
 }
 
 func (t *tolerationTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/toleration_test.go b/pkg/trait/toleration_test.go
index 6b0cd6695..48b472113 100644
--- a/pkg/trait/toleration_test.go
+++ b/pkg/trait/toleration_test.go
@@ -30,10 +30,11 @@ func TestConfigureTolerationTraitMissingTaint(t *testing.T) {
 	environment, _ := createNominalDeploymentTraitTest()
 	tolerationTrait := createNominalTolerationTrait()
 
-	success, err := tolerationTrait.Configure(environment)
+	success, condition, err := tolerationTrait.Configure(environment)
 
 	assert.Equal(t, false, success)
 	assert.NotNil(t, err)
+	assert.Nil(t, condition)
 }
 
 func TestApplyTolerationTraitMalformedTaint(t *testing.T) {
diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go
index ec4a9ca3c..33676616f 100644
--- a/pkg/trait/trait.go
+++ b/pkg/trait/trait.go
@@ -55,7 +55,20 @@ func Apply(ctx context.Context, c client.Client, integration *v1.Integration, ki
 	environment.Catalog = catalog
 
 	// invoke the trait framework to determine the needed resources
-	if err := catalog.apply(environment); err != nil {
+	conditions, err := catalog.apply(environment)
+	// Conditions contains informative message coming from the trait execution and useful to be reported into it or ik CR
+	// they must be applied before returning after an error
+	for _, tc := range conditions {
+		switch {
+		case integration != nil:
+			// set an Integration condition
+			integration.Status.SetCondition(tc.integrationCondition())
+		case kit != nil:
+			// set an IntegrationKit condition
+			kit.Status.SetCondition(tc.integrationKitCondition())
+		}
+	}
+	if err != nil {
 		return nil, fmt.Errorf("error during trait customization: %w", err)
 	}
 
diff --git a/pkg/trait/trait_catalog.go b/pkg/trait/trait_catalog.go
index 025a9cc98..dc1160709 100644
--- a/pkg/trait/trait_catalog.go
+++ b/pkg/trait/trait_catalog.go
@@ -85,9 +85,10 @@ func (c *Catalog) TraitsForProfile(profile v1.TraitProfile) []Trait {
 	return res
 }
 
-func (c *Catalog) apply(environment *Environment) error {
+func (c *Catalog) apply(environment *Environment) ([]*TraitCondition, error) {
+	traitsConditions := []*TraitCondition{}
 	if err := c.Configure(environment); err != nil {
-		return err
+		return traitsConditions, err
 	}
 	traits := c.traitsFor(environment)
 	environment.ConfiguredTraits = traits
@@ -100,15 +101,19 @@ func (c *Catalog) apply(environment *Environment) error {
 			continue
 		}
 		applicable = true
-		enabled, err := trait.Configure(environment)
+		enabled, condition, err := trait.Configure(environment)
+		if condition != nil {
+			condition.message = fmt.Sprintf("%s trait configuration", trait.ID())
+			traitsConditions = append(traitsConditions, condition)
+		}
 		if err != nil {
-			return fmt.Errorf("%s trait configuration failed: %w", trait.ID(), err)
+			return traitsConditions, fmt.Errorf("%s trait configuration failed: %w", trait.ID(), err)
 		}
 
 		if enabled {
 			err = trait.Apply(environment)
 			if err != nil {
-				return fmt.Errorf("%s trait execution failed: %w", trait.ID(), err)
+				return traitsConditions, fmt.Errorf("%s trait execution failed: %w", trait.ID(), err)
 			}
 
 			environment.ExecutedTraits = append(environment.ExecutedTraits, trait)
@@ -117,7 +122,7 @@ func (c *Catalog) apply(environment *Environment) error {
 			for _, processor := range environment.PostStepProcessors {
 				err := processor(environment)
 				if err != nil {
-					return fmt.Errorf("%s trait executing post step action failed: %w", trait.ID(), err)
+					return traitsConditions, fmt.Errorf("%s trait executing post step action failed: %w", trait.ID(), err)
 				}
 			}
 		}
@@ -130,17 +135,17 @@ func (c *Catalog) apply(environment *Environment) error {
 	c.L.Debugf("Applied traits: %s", strings.Join(traitIds, ","))
 
 	if !applicable && environment.PlatformInPhase(v1.IntegrationPlatformPhaseReady) {
-		return errors.New("no trait can be executed because of no ready platform found")
+		return traitsConditions, errors.New("no trait can be executed because of no ready platform found")
 	}
 
 	for _, processor := range environment.PostProcessors {
 		err := processor(environment)
 		if err != nil {
-			return fmt.Errorf("error executing post processor: %w", err)
+			return traitsConditions, fmt.Errorf("error executing post processor: %w", err)
 		}
 	}
 
-	return nil
+	return traitsConditions, nil
 }
 
 // GetTrait returns the trait with the given ID.
diff --git a/pkg/trait/trait_condition_types.go b/pkg/trait/trait_condition_types.go
new file mode 100644
index 000000000..9b35647c9
--- /dev/null
+++ b/pkg/trait/trait_condition_types.go
@@ -0,0 +1,80 @@
+/*
+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 (
+	"fmt"
+
+	corev1 "k8s.io/api/core/v1"
+
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+)
+
+const (
+	traitConfigurationMessage = "Trait configuration"
+	userDisabledMessage       = "explicitly disabled by the user"
+	platformDisabledMessage   = "explicitly disabled by the platform"
+)
+
+// TraitCondition is used to get all information/warning about a trait configuration.
+// It should either use an IntegrationConditionType or IntegrationKitConditionType.
+type TraitCondition struct {
+	integrationConditionType    v1.IntegrationConditionType
+	integrationKitConditionType v1.IntegrationKitConditionType
+	conditionStatus             corev1.ConditionStatus
+	message                     string
+	reason                      string
+}
+
+func NewIntegrationCondition(ict v1.IntegrationConditionType, cs corev1.ConditionStatus, message, reason string) *TraitCondition {
+	return &TraitCondition{
+		integrationConditionType: ict,
+		conditionStatus:          cs,
+		message:                  message,
+		reason:                   reason,
+	}
+}
+
+func NewIntegrationConditionUserDisabled() *TraitCondition {
+	return NewIntegrationCondition(v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationMessage, userDisabledMessage)
+}
+
+func newIntegrationConditionPlatformDisabled() *TraitCondition {
+	return NewIntegrationCondition(v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationMessage, platformDisabledMessage)
+}
+
+func newIntegrationConditionPlatformDisabledWithReason(reason string) *TraitCondition {
+	return NewIntegrationCondition(v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationMessage, fmt.Sprintf("%s: %s", platformDisabledMessage, reason))
+}
+
+func newIntegrationKitCondition(ikct v1.IntegrationKitConditionType, cs corev1.ConditionStatus, message, reason string) *TraitCondition {
+	return &TraitCondition{
+		integrationKitConditionType: ikct,
+		conditionStatus:             cs,
+		message:                     message,
+		reason:                      reason,
+	}
+}
+
+func (tc *TraitCondition) integrationCondition() (v1.IntegrationConditionType, corev1.ConditionStatus, string, string) {
+	return tc.integrationConditionType, tc.conditionStatus, tc.message, tc.reason
+}
+
+func (tc *TraitCondition) integrationKitCondition() (v1.IntegrationKitConditionType, corev1.ConditionStatus, string, string) {
+	return tc.integrationKitConditionType, tc.conditionStatus, tc.message, tc.reason
+}
diff --git a/pkg/trait/trait_test.go b/pkg/trait/trait_test.go
index edefb8586..1acb07f5a 100644
--- a/pkg/trait/trait_test.go
+++ b/pkg/trait/trait_test.go
@@ -485,7 +485,7 @@ func processTestEnv(t *testing.T, env *Environment) *kubernetes.Collection {
 	t.Helper()
 
 	catalog := NewTraitTestCatalog()
-	err := catalog.apply(env)
+	_, err := catalog.apply(env)
 	assert.Nil(t, err)
 	return env.Resources
 }
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index 9471ddb66..9d838a688 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -61,7 +61,7 @@ type Trait interface {
 	client.Injectable
 
 	// Configure the trait
-	Configure(environment *Environment) (bool, error)
+	Configure(environment *Environment) (bool, *TraitCondition, error)
 
 	// Apply executes a customization of the Environment
 	Apply(environment *Environment) error
diff --git a/pkg/trait/util.go b/pkg/trait/util.go
index e047576eb..59445247c 100644
--- a/pkg/trait/util.go
+++ b/pkg/trait/util.go
@@ -47,13 +47,6 @@ func ptrFrom[T any](value T) *T {
 	return &value
 }
 
-func ptrDerefOr[T any](value *T, def T) T {
-	if value != nil {
-		return *value
-	}
-	return def
-}
-
 type Options map[string]map[string]interface{}
 
 func (u Options) Get(id string) (map[string]interface{}, bool) {