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 <[email protected]>
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)
+}