You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pc...@apache.org on 2023/08/01 08:03:38 UTC

[camel-k] branch main updated (2463f0b38 -> 3988ba34f)

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

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


    from 2463f0b38 chore: nightly SBOM update
     new 35708255b fix(cmd): don't validate on dry-run
     new 629e5ca67 feat(cmd): promote image only
     new 3988ba34f feat(cmd): promote multi tenancy

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 pkg/cmd/promote.go      | 100 ++++++++++++++++++++++++++++++++---------------
 pkg/cmd/promote_test.go | 102 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 166 insertions(+), 36 deletions(-)


[camel-k] 01/03: fix(cmd): don't validate on dry-run

Posted by pc...@apache.org.
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 35708255bbe84dbe92538f33aee8101036dcf435
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Fri Jul 28 14:52:17 2023 +0200

    fix(cmd): don't validate on dry-run
    
    Closes #4534
---
 pkg/cmd/promote.go      | 52 ++++++++++++++++++++++++++++---------------------
 pkg/cmd/promote_test.go |  7 ++-----
 2 files changed, 32 insertions(+), 27 deletions(-)

diff --git a/pkg/cmd/promote.go b/pkg/cmd/promote.go
index b87170f73..e332f4da2 100644
--- a/pkg/cmd/promote.go
+++ b/pkg/cmd/promote.go
@@ -88,19 +88,23 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args []string) error {
 	if err != nil {
 		return fmt.Errorf("could not retrieve cluster client: %w", err)
 	}
-	opSource, err := operatorInfo(o.Context, c, o.Namespace)
-	if err != nil {
-		return fmt.Errorf("could not retrieve info for Camel K operator source: %w", err)
-	}
-	opDest, err := operatorInfo(o.Context, c, o.To)
-	if err != nil {
-		return fmt.Errorf("could not retrieve info for Camel K operator destination: %w", err)
-	}
+	if o.OutputFormat == "" {
+		// Skip these checks if in dry mode
+		opSource, err := operatorInfo(o.Context, c, o.Namespace)
+		if err != nil {
+			return fmt.Errorf("could not retrieve info for Camel K operator source: %w", err)
+		}
+		opDest, err := operatorInfo(o.Context, c, o.To)
+		if err != nil {
+			return fmt.Errorf("could not retrieve info for Camel K operator destination: %w", err)
+		}
 
-	err = checkOpsCompatibility(cmd, opSource, opDest)
-	if err != nil {
-		return fmt.Errorf("could not verify operators compatibility: %w", err)
+		err = checkOpsCompatibility(cmd, opSource, opDest)
+		if err != nil {
+			return fmt.Errorf("could not verify operators compatibility: %w", err)
+		}
 	}
+
 	promotePipe := false
 	var sourceIntegration *v1.Integration
 	// We first look if a Pipe with the name exists
@@ -118,41 +122,45 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args []string) error {
 	if sourceIntegration.Status.Phase != v1.IntegrationPhaseRunning {
 		return fmt.Errorf("could not promote an Integration in %s status", sourceIntegration.Status.Phase)
 	}
-	err = o.validateDestResources(c, sourceIntegration)
-	if err != nil {
-		return fmt.Errorf("could not validate destination resources: %w", err)
+
+	if o.OutputFormat == "" {
+		// Skip these checks if in dry mode
+		err = o.validateDestResources(c, sourceIntegration)
+		if err != nil {
+			return fmt.Errorf("could not validate destination resources: %w", err)
+		}
 	}
 
 	// Pipe promotion
 	if promotePipe {
 		destPipe := o.editPipe(sourcePipe, sourceIntegration)
+		if o.OutputFormat != "" {
+			return showPipeOutput(cmd, destPipe, o.OutputFormat, c.GetScheme())
+		}
 		// Ensure the destination namespace has access to the source namespace images
 		err = addSystemPullerRoleBinding(o.Context, c, sourceIntegration.Namespace, destPipe.Namespace)
 		if err != nil {
 			return err
 		}
 		replaced, err := o.replaceResource(destPipe)
-		if o.OutputFormat != "" {
-			return showPipeOutput(cmd, destPipe, o.OutputFormat, c.GetScheme())
-		}
 		if !replaced {
-			fmt.Fprintln(cmd.OutOrStdout(), `Promoted Integration "`+name+`" created`)
+			fmt.Fprintln(cmd.OutOrStdout(), `Promoted Pipe "`+name+`" created`)
 		} else {
-			fmt.Fprintln(cmd.OutOrStdout(), `Promoted Integration "`+name+`" updated`)
+			fmt.Fprintln(cmd.OutOrStdout(), `Promoted Pipe "`+name+`" updated`)
 		}
 		return err
 	}
 
 	// Plain Integration promotion
 	destIntegration := o.editIntegration(sourceIntegration)
+	if o.OutputFormat != "" {
+		return showIntegrationOutput(cmd, destIntegration, o.OutputFormat)
+	}
 	// Ensure the destination namespace has access to the source namespace images
 	err = addSystemPullerRoleBinding(o.Context, c, sourceIntegration.Namespace, destIntegration.Namespace)
 	if err != nil {
 		return err
 	}
-	if o.OutputFormat != "" {
-		return showIntegrationOutput(cmd, destIntegration, o.OutputFormat)
-	}
 	replaced, err := o.replaceResource(destIntegration)
 	if !replaced {
 		fmt.Fprintln(cmd.OutOrStdout(), `Promoted Integration "`+name+`" created`)
diff --git a/pkg/cmd/promote_test.go b/pkg/cmd/promote_test.go
index de35de413..22529788a 100644
--- a/pkg/cmd/promote_test.go
+++ b/pkg/cmd/promote_test.go
@@ -65,9 +65,8 @@ func TestIntegrationNotCompatible(t *testing.T) {
 	srcCatalog := createTestCamelCatalog(srcPlatform)
 	dstCatalog := createTestCamelCatalog(dstPlatform)
 
-	promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
-	_, err := test.ExecuteCommand(promoteCmd, cmdPromote, "my-it-test", "--to", "prod-namespace", "-o", "yaml", "-n", "default")
-	assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
+	_, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+	_, err := test.ExecuteCommand(promoteCmd, cmdPromote, "my-it-test", "--to", "prod-namespace", "-n", "default")
 	assert.NotNil(t, err)
 	assert.Equal(t,
 		fmt.Sprintf("could not verify operators compatibility: source (%s) and destination (0.0.1) Camel K operator versions are not compatible", defaults.Version),
@@ -137,7 +136,6 @@ metadata:
   creationTimestamp: null
   name: my-kb-test
   namespace: prod-namespace
-  resourceVersion: "1"
 spec:
   integration:
     traits:
@@ -238,7 +236,6 @@ metadata:
     my-label: my-value
   name: my-kb-test
   namespace: prod-namespace
-  resourceVersion: "1"
 spec:
   integration:
     traits:


[camel-k] 02/03: feat(cmd): promote image only

Posted by pc...@apache.org.
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 629e5ca6774189cd02b1fa4dff917494554d6d57
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Fri Jul 28 15:21:24 2023 +0200

    feat(cmd): promote image only
    
    Ability to show the container image used in some integration
---
 pkg/cmd/promote.go      | 20 ++++++++++++++++++--
 pkg/cmd/promote_test.go | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/pkg/cmd/promote.go b/pkg/cmd/promote.go
index e332f4da2..b12ebc948 100644
--- a/pkg/cmd/promote.go
+++ b/pkg/cmd/promote.go
@@ -58,6 +58,7 @@ func newCmdPromote(rootCmdOptions *RootCmdOptions) (*cobra.Command, *promoteCmdO
 
 	cmd.Flags().String("to", "", "The namespace where to promote the Integration")
 	cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml")
+	cmd.Flags().BoolP("image", "i", false, "Output the container image only")
 
 	return &cmd, &options
 }
@@ -66,6 +67,7 @@ type promoteCmdOptions struct {
 	*RootCmdOptions
 	To           string `mapstructure:"to" yaml:",omitempty"`
 	OutputFormat string `mapstructure:"output" yaml:",omitempty"`
+	Image        bool   `mapstructure:"image" yaml:",omitempty"`
 }
 
 func (o *promoteCmdOptions) validate(_ *cobra.Command, args []string) error {
@@ -88,7 +90,7 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args []string) error {
 	if err != nil {
 		return fmt.Errorf("could not retrieve cluster client: %w", err)
 	}
-	if o.OutputFormat == "" {
+	if !o.isDryRun() {
 		// Skip these checks if in dry mode
 		opSource, err := operatorInfo(o.Context, c, o.Namespace)
 		if err != nil {
@@ -123,7 +125,13 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args []string) error {
 		return fmt.Errorf("could not promote an Integration in %s status", sourceIntegration.Status.Phase)
 	}
 
-	if o.OutputFormat == "" {
+	// Image only mode
+	if o.Image {
+		showImageOnly(cmd, sourceIntegration)
+		return nil
+	}
+
+	if !o.isDryRun() {
 		// Skip these checks if in dry mode
 		err = o.validateDestResources(c, sourceIntegration)
 		if err != nil {
@@ -511,6 +519,10 @@ func (o *promoteCmdOptions) replaceResource(res k8sclient.Object) (bool, error)
 	return kubernetes.ReplaceResource(o.Context, o._client, res)
 }
 
+func (o *promoteCmdOptions) isDryRun() bool {
+	return o.OutputFormat != "" || o.Image
+}
+
 // RoleBinding is required to allow access to images in one namespace
 // by another namespace. Without this on rbac-enabled clusters, the
 // image cannot be pulled.
@@ -541,3 +553,7 @@ func addSystemPullerRoleBinding(ctx context.Context, c client.Client, sourceNS s
 
 	return err
 }
+
+func showImageOnly(cmd *cobra.Command, integration *v1.Integration) {
+	fmt.Fprintln(cmd.OutOrStdout(), integration.Status.Image)
+}
diff --git a/pkg/cmd/promote_test.go b/pkg/cmd/promote_test.go
index 22529788a..f6817ecbe 100644
--- a/pkg/cmd/promote_test.go
+++ b/pkg/cmd/promote_test.go
@@ -246,3 +246,42 @@ spec:
 status: {}
 `, output)
 }
+
+func TestItImageOnly(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)
+
+	_, 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)
+}
+
+func TestPipeImageOnly(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
+	defaultKB := nominalPipe("my-kb-test")
+	defaultIntegration := nominalIntegration("my-kb-test")
+	srcCatalog := createTestCamelCatalog(srcPlatform)
+	dstCatalog := createTestCamelCatalog(dstPlatform)
+
+	_, 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)
+}


[camel-k] 03/03: feat(cmd): promote multi tenancy

Posted by pc...@apache.org.
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 <pa...@gmail.com>
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)
 }