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/22 12:15:09 UTC

[camel-k] branch main updated (43318206c -> fab227dc0)

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 43318206c chore(deps): bump github.com/google/uuid from 1.3.0 to 1.3.1
     new 91c9ff923 chore(trait): remove autogenerated cm code
     new e928b6786 fix(ctrl): allow rebuild after configmap/secret change
     new 7d16b8b29 feat(ctrl): confimap and secret hot reload
     new 4960c7efd feat(test): hot reload cm/secrets
     new aece6c993 chore: default catalog build time to 2 mins
     new fab227dc0 feat(trait): hot reload option

The 6 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:
 .../camel.apache.org_integrationplatforms.yaml     |   8 ++
 .../crd/bases/camel.apache.org_integrations.yaml   |   4 +
 .../bases/camel.apache.org_kameletbindings.yaml    |   4 +
 config/crd/bases/camel.apache.org_pipes.yaml       |   4 +
 docs/modules/ROOT/partials/apis/camel-k-crds.adoc  |   7 ++
 docs/modules/traits/pages/mount.adoc               |   4 +
 e2e/common/config/config_reload_test.go            |  97 ++++++++++++++++
 e2e/support/test_support.go                        |  15 +++
 helm/camel-k/crds/crd-integration-platform.yaml    |   8 ++
 helm/camel-k/crds/crd-integration.yaml             |   4 +
 helm/camel-k/crds/crd-kamelet-binding.yaml         |   4 +
 helm/camel-k/crds/crd-pipe.yaml                    |   4 +
 pkg/apis/camel/v1/trait/mount.go                   |   2 +
 pkg/apis/camel/v1/trait/zz_generated.deepcopy.go   |   5 +
 pkg/controller/integration/build_kit.go            |   4 +-
 .../integration/integration_controller.go          | 126 ++++++++++++++++++++-
 pkg/controller/integration/monitor.go              |  43 ++++++-
 pkg/platform/defaults.go                           |   4 +-
 pkg/trait/mount.go                                 |  17 ---
 pkg/util/digest/digest.go                          |  16 ++-
 pkg/util/digest/digest_test.go                     |   6 +-
 pkg/util/resource/config.go                        |  42 -------
 resources/traits.yaml                              |   4 +
 23 files changed, 358 insertions(+), 74 deletions(-)
 create mode 100644 e2e/common/config/config_reload_test.go


[camel-k] 06/06: feat(trait): hot reload option

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 fab227dc03b9a6e39fd6fcaf9d7f97db947bc50c
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Tue Aug 22 09:07:35 2023 +0200

    feat(trait): hot reload option
---
 .../camel.apache.org_integrationplatforms.yaml     |  8 +++++++
 .../crd/bases/camel.apache.org_integrations.yaml   |  4 ++++
 .../bases/camel.apache.org_kameletbindings.yaml    |  4 ++++
 config/crd/bases/camel.apache.org_pipes.yaml       |  4 ++++
 docs/modules/ROOT/partials/apis/camel-k-crds.adoc  |  7 ++++++
 docs/modules/traits/pages/mount.adoc               |  4 ++++
 e2e/common/config/config_reload_test.go            | 25 ++++++++++++++++++++++
 helm/camel-k/crds/crd-integration-platform.yaml    |  8 +++++++
 helm/camel-k/crds/crd-integration.yaml             |  4 ++++
 helm/camel-k/crds/crd-kamelet-binding.yaml         |  4 ++++
 helm/camel-k/crds/crd-pipe.yaml                    |  4 ++++
 pkg/apis/camel/v1/trait/mount.go                   |  2 ++
 pkg/apis/camel/v1/trait/zz_generated.deepcopy.go   |  5 +++++
 .../integration/integration_controller.go          |  5 +++--
 resources/traits.yaml                              |  4 ++++
 15 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/config/crd/bases/camel.apache.org_integrationplatforms.yaml b/config/crd/bases/camel.apache.org_integrationplatforms.yaml
index ba79f08de..5b8fcb43c 100644
--- a/config/crd/bases/camel.apache.org_integrationplatforms.yaml
+++ b/config/crd/bases/camel.apache.org_integrationplatforms.yaml
@@ -1384,6 +1384,10 @@ spec:
                         description: Can be used to enable or disable a trait. All
                           traits share this common property.
                         type: boolean
+                      hotReload:
+                        description: Enable "hot reload" when a secret/configmap mounted
+                          is edited (default true)
+                        type: boolean
                       resources:
                         description: 'A list of resources (text or binary content)
                           pointing to configmap/secret. The resources are expected
@@ -3140,6 +3144,10 @@ spec:
                         description: Can be used to enable or disable a trait. All
                           traits share this common property.
                         type: boolean
+                      hotReload:
+                        description: Enable "hot reload" when a secret/configmap mounted
+                          is edited (default true)
+                        type: boolean
                       resources:
                         description: 'A list of resources (text or binary content)
                           pointing to configmap/secret. The resources are expected
diff --git a/config/crd/bases/camel.apache.org_integrations.yaml b/config/crd/bases/camel.apache.org_integrations.yaml
index 92b5c93eb..0f6b328fb 100644
--- a/config/crd/bases/camel.apache.org_integrations.yaml
+++ b/config/crd/bases/camel.apache.org_integrations.yaml
@@ -7067,6 +7067,10 @@ spec:
                         description: Can be used to enable or disable a trait. All
                           traits share this common property.
                         type: boolean
+                      hotReload:
+                        description: Enable "hot reload" when a secret/configmap mounted
+                          is edited (default true)
+                        type: boolean
                       resources:
                         description: 'A list of resources (text or binary content)
                           pointing to configmap/secret. The resources are expected
diff --git a/config/crd/bases/camel.apache.org_kameletbindings.yaml b/config/crd/bases/camel.apache.org_kameletbindings.yaml
index f05ef63a4..e0a56fcf5 100644
--- a/config/crd/bases/camel.apache.org_kameletbindings.yaml
+++ b/config/crd/bases/camel.apache.org_kameletbindings.yaml
@@ -7355,6 +7355,10 @@ spec:
                             description: Can be used to enable or disable a trait.
                               All traits share this common property.
                             type: boolean
+                          hotReload:
+                            description: Enable "hot reload" when a secret/configmap
+                              mounted is edited (default true)
+                            type: boolean
                           resources:
                             description: 'A list of resources (text or binary content)
                               pointing to configmap/secret. The resources are expected
diff --git a/config/crd/bases/camel.apache.org_pipes.yaml b/config/crd/bases/camel.apache.org_pipes.yaml
index 076dad280..76a0ade90 100644
--- a/config/crd/bases/camel.apache.org_pipes.yaml
+++ b/config/crd/bases/camel.apache.org_pipes.yaml
@@ -7352,6 +7352,10 @@ spec:
                             description: Can be used to enable or disable a trait.
                               All traits share this common property.
                             type: boolean
+                          hotReload:
+                            description: Enable "hot reload" when a secret/configmap
+                              mounted is edited (default true)
+                            type: boolean
                           resources:
                             description: 'A list of resources (text or binary content)
                               pointing to configmap/secret. The resources are expected
diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index a7d86ea4e..d0480ef70 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -6856,6 +6856,13 @@ Syntax: [configmap{vbar}secret]:name[/key][@path], where name represents the res
 
 A list of Persistent Volume Claims to be mounted. Syntax: [pvcname:/container/path]
 
+|`hotReload` +
+bool
+|
+
+
+Enable "hot reload" when a secret/configmap mounted is edited (default true)
+
 
 |===
 
diff --git a/docs/modules/traits/pages/mount.adoc b/docs/modules/traits/pages/mount.adoc
index 45f5503d4..2847d362a 100644
--- a/docs/modules/traits/pages/mount.adoc
+++ b/docs/modules/traits/pages/mount.adoc
@@ -45,6 +45,10 @@ Syntax: [configmap\|secret]:name[/key][@path], where name represents the resourc
 | []string
 | A list of Persistent Volume Claims to be mounted. Syntax: [pvcname:/container/path]
 
+| mount.hot-reload
+| bool
+| Enable "hot reload" when a secret/configmap mounted is edited (default true)
+
 |===
 
 // End of autogenerated code - DO NOT EDIT! (configuration)
diff --git a/e2e/common/config/config_reload_test.go b/e2e/common/config/config_reload_test.go
index 71106d1ce..c419838f8 100644
--- a/e2e/common/config/config_reload_test.go
+++ b/e2e/common/config/config_reload_test.go
@@ -52,6 +52,31 @@ func TestConfigmapHotReload(t *testing.T) {
 	Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
 }
 
+func TestConfigmapHotReloadFalse(t *testing.T) {
+	RegisterTestingT(t)
+
+	var cmData = make(map[string]string)
+	cmData["my-configmap-key"] = "my configmap content"
+	CreatePlainTextConfigmap(ns, "my-hot-cm-2", cmData)
+
+	Expect(KamelRunWithID(operatorID, ns, "./files/config-configmap-route.groovy",
+		"--config",
+		"configmap:my-hot-cm-2",
+		// DO NOT hot reload
+		"-t",
+		"mount.hot-reload=false",
+	).Execute()).To(Succeed())
+	Eventually(IntegrationPodPhase(ns, "config-configmap-route"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+	Eventually(IntegrationConditionStatus(ns, "config-configmap-route", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+	Eventually(IntegrationLogs(ns, "config-configmap-route"), TestTimeoutShort).Should(ContainSubstring("my configmap content"))
+
+	cmData["my-configmap-key"] = "my configmap content updated"
+	UpdatePlainTextConfigmap(ns, "my-hot-cm-2", cmData)
+	Eventually(IntegrationLogs(ns, "config-configmap-route"), TestTimeoutShort).Should(Not(ContainSubstring("my configmap content updated")))
+
+	Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+}
+
 func TestSecretHotReload(t *testing.T) {
 	RegisterTestingT(t)
 
diff --git a/helm/camel-k/crds/crd-integration-platform.yaml b/helm/camel-k/crds/crd-integration-platform.yaml
index ba79f08de..5b8fcb43c 100644
--- a/helm/camel-k/crds/crd-integration-platform.yaml
+++ b/helm/camel-k/crds/crd-integration-platform.yaml
@@ -1384,6 +1384,10 @@ spec:
                         description: Can be used to enable or disable a trait. All
                           traits share this common property.
                         type: boolean
+                      hotReload:
+                        description: Enable "hot reload" when a secret/configmap mounted
+                          is edited (default true)
+                        type: boolean
                       resources:
                         description: 'A list of resources (text or binary content)
                           pointing to configmap/secret. The resources are expected
@@ -3140,6 +3144,10 @@ spec:
                         description: Can be used to enable or disable a trait. All
                           traits share this common property.
                         type: boolean
+                      hotReload:
+                        description: Enable "hot reload" when a secret/configmap mounted
+                          is edited (default true)
+                        type: boolean
                       resources:
                         description: 'A list of resources (text or binary content)
                           pointing to configmap/secret. The resources are expected
diff --git a/helm/camel-k/crds/crd-integration.yaml b/helm/camel-k/crds/crd-integration.yaml
index 92b5c93eb..0f6b328fb 100644
--- a/helm/camel-k/crds/crd-integration.yaml
+++ b/helm/camel-k/crds/crd-integration.yaml
@@ -7067,6 +7067,10 @@ spec:
                         description: Can be used to enable or disable a trait. All
                           traits share this common property.
                         type: boolean
+                      hotReload:
+                        description: Enable "hot reload" when a secret/configmap mounted
+                          is edited (default true)
+                        type: boolean
                       resources:
                         description: 'A list of resources (text or binary content)
                           pointing to configmap/secret. The resources are expected
diff --git a/helm/camel-k/crds/crd-kamelet-binding.yaml b/helm/camel-k/crds/crd-kamelet-binding.yaml
index f05ef63a4..e0a56fcf5 100644
--- a/helm/camel-k/crds/crd-kamelet-binding.yaml
+++ b/helm/camel-k/crds/crd-kamelet-binding.yaml
@@ -7355,6 +7355,10 @@ spec:
                             description: Can be used to enable or disable a trait.
                               All traits share this common property.
                             type: boolean
+                          hotReload:
+                            description: Enable "hot reload" when a secret/configmap
+                              mounted is edited (default true)
+                            type: boolean
                           resources:
                             description: 'A list of resources (text or binary content)
                               pointing to configmap/secret. The resources are expected
diff --git a/helm/camel-k/crds/crd-pipe.yaml b/helm/camel-k/crds/crd-pipe.yaml
index 076dad280..76a0ade90 100644
--- a/helm/camel-k/crds/crd-pipe.yaml
+++ b/helm/camel-k/crds/crd-pipe.yaml
@@ -7352,6 +7352,10 @@ spec:
                             description: Can be used to enable or disable a trait.
                               All traits share this common property.
                             type: boolean
+                          hotReload:
+                            description: Enable "hot reload" when a secret/configmap
+                              mounted is edited (default true)
+                            type: boolean
                           resources:
                             description: 'A list of resources (text or binary content)
                               pointing to configmap/secret. The resources are expected
diff --git a/pkg/apis/camel/v1/trait/mount.go b/pkg/apis/camel/v1/trait/mount.go
index 284debb8a..2782a0eb3 100644
--- a/pkg/apis/camel/v1/trait/mount.go
+++ b/pkg/apis/camel/v1/trait/mount.go
@@ -35,4 +35,6 @@ type MountTrait struct {
 	Resources []string `property:"resources" json:"resources,omitempty"`
 	// A list of Persistent Volume Claims to be mounted. Syntax: [pvcname:/container/path]
 	Volumes []string `property:"volumes" json:"volumes,omitempty"`
+	// Enable "hot reload" when a secret/configmap mounted is edited (default true)
+	HotReload *bool `property:"hot-reload" json:"hotReload,omitempty"`
 }
diff --git a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
index c1d0423f9..bad665a54 100644
--- a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
@@ -685,6 +685,11 @@ func (in *MountTrait) DeepCopyInto(out *MountTrait) {
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
+	if in.HotReload != nil {
+		in, out := &in.HotReload, &out.HotReload
+		*out = new(bool)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MountTrait.
diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index 51970810d..c4013d382 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -31,6 +31,7 @@ import (
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/client-go/tools/record"
+	"k8s.io/utils/pointer"
 
 	"sigs.k8s.io/controller-runtime/pkg/builder"
 	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
@@ -186,7 +187,7 @@ func configmapEnqueueRequestsFromMapFunc(ctx context.Context, c client.Client, c
 
 	for _, integration := range list.Items {
 		found := false
-		if integration.Spec.Traits.Mount == nil {
+		if integration.Spec.Traits.Mount == nil || !pointer.BoolDeref(integration.Spec.Traits.Mount.HotReload, true) {
 			continue
 		}
 		for _, c := range integration.Spec.Traits.Mount.Configs {
@@ -236,7 +237,7 @@ func secretEnqueueRequestsFromMapFunc(ctx context.Context, c client.Client, sec
 
 	for _, integration := range list.Items {
 		found := false
-		if integration.Spec.Traits.Mount == nil {
+		if integration.Spec.Traits.Mount == nil || !pointer.BoolDeref(integration.Spec.Traits.Mount.HotReload, true) {
 			continue
 		}
 		for _, c := range integration.Spec.Traits.Mount.Configs {
diff --git a/resources/traits.yaml b/resources/traits.yaml
index 94a178c8c..863267f3b 100755
--- a/resources/traits.yaml
+++ b/resources/traits.yaml
@@ -1132,6 +1132,10 @@ traits:
   - name: volumes
     type: '[]string'
     description: 'A list of Persistent Volume Claims to be mounted. Syntax: [pvcname:/container/path]'
+  - name: hot-reload
+    type: bool
+    description: Enable "hot reload" when a secret/configmap mounted is edited (default
+      true)
 - name: openapi
   platform: true
   profiles:


[camel-k] 01/06: chore(trait): remove autogenerated cm code

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 91c9ff9234f18039cd834f4e51436b1d9d4fb2ac
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Fri Aug 11 09:22:53 2023 +0200

    chore(trait): remove autogenerated cm code
---
 pkg/trait/mount.go          | 17 -----------------
 pkg/util/resource/config.go | 42 ------------------------------------------
 2 files changed, 59 deletions(-)

diff --git a/pkg/trait/mount.go b/pkg/trait/mount.go
index 1e5bf19d0..eaf58a9c3 100644
--- a/pkg/trait/mount.go
+++ b/pkg/trait/mount.go
@@ -25,7 +25,6 @@ import (
 	appsv1 "k8s.io/api/apps/v1"
 	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/utils/pointer"
 
 	serving "knative.dev/serving/pkg/apis/serving/v1"
@@ -129,7 +128,6 @@ func (t *mountTrait) Apply(e *Environment) error {
 func (t *mountTrait) configureVolumesAndMounts(e *Environment, vols *[]corev1.Volume, mnts *[]corev1.VolumeMount) error {
 	for _, c := range t.Configs {
 		if conf, parseErr := utilResource.ParseConfig(c); parseErr == nil {
-			t.attachResource(e, conf)
 			t.mountResource(vols, mnts, conf)
 		} else {
 			return parseErr
@@ -137,7 +135,6 @@ func (t *mountTrait) configureVolumesAndMounts(e *Environment, vols *[]corev1.Vo
 	}
 	for _, r := range t.Resources {
 		if res, parseErr := utilResource.ParseResource(r); parseErr == nil {
-			t.attachResource(e, res)
 			t.mountResource(vols, mnts, res)
 		} else {
 			return parseErr
@@ -154,20 +151,6 @@ func (t *mountTrait) configureVolumesAndMounts(e *Environment, vols *[]corev1.Vo
 	return nil
 }
 
-// attachResource is in charge to filter the autogenerated configmap and attach to the Integration resources.
-// The owner trait will be in charge to bind it accordingly.
-func (t *mountTrait) attachResource(e *Environment, conf *utilResource.Config) {
-	if conf.StorageType() == utilResource.StorageTypeConfigmap {
-		// verify if it was autogenerated
-		cm, err := kubernetes.GetUnstructured(e.Ctx, e.Client, schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"},
-			conf.Name(), e.Integration.Namespace)
-		if err == nil && cm != nil && cm.GetLabels()[kubernetes.ConfigMapAutogenLabel] == "true" {
-			refCm := kubernetes.NewConfigMap(e.Integration.Namespace, conf.Name(), "", "", "", nil)
-			e.Resources.Add(refCm)
-		}
-	}
-}
-
 func (t *mountTrait) mountResource(vols *[]corev1.Volume, mnts *[]corev1.VolumeMount, conf *utilResource.Config) {
 	refName := kubernetes.SanitizeLabel(conf.Name())
 	dstDir := conf.DestinationPath()
diff --git a/pkg/util/resource/config.go b/pkg/util/resource/config.go
index 474c14aee..8f52444ea 100644
--- a/pkg/util/resource/config.go
+++ b/pkg/util/resource/config.go
@@ -18,18 +18,10 @@ limitations under the License.
 package resource
 
 import (
-	"context"
 	"crypto/sha1" // nolint: gosec
 	"fmt"
-	"path/filepath"
 	"regexp"
 	"strings"
-
-	"github.com/apache/camel-k/v2/pkg/client"
-	"github.com/apache/camel-k/v2/pkg/util/camel"
-	"github.com/apache/camel-k/v2/pkg/util/kubernetes"
-	corev1 "k8s.io/api/core/v1"
-	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 )
 
 // Config represents a config option.
@@ -184,40 +176,6 @@ func parse(item string, contentType ContentType) (*Config, error) {
 	return newConfig(cot, contentType, value), nil
 }
 
-// ConvertFileToConfigmap convert a local file resource type in a configmap type
-// taking care to create the Configmap on the cluster. The method will change the value of config parameter
-// to reflect the conversion applied transparently.
-func ConvertFileToConfigmap(ctx context.Context, c client.Client, config *Config, namespace string, integrationName string,
-	content string, rawContent []byte) (*corev1.ConfigMap, error) {
-	filename := filepath.Base(config.Name())
-	if config.DestinationPath() == "" {
-		config.resourceKey = filename
-		// As we are changing the resource to a configmap type
-		// we must declare the destination path
-		if config.ContentType() == ContentTypeData {
-			config.destinationPath = camel.ResourcesDefaultMountPath + "/" + filename
-		} else {
-			config.destinationPath = camel.ConfigResourcesMountPath + "/" + filename
-		}
-	} else {
-		config.resourceKey = filepath.Base(config.DestinationPath())
-	}
-	genCmName := fmt.Sprintf("cm-%s", hashFrom([]byte(filename), []byte(integrationName), []byte(content), rawContent))
-	cm := kubernetes.NewConfigMap(namespace, genCmName, filename, config.Key(), content, rawContent)
-	err := c.Create(ctx, cm)
-	if err != nil {
-		if k8serrors.IsAlreadyExists(err) {
-			// We'll reuse it, as is
-		} else {
-			return cm, err
-		}
-	}
-	config.storageType = StorageTypeConfigmap
-	config.resourceName = cm.Name
-
-	return cm, nil
-}
-
 func hashFrom(contents ...[]byte) string {
 	// SHA1 because we need to limit the length to less than 64 chars
 	hash := sha1.New() // nolint: gosec


[camel-k] 02/06: fix(ctrl): allow rebuild after configmap/secret change

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 e928b678606b580dc5e41db189c475aa1ed8f6fb
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Fri Aug 11 11:56:37 2023 +0200

    fix(ctrl): allow rebuild after configmap/secret change
    
    * kamel rebuild command will rollout a new deployment reflecting the changes
    
    Ref #1235
---
 pkg/controller/integration/build_kit.go            |  4 +--
 .../integration/integration_controller.go          |  3 +-
 pkg/controller/integration/monitor.go              | 32 ++++++++++++++++++----
 pkg/util/digest/digest.go                          | 16 ++++++++++-
 pkg/util/digest/digest_test.go                     |  6 ++--
 5 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/pkg/controller/integration/build_kit.go b/pkg/controller/integration/build_kit.go
index a110218d9..a2f3f4238 100644
--- a/pkg/controller/integration/build_kit.go
+++ b/pkg/controller/integration/build_kit.go
@@ -46,8 +46,8 @@ func (action *buildKitAction) CanHandle(integration *v1.Integration) bool {
 func (action *buildKitAction) Handle(ctx context.Context, integration *v1.Integration) (*v1.Integration, error) {
 	// TODO: we may need to add a timeout strategy, i.e give up after some time in case of an unrecoverable error.
 
-	// Check if the Integration has changed and requires a rebuild
-	hash, err := digest.ComputeForIntegration(integration)
+	secrets, configmaps := getIntegrationSecretsAndConfigmaps(ctx, action.client, integration)
+	hash, err := digest.ComputeForIntegration(integration, configmaps, secrets)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index 54af147c2..e39249c91 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -384,7 +384,8 @@ func (r *reconcileIntegration) Reconcile(ctx context.Context, request reconcile.
 }
 
 func (r *reconcileIntegration) update(ctx context.Context, base *v1.Integration, target *v1.Integration, log *log.Logger) error {
-	d, err := digest.ComputeForIntegration(target)
+	secrets, configmaps := getIntegrationSecretsAndConfigmaps(ctx, r.client, target)
+	d, err := digest.ComputeForIntegration(target, configmaps, secrets)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/controller/integration/monitor.go b/pkg/controller/integration/monitor.go
index c9c1ccc5e..471b1fbda 100644
--- a/pkg/controller/integration/monitor.go
+++ b/pkg/controller/integration/monitor.go
@@ -36,9 +36,11 @@ import (
 	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
 
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/v2/pkg/client"
 	"github.com/apache/camel-k/v2/pkg/trait"
 	"github.com/apache/camel-k/v2/pkg/util/digest"
 	"github.com/apache/camel-k/v2/pkg/util/kubernetes"
+	utilResource "github.com/apache/camel-k/v2/pkg/util/resource"
 )
 
 func NewMonitorAction() Action {
@@ -64,7 +66,7 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
 	// so handle it differently from the rest
 	if isInInitializationFailed(integration.Status) {
 		// Only check if the Integration requires a rebuild
-		return action.checkDigestAndRebuild(integration, nil)
+		return action.checkDigestAndRebuild(ctx, integration, nil)
 	}
 
 	// At that staged the Integration must have a Kit
@@ -80,7 +82,7 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
 	}
 
 	// Check if the Integration requires a rebuild
-	if changed, err := action.checkDigestAndRebuild(integration, kit); err != nil {
+	if changed, err := action.checkDigestAndRebuild(ctx, integration, kit); err != nil {
 		return nil, err
 	} else if changed != nil {
 		return changed, nil
@@ -175,10 +177,9 @@ func isInInitializationFailed(status v1.IntegrationStatus) bool {
 	return false
 }
 
-func (action *monitorAction) checkDigestAndRebuild(
-	integration *v1.Integration, kit *v1.IntegrationKit,
-) (*v1.Integration, error) {
-	hash, err := digest.ComputeForIntegration(integration)
+func (action *monitorAction) checkDigestAndRebuild(ctx context.Context, integration *v1.Integration, kit *v1.IntegrationKit) (*v1.Integration, error) {
+	secrets, configmaps := getIntegrationSecretsAndConfigmaps(ctx, action.client, integration)
+	hash, err := digest.ComputeForIntegration(integration, configmaps, secrets)
 	if err != nil {
 		return nil, err
 	}
@@ -203,6 +204,25 @@ func (action *monitorAction) checkDigestAndRebuild(
 	return nil, nil
 }
 
+func getIntegrationSecretsAndConfigmaps(ctx context.Context, client client.Client, integration *v1.Integration) ([]*corev1.Secret, []*corev1.ConfigMap) {
+	configmaps := make([]*corev1.ConfigMap, 0)
+	secrets := make([]*corev1.Secret, 0)
+	if integration.Spec.Traits.Mount != nil {
+		for _, c := range integration.Spec.Traits.Mount.Configs {
+			if conf, parseErr := utilResource.ParseConfig(c); parseErr == nil {
+				if conf.StorageType() == utilResource.StorageTypeConfigmap {
+					configmap := kubernetes.LookupConfigmap(ctx, client, integration.Namespace, conf.Name())
+					configmaps = append(configmaps, configmap)
+				} else if conf.StorageType() == utilResource.StorageTypeSecret {
+					secret := kubernetes.LookupSecret(ctx, client, integration.Namespace, conf.Name())
+					secrets = append(secrets, secret)
+				}
+			}
+		}
+	}
+	return secrets, configmaps
+}
+
 type controller interface {
 	checkReadyCondition(ctx context.Context) (bool, error)
 	getPodSpec() corev1.PodSpec
diff --git a/pkg/util/digest/digest.go b/pkg/util/digest/digest.go
index 8f252998e..ed5e8331d 100644
--- a/pkg/util/digest/digest.go
+++ b/pkg/util/digest/digest.go
@@ -36,15 +36,17 @@ import (
 	"github.com/apache/camel-k/v2/pkg/util"
 	"github.com/apache/camel-k/v2/pkg/util/defaults"
 	"github.com/apache/camel-k/v2/pkg/util/dsl"
+	corev1 "k8s.io/api/core/v1"
 )
 
 const (
+	// IntegrationDigestEnvVar --
 	IntegrationDigestEnvVar = "CAMEL_K_DIGEST"
 )
 
 // ComputeForIntegration a digest of the fields that are relevant for the deployment
 // Produces a digest that can be used as docker image tag.
-func ComputeForIntegration(integration *v1.Integration) (string, error) {
+func ComputeForIntegration(integration *v1.Integration, configmaps []*corev1.ConfigMap, secrets []*corev1.Secret) (string, error) {
 	hash := sha256.New()
 	// Integration version is relevant
 	if _, err := hash.Write([]byte(integration.Status.Version)); err != nil {
@@ -134,6 +136,18 @@ func ComputeForIntegration(integration *v1.Integration) (string, error) {
 		}
 	}
 
+	// Configmap and secret content
+	for _, cm := range configmaps {
+		if _, err := hash.Write([]byte(cm.String())); err != nil {
+			return "", err
+		}
+	}
+	for _, s := range secrets {
+		if _, err := hash.Write([]byte(s.String())); err != nil {
+			return "", err
+		}
+	}
+
 	// Add a letter at the beginning and use URL safe encoding
 	digest := "v" + base64.RawURLEncoding.EncodeToString(hash.Sum(nil))
 	return digest, nil
diff --git a/pkg/util/digest/digest_test.go b/pkg/util/digest/digest_test.go
index f015b576e..3139b88c3 100644
--- a/pkg/util/digest/digest_test.go
+++ b/pkg/util/digest/digest_test.go
@@ -27,13 +27,13 @@ import (
 
 func TestDigestUsesAnnotations(t *testing.T) {
 	it := v1.Integration{}
-	digest1, err := ComputeForIntegration(&it)
+	digest1, err := ComputeForIntegration(&it, nil, nil)
 	assert.NoError(t, err)
 
 	it.Annotations = map[string]string{
 		"another.annotation": "hello",
 	}
-	digest2, err := ComputeForIntegration(&it)
+	digest2, err := ComputeForIntegration(&it, nil, nil)
 	assert.NoError(t, err)
 	assert.Equal(t, digest1, digest2)
 
@@ -41,7 +41,7 @@ func TestDigestUsesAnnotations(t *testing.T) {
 		"another.annotation":                   "hello",
 		"trait.camel.apache.org/cron.fallback": "true",
 	}
-	digest3, err := ComputeForIntegration(&it)
+	digest3, err := ComputeForIntegration(&it, nil, nil)
 	assert.NoError(t, err)
 	assert.NotEqual(t, digest1, digest3)
 }


[camel-k] 03/06: feat(ctrl): confimap and secret hot reload

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 7d16b8b29808cb86db4de51f43b8b2529abc3a21
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Fri Aug 11 15:31:41 2023 +0200

    feat(ctrl): confimap and secret hot reload
    
    Watch the resources and if they belong to an Integration, kick a reconcile loop
---
 .../integration/integration_controller.go          | 122 +++++++++++++++++++++
 pkg/controller/integration/monitor.go              |  11 ++
 2 files changed, 133 insertions(+)

diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index e39249c91..51970810d 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -52,6 +52,7 @@ import (
 	"github.com/apache/camel-k/v2/pkg/util/kubernetes"
 	"github.com/apache/camel-k/v2/pkg/util/log"
 	"github.com/apache/camel-k/v2/pkg/util/monitoring"
+	utilResource "github.com/apache/camel-k/v2/pkg/util/resource"
 )
 
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
@@ -168,6 +169,106 @@ func integrationKitEnqueueRequestsFromMapFunc(ctx context.Context, c client.Clie
 	return requests
 }
 
+func configmapEnqueueRequestsFromMapFunc(ctx context.Context, c client.Client, cm *corev1.ConfigMap) []reconcile.Request {
+	var requests []reconcile.Request
+
+	// Do global search in case of global operator (it may be using a global platform)
+	list := &v1.IntegrationList{}
+	var opts []ctrl.ListOption
+	if !platform.IsCurrentOperatorGlobal() {
+		opts = append(opts, ctrl.InNamespace(cm.Namespace))
+	}
+
+	if err := c.List(ctx, list, opts...); err != nil {
+		log.Error(err, "Failed to list integrations")
+		return requests
+	}
+
+	for _, integration := range list.Items {
+		found := false
+		if integration.Spec.Traits.Mount == nil {
+			continue
+		}
+		for _, c := range integration.Spec.Traits.Mount.Configs {
+			if conf, parseErr := utilResource.ParseConfig(c); parseErr == nil {
+				if conf.StorageType() == utilResource.StorageTypeConfigmap && conf.Name() == cm.Name {
+					found = true
+					break
+				}
+			}
+		}
+		for _, r := range integration.Spec.Traits.Mount.Resources {
+			if conf, parseErr := utilResource.ParseConfig(r); parseErr == nil {
+				if conf.StorageType() == utilResource.StorageTypeConfigmap && conf.Name() == cm.Name {
+					found = true
+					break
+				}
+			}
+		}
+		if found {
+			log.Infof("Configmap %s updated, wake-up integration: %s", cm.Name, integration.Name)
+			requests = append(requests, reconcile.Request{
+				NamespacedName: types.NamespacedName{
+					Namespace: integration.Namespace,
+					Name:      integration.Name,
+				},
+			})
+		}
+	}
+
+	return requests
+}
+
+func secretEnqueueRequestsFromMapFunc(ctx context.Context, c client.Client, sec *corev1.Secret) []reconcile.Request {
+	var requests []reconcile.Request
+
+	// Do global search in case of global operator (it may be using a global platform)
+	list := &v1.IntegrationList{}
+	var opts []ctrl.ListOption
+	if !platform.IsCurrentOperatorGlobal() {
+		opts = append(opts, ctrl.InNamespace(sec.Namespace))
+	}
+
+	if err := c.List(ctx, list, opts...); err != nil {
+		log.Error(err, "Failed to list integrations")
+		return requests
+	}
+
+	for _, integration := range list.Items {
+		found := false
+		if integration.Spec.Traits.Mount == nil {
+			continue
+		}
+		for _, c := range integration.Spec.Traits.Mount.Configs {
+			if conf, parseErr := utilResource.ParseConfig(c); parseErr == nil {
+				if conf.StorageType() == utilResource.StorageTypeSecret && conf.Name() == sec.Name {
+					found = true
+					break
+				}
+			}
+		}
+		for _, r := range integration.Spec.Traits.Mount.Resources {
+			if conf, parseErr := utilResource.ParseConfig(r); parseErr == nil {
+				if conf.StorageType() == utilResource.StorageTypeSecret && conf.Name() == sec.Name {
+					found = true
+					break
+				}
+			}
+		}
+		if found {
+			log.Infof("Secret %s updated, wake-up integration: %s", sec.Name, integration.Name)
+			requests = append(requests, reconcile.Request{
+				NamespacedName: types.NamespacedName{
+					Namespace: integration.Namespace,
+					Name:      integration.Name,
+				},
+			})
+		}
+	}
+
+	return requests
+}
+
 func integrationPlatformEnqueueRequestsFromMapFunc(ctx context.Context, c client.Client, p *v1.IntegrationPlatform) []reconcile.Request {
 	var requests []reconcile.Request
 
@@ -249,6 +350,27 @@ func add(ctx context.Context, mgr manager.Manager, c client.Client, r reconcile.
 
 				return integrationPlatformEnqueueRequestsFromMapFunc(ctx, c, p)
 			})).
+		// Watch for Configmaps or Secret used in the Integrations for updates.
+		Watches(&source.Kind{Type: &corev1.ConfigMap{}},
+			handler.EnqueueRequestsFromMapFunc(func(a ctrl.Object) []reconcile.Request {
+				cm, ok := a.(*corev1.ConfigMap)
+				if !ok {
+					log.Error(fmt.Errorf("type assertion failed: %v", a), "Failed to retrieve integration list")
+					return []reconcile.Request{}
+				}
+
+				return configmapEnqueueRequestsFromMapFunc(ctx, c, cm)
+			})).
+		Watches(&source.Kind{Type: &corev1.Secret{}},
+			handler.EnqueueRequestsFromMapFunc(func(a ctrl.Object) []reconcile.Request {
+				secret, ok := a.(*corev1.Secret)
+				if !ok {
+					log.Error(fmt.Errorf("type assertion failed: %v", a), "Failed to retrieve integration list")
+					return []reconcile.Request{}
+				}
+
+				return secretEnqueueRequestsFromMapFunc(ctx, c, secret)
+			})).
 		// Watch for the owned Deployments
 		Owns(&appsv1.Deployment{}, builder.WithPredicates(StatusChangedPredicate{})).
 		// Watch for the Integration Pods
diff --git a/pkg/controller/integration/monitor.go b/pkg/controller/integration/monitor.go
index 471b1fbda..04d539174 100644
--- a/pkg/controller/integration/monitor.go
+++ b/pkg/controller/integration/monitor.go
@@ -219,6 +219,17 @@ func getIntegrationSecretsAndConfigmaps(ctx context.Context, client client.Clien
 				}
 			}
 		}
+		for _, r := range integration.Spec.Traits.Mount.Resources {
+			if conf, parseErr := utilResource.ParseConfig(r); parseErr == nil {
+				if conf.StorageType() == utilResource.StorageTypeConfigmap {
+					configmap := kubernetes.LookupConfigmap(ctx, client, integration.Namespace, conf.Name())
+					configmaps = append(configmaps, configmap)
+				} else if conf.StorageType() == utilResource.StorageTypeSecret {
+					secret := kubernetes.LookupSecret(ctx, client, integration.Namespace, conf.Name())
+					secrets = append(secrets, secret)
+				}
+			}
+		}
 	}
 	return secrets, configmaps
 }


[camel-k] 04/06: feat(test): hot reload cm/secrets

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 4960c7efd19f1433fb00e17142062bcdc0061915
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Mon Aug 21 13:07:27 2023 +0200

    feat(test): hot reload cm/secrets
---
 e2e/common/config/config_reload_test.go | 72 +++++++++++++++++++++++++++++++++
 e2e/support/test_support.go             | 15 +++++++
 2 files changed, 87 insertions(+)

diff --git a/e2e/common/config/config_reload_test.go b/e2e/common/config/config_reload_test.go
new file mode 100644
index 000000000..71106d1ce
--- /dev/null
+++ b/e2e/common/config/config_reload_test.go
@@ -0,0 +1,72 @@
+//go:build integration
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import (
+	"testing"
+
+	. "github.com/onsi/gomega"
+
+	corev1 "k8s.io/api/core/v1"
+
+	. "github.com/apache/camel-k/v2/e2e/support"
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+)
+
+func TestConfigmapHotReload(t *testing.T) {
+	RegisterTestingT(t)
+
+	var cmData = make(map[string]string)
+	cmData["my-configmap-key"] = "my configmap content"
+	CreatePlainTextConfigmap(ns, "my-hot-cm", cmData)
+
+	Expect(KamelRunWithID(operatorID, ns, "./files/config-configmap-route.groovy", "--config", "configmap:my-hot-cm").Execute()).To(Succeed())
+	Eventually(IntegrationPodPhase(ns, "config-configmap-route"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+	Eventually(IntegrationConditionStatus(ns, "config-configmap-route", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+	Eventually(IntegrationLogs(ns, "config-configmap-route"), TestTimeoutShort).Should(ContainSubstring("my configmap content"))
+
+	cmData["my-configmap-key"] = "my configmap content updated"
+	UpdatePlainTextConfigmap(ns, "my-hot-cm", cmData)
+	Eventually(IntegrationLogs(ns, "config-configmap-route"), TestTimeoutShort).Should(ContainSubstring("my configmap content updated"))
+
+	Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+}
+
+func TestSecretHotReload(t *testing.T) {
+	RegisterTestingT(t)
+
+	var secData = make(map[string]string)
+	secData["my-secret-key"] = "very top secret"
+	CreatePlainTextSecret(ns, "my-hot-sec", secData)
+
+	Expect(KamelRunWithID(operatorID, ns, "./files/config-secret-route.groovy", "--config", "secret:my-hot-sec").Execute()).To(Succeed())
+	Eventually(IntegrationPodPhase(ns, "config-secret-route"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+	Eventually(IntegrationConditionStatus(ns, "config-secret-route", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+	Eventually(IntegrationLogs(ns, "config-secret-route"), TestTimeoutShort).Should(ContainSubstring("very top secret"))
+
+	secData["my-secret-key"] = "very top secret updated"
+	UpdatePlainTextSecret(ns, "my-hot-sec", secData)
+	Eventually(IntegrationLogs(ns, "config-secret-route"), TestTimeoutShort).Should(ContainSubstring("very top secret updated"))
+
+	Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+}
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index 19af82c72..3de4c50fe 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -1523,6 +1523,21 @@ func CreatePlainTextSecret(ns string, name string, data map[string]string) error
 	return CreatePlainTextSecretWithLabels(ns, name, data, map[string]string{})
 }
 
+func UpdateCreatePlainTextSecret(ns string, name string, data map[string]string) error {
+	sec := corev1.Secret{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "Secret",
+			APIVersion: corev1.SchemeGroupVersion.String(),
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: ns,
+			Name:      name,
+		},
+		StringData: data,
+	}
+	return TestClient().Update(TestContext, &sec)
+}
+
 func CreatePlainTextSecretWithLabels(ns string, name string, data map[string]string, labels map[string]string) error {
 	sec := corev1.Secret{
 		TypeMeta: metav1.TypeMeta{


[camel-k] 05/06: chore: default catalog build time to 2 mins

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 aece6c9937ccbeafe0d20091df899771dedb6c02
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Mon Aug 21 13:07:48 2023 +0200

    chore: default catalog build time to 2 mins
---
 e2e/support/test_support.go | 2 +-
 pkg/platform/defaults.go    | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index 3de4c50fe..9e8e07b1f 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -1523,7 +1523,7 @@ func CreatePlainTextSecret(ns string, name string, data map[string]string) error
 	return CreatePlainTextSecretWithLabels(ns, name, data, map[string]string{})
 }
 
-func UpdateCreatePlainTextSecret(ns string, name string, data map[string]string) error {
+func UpdatePlainTextSecret(ns string, name string, data map[string]string) error {
 	sec := corev1.Secret{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "Secret",
diff --git a/pkg/platform/defaults.go b/pkg/platform/defaults.go
index a7711e4cc..fe732420b 100644
--- a/pkg/platform/defaults.go
+++ b/pkg/platform/defaults.go
@@ -378,9 +378,9 @@ func setPlatformDefaults(p *v1.IntegrationPlatform, verbose bool) error {
 
 	// Catalog tools build timeout
 	if p.Status.Build.GetBuildCatalogToolTimeout().Duration == 0 {
-		log.Debugf("Integration Platform %s [%s]: setting default build camel catalog tool timeout (1 minute)", p.Name, p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting default build camel catalog tool timeout (2 minutes)", p.Name, p.Namespace)
 		p.Status.Build.BuildCatalogToolTimeout = &metav1.Duration{
-			Duration: 1 * time.Minute,
+			Duration: 2 * time.Minute,
 		}
 	} else {
 		d := p.Status.Build.GetBuildCatalogToolTimeout().Duration.Truncate(time.Second)