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 3988ba34fb7686a37ae941b99d1e733d9c4c74e3
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Fri Jul 28 16:19:48 2023 +0200

    feat(cmd): promote multi tenancy
    
    Closes #3890
---
 pkg/cmd/promote.go      | 32 ++++++++++++++++++--------
 pkg/cmd/promote_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/pkg/cmd/promote.go b/pkg/cmd/promote.go
index b12ebc948..b15cc0838 100644
--- a/pkg/cmd/promote.go
+++ b/pkg/cmd/promote.go
@@ -49,14 +49,15 @@ func newCmdPromote(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *promoteCmdO
                RootCmdOptions: rootCmdOptions,
        }
        cmd := cobra.Command{
-               Use:     "promote my-it --to [namespace]",
+               Use:     "promote my-it [--to <namespace>] [-x 
<promoted-operator-id>]",
                Short:   "Promote an Integration/Pipe from an environment to 
another",
                Long:    "Promote an Integration/Pipe from an environment to 
another, for example from a Development environment to a Production 
environment",
                PreRunE: decode(&options),
                RunE:    options.run,
        }
 
-       cmd.Flags().String("to", "", "The namespace where to promote the 
Integration")
+       cmd.Flags().String("to", "", "The namespace where to promote the 
Integration/Pipe")
+       cmd.Flags().StringP("to-operator", "x", "", "The operator id which will 
reconcile the promoted Integration/Pipe")
        cmd.Flags().StringP("output", "o", "", "Output format. One of: 
json|yaml")
        cmd.Flags().BoolP("image", "i", false, "Output the container image 
only")
 
@@ -66,16 +67,20 @@ func newCmdPromote(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *promoteCmdO
 type promoteCmdOptions struct {
        *RootCmdOptions
        To           string `mapstructure:"to" yaml:",omitempty"`
+       ToOperator   string `mapstructure:"to-operator" yaml:",omitempty"`
        OutputFormat string `mapstructure:"output" yaml:",omitempty"`
        Image        bool   `mapstructure:"image" yaml:",omitempty"`
 }
 
 func (o *promoteCmdOptions) validate(_ *cobra.Command, args []string) error {
        if len(args) != 1 {
-               return errors.New("promote expects an Integration/Pipe name 
argument")
+               return errors.New("promote requires an Integration/Pipe name 
argument")
        }
        if o.To == "" {
-               return errors.New("promote expects a destination namespace as 
--to argument")
+               return errors.New("promote requires a destination namespace as 
--to argument")
+       }
+       if o.To == o.Namespace {
+               return errors.New("source and destination namespaces must be 
different in order to avoid promoted Integration/Pipe clashes with the source 
Integration/Pipe")
        }
        return nil
 }
@@ -457,7 +462,7 @@ func (o *promoteCmdOptions) editIntegration(it 
*v1.Integration) *v1.Integration
        dst := v1.NewIntegration(o.To, it.Name)
        contImage := it.Status.Image
        dst.Spec = *it.Spec.DeepCopy()
-       dst.Annotations = cloneAnnotations(it.Annotations)
+       dst.Annotations = cloneAnnotations(it.Annotations, o.ToOperator)
        dst.Labels = cloneLabels(it.Labels)
        if dst.Spec.Traits.Container == nil {
                dst.Spec.Traits.Container = &traitv1.ContainerTrait{}
@@ -466,14 +471,23 @@ func (o *promoteCmdOptions) editIntegration(it 
*v1.Integration) *v1.Integration
        return &dst
 }
 
-// Return all annotations but the ones specific to source (ie, the operator).
-func cloneAnnotations(ann map[string]string) map[string]string {
+// Return all annotations overriding the operator Id if provided.
+func cloneAnnotations(ann map[string]string, operatorID string) 
map[string]string {
+       operatorIDAnnotationSet := false
        newMap := make(map[string]string)
        for k, v := range ann {
-               if k != v1.OperatorIDAnnotation {
+               if k == v1.OperatorIDAnnotation {
+                       if operatorID != "" {
+                               newMap[v1.OperatorIDAnnotation] = operatorID
+                               operatorIDAnnotationSet = true
+                       }
+               } else {
                        newMap[k] = v
                }
        }
+       if !operatorIDAnnotationSet && operatorID != "" {
+               newMap[v1.OperatorIDAnnotation] = operatorID
+       }
        return newMap
 }
 
@@ -489,7 +503,7 @@ func cloneLabels(lbs map[string]string) map[string]string {
 func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it *v1.Integration) *v1.Pipe 
{
        dst := v1.NewPipe(o.To, kb.Name)
        dst.Spec = *kb.Spec.DeepCopy()
-       dst.Annotations = cloneAnnotations(kb.Annotations)
+       dst.Annotations = cloneAnnotations(kb.Annotations, o.ToOperator)
        dst.Labels = cloneLabels(kb.Labels)
        contImage := it.Status.Image
        if dst.Spec.Integration == nil {
diff --git a/pkg/cmd/promote_test.go b/pkg/cmd/promote_test.go
index f6817ecbe..bc39d63de 100644
--- a/pkg/cmd/promote_test.go
+++ b/pkg/cmd/promote_test.go
@@ -263,7 +263,7 @@ func TestItImageOnly(t *testing.T) {
        _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-it-test", "--to", "prod-namespace", "-i", "-n", "default")
        assert.Nil(t, err)
-       assert.Equal(t, fmt.Sprintf("my-special-image\n"), output)
+       assert.Equal(t, "my-special-image\n", output)
 }
 
 func TestPipeImageOnly(t *testing.T) {
@@ -283,5 +283,61 @@ func TestPipeImageOnly(t *testing.T) {
        _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultKB, &defaultIntegration, &srcCatalog, &dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-kb-test", "--to", "prod-namespace", "-i", "-n", "default")
        assert.Nil(t, err)
-       assert.Equal(t, fmt.Sprintf("my-special-image\n"), output)
+       assert.Equal(t, "my-special-image\n", output)
+}
+
+func TestIntegrationToOperatorId(t *testing.T) {
+       srcPlatform := v1.NewIntegrationPlatform("default", 
platform.DefaultPlatformName)
+       srcPlatform.Status.Version = defaults.Version
+       srcPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
+       srcPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
+       dstPlatform := v1.NewIntegrationPlatform("prod-namespace", 
platform.DefaultPlatformName)
+       dstPlatform.Status.Version = defaults.Version
+       dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
+       dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
+       defaultIntegration := nominalIntegration("my-it-test")
+       srcCatalog := createTestCamelCatalog(srcPlatform)
+       dstCatalog := createTestCamelCatalog(dstPlatform)
+
+       // Verify default (missing) operator Id
+       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+       output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-it-test", "-x", "my-prod-operator", "-o", "yaml", "--to", "prod")
+       assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
+       assert.Nil(t, err)
+       assert.Equal(t, `apiVersion: camel.apache.org/v1
+kind: Integration
+metadata:
+  annotations:
+    camel.apache.org/operator.id: my-prod-operator
+  creationTimestamp: null
+  name: my-it-test
+  namespace: prod
+spec:
+  traits:
+    container:
+      image: my-special-image
+status: {}
+`, output)
+       // Verify also when the operator Id is set in the integration
+       defaultIntegration.Annotations = map[string]string{
+               "camel.apache.org/operator.id": "camel-k",
+       }
+       promoteCmdOptions, promoteCmd, _ = initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+       output, err = test.ExecuteCommand(promoteCmd, cmdPromote, "my-it-test", 
"-x", "my-prod-operator", "-o", "yaml", "--to", "prod")
+       assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
+       assert.Nil(t, err)
+       assert.Equal(t, `apiVersion: camel.apache.org/v1
+kind: Integration
+metadata:
+  annotations:
+    camel.apache.org/operator.id: my-prod-operator
+  creationTimestamp: null
+  name: my-it-test
+  namespace: prod
+spec:
+  traits:
+    container:
+      image: my-special-image
+status: {}
+`, output)
 }

Reply via email to