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

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

commit c33e0cc189c5b516f5da524b9a5f88032775fbd1
Author: Christoph Deppisch <cdeppi...@redhat.com>
AuthorDate: Wed Jun 8 20:11:44 2022 +0200

    Fix #2177: Use operator id in KameletBindings
    
    - Introduce operator-id option to kamel CLI bind command
    - Make sure to use proper operator id when creating the binding
    - Rebuild Kamelet binding when operator id annotation changes
---
 .../v1alpha1/kamelet_binding_types_support.go      |  9 ++++
 pkg/cmd/bind.go                                    | 48 ++++++++++++++++++++++
 pkg/cmd/bind_test.go                               | 19 ++++++++-
 pkg/controller/kameletbinding/monitor.go           |  7 +++-
 4 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/pkg/apis/camel/v1alpha1/kamelet_binding_types_support.go 
b/pkg/apis/camel/v1alpha1/kamelet_binding_types_support.go
index d47024609..90c36c821 100644
--- a/pkg/apis/camel/v1alpha1/kamelet_binding_types_support.go
+++ b/pkg/apis/camel/v1alpha1/kamelet_binding_types_support.go
@@ -66,6 +66,15 @@ func (c KameletBindingCondition) GetMessage() string {
        return c.Message
 }
 
+// SetOperatorID sets the given operator id as an annotation
+func (in *KameletBinding) SetOperatorID(operatorID string) {
+       if in.Annotations == nil {
+               in.Annotations = make(map[string]string)
+       }
+
+       in.Annotations[v1.OperatorIDAnnotation] = operatorID
+}
+
 // GetCondition returns the condition with the provided type.
 func (in *KameletBindingStatus) GetCondition(condType 
KameletBindingConditionType) *KameletBindingCondition {
        for i := range in.Conditions {
diff --git a/pkg/cmd/bind.go b/pkg/cmd/bind.go
index 2a1c4ad26..b86b08e88 100644
--- a/pkg/cmd/bind.go
+++ b/pkg/cmd/bind.go
@@ -25,6 +25,7 @@ import (
 
        v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       platformutil "github.com/apache/camel-k/pkg/platform"
        "github.com/apache/camel-k/pkg/trait"
        "github.com/apache/camel-k/pkg/util/kubernetes"
        "github.com/apache/camel-k/pkg/util/reference"
@@ -60,6 +61,9 @@ func newCmdBind(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *bindCmdOptions
        cmd.Flags().Bool("skip-checks", false, "Do not verify the binding for 
compliance with Kamelets and other Kubernetes resources")
        cmd.Flags().StringArray("step", nil, `Add binding steps as Kubernetes 
resources. Endpoints are expected in the format 
"[[apigroup/]version:]kind:[namespace/]name", plain Camel URIs or Kamelet 
name.`)
        cmd.Flags().StringArrayP("trait", "t", nil, `Add a trait to the 
corresponding Integration.`)
+       cmd.Flags().String("operator-id", "camel-k", "Operator id selected to 
manage this Kamelet binding.")
+       cmd.Flags().StringArray("annotation", nil, "Add an annotation to the 
Kamelet binding. E.g. \"--annotation my.company=hello\"")
+       cmd.Flags().Bool("force", false, "Force creation of Kamelet binding 
regardless of potential misconfiguration.")
 
        return &cmd, &options
 }
@@ -81,6 +85,9 @@ type bindCmdOptions struct {
        SkipChecks   bool     `mapstructure:"skip-checks" yaml:",omitempty"`
        Steps        []string `mapstructure:"steps" yaml:",omitempty"`
        Traits       []string `mapstructure:"traits" yaml:",omitempty"`
+       OperatorId   string   `mapstructure:"operator-id" yaml:",omitempty"`
+       Annotations  []string `mapstructure:"annotations" yaml:",omitempty"`
+       Force        bool     `mapstructure:"force" yaml:",omitempty"`
 }
 
 func (o *bindCmdOptions) preRunE(cmd *cobra.Command, args []string) error {
@@ -109,6 +116,17 @@ func (o *bindCmdOptions) validate(cmd *cobra.Command, args 
[]string) error {
                return errors.New("source or sink arguments are missing")
        }
 
+       if o.OperatorId == "" {
+               return fmt.Errorf("cannot use empty operator id")
+       }
+
+       for _, annotation := range o.Annotations {
+               parts := strings.SplitN(annotation, "=", 2)
+               if len(parts) != 2 {
+                       return fmt.Errorf(`invalid annotation specification %s. 
Expected "<annotationkey>=<annotationvalue>"`, annotation)
+               }
+       }
+
        for _, p := range o.Properties {
                if _, _, _, err := o.parseProperty(p); err != nil {
                        return err
@@ -215,6 +233,36 @@ func (o *bindCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
                }
        }
 
+       if binding.Annotations == nil {
+               binding.Annotations = make(map[string]string)
+       }
+
+       if o.OperatorId != "" {
+               if pl, err := platformutil.LookupForPlatformName(o.Context, 
client, o.OperatorId); err != nil {
+                       if k8serrors.IsForbidden(err) {
+                               o.PrintfVerboseOutf(cmd, "Unable to verify 
existence of operator id [%s] due to lack of user privileges\n", o.OperatorId)
+                       } else {
+                               return err
+                       }
+               } else if pl == nil {
+                       if o.Force {
+                               o.PrintfVerboseOutf(cmd, "Unable to find 
operator with given id [%s] - Kamelet binding may not be reconciled and get 
stuck in waiting state\n", o.OperatorId)
+                       } else {
+                               return errors.New(fmt.Sprintf("unable to find 
integration platform for given operator id '%s', use --force option or make 
sure to use a proper operator id", o.OperatorId))
+                       }
+               }
+       }
+
+       // --operator-id={id} is a syntax sugar for '--annotation 
camel.apache.org/operator.id={id}'
+       binding.SetOperatorID(strings.TrimSpace(o.OperatorId))
+
+       for _, annotation := range o.Annotations {
+               parts := strings.SplitN(annotation, "=", 2)
+               if len(parts) == 2 {
+                       binding.Annotations[parts[0]] = parts[1]
+               }
+       }
+
        if o.OutputFormat != "" {
                return showOutput(cmd, &binding, o.OutputFormat, 
client.GetScheme())
        }
diff --git a/pkg/cmd/bind_test.go b/pkg/cmd/bind_test.go
index aa5778a5c..e4583b7bd 100644
--- a/pkg/cmd/bind_test.go
+++ b/pkg/cmd/bind_test.go
@@ -20,6 +20,8 @@ package cmd
 import (
        "testing"
 
+       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       "github.com/apache/camel-k/pkg/platform"
        "github.com/apache/camel-k/pkg/util/test"
        "github.com/spf13/cobra"
        "github.com/stretchr/testify/assert"
@@ -31,7 +33,10 @@ const cmdBind = "bind"
 func initializeBindCmdOptions(t *testing.T) (*bindCmdOptions, *cobra.Command, 
RootCmdOptions) {
        t.Helper()
 
-       options, rootCmd := kamelTestPreAddCommandInit()
+       defaultIntegrationPlatform := v1.NewIntegrationPlatform("default", 
platform.DefaultPlatformName)
+       fakeClient, _ := test.NewFakeClient(&defaultIntegrationPlatform)
+
+       options, rootCmd := kamelTestPreAddCommandInitWithClient(fakeClient)
        bindCmdOptions := addTestBindCmd(*options, rootCmd)
        kamelTestPostAddCommandInit(t, rootCmd)
 
@@ -52,7 +57,7 @@ func TestBindOutputJSON(t *testing.T) {
        assert.Equal(t, "json", buildCmdOptions.OutputFormat)
 
        assert.Nil(t, err)
-       assert.Equal(t, 
`{"kind":"KameletBinding","apiVersion":"camel.apache.org/v1alpha1","metadata":{"name":"my-to-my","creationTimestamp":null},"spec":{"source":{"uri":"my:src"},"sink":{"uri":"my:dst"}},"status":{}}`,
 output)
+       assert.Equal(t, 
`{"kind":"KameletBinding","apiVersion":"camel.apache.org/v1alpha1","metadata":{"name":"my-to-my","creationTimestamp":null,"annotations":{"camel.apache.org/operator.id":"camel-k"}},"spec":{"source":{"uri":"my:src"},"sink":{"uri":"my:dst"}},"status":{}}`,
 output)
 }
 
 func TestBindOutputYAML(t *testing.T) {
@@ -64,6 +69,8 @@ func TestBindOutputYAML(t *testing.T) {
        assert.Equal(t, `apiVersion: camel.apache.org/v1alpha1
 kind: KameletBinding
 metadata:
+  annotations:
+    camel.apache.org/operator.id: camel-k
   creationTimestamp: null
   name: my-to-my
 spec:
@@ -93,6 +100,8 @@ func TestBindErrorHandlerDLCKamelet(t *testing.T) {
        assert.Equal(t, `apiVersion: camel.apache.org/v1alpha1
 kind: KameletBinding
 metadata:
+  annotations:
+    camel.apache.org/operator.id: camel-k
   creationTimestamp: null
   name: my-to-my
 spec:
@@ -123,6 +132,8 @@ func TestBindErrorHandlerNone(t *testing.T) {
        assert.Equal(t, `apiVersion: camel.apache.org/v1alpha1
 kind: KameletBinding
 metadata:
+  annotations:
+    camel.apache.org/operator.id: camel-k
   creationTimestamp: null
   name: my-to-my
 spec:
@@ -146,6 +157,8 @@ func TestBindErrorHandlerLog(t *testing.T) {
        assert.Equal(t, `apiVersion: camel.apache.org/v1alpha1
 kind: KameletBinding
 metadata:
+  annotations:
+    camel.apache.org/operator.id: camel-k
   creationTimestamp: null
   name: my-to-my
 spec:
@@ -168,6 +181,8 @@ func TestBindTraits(t *testing.T) {
        assert.Equal(t, `apiVersion: camel.apache.org/v1alpha1
 kind: KameletBinding
 metadata:
+  annotations:
+    camel.apache.org/operator.id: camel-k
   creationTimestamp: null
   name: my-to-my
 spec:
diff --git a/pkg/controller/kameletbinding/monitor.go 
b/pkg/controller/kameletbinding/monitor.go
index 5c9b599aa..d6465573c 100644
--- a/pkg/controller/kameletbinding/monitor.go
+++ b/pkg/controller/kameletbinding/monitor.go
@@ -73,13 +73,18 @@ func (action *monitorAction) Handle(ctx context.Context, 
kameletbinding *v1alpha
                return nil, errors.Wrapf(err, "could not load integration for 
KameletBinding %q", kameletbinding.Name)
        }
 
+       operatorIdChanged := v1.GetOperatorIDAnnotation(kameletbinding) != "" &&
+               (v1.GetOperatorIDAnnotation(kameletbinding) != 
v1.GetOperatorIDAnnotation(&it))
+
        // Check if the integration needs to be changed
        expected, err := CreateIntegrationFor(ctx, action.client, 
kameletbinding)
        if err != nil {
                return nil, err
        }
 
-       if !equality.Semantic.DeepDerivative(expected.Spec, it.Spec) {
+       if !equality.Semantic.DeepDerivative(expected.Spec, it.Spec) || 
operatorIdChanged {
+               action.L.Info("Monitor: KameletBinding needs a rebuild")
+
                // KameletBinding has changed and needs rebuild
                target := kameletbinding.DeepCopy()
                // Rebuild the integration

Reply via email to