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 ca5239b57c6e450b527204163d6cea33da297f3e
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Fri Jun 14 12:21:23 2024 +0200

    chore(ctrl): deprecate annotations trait
    
    The previous development was flawed, as it did not do the proper comparison 
with the configuration coming from annotation to the configuration coming from 
trait spec.
    This commit is supporting the comparison in a proper manner, however, we're 
deprecating the feature from other resources which are not Pipe as it does not 
make sense to support.
    
    Ref #5620
---
 addons/addons_test.go                              |  36 -----
 e2e/common/misc/pipe_with_image_test.go            |  10 +-
 pkg/controller/integration/build_kit.go            |   2 +-
 .../integration/integration_controller.go          |   6 +-
 pkg/controller/integration/kits.go                 |  10 +-
 pkg/controller/integration/kits_test.go            |  17 +-
 pkg/controller/integration/monitor.go              |  24 +++
 pkg/controller/integrationkit/monitor.go           |  26 +++
 pkg/controller/integrationplatform/monitor.go      |  23 +++
 .../kameletbinding/kameletbinding_controller.go    |  12 +-
 pkg/controller/kameletbinding/monitor.go           |   2 +-
 pkg/controller/pipe/integration.go                 |  52 +-----
 pkg/controller/pipe/monitor.go                     |   2 +-
 pkg/controller/pipe/monitor_test.go                |  48 ++++++
 pkg/controller/pipe/pipe_controller.go             |  12 +-
 pkg/trait/quarkus.go                               |   6 -
 pkg/trait/quarkus_test.go                          |  19 ---
 pkg/trait/trait_configure.go                       |   6 +
 pkg/trait/util.go                                  | 174 ++++++++++++---------
 pkg/trait/util_test.go                             |  67 +++-----
 pkg/util/digest/digest.go                          |   1 +
 21 files changed, 295 insertions(+), 260 deletions(-)

diff --git a/addons/addons_test.go b/addons/addons_test.go
index 600b80c52..3adda05d2 100644
--- a/addons/addons_test.go
+++ b/addons/addons_test.go
@@ -20,8 +20,6 @@ package addons
 import (
        "testing"
 
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
        "github.com/apache/camel-k/v2/addons/master"
        "github.com/apache/camel-k/v2/addons/telemetry"
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -68,37 +66,3 @@ func TestTraitConfiguration(t *testing.T) {
        require.True(t, ok)
        assert.True(t, *telemetry.Enabled)
 }
-
-func TestTraitConfigurationFromAnnotations(t *testing.T) {
-       env := trait.Environment{
-               Integration: &v1.Integration{
-                       ObjectMeta: metav1.ObjectMeta{
-                               Annotations: map[string]string{
-                                       
"trait.camel.apache.org/master.enabled":       "true",
-                                       
"trait.camel.apache.org/master.resource-name": "test-lock",
-                                       
"trait.camel.apache.org/master.label-key":     "test-label",
-                                       
"trait.camel.apache.org/master.label-value":   "test-value",
-                                       
"trait.camel.apache.org/telemetry.enabled":    "true",
-                               },
-                       },
-                       Spec: v1.IntegrationSpec{
-                               Profile: v1.TraitProfileKubernetes,
-                       },
-               },
-       }
-       c := trait.NewCatalog(nil)
-       require.NoError(t, c.Configure(&env))
-
-       require.NotNil(t, c.GetTrait("master"))
-       master, ok := c.GetTrait("master").(*master.TestMasterTrait)
-       require.True(t, ok)
-       assert.True(t, *master.Enabled)
-       assert.Equal(t, "test-lock", *master.ResourceName)
-       assert.Equal(t, "test-label", *master.LabelKey)
-       assert.Equal(t, "test-value", *master.LabelValue)
-
-       require.NotNil(t, c.GetTrait("telemetry"))
-       telemetry, ok := c.GetTrait("telemetry").(*telemetry.TestTelemetryTrait)
-       require.True(t, ok)
-       assert.True(t, *telemetry.Enabled)
-}
diff --git a/e2e/common/misc/pipe_with_image_test.go 
b/e2e/common/misc/pipe_with_image_test.go
index 0cb9b53b8..ff68b9b06 100644
--- a/e2e/common/misc/pipe_with_image_test.go
+++ b/e2e/common/misc/pipe_with_image_test.go
@@ -55,10 +55,9 @@ func TestPipeWithImage(t *testing.T) {
 
                        g.Eventually(IntegrationGeneration(t, ctx, ns, 
bindingID)).
                                Should(gstruct.PointTo(BeNumerically("==", 1)))
-                       g.Eventually(Integration(t, ctx, ns, 
bindingID)).Should(WithTransform(Annotations, And(
+                       g.Eventually(Integration(t, ctx, ns, 
bindingID)).Should(WithTransform(Annotations,
                                HaveKeyWithValue("test", "1"),
-                               
HaveKeyWithValue("trait.camel.apache.org/container.image", expectedImage),
-                       )))
+                       ))
                        g.Eventually(IntegrationStatusImage(t, ctx, ns, 
bindingID)).
                                Should(Equal(expectedImage))
                        g.Eventually(IntegrationPodPhase(t, ctx, ns, 
bindingID), TestTimeoutShort).
@@ -73,10 +72,9 @@ func TestPipeWithImage(t *testing.T) {
                        g.Expect(KamelBindWithID(t, ctx, operatorID, ns, 
"my-own-timer-source", "my-own-log-sink", "--annotation", 
"trait.camel.apache.org/container.image="+expectedImage, "--annotation", 
"trait.camel.apache.org/jvm.enabled=false", "--annotation", 
"trait.camel.apache.org/kamelets.enabled=false", "--annotation", 
"trait.camel.apache.org/dependencies.enabled=false", "--annotation", "test=2", 
"--name", bindingID).Execute()).To(Succeed())
                        g.Eventually(IntegrationGeneration(t, ctx, ns, 
bindingID)).
                                Should(gstruct.PointTo(BeNumerically("==", 1)))
-                       g.Eventually(Integration(t, ctx, ns, 
bindingID)).Should(WithTransform(Annotations, And(
+                       g.Eventually(Integration(t, ctx, ns, 
bindingID)).Should(WithTransform(Annotations,
                                HaveKeyWithValue("test", "2"),
-                               
HaveKeyWithValue("trait.camel.apache.org/container.image", expectedImage),
-                       )))
+                       ))
                        g.Eventually(IntegrationStatusImage(t, ctx, ns, 
bindingID)).
                                Should(Equal(expectedImage))
                        g.Eventually(IntegrationPodPhase(t, ctx, ns, 
bindingID), TestTimeoutShort).
diff --git a/pkg/controller/integration/build_kit.go 
b/pkg/controller/integration/build_kit.go
index acbc01966..af2d164ae 100644
--- a/pkg/controller/integration/build_kit.go
+++ b/pkg/controller/integration/build_kit.go
@@ -99,7 +99,7 @@ kits:
                        k := &existingKits[i]
 
                        action.L.Debug("Comparing existing kit with 
environment", "env kit", kit.Name, "existing kit", k.Name)
-                       match, err := kitMatches(&kit, k)
+                       match, err := kitMatches(action.client, &kit, k)
                        if err != nil {
                                return nil, fmt.Errorf("error occurred matches 
integration kits with environment for integration %s/%s: %w",
                                        integration.Namespace, 
integration.Name, err)
diff --git a/pkg/controller/integration/integration_controller.go 
b/pkg/controller/integration/integration_controller.go
index 4fbdc39b4..a3c895c2f 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -85,7 +85,7 @@ func newReconciler(mgr manager.Manager, c client.Client) 
reconcile.Reconciler {
        )
 }
 
-func integrationUpdateFunc(old *v1.Integration, it *v1.Integration) bool {
+func integrationUpdateFunc(c client.Client, old *v1.Integration, it 
*v1.Integration) bool {
        // Observe the time to first readiness metric
        previous := old.Status.GetCondition(v1.IntegrationConditionReady)
        next := it.Status.GetCondition(v1.IntegrationConditionReady)
@@ -99,7 +99,7 @@ func integrationUpdateFunc(old *v1.Integration, it 
*v1.Integration) bool {
        updateIntegrationPhase(it.Name, string(it.Status.Phase))
        // If traits have changed, the reconciliation loop must kick in as
        // traits may have impact
-       sameTraits, err := trait.IntegrationsHaveSameTraits(old, it)
+       sameTraits, err := trait.IntegrationsHaveSameTraits(c, old, it)
        if err != nil {
                Log.ForIntegration(it).Error(
                        err,
@@ -324,7 +324,7 @@ func add(ctx context.Context, mgr manager.Manager, c 
client.Client, r reconcile.
                                                return false
                                        }
 
-                                       return integrationUpdateFunc(old, it)
+                                       return integrationUpdateFunc(c, old, it)
                                },
                                DeleteFunc: func(e event.DeleteEvent) bool {
                                        // Evaluates to false if the object has 
been confirmed deleted
diff --git a/pkg/controller/integration/kits.go 
b/pkg/controller/integration/kits.go
index 22adf0f03..9832139fa 100644
--- a/pkg/controller/integration/kits.go
+++ b/pkg/controller/integration/kits.go
@@ -121,11 +121,11 @@ func integrationMatches(ctx context.Context, c 
client.Client, integration *v1.In
                return false, err
        }
 
-       itc, err := 
trait.NewSpecTraitsOptionsForIntegrationAndPlatform(integration, pl)
+       itc, err := trait.NewSpecTraitsOptionsForIntegrationAndPlatform(c, 
integration, pl)
        if err != nil {
                return false, err
        }
-       ikc, err := trait.NewSpecTraitsOptionsForIntegrationKit(kit)
+       ikc, err := trait.NewSpecTraitsOptionsForIntegrationKit(c, kit)
        if err != nil {
                return false, err
        }
@@ -170,7 +170,7 @@ func statusMatches(integration *v1.Integration, kit 
*v1.IntegrationKit, ilog *lo
 }
 
 // kitMatches returns whether the kit matches with the existing target kit.
-func kitMatches(kit *v1.IntegrationKit, target *v1.IntegrationKit) (bool, 
error) {
+func kitMatches(c client.Client, kit *v1.IntegrationKit, target 
*v1.IntegrationKit) (bool, error) {
        version := kit.Status.Version
        if version == "" {
                // Defaults with the version that is going to be set during the 
kit initialization
@@ -184,11 +184,11 @@ func kitMatches(kit *v1.IntegrationKit, target 
*v1.IntegrationKit) (bool, error)
        }
 
        // We cannot have yet the status set
-       c1, err := trait.NewSpecTraitsOptionsForIntegrationKit(kit)
+       c1, err := trait.NewSpecTraitsOptionsForIntegrationKit(c, kit)
        if err != nil {
                return false, err
        }
-       c2, err := trait.NewSpecTraitsOptionsForIntegrationKit(target)
+       c2, err := trait.NewSpecTraitsOptionsForIntegrationKit(c, target)
        if err != nil {
                return false, err
        }
diff --git a/pkg/controller/integration/kits_test.go 
b/pkg/controller/integration/kits_test.go
index 1f946aa35..9f1085526 100644
--- a/pkg/controller/integration/kits_test.go
+++ b/pkg/controller/integration/kits_test.go
@@ -25,6 +25,7 @@ import (
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+       "github.com/apache/camel-k/v2/pkg/client"
 
        "github.com/apache/camel-k/v2/pkg/trait"
        "github.com/apache/camel-k/v2/pkg/util/test"
@@ -279,7 +280,10 @@ func TestHasMatchingTraits_KitNoTraitShouldNotBePicked(t 
*testing.T) {
                },
        }
 
-       ok, err := integrationAndKitHaveSameTraits(integration, kit)
+       c, err := test.NewFakeClient(integration, kit)
+       require.NoError(t, err)
+
+       ok, err := integrationAndKitHaveSameTraits(c, integration, kit)
        require.NoError(t, err)
        assert.False(t, ok)
 }
@@ -326,8 +330,9 @@ func TestHasMatchingTraits_KitSameTraitShouldBePicked(t 
*testing.T) {
                        },
                },
        }
-
-       ok, err := integrationAndKitHaveSameTraits(integration, kit)
+       c, err := test.NewFakeClient(integration, kit)
+       require.NoError(t, err)
+       ok, err := integrationAndKitHaveSameTraits(c, integration, kit)
        require.NoError(t, err)
        assert.True(t, ok)
 }
@@ -429,12 +434,12 @@ func TestHasNotMatchingSources(t *testing.T) {
        assert.False(t, hsm2)
 }
 
-func integrationAndKitHaveSameTraits(i1 *v1.Integration, i2 
*v1.IntegrationKit) (bool, error) {
-       itOpts, err := trait.NewSpecTraitsOptionsForIntegration(i1)
+func integrationAndKitHaveSameTraits(c client.Client, i1 *v1.Integration, i2 
*v1.IntegrationKit) (bool, error) {
+       itOpts, err := trait.NewSpecTraitsOptionsForIntegration(c, i1)
        if err != nil {
                return false, err
        }
-       ikOpts, err := trait.NewSpecTraitsOptionsForIntegrationKit(i2)
+       ikOpts, err := trait.NewSpecTraitsOptionsForIntegrationKit(c, i2)
        if err != nil {
                return false, err
        }
diff --git a/pkg/controller/integration/monitor.go 
b/pkg/controller/integration/monitor.go
index 47bb9829a..5d908cca6 100644
--- a/pkg/controller/integration/monitor.go
+++ b/pkg/controller/integration/monitor.go
@@ -23,6 +23,7 @@ import (
        "fmt"
        "reflect"
        "strconv"
+       "strings"
 
        appsv1 "k8s.io/api/apps/v1"
        batchv1 "k8s.io/api/batch/v1"
@@ -131,9 +132,32 @@ func (action *monitorAction) Handle(ctx context.Context, 
integration *v1.Integra
                return integration, err
        }
 
+       action.checkTraitAnnotationsDeprecatedNotice(integration)
+
        return action.monitorPods(ctx, environment, integration)
 }
 
+// Deprecated: to be removed in future versions, when we won't support any 
longer trait annotations into Integrations.
+func (action *monitorAction) checkTraitAnnotationsDeprecatedNotice(integration 
*v1.Integration) {
+       if integration.Annotations != nil {
+               for k := range integration.Annotations {
+                       if strings.HasPrefix(k, v1.TraitAnnotationPrefix) {
+                               integration.Status.SetCondition(
+                                       
v1.IntegrationConditionType("AnnotationTraitsDeprecated"),
+                                       corev1.ConditionTrue,
+                                       "DeprecationNotice",
+                                       "Annotation traits configuration is 
deprecated and will be removed soon. Use .spec.traits configuration instead.",
+                               )
+                               action.L.Infof(
+                                       "WARN: annotation traits configuration 
is deprecated and will be removed soon. Use .spec.traits configuration for %s 
integration instead.",
+                                       integration.Name,
+                               )
+                               return
+                       }
+               }
+       }
+}
+
 func (action *monitorAction) monitorPods(ctx context.Context, environment 
*trait.Environment, integration *v1.Integration) (*v1.Integration, error) {
        controller, err := action.newController(environment, integration)
        if err != nil {
diff --git a/pkg/controller/integrationkit/monitor.go 
b/pkg/controller/integrationkit/monitor.go
index 5b72ef153..7a71d9a76 100644
--- a/pkg/controller/integrationkit/monitor.go
+++ b/pkg/controller/integrationkit/monitor.go
@@ -19,9 +19,11 @@ package integrationkit
 
 import (
        "context"
+       "strings"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        "github.com/apache/camel-k/v2/pkg/util/digest"
+       corev1 "k8s.io/api/core/v1"
 )
 
 // NewMonitorAction creates a new monitoring handling action for the kit.
@@ -64,5 +66,29 @@ func (action *monitorAction) Handle(ctx context.Context, kit 
*v1.IntegrationKit)
                return kit, nil
        }
 
+       action.checkTraitAnnotationsDeprecatedNotice(kit)
+
        return nil, nil
 }
+
+// Deprecated: to be removed in future versions, when we won't support any 
longer trait annotations into IntegrationKits.
+func (action *monitorAction) 
checkTraitAnnotationsDeprecatedNotice(integrationKit *v1.IntegrationKit) {
+       if integrationKit.Annotations != nil {
+               for k := range integrationKit.Annotations {
+                       if strings.HasPrefix(k, v1.TraitAnnotationPrefix) {
+                               integrationKit.Status.SetCondition(
+                                       
v1.IntegrationKitConditionType("AnnotationTraitsDeprecated"),
+                                       corev1.ConditionTrue,
+                                       "DeprecationNotice",
+                                       "Annotation traits configuration is 
deprecated and will be removed soon. Use .spec.traits configuration instead.",
+                               )
+
+                               action.L.Infof(
+                                       "WARN: annotation traits configuration 
is deprecated and will be removed soon. Use .spec.traits configuration for %s 
integration kit instead.",
+                                       integrationKit.Name,
+                               )
+                               return
+                       }
+               }
+       }
+}
diff --git a/pkg/controller/integrationplatform/monitor.go 
b/pkg/controller/integrationplatform/monitor.go
index 1156a80f9..3a3b3c25e 100644
--- a/pkg/controller/integrationplatform/monitor.go
+++ b/pkg/controller/integrationplatform/monitor.go
@@ -20,6 +20,7 @@ package integrationplatform
 import (
        "context"
        "fmt"
+       "strings"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        platformutil "github.com/apache/camel-k/v2/pkg/platform"
@@ -124,6 +125,28 @@ func (action *monitorAction) Handle(ctx context.Context, 
platform *v1.Integratio
        }
 
        platform.Status.Phase = platformPhase
+       action.checkTraitAnnotationsDeprecatedNotice(platform)
 
        return platform, nil
 }
+
+// Deprecated: to be removed in future versions, when we won't support any 
longer trait annotations into IntegrationPlatforms.
+func (action *monitorAction) checkTraitAnnotationsDeprecatedNotice(platform 
*v1.IntegrationPlatform) {
+       if platform.Annotations != nil {
+               for k := range platform.Annotations {
+                       if strings.HasPrefix(k, v1.TraitAnnotationPrefix) {
+                               platform.Status.SetCondition(
+                                       
v1.IntegrationPlatformConditionType("AnnotationTraitsDeprecated"),
+                                       corev1.ConditionTrue,
+                                       "DeprecationNotice",
+                                       "Annotation traits configuration is 
deprecated and will be removed soon. Use .spec.traits configuration instead.",
+                               )
+                               action.L.Infof(
+                                       "WARN: annotation traits configuration 
is deprecated and will be removed soon. Use .spec.traits configuration for %s 
platform instead.",
+                                       platform.Name,
+                               )
+                               return
+                       }
+               }
+       }
+}
diff --git a/pkg/controller/kameletbinding/kameletbinding_controller.go 
b/pkg/controller/kameletbinding/kameletbinding_controller.go
index 2c6313a19..2da902b22 100644
--- a/pkg/controller/kameletbinding/kameletbinding_controller.go
+++ b/pkg/controller/kameletbinding/kameletbinding_controller.go
@@ -47,7 +47,7 @@ import (
 // Add creates a new KameletBinding Controller and adds it to the Manager. The 
Manager will set fields on the Controller
 // and Start it when the Manager is Started.
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
-       return add(mgr, newReconciler(mgr, c))
+       return add(mgr, newReconciler(mgr, c), c)
 }
 
 func newReconciler(mgr manager.Manager, c client.Client) reconcile.Reconciler {
@@ -65,14 +65,14 @@ func newReconciler(mgr manager.Manager, c client.Client) 
reconcile.Reconciler {
        )
 }
 
-func add(mgr manager.Manager, r reconcile.Reconciler) error {
-       c, err := controller.New("kamelet-binding-controller", mgr, 
controller.Options{Reconciler: r})
+func add(mgr manager.Manager, r reconcile.Reconciler, c client.Client) error {
+       ctrl, err := controller.New("kamelet-binding-controller", mgr, 
controller.Options{Reconciler: r})
        if err != nil {
                return err
        }
 
        // Watch for changes to primary resource KameletBinding
-       err = c.Watch(source.Kind(mgr.GetCache(), &v1alpha1.KameletBinding{}),
+       err = ctrl.Watch(source.Kind(mgr.GetCache(), 
&v1alpha1.KameletBinding{}),
                &handler.EnqueueRequestForObject{},
                platform.FilteringFuncs{
                        UpdateFunc: func(e event.UpdateEvent) bool {
@@ -87,7 +87,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
 
                                // If traits have changed, the reconciliation 
loop must kick in as
                                // traits may have impact
-                               sameTraits, err := 
trait.KameletBindingsHaveSameTraits(oldKameletBinding, newKameletBinding)
+                               sameTraits, err := 
trait.KameletBindingsHaveSameTraits(c, oldKameletBinding, newKameletBinding)
                                if err != nil {
                                        
Log.ForKameletBinding(newKameletBinding).Error(
                                                err,
@@ -114,7 +114,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error 
{
        }
 
        // Watch Integration to propagate changes downstream
-       err = c.Watch(source.Kind(mgr.GetCache(), &v1.Integration{}),
+       err = ctrl.Watch(source.Kind(mgr.GetCache(), &v1.Integration{}),
                handler.EnqueueRequestForOwner(
                        mgr.GetScheme(),
                        mgr.GetRESTMapper(),
diff --git a/pkg/controller/kameletbinding/monitor.go 
b/pkg/controller/kameletbinding/monitor.go
index 2c6d409f8..8c0187fcf 100644
--- a/pkg/controller/kameletbinding/monitor.go
+++ b/pkg/controller/kameletbinding/monitor.go
@@ -82,7 +82,7 @@ func (action *monitorAction) Handle(ctx context.Context, 
binding *v1alpha1.Kamel
        integrationProfileNamespaceChanged := 
v1.GetIntegrationProfileNamespaceAnnotation(binding) != "" &&
                (v1.GetIntegrationProfileNamespaceAnnotation(binding) != 
v1.GetIntegrationProfileNamespaceAnnotation(&it))
 
-       sameTraits, err := trait.IntegrationAndKameletBindingSameTraits(&it, 
binding)
+       sameTraits, err := 
trait.IntegrationAndKameletBindingSameTraits(action.client, &it, binding)
        if err != nil {
                return nil, err
        }
diff --git a/pkg/controller/pipe/integration.go 
b/pkg/controller/pipe/integration.go
index 8e8cc25c4..15f5a3556 100644
--- a/pkg/controller/pipe/integration.go
+++ b/pkg/controller/pipe/integration.go
@@ -22,7 +22,6 @@ import (
        "encoding/json"
        "fmt"
        "sort"
-       "strings"
 
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -88,10 +87,6 @@ func CreateIntegrationFor(ctx context.Context, c 
client.Client, binding *v1.Pipe
                it.Spec = *binding.Spec.Integration.DeepCopy()
        }
 
-       if &it.Spec != nil && traits != nil {
-               it.Spec = v1.IntegrationSpec{}
-       }
-
        if traits != nil {
                it.Spec.Traits = *traits
        }
@@ -226,52 +221,7 @@ func CreateIntegrationFor(ctx context.Context, c 
client.Client, binding *v1.Pipe
 
 // extractAndDeleteTraits will extract the annotation traits into v1.Traits 
struct, removing from the value from the input map.
 func extractAndDeleteTraits(c client.Client, annotations map[string]string) 
(*v1.Traits, error) {
-       // structure that will be marshalled into a v1.Traits as it was a kamel 
run command
-       catalog := trait.NewCatalog(c)
-       traitsPlainParams := []string{}
-       for k, v := range annotations {
-               if strings.HasPrefix(k, v1.TraitAnnotationPrefix) {
-                       key := strings.ReplaceAll(k, v1.TraitAnnotationPrefix, 
"")
-                       traitId := strings.Split(key, ".")[0]
-                       if err := trait.ValidateTrait(catalog, traitId); err != 
nil {
-                               return nil, err
-                       }
-                       traitArrayParams := extractAsArray(v)
-                       for _, param := range traitArrayParams {
-                               traitsPlainParams = append(traitsPlainParams, 
fmt.Sprintf("%s=%s", key, param))
-                       }
-                       delete(annotations, k)
-               }
-       }
-       if len(traitsPlainParams) == 0 {
-               return nil, nil
-       }
-       var traits v1.Traits
-       if err := trait.ConfigureTraits(traitsPlainParams, &traits, catalog); 
err != nil {
-               return nil, err
-       }
-
-       return &traits, nil
-}
-
-// extractTraitValue can detect if the value is an array representation as 
["prop1=1", "prop2=2"] and
-// return an array with the values or with the single value passed as a 
parameter.
-func extractAsArray(value string) []string {
-       if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
-               arrayValue := []string{}
-               data := value[1 : len(value)-1]
-               vals := strings.Split(data, ",")
-               for _, v := range vals {
-                       prop := strings.Trim(v, " ")
-                       if strings.HasPrefix(prop, `"`) && 
strings.HasSuffix(prop, `"`) {
-                               prop = prop[1 : len(prop)-1]
-                       }
-                       arrayValue = append(arrayValue, prop)
-               }
-               return arrayValue
-       }
-
-       return []string{value}
+       return trait.ExtractAndMaybeDeleteTraits(c, annotations, true)
 }
 
 func configureBinding(integration *v1.Integration, bindings 
...*bindings.Binding) error {
diff --git a/pkg/controller/pipe/monitor.go b/pkg/controller/pipe/monitor.go
index d8f2739ae..b7e109f3e 100644
--- a/pkg/controller/pipe/monitor.go
+++ b/pkg/controller/pipe/monitor.go
@@ -72,7 +72,7 @@ func (action *monitorAction) Handle(ctx context.Context, pipe 
*v1.Pipe) (*v1.Pip
        integrationProfileNamespaceChanged := 
v1.GetIntegrationProfileNamespaceAnnotation(pipe) != "" &&
                (v1.GetIntegrationProfileNamespaceAnnotation(pipe) != 
v1.GetIntegrationProfileNamespaceAnnotation(&it))
 
-       sameTraits, err := trait.IntegrationAndPipeSameTraits(&it, pipe)
+       sameTraits, err := trait.IntegrationAndPipeSameTraits(action.client, 
&it, pipe)
        if err != nil {
                return nil, err
        }
diff --git a/pkg/controller/pipe/monitor_test.go 
b/pkg/controller/pipe/monitor_test.go
index a05f6e4dd..a911599d6 100644
--- a/pkg/controller/pipe/monitor_test.go
+++ b/pkg/controller/pipe/monitor_test.go
@@ -312,8 +312,56 @@ func TestPipeIntegrationCreatingFromPipeCreatingPhase(t 
*testing.T) {
        // We calculate the integration the same way it does the operator
        // as we don't expect it to change in this test.
        it, err := CreateIntegrationFor(context.TODO(), c, pipe)
+       require.NoError(t, err)
        it.Status.Phase = v1.IntegrationPhaseBuildingKit
+       c, err = test.NewFakeClient(pipe, it)
+       require.NoError(t, err)
+
+       a := NewMonitorAction()
+       a.InjectLogger(log.Log)
+       a.InjectClient(c)
+       assert.Equal(t, "monitor", a.Name())
+       assert.True(t, a.CanHandle(pipe))
+       handledPipe, err := a.Handle(context.TODO(), pipe)
        require.NoError(t, err)
+       assert.Equal(t, v1.PipePhaseCreating, handledPipe.Status.Phase)
+       assert.Equal(t, corev1.ConditionFalse, 
handledPipe.Status.GetCondition(v1.PipeConditionReady).Status)
+       assert.Equal(t, "Integration \"my-pipe\" is in \"Creating\" phase", 
handledPipe.Status.GetCondition(v1.PipeConditionReady).Message)
+}
+
+func TestPipeIntegrationPipeTraitAnnotations(t *testing.T) {
+       pipe := &v1.Pipe{
+               TypeMeta: metav1.TypeMeta{
+                       APIVersion: v1.SchemeGroupVersion.String(),
+                       Kind:       v1.PipeKind,
+               },
+               ObjectMeta: metav1.ObjectMeta{
+                       Namespace: "ns",
+                       Name:      "my-pipe",
+                       Annotations: map[string]string{
+                               "trait.camel.apache.org/camel.runtime-version": 
"1.2.3",
+                       },
+               },
+               Spec: v1.PipeSpec{
+                       Source: v1.Endpoint{
+                               URI: pointer.String("timer:tick"),
+                       },
+                       Sink: v1.Endpoint{
+                               URI: pointer.String("log:info"),
+                       },
+               },
+               Status: v1.PipeStatus{
+                       Phase: v1.PipePhaseCreating,
+               },
+       }
+
+       c, err := test.NewFakeClient(pipe)
+       require.NoError(t, err)
+       // We calculate the integration the same way it does the operator
+       // as we don't expect it to change in this test.
+       it, err := CreateIntegrationFor(context.TODO(), c, pipe)
+       require.NoError(t, err)
+       it.Status.Phase = v1.IntegrationPhaseBuildingKit
        c, err = test.NewFakeClient(pipe, it)
        require.NoError(t, err)
 
diff --git a/pkg/controller/pipe/pipe_controller.go 
b/pkg/controller/pipe/pipe_controller.go
index 3060cefc5..9ad801b8d 100644
--- a/pkg/controller/pipe/pipe_controller.go
+++ b/pkg/controller/pipe/pipe_controller.go
@@ -47,7 +47,7 @@ import (
 // Add creates a new Pipe Controller and adds it to the Manager. The Manager 
will set fields on the Controller
 // and Start it when the Manager is Started.
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
-       return add(mgr, newReconciler(mgr, c))
+       return add(mgr, newReconciler(mgr, c), c)
 }
 
 func newReconciler(mgr manager.Manager, c client.Client) reconcile.Reconciler {
@@ -65,14 +65,14 @@ func newReconciler(mgr manager.Manager, c client.Client) 
reconcile.Reconciler {
        )
 }
 
-func add(mgr manager.Manager, r reconcile.Reconciler) error {
-       c, err := controller.New("pipe-controller", mgr, 
controller.Options{Reconciler: r})
+func add(mgr manager.Manager, r reconcile.Reconciler, c client.Client) error {
+       ctrl, err := controller.New("pipe-controller", mgr, 
controller.Options{Reconciler: r})
        if err != nil {
                return err
        }
 
        // Watch for changes to primary resource Pipe
-       err = c.Watch(source.Kind(mgr.GetCache(), &v1.Pipe{}),
+       err = ctrl.Watch(source.Kind(mgr.GetCache(), &v1.Pipe{}),
                &handler.EnqueueRequestForObject{},
                platform.FilteringFuncs{
                        UpdateFunc: func(e event.UpdateEvent) bool {
@@ -87,7 +87,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
 
                                // If traits have changed, the reconciliation 
loop must kick in as
                                // traits may have impact
-                               sameTraits, err := 
trait.PipesHaveSameTraits(oldPipe, newPipe)
+                               sameTraits, err := trait.PipesHaveSameTraits(c, 
oldPipe, newPipe)
                                if err != nil {
                                        Log.ForPipe(newPipe).Error(
                                                err,
@@ -114,7 +114,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error 
{
        }
 
        // Watch Integration to propagate changes downstream
-       err = c.Watch(source.Kind(mgr.GetCache(), &v1.Integration{}),
+       err = ctrl.Watch(source.Kind(mgr.GetCache(), &v1.Integration{}),
                handler.EnqueueRequestForOwner(
                        mgr.GetScheme(),
                        mgr.GetRESTMapper(),
diff --git a/pkg/trait/quarkus.go b/pkg/trait/quarkus.go
index 08dd0aafa..8d4744614 100644
--- a/pkg/trait/quarkus.go
+++ b/pkg/trait/quarkus.go
@@ -20,7 +20,6 @@ package trait
 import (
        "fmt"
        "sort"
-       "strings"
 
        "github.com/rs/xid"
 
@@ -277,11 +276,6 @@ func (t *quarkusTrait) newIntegrationKit(e *Environment, 
packageType quarkusPack
                        v1.SetAnnotation(&kit.ObjectMeta, 
v1.IntegrationProfileNamespaceAnnotation, e.Integration.Namespace)
                }
        }
-       for k, v := range integration.Annotations {
-               if strings.HasPrefix(k, v1.TraitAnnotationPrefix) {
-                       v1.SetAnnotation(&kit.ObjectMeta, k, v)
-               }
-       }
        operatorID := defaults.OperatorID()
        if operatorID != "" {
                kit.SetOperatorID(operatorID)
diff --git a/pkg/trait/quarkus_test.go b/pkg/trait/quarkus_test.go
index 473da5c44..6c0ae919d 100644
--- a/pkg/trait/quarkus_test.go
+++ b/pkg/trait/quarkus_test.go
@@ -70,25 +70,6 @@ func TestApplyQuarkusTraitDefaultKitLayout(t *testing.T) {
        assert.Equal(t, 
environment.IntegrationKits[0].Labels[v1.IntegrationKitLayoutLabel], 
v1.IntegrationKitLayoutFastJar)
 }
 
-func TestApplyQuarkusTraitAnnotationKitConfiguration(t *testing.T) {
-       quarkusTrait, environment := createNominalQuarkusTest()
-       environment.Integration.Status.Phase = v1.IntegrationPhaseBuildingKit
-
-       v1.SetAnnotation(&environment.Integration.ObjectMeta, 
v1.TraitAnnotationPrefix+"quarkus.foo", "camel-k")
-
-       configured, condition, err := quarkusTrait.Configure(environment)
-       assert.True(t, configured)
-       require.NoError(t, err)
-       assert.Nil(t, condition)
-
-       err = quarkusTrait.Apply(environment)
-       require.NoError(t, err)
-       assert.Len(t, environment.IntegrationKits, 1)
-       assert.Equal(t, v1.IntegrationKitLayoutFastJar, 
environment.IntegrationKits[0].Labels[v1.IntegrationKitLayoutLabel])
-       assert.Equal(t, "camel-k", 
environment.IntegrationKits[0].Annotations[v1.TraitAnnotationPrefix+"quarkus.foo"])
-
-}
-
 func TestQuarkusTraitBuildModeOrder(t *testing.T) {
        quarkusTrait, environment := createNominalQuarkusTest()
        quarkusTrait.Modes = []traitv1.QuarkusMode{traitv1.NativeQuarkusMode, 
traitv1.JvmQuarkusMode}
diff --git a/pkg/trait/trait_configure.go b/pkg/trait/trait_configure.go
index 8efb45a1c..b14d40b77 100644
--- a/pkg/trait/trait_configure.go
+++ b/pkg/trait/trait_configure.go
@@ -36,6 +36,7 @@ func (c *Catalog) Configure(env *Environment) error {
                if err := c.configureTraits(env.Platform.Status.Traits); err != 
nil {
                        return err
                }
+               // Deprecated: to be removed in future version
                if err := 
c.configureTraitsFromAnnotations(env.Platform.Annotations); err != nil {
                        return err
                }
@@ -49,6 +50,7 @@ func (c *Catalog) Configure(env *Environment) error {
                if err := c.configureTraits(env.IntegrationKit.Spec.Traits); 
err != nil {
                        return err
                }
+               // Deprecated: to be removed in future version
                if err := 
c.configureTraitsFromAnnotations(env.IntegrationKit.Annotations); err != nil {
                        return err
                }
@@ -57,6 +59,7 @@ func (c *Catalog) Configure(env *Environment) error {
                if err := c.configureTraits(env.Integration.Spec.Traits); err 
!= nil {
                        return err
                }
+               // Deprecated: to be removed in future version
                if err := 
c.configureTraitsFromAnnotations(env.Integration.Annotations); err != nil {
                        return err
                }
@@ -117,6 +120,7 @@ func decodeTrait(in map[string]interface{}, target Trait) 
error {
        return json.Unmarshal(data, target)
 }
 
+// Deprecated: to be removed in future versions.
 func (c *Catalog) configureTraitsFromAnnotations(annotations 
map[string]string) error {
        options := make(map[string]map[string]interface{}, len(annotations))
        for k, v := range annotations {
@@ -154,6 +158,7 @@ func (c *Catalog) 
configureTraitsFromAnnotations(annotations map[string]string)
        return c.configureFromOptions(options)
 }
 
+// Deprecated: to be removed in future versions.
 func (c *Catalog) configureFromOptions(traits 
map[string]map[string]interface{}) error {
        for id, config := range traits {
                t := c.GetTrait(id)
@@ -167,6 +172,7 @@ func (c *Catalog) configureFromOptions(traits 
map[string]map[string]interface{})
        return nil
 }
 
+// Deprecated: to be removed in future versions.
 func configureTrait(id string, config map[string]interface{}, trait 
interface{}) error {
        md := mapstructure.Metadata{}
 
diff --git a/pkg/trait/util.go b/pkg/trait/util.go
index 374d90e48..94581dad4 100644
--- a/pkg/trait/util.go
+++ b/pkg/trait/util.go
@@ -27,8 +27,6 @@ import (
        "sort"
        "strings"
 
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
        ctrl "sigs.k8s.io/controller-runtime/pkg/client"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -348,12 +346,12 @@ func Equals(i1 Options, i2 Options) bool {
 }
 
 // IntegrationsHaveSameTraits return if traits are the same.
-func IntegrationsHaveSameTraits(i1 *v1.Integration, i2 *v1.Integration) (bool, 
error) {
-       c1, err := NewSpecTraitsOptionsForIntegration(i1)
+func IntegrationsHaveSameTraits(c client.Client, i1 *v1.Integration, i2 
*v1.Integration) (bool, error) {
+       c1, err := NewSpecTraitsOptionsForIntegration(c, i1)
        if err != nil {
                return false, err
        }
-       c2, err := NewSpecTraitsOptionsForIntegration(i2)
+       c2, err := NewSpecTraitsOptionsForIntegration(c, i2)
        if err != nil {
                return false, err
        }
@@ -362,12 +360,12 @@ func IntegrationsHaveSameTraits(i1 *v1.Integration, i2 
*v1.Integration) (bool, e
 }
 
 // PipesHaveSameTraits return if traits are the same.
-func PipesHaveSameTraits(i1 *v1.Pipe, i2 *v1.Pipe) (bool, error) {
-       c1, err := NewTraitsOptionsForPipe(i1)
+func PipesHaveSameTraits(c client.Client, i1 *v1.Pipe, i2 *v1.Pipe) (bool, 
error) {
+       c1, err := NewTraitsOptionsForPipe(c, i1)
        if err != nil {
                return false, err
        }
-       c2, err := NewTraitsOptionsForPipe(i2)
+       c2, err := NewTraitsOptionsForPipe(c, i2)
        if err != nil {
                return false, err
        }
@@ -377,12 +375,12 @@ func PipesHaveSameTraits(i1 *v1.Pipe, i2 *v1.Pipe) (bool, 
error) {
 
 // KameletBindingsHaveSameTraits return if traits are the same.
 // Deprecated.
-func KameletBindingsHaveSameTraits(i1 *v1alpha1.KameletBinding, i2 
*v1alpha1.KameletBinding) (bool, error) {
-       c1, err := NewTraitsOptionsForKameletBinding(i1)
+func KameletBindingsHaveSameTraits(c client.Client, i1 
*v1alpha1.KameletBinding, i2 *v1alpha1.KameletBinding) (bool, error) {
+       c1, err := NewTraitsOptionsForKameletBinding(c, i1)
        if err != nil {
                return false, err
        }
-       c2, err := NewTraitsOptionsForKameletBinding(i2)
+       c2, err := NewTraitsOptionsForKameletBinding(c, i2)
        if err != nil {
                return false, err
        }
@@ -393,16 +391,15 @@ func KameletBindingsHaveSameTraits(i1 
*v1alpha1.KameletBinding, i2 *v1alpha1.Kam
 // IntegrationAndPipeSameTraits return if traits are the same.
 // The comparison is done for the subset of traits defines on the binding as 
during the trait processing,
 // some traits may be added to the Integration i.e. knative configuration in 
case of sink binding.
-func IntegrationAndPipeSameTraits(i1 *v1.Integration, i2 *v1.Pipe) (bool, 
error) {
-       itOpts, err := NewSpecTraitsOptionsForIntegration(i1)
+func IntegrationAndPipeSameTraits(c client.Client, i1 *v1.Integration, i2 
*v1.Pipe) (bool, error) {
+       itOpts, err := NewSpecTraitsOptionsForIntegration(c, i1)
        if err != nil {
                return false, err
        }
-       klbOpts, err := NewTraitsOptionsForPipe(i2)
+       klbOpts, err := NewTraitsOptionsForPipe(c, i2)
        if err != nil {
                return false, err
        }
-
        toCompare := make(Options)
        for k := range klbOpts {
                if v, ok := itOpts[k]; ok {
@@ -417,12 +414,12 @@ func IntegrationAndPipeSameTraits(i1 *v1.Integration, i2 
*v1.Pipe) (bool, error)
 // The comparison is done for the subset of traits defines on the binding as 
during the trait processing,
 // some traits may be added to the Integration i.e. knative configuration in 
case of sink binding.
 // Deprecated.
-func IntegrationAndKameletBindingSameTraits(i1 *v1.Integration, i2 
*v1alpha1.KameletBinding) (bool, error) {
-       itOpts, err := NewSpecTraitsOptionsForIntegration(i1)
+func IntegrationAndKameletBindingSameTraits(c client.Client, i1 
*v1.Integration, i2 *v1alpha1.KameletBinding) (bool, error) {
+       itOpts, err := NewSpecTraitsOptionsForIntegration(c, i1)
        if err != nil {
                return false, err
        }
-       klbOpts, err := NewTraitsOptionsForKameletBinding(i2)
+       klbOpts, err := NewTraitsOptionsForKameletBinding(c, i2)
        if err != nil {
                return false, err
        }
@@ -437,8 +434,17 @@ func IntegrationAndKameletBindingSameTraits(i1 
*v1.Integration, i2 *v1alpha1.Kam
        return Equals(klbOpts, toCompare), nil
 }
 
-func newTraitsOptions(opts Options, objectMeta *metav1.ObjectMeta) (Options, 
error) {
-       m2, err := FromAnnotations(objectMeta)
+// newTraitsOptions will merge the traits annotations with the traits spec 
using the same format.
+func newTraitsOptions(c client.Client, opts Options, annotations 
map[string]string) (Options, error) {
+       annotationTraits, err := ExtractAndMaybeDeleteTraits(c, annotations, 
false)
+       if err != nil {
+               return nil, err
+       }
+       if annotationTraits == nil {
+               return opts, nil
+       }
+
+       m2, err := ToTraitMap(*annotationTraits)
        if err != nil {
                return nil, err
        }
@@ -450,7 +456,59 @@ func newTraitsOptions(opts Options, objectMeta 
*metav1.ObjectMeta) (Options, err
        return opts, nil
 }
 
-func NewSpecTraitsOptionsForIntegrationAndPlatform(i *v1.Integration, pl 
*v1.IntegrationPlatform) (Options, error) {
+// ExtractAndDeleteTraits will extract the annotation traits into v1.Traits 
struct, removing from the value from the input map.
+func ExtractAndMaybeDeleteTraits(c client.Client, annotations 
map[string]string, del bool) (*v1.Traits, error) {
+       // structure that will be marshalled into a v1.Traits as it was a kamel 
run command
+       catalog := NewCatalog(c)
+       traitsPlainParams := []string{}
+       for k, v := range annotations {
+               if strings.HasPrefix(k, v1.TraitAnnotationPrefix) {
+                       key := strings.ReplaceAll(k, v1.TraitAnnotationPrefix, 
"")
+                       traitID := strings.Split(key, ".")[0]
+                       if err := ValidateTrait(catalog, traitID); err != nil {
+                               return nil, err
+                       }
+                       traitArrayParams := extractAsArray(v)
+                       for _, param := range traitArrayParams {
+                               traitsPlainParams = append(traitsPlainParams, 
fmt.Sprintf("%s=%s", key, param))
+                       }
+                       if del {
+                               delete(annotations, k)
+                       }
+               }
+       }
+       if len(traitsPlainParams) == 0 {
+               return nil, nil
+       }
+       var traits v1.Traits
+       if err := ConfigureTraits(traitsPlainParams, &traits, catalog); err != 
nil {
+               return nil, err
+       }
+
+       return &traits, nil
+}
+
+// extractTraitValue can detect if the value is an array representation as 
["prop1=1", "prop2=2"] and
+// return an array with the values or with the single value passed as a 
parameter.
+func extractAsArray(value string) []string {
+       if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
+               arrayValue := []string{}
+               data := value[1 : len(value)-1]
+               vals := strings.Split(data, ",")
+               for _, v := range vals {
+                       prop := strings.Trim(v, " ")
+                       if strings.HasPrefix(prop, `"`) && 
strings.HasSuffix(prop, `"`) {
+                               prop = prop[1 : len(prop)-1]
+                       }
+                       arrayValue = append(arrayValue, prop)
+               }
+               return arrayValue
+       }
+
+       return []string{value}
+}
+
+func NewSpecTraitsOptionsForIntegrationAndPlatform(c client.Client, i 
*v1.Integration, pl *v1.IntegrationPlatform) (Options, error) {
        var options Options
        var err error
        if pl != nil {
@@ -471,32 +529,44 @@ func NewSpecTraitsOptionsForIntegrationAndPlatform(i 
*v1.Integration, pl *v1.Int
                options[k] = v
        }
 
-       return newTraitsOptions(options, &i.ObjectMeta)
+       // Deprecated: to remove when we remove support for traits annotations.
+       // IMPORTANT: when we remove this we'll need to remove the cli from the 
func,
+       // which will bring to more cascade removal. It had to be introduced to 
support the deprecated feature
+       // in a properly manner (ie, comparing the spec.traits with annotations 
in a proper way).
+       return newTraitsOptions(c, options, i.ObjectMeta.Annotations)
 }
 
-func NewSpecTraitsOptionsForIntegration(i *v1.Integration) (Options, error) {
+func NewSpecTraitsOptionsForIntegration(c client.Client, i *v1.Integration) 
(Options, error) {
        m1, err := ToTraitMap(i.Spec.Traits)
        if err != nil {
                return nil, err
        }
 
-       return newTraitsOptions(m1, &i.ObjectMeta)
+       // Deprecated: to remove when we remove support for traits annotations.
+       // IMPORTANT: when we remove this we'll need to remove the cli from the 
func,
+       // which will bring to more cascade removal. It had to be introduced to 
support the deprecated feature
+       // in a properly manner (ie, comparing the spec.traits with annotations 
in a proper way).
+       return newTraitsOptions(c, m1, i.ObjectMeta.Annotations)
 }
 
-func newTraitsOptionsForIntegrationKit(i *v1.IntegrationKit, traits 
v1.IntegrationKitTraits) (Options, error) {
+func newTraitsOptionsForIntegrationKit(c client.Client, i *v1.IntegrationKit, 
traits v1.IntegrationKitTraits) (Options, error) {
        m1, err := ToTraitMap(traits)
        if err != nil {
                return nil, err
        }
 
-       return newTraitsOptions(m1, &i.ObjectMeta)
+       // Deprecated: to remove when we remove support for traits annotations.
+       // IMPORTANT: when we remove this we'll need to remove the cli from the 
func,
+       // which will bring to more cascade removal. It had to be introduced to 
support the deprecated feature
+       // in a properly manner (ie, comparing the spec.traits with annotations 
in a proper way).
+       return newTraitsOptions(c, m1, i.ObjectMeta.Annotations)
 }
 
-func NewSpecTraitsOptionsForIntegrationKit(i *v1.IntegrationKit) (Options, 
error) {
-       return newTraitsOptionsForIntegrationKit(i, i.Spec.Traits)
+func NewSpecTraitsOptionsForIntegrationKit(c client.Client, i 
*v1.IntegrationKit) (Options, error) {
+       return newTraitsOptionsForIntegrationKit(c, i, i.Spec.Traits)
 }
 
-func NewTraitsOptionsForPipe(pipe *v1.Pipe) (Options, error) {
+func NewTraitsOptionsForPipe(c client.Client, pipe *v1.Pipe) (Options, error) {
        options := Options{}
 
        if pipe.Spec.Integration != nil {
@@ -510,11 +580,11 @@ func NewTraitsOptionsForPipe(pipe *v1.Pipe) (Options, 
error) {
                }
        }
 
-       return newTraitsOptions(options, &pipe.ObjectMeta)
+       return newTraitsOptions(c, options, pipe.ObjectMeta.Annotations)
 }
 
 // Deprecated.
-func NewTraitsOptionsForKameletBinding(kb *v1alpha1.KameletBinding) (Options, 
error) {
+func NewTraitsOptionsForKameletBinding(c client.Client, kb 
*v1alpha1.KameletBinding) (Options, error) {
        options := Options{}
 
        if kb.Spec.Integration != nil {
@@ -528,47 +598,7 @@ func NewTraitsOptionsForKameletBinding(kb 
*v1alpha1.KameletBinding) (Options, er
                }
        }
 
-       return newTraitsOptions(options, &kb.ObjectMeta)
-}
-
-func FromAnnotations(meta *metav1.ObjectMeta) (Options, error) {
-       options := make(Options)
-       for k, v := range meta.Annotations {
-               if strings.HasPrefix(k, v1.TraitAnnotationPrefix) {
-                       configKey := strings.TrimPrefix(k, 
v1.TraitAnnotationPrefix)
-                       if strings.Contains(configKey, ".") {
-                               parts := strings.SplitN(configKey, ".", 2)
-                               id := parts[0]
-                               prop := parts[1]
-                               if _, ok := options[id]; !ok {
-                                       options[id] = 
make(map[string]interface{})
-                               }
-                               options[id][prop] = stringOrSlice(v)
-                       } else {
-                               return options, fmt.Errorf("wrong format for 
trait annotation %q: missing trait ID", k)
-                       }
-               }
-       }
-
-       return options, nil
-}
-
-// stringOrSlice returns either a string or a slice with trimmed values when 
the input is
-// represented as an array style (ie, [a,b,c]).
-func stringOrSlice(val string) interface{} {
-       if val == "[]" {
-               // empty array
-               return []string{}
-       }
-       if strings.HasPrefix(val, "[") && strings.HasSuffix(val, "]") {
-               slice := strings.Split(val[1:len(val)-1], ",")
-               for i := range slice {
-                       slice[i] = strings.Trim(slice[i], " ")
-               }
-               return slice
-       } else {
-               return val
-       }
+       return newTraitsOptions(c, options, kb.ObjectMeta.Annotations)
 }
 
 // verify if the integration in the Environment contains an endpoint.
diff --git a/pkg/trait/util_test.go b/pkg/trait/util_test.go
index d89262bbf..6e56b15a1 100644
--- a/pkg/trait/util_test.go
+++ b/pkg/trait/util_test.go
@@ -25,6 +25,7 @@ import (
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+       "github.com/apache/camel-k/v2/pkg/util/test"
 
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
@@ -174,6 +175,8 @@ func TestToTrait(t *testing.T) {
 }
 
 func TestSameTraits(t *testing.T) {
+       c, err := test.NewFakeClient()
+       require.NoError(t, err)
        t.Run("empty traits", func(t *testing.T) {
                oldKlb := &v1.Pipe{
                        Spec: v1.PipeSpec{
@@ -190,7 +193,7 @@ func TestSameTraits(t *testing.T) {
                        },
                }
 
-               ok, err := PipesHaveSameTraits(oldKlb, newKlb)
+               ok, err := PipesHaveSameTraits(c, oldKlb, newKlb)
                require.NoError(t, err)
                assert.True(t, ok)
        })
@@ -219,7 +222,7 @@ func TestSameTraits(t *testing.T) {
                        },
                }
 
-               ok, err := PipesHaveSameTraits(oldKlb, newKlb)
+               ok, err := PipesHaveSameTraits(c, oldKlb, newKlb)
                require.NoError(t, err)
                assert.True(t, ok)
        })
@@ -248,7 +251,7 @@ func TestSameTraits(t *testing.T) {
                        },
                }
 
-               ok, err := PipesHaveSameTraits(oldKlb, newKlb)
+               ok, err := PipesHaveSameTraits(c, oldKlb, newKlb)
                require.NoError(t, err)
                assert.False(t, ok)
        })
@@ -273,7 +276,7 @@ func TestSameTraits(t *testing.T) {
                        },
                }
 
-               ok, err := PipesHaveSameTraits(oldKlb, newKlb)
+               ok, err := PipesHaveSameTraits(c, oldKlb, newKlb)
                require.NoError(t, err)
                assert.True(t, ok)
        })
@@ -294,7 +297,7 @@ func TestSameTraits(t *testing.T) {
                        },
                }
 
-               ok, err := PipesHaveSameTraits(oldKlb, newKlb)
+               ok, err := PipesHaveSameTraits(c, oldKlb, newKlb)
                require.NoError(t, err)
                assert.True(t, ok)
        })
@@ -319,7 +322,7 @@ func TestSameTraits(t *testing.T) {
                        },
                }
 
-               ok, err := PipesHaveSameTraits(oldKlb, newKlb)
+               ok, err := PipesHaveSameTraits(c, oldKlb, newKlb)
                require.NoError(t, err)
                assert.False(t, ok)
        })
@@ -340,7 +343,7 @@ func TestSameTraits(t *testing.T) {
                        },
                }
 
-               ok, err := PipesHaveSameTraits(oldKlb, newKlb)
+               ok, err := PipesHaveSameTraits(c, oldKlb, newKlb)
                require.NoError(t, err)
                assert.False(t, ok)
        })
@@ -392,46 +395,28 @@ func TestHasMathchingTraitsMissing(t *testing.T) {
        assert.True(t, b1)
 }
 
-func TestFromAnnotationsPlain(t *testing.T) {
-       meta := metav1.ObjectMeta{
-               Annotations: map[string]string{
-                       "trait.camel.apache.org/trait.prop1": "hello1",
-                       "trait.camel.apache.org/trait.prop2": "hello2",
+func TestIntegrationAndPipeSameTraits(t *testing.T) {
+       pipe := &v1.Pipe{
+               ObjectMeta: metav1.ObjectMeta{
+                       Annotations: map[string]string{
+                               "trait.camel.apache.org/camel.runtime-version": 
"1.2.3",
+                       },
                },
        }
-       opt, err := FromAnnotations(&meta)
-       require.NoError(t, err)
-       tt, ok := opt.Get("trait")
-       assert.True(t, ok)
-       assert.Equal(t, "hello1", tt["prop1"])
-       assert.Equal(t, "hello2", tt["prop2"])
-}
 
-func TestFromAnnotationsArray(t *testing.T) {
-       meta := metav1.ObjectMeta{
-               Annotations: map[string]string{
-                       "trait.camel.apache.org/trait.prop1": "[hello,world]",
-                       // The func should trim empty spaces as well
-                       "trait.camel.apache.org/trait.prop2": "[\"hello=1\", 
\"world=2\"]",
+       integration := &v1.Integration{
+               Spec: v1.IntegrationSpec{
+                       Traits: v1.Traits{
+                               Camel: &traitv1.CamelTrait{
+                                       RuntimeVersion: "1.2.3",
+                               },
+                       },
                },
        }
-       opt, err := FromAnnotations(&meta)
+       c, err := test.NewFakeClient(pipe, integration)
        require.NoError(t, err)
-       tt, ok := opt.Get("trait")
-       assert.True(t, ok)
-       assert.Equal(t, []string{"hello", "world"}, tt["prop1"])
-       assert.Equal(t, []string{"\"hello=1\"", "\"world=2\""}, tt["prop2"])
-}
 
-func TestFromAnnotationsArrayEmpty(t *testing.T) {
-       meta := metav1.ObjectMeta{
-               Annotations: map[string]string{
-                       "trait.camel.apache.org/trait.prop": "[]",
-               },
-       }
-       opt, err := FromAnnotations(&meta)
+       result, err := IntegrationAndPipeSameTraits(c, integration, pipe)
        require.NoError(t, err)
-       tt, ok := opt.Get("trait")
-       assert.True(t, ok)
-       assert.Equal(t, []string{}, tt["prop"])
+       assert.True(t, result)
 }
diff --git a/pkg/util/digest/digest.go b/pkg/util/digest/digest.go
index 946b399f1..9630467db 100644
--- a/pkg/util/digest/digest.go
+++ b/pkg/util/digest/digest.go
@@ -336,6 +336,7 @@ func sortedTraitsMapKeys(m 
map[string]map[string]interface{}) []string {
        return res
 }
 
+// Deprecated: to be removed in future versions.
 func sortedTraitAnnotationsKeys(it *v1.Integration) []string {
        res := make([]string, 0, len(it.Annotations))
        for k := range it.Annotations {


Reply via email to