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 {
