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


The following commit(s) were added to refs/heads/main by this push:
     new 25f599324 Compute digest of configmap and secret from its data (#5115)
25f599324 is described below

commit 25f59932476c12f81370fc8abcbacb6926f46fa9
Author: Lucie Krejcirova <lfabr...@redhat.com>
AuthorDate: Mon Feb 12 18:43:25 2024 +0100

    Compute digest of configmap and secret from its data (#5115)
---
 e2e/common/config/config_reload_test.go | 39 +++++++++++++++++
 e2e/support/test_support.go             | 25 +++++++++++
 pkg/util/digest/digest.go               | 61 +++++++++++++++++++++++---
 pkg/util/digest/digest_test.go          | 78 +++++++++++++++++++++++++++++++++
 4 files changed, 197 insertions(+), 6 deletions(-)

diff --git a/e2e/common/config/config_reload_test.go 
b/e2e/common/config/config_reload_test.go
index cb43fac0f..94a18a86b 100644
--- a/e2e/common/config/config_reload_test.go
+++ b/e2e/common/config/config_reload_test.go
@@ -23,6 +23,7 @@ limitations under the License.
 package config
 
 import (
+       "strconv"
        "testing"
 
        . "github.com/onsi/gomega"
@@ -115,3 +116,41 @@ func TestSecretHotReload(t *testing.T) {
 
        Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
 }
+
+func TestConfigmapWithOwnerRefHotReloadDefault(t *testing.T) {
+       CheckConfigmapWithOwnerRef(t, false)
+}
+
+func TestConfigmapWithOwnerRefHotReload(t *testing.T) {
+       CheckConfigmapWithOwnerRef(t, true)
+}
+
+func CheckConfigmapWithOwnerRef(t *testing.T, hotreload bool) {
+       RegisterTestingT(t)
+       name := RandomizedSuffixName("config-configmap-route")
+       cmName := RandomizedSuffixName("my-hot-cm-")
+       Expect(KamelRunWithID(operatorID, ns, 
"./files/config-configmap-route.groovy",
+               "--config",
+               "configmap:"+cmName,
+               "--name",
+               name,
+               "-t",
+               "mount.hot-reload="+strconv.FormatBool(hotreload),
+       ).Execute()).To(Succeed())
+
+       Eventually(IntegrationPhase(ns, name), 
TestTimeoutLong).Should(Equal(v1.IntegrationPhaseError))
+       var cmData = make(map[string]string)
+       cmData["my-configmap-key"] = "my configmap content"
+       CreatePlainTextConfigmapWithOwnerRefWithLabels(ns, cmName, cmData, 
name, Integration(ns, name)().UID, 
map[string]string{"camel.apache.org/integration": "test"})
+       Eventually(IntegrationPodPhase(ns, name), 
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+       Eventually(IntegrationLogs(ns, name), 
TestTimeoutLong).Should(ContainSubstring("my configmap content"))
+       cmData["my-configmap-key"] = "my configmap content updated"
+       UpdatePlainTextConfigmapWithLabels(ns, cmName, cmData, 
map[string]string{"camel.apache.org/integration": "test"})
+       if hotreload {
+               Eventually(IntegrationLogs(ns, name), 
TestTimeoutLong).Should(ContainSubstring("my configmap content updated"))
+       } else {
+               Eventually(IntegrationLogs(ns, name), 
TestTimeoutLong).Should(Not(ContainSubstring("my configmap content updated")))
+       }
+       Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+       DeleteConfigmap(ns, cmName)
+}
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index 457c3b0a9..4036206b5 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -1606,6 +1606,31 @@ func CreatePlainTextConfigmapWithLabels(ns string, name 
string, data map[string]
        return TestClient().Create(TestContext, &cm)
 }
 
+func CreatePlainTextConfigmapWithOwnerRefWithLabels(ns string, name string, 
data map[string]string, orname string, uid types.UID, labels map[string]string) 
error {
+       cm := corev1.ConfigMap{
+               TypeMeta: metav1.TypeMeta{
+                       Kind:       "ConfigMap",
+                       APIVersion: corev1.SchemeGroupVersion.String(),
+               },
+               ObjectMeta: metav1.ObjectMeta{
+                       Namespace: ns,
+                       Name:      name,
+                       OwnerReferences: []metav1.OwnerReference{{
+                               APIVersion:         
v1.SchemeGroupVersion.String(),
+                               Kind:               "Integration",
+                               Name:               orname,
+                               UID:                uid,
+                               Controller:         pointer.Bool(true),
+                               BlockOwnerDeletion: pointer.Bool(true),
+                       },
+                       },
+                       Labels: labels,
+               },
+               Data: data,
+       }
+       return TestClient().Create(TestContext, &cm)
+}
+
 func UpdatePlainTextConfigmap(ns string, name string, data map[string]string) 
error {
        return UpdatePlainTextConfigmapWithLabels(ns, name, data, nil)
 }
diff --git a/pkg/util/digest/digest.go b/pkg/util/digest/digest.go
index 4965aedd9..52a9a01ae 100644
--- a/pkg/util/digest/digest.go
+++ b/pkg/util/digest/digest.go
@@ -24,7 +24,6 @@ import (
        "crypto/sha256"
        "encoding/base64"
        "encoding/json"
-       "fmt"
        "hash"
        "io"
        "path/filepath"
@@ -37,6 +36,8 @@ import (
        "github.com/apache/camel-k/v2/pkg/util/defaults"
        "github.com/apache/camel-k/v2/pkg/util/dsl"
        corev1 "k8s.io/api/core/v1"
+
+       "fmt"
 )
 
 const (
@@ -136,15 +137,63 @@ func ComputeForIntegration(integration *v1.Integration, 
configmaps []*corev1.Con
                }
        }
 
-       // Configmap and secret content
+       // Configmap content
        for _, cm := range configmaps {
-               if _, err := hash.Write([]byte(cm.String())); err != nil {
-                       return "", err
+               if cm != nil {
+                       // name, ns
+                       if _, err := hash.Write([]byte(fmt.Sprintf("%s/%s", 
cm.Name, cm.Namespace))); err != nil {
+                               return "", err
+                       }
+                       // Data with sorted keys
+                       if cm.Data != nil {
+                               // sort keys
+                               keys := make([]string, 0, len(cm.Data))
+                               for k := range cm.Data {
+                                       keys = append(keys, k)
+                               }
+                               sort.Strings(keys)
+                               for _, k := range keys {
+                                       if _, err := 
hash.Write([]byte(fmt.Sprintf("%s=%v,", k, cm.Data[k]))); err != nil {
+                                               return "", err
+                                       }
+                               }
+                       }
+                       // BinaryData with sorted keys
+                       if cm.BinaryData != nil {
+                               keys := make([]string, 0, len(cm.BinaryData))
+                               for k := range cm.BinaryData {
+                                       keys = append(keys, k)
+                               }
+                               sort.Strings(keys)
+                               for _, k := range keys {
+                                       if _, err := 
hash.Write([]byte(fmt.Sprintf("%s=%v,", k, cm.BinaryData[k]))); err != nil {
+                                               return "", err
+                                       }
+                               }
+                       }
                }
        }
+
+       // Secret content
        for _, s := range secrets {
-               if _, err := hash.Write([]byte(s.String())); err != nil {
-                       return "", err
+               if s != nil {
+                       // name, ns
+                       if _, err := hash.Write([]byte(fmt.Sprintf("%s/%s", 
s.Name, s.Namespace))); err != nil {
+                               return "", err
+                       }
+                       // Data with sorted keys
+                       if s.Data != nil {
+                               keys := make([]string, 0, len(s.Data))
+                               for k := range s.Data {
+                                       keys = append(keys, k)
+                               }
+                               sort.Strings(keys)
+                               for _, k := range keys {
+                                       if _, err := 
hash.Write([]byte(fmt.Sprintf("%s=%v,", k, s.Data[k]))); err != nil {
+                                               return "", err
+                                       }
+                               }
+                       }
                }
        }
 
diff --git a/pkg/util/digest/digest_test.go b/pkg/util/digest/digest_test.go
index 3139b88c3..a40a174a9 100644
--- a/pkg/util/digest/digest_test.go
+++ b/pkg/util/digest/digest_test.go
@@ -21,6 +21,12 @@ import (
        "os"
        "testing"
 
+       "github.com/stretchr/testify/require"
+
+       "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+       corev1 "k8s.io/api/core/v1"
+       "k8s.io/utils/pointer"
+
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        "github.com/stretchr/testify/assert"
 )
@@ -60,3 +66,75 @@ func TestDigestSHA1FromTempFile(t *testing.T) {
        assert.NoError(t, err)
        assert.Equal(t, "OXPdxTeLf5rqnsqvTi0CgmWoN/0=", sha1)
 }
+
+func TestDigestUsesConfigmap(t *testing.T) {
+       it := v1.Integration{
+               Spec: v1.IntegrationSpec{
+                       Traits: v1.Traits{
+                               Mount: &trait.MountTrait{
+                                       Configs:   []string{"configmap:cm"},
+                                       HotReload: pointer.Bool(true),
+                               },
+                       },
+               },
+       }
+
+       digest1, err := ComputeForIntegration(&it, nil, nil)
+       require.NoError(t, err)
+
+       cm := corev1.ConfigMap{
+               Data: map[string]string{
+                       "foo": "bar",
+               },
+       }
+       cms := []*corev1.ConfigMap{&cm}
+
+       digest2, err := ComputeForIntegration(&it, cms, nil)
+       require.NoError(t, err)
+       assert.NotEqual(t, digest1, digest2)
+
+       cm.Data["foo"] = "bar updated"
+       digest3, err := ComputeForIntegration(&it, cms, nil)
+       require.NoError(t, err)
+       assert.NotEqual(t, digest2, digest3)
+
+       digest4, err := ComputeForIntegration(&it, cms, nil)
+       require.NoError(t, err)
+       assert.Equal(t, digest4, digest3)
+}
+
+func TestDigestUsesSecret(t *testing.T) {
+       it := v1.Integration{
+               Spec: v1.IntegrationSpec{
+                       Traits: v1.Traits{
+                               Mount: &trait.MountTrait{
+                                       Configs:   []string{"secret:mysec"},
+                                       HotReload: pointer.Bool(true),
+                               },
+                       },
+               },
+       }
+
+       digest1, err := ComputeForIntegration(&it, nil, nil)
+       require.NoError(t, err)
+
+       sec := corev1.Secret{
+               Data: map[string][]byte{
+                       "foo": []byte("bar"),
+               },
+               StringData: map[string]string{
+                       "foo2": "bar2",
+               },
+       }
+
+       secrets := []*corev1.Secret{&sec}
+
+       digest2, err := ComputeForIntegration(&it, nil, secrets)
+       require.NoError(t, err)
+       assert.NotEqual(t, digest1, digest2)
+
+       sec.Data["foo"] = []byte("bar updated")
+       digest3, err := ComputeForIntegration(&it, nil, secrets)
+       require.NoError(t, err)
+       assert.NotEqual(t, digest2, digest3)
+}

Reply via email to