From b84804f97241f9aa9c558c301fcf01d66db15f40 Mon Sep 17 00:00:00 2001 From: Gus Parvin Date: Tue, 28 Mar 2023 16:04:35 -0400 Subject: [PATCH] Pull in the new template utils with copy template functions Adding support for the new go template functions: - copyConfigMapData - copySecretData These copy the data section of ConfigMap or Secret resources so individual keys don't have to be specified Refs: - https://issues.redhat.com/browse/ACM-2611 Signed-off-by: Gus Parvin (cherry picked from commit 4da4e06d1b378e416befd12efc79a332f8d57763) --- go.mod | 2 +- go.sum | 4 +- test/e2e/case13_templatization_test.go | 94 ++++++++++++++++++- .../case13_copy_referenced_configmap.yaml | 18 ++++ .../case13_copysecret.yaml | 4 +- .../case13_fromsecret.yaml | 20 ++++ 6 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 test/resources/case13_templatization/case13_copy_referenced_configmap.yaml create mode 100644 test/resources/case13_templatization/case13_fromsecret.yaml diff --git a/go.mod b/go.mod index 8fbfc111..b288156a 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/prometheus/client_golang v1.13.0 github.com/spf13/pflag v1.0.5 github.com/stolostron/go-log-utils v0.1.1 - github.com/stolostron/go-template-utils/v3 v3.0.2 + github.com/stolostron/go-template-utils/v3 v3.1.0 github.com/stretchr/testify v1.7.0 k8s.io/api v0.23.9 k8s.io/apiextensions-apiserver v0.23.5 diff --git a/go.sum b/go.sum index ee5d1b5a..77942133 100644 --- a/go.sum +++ b/go.sum @@ -552,8 +552,8 @@ github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stolostron/go-log-utils v0.1.1 h1:T48GyfuGpn2+6817FQVec1CyxGf0ibuVhoBiz9SeCec= github.com/stolostron/go-log-utils v0.1.1/go.mod h1:2Uc5mbuLvSFpoXFFEKRTEFOlR7nqGVMu9mbU+FIttTI= -github.com/stolostron/go-template-utils/v3 v3.0.2 h1:0wUbfcvG5pYoEa0p4qj3oBpz9k6WPyE5S5IaYIBWbbg= -github.com/stolostron/go-template-utils/v3 v3.0.2/go.mod h1:k9qoQ/OH/jOQI5ovfC11QJ6ApWsa3E5rmbkfUAEUF3g= +github.com/stolostron/go-template-utils/v3 v3.1.0 h1:wizzuURDnI2fewOx/AxHLpKx06FXUGjkUnMjdcgat3o= +github.com/stolostron/go-template-utils/v3 v3.1.0/go.mod h1:k9qoQ/OH/jOQI5ovfC11QJ6ApWsa3E5rmbkfUAEUF3g= github.com/stolostron/kubernetes-dependency-watches v0.0.0-20221007134235-7551d84cf688 h1:Q/0MspxKFkqBN59keMsJI2hGqGGpTSxdNEvrxTOBlRg= github.com/stolostron/kubernetes-dependency-watches v0.0.0-20221007134235-7551d84cf688/go.mod h1:jGnjY4g8N1PaBqt35EjqNRjymjG0DWqki/2JOLMN1Pg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/test/e2e/case13_templatization_test.go b/test/e2e/case13_templatization_test.go index 8ab4c1b2..528056c3 100644 --- a/test/e2e/case13_templatization_test.go +++ b/test/e2e/case13_templatization_test.go @@ -22,7 +22,8 @@ const ( case13SecretYaml string = "../resources/case13_templatization/case13_secret.yaml" case13CfgPolCreateSecret string = "tmplt-policy-secret-duplicate" case13CfgPolCheckSecret string = "tmplt-policy-secret-duplicate-check" - case13CfgPolCreateSecretYaml string = "../resources/case13_templatization/case13_copysecret.yaml" + case13CfgPolCopySecretYaml string = "../resources/case13_templatization/case13_copysecret.yaml" + case13CfgPolCreateSecretYaml string = "../resources/case13_templatization/case13_fromsecret.yaml" case13CfgPolCheckSecretYaml string = "../resources/case13_templatization/case13_verifysecret.yaml" ) @@ -58,6 +59,8 @@ const ( const ( case13UpdateRefObject = "policy-update-referenced-object" case13UpdateRefObjectYaml = "../resources/case13_templatization/case13_update_referenced_object.yaml" + case13CopyRefObject = "policy-copy-referenced-configmap" + case13CopyRefObjectYaml = "../resources/case13_templatization/case13_copy_referenced_configmap.yaml" ) var _ = Describe("Test templatization", func() { @@ -101,6 +104,46 @@ var _ = Describe("Test templatization", func() { utils.Kubectl("delete", "configurationpolicy", case13CfgPolCheckSecret, "-n", testNamespace) }) }) + Describe("Create a secret and copy all secret data into a configurationPolicy", func() { + It("should be created properly on the managed cluster", func() { + By("Creating " + case13CfgPolCreateSecret + " and " + case13CfgPolCheckSecret + " on managed") + // create secret + utils.Kubectl("apply", "-f", case13SecretYaml, "-n", "default") + secret := utils.GetWithTimeout(clientManagedDynamic, gvrSecret, + case13Secret, "default", true, defaultTimeoutSeconds) + Expect(secret).NotTo(BeNil()) + // create full data copy from original secret using a templatized policy + utils.Kubectl("apply", "-f", case13CfgPolCopySecretYaml, "-n", testNamespace) + plc := utils.GetWithTimeout(clientManagedDynamic, gvrConfigPolicy, + case13CfgPolCreateSecret, testNamespace, true, defaultTimeoutSeconds) + Expect(plc).NotTo(BeNil()) + Eventually(func() interface{} { + managedPlc := utils.GetWithTimeout(clientManagedDynamic, gvrConfigPolicy, + case13CfgPolCreateSecret, testNamespace, true, defaultTimeoutSeconds) + + return utils.GetComplianceState(managedPlc) + }, defaultTimeoutSeconds, 1).Should(Equal("Compliant")) + Eventually(func() interface{} { + copiedSecret := utils.GetWithTimeout(clientManagedDynamic, gvrSecret, + case13Secret, "default", true, defaultTimeoutSeconds) + + return utils.GetFieldFromSecret(copiedSecret, "PASSWORD") + }, defaultTimeoutSeconds, 1).Should(Equal("MWYyZDFlMmU2N2Rm")) + // check copied secret with a templatized inform policy + utils.Kubectl("apply", "-f", case13CfgPolCheckSecretYaml, "-n", testNamespace) + plc = utils.GetWithTimeout(clientManagedDynamic, gvrConfigPolicy, + case13CfgPolCheckSecret, testNamespace, true, defaultTimeoutSeconds) + Expect(plc).NotTo(BeNil()) + Eventually(func() interface{} { + managedPlc := utils.GetWithTimeout(clientManagedDynamic, gvrConfigPolicy, + case13CfgPolCheckSecret, testNamespace, true, defaultTimeoutSeconds) + + return utils.GetComplianceState(managedPlc) + }, defaultTimeoutSeconds, 1).Should(Equal("Compliant")) + utils.Kubectl("delete", "configurationpolicy", case13CfgPolCreateSecret, "-n", testNamespace) + utils.Kubectl("delete", "configurationpolicy", case13CfgPolCheckSecret, "-n", testNamespace) + }) + }) Describe("Create a clusterclaim and pull data from it into a configurationPolicy", func() { It("should be created properly on the managed cluster", func() { By("Creating " + case13CfgPolCreatePod + " and " + case13CfgPolVerifyPod + " on managed") @@ -324,4 +367,53 @@ var _ = Describe("Test templatization", func() { utils.Kubectl("delete", "configmap", configMapReplName, "-n", "default") }) }) + Describe("Test the copy configMap function", func() { + const configMapName = "configmap-copy-configmap-object" + const configMapReplName = configMapName + "-repl" + It("Should have the expected ConfigMap created", func() { + By("Creating the ConfigMap to reference") + configMap := corev1.ConfigMap{ + ObjectMeta: v1.ObjectMeta{ + Name: configMapName, + }, + Data: map[string]string{"message": "Hello Raleigh!"}, + } + _, err := clientManaged.CoreV1().ConfigMaps("default").Create( + context.TODO(), &configMap, v1.CreateOptions{}, + ) + Expect(err).To(BeNil()) + By("Creating the configuration policy that references the ConfigMap") + utils.Kubectl("apply", "-f", case13CopyRefObjectYaml, "-n", testNamespace) + + By("By verifying that the policy is compliant") + Eventually( + func() interface{} { + managedPlc := utils.GetWithTimeout( + clientManagedDynamic, + gvrConfigPolicy, + case13CopyRefObject, + testNamespace, + true, + defaultTimeoutSeconds, + ) + + return utils.GetComplianceState(managedPlc) + }, + defaultTimeoutSeconds, + 1, + ).Should(Equal("Compliant")) + + By("By verifying that the replicated ConfigMap has the expected data") + replConfigMap, err := clientManaged.CoreV1().ConfigMaps("default").Get( + context.TODO(), configMapReplName, v1.GetOptions{}, + ) + Expect(err).To(BeNil()) + Expect(replConfigMap.Data["message"]).To(Equal("Hello Raleigh!")) + }) + It("Cleans up", func() { + deleteConfigPolicies([]string{case13CopyRefObject}) + utils.Kubectl("delete", "configmap", configMapName, "-n", "default", "--ignore-not-found") + utils.Kubectl("delete", "configmap", configMapReplName, "-n", "default", "--ignore-not-found") + }) + }) }) diff --git a/test/resources/case13_templatization/case13_copy_referenced_configmap.yaml b/test/resources/case13_templatization/case13_copy_referenced_configmap.yaml new file mode 100644 index 00000000..e065b5f3 --- /dev/null +++ b/test/resources/case13_templatization/case13_copy_referenced_configmap.yaml @@ -0,0 +1,18 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: ConfigurationPolicy +metadata: + name: policy-copy-referenced-configmap +spec: + remediationAction: enforce + namespaceSelector: + exclude: ["kube-*"] + include: ["default"] + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: v1 + kind: ConfigMap + metadata: + name: configmap-copy-configmap-object-repl + namespace: default + data: '{{ copyConfigMapData "default" "configmap-copy-configmap-object" }}' diff --git a/test/resources/case13_templatization/case13_copysecret.yaml b/test/resources/case13_templatization/case13_copysecret.yaml index 7b857a3b..9e84279f 100644 --- a/test/resources/case13_templatization/case13_copysecret.yaml +++ b/test/resources/case13_templatization/case13_copysecret.yaml @@ -15,6 +15,4 @@ spec: metadata: name: e2esecret2 type: Opaque - data: - USER_NAME: YWRtaW4= - PASSWORD: '{{ fromSecret "default" "e2esecret" "PASSWORD" }}' + data: '{{ copySecretData "default" "e2esecret" }}' diff --git a/test/resources/case13_templatization/case13_fromsecret.yaml b/test/resources/case13_templatization/case13_fromsecret.yaml new file mode 100644 index 00000000..7b857a3b --- /dev/null +++ b/test/resources/case13_templatization/case13_fromsecret.yaml @@ -0,0 +1,20 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: ConfigurationPolicy +metadata: + name: tmplt-policy-secret-duplicate +spec: + remediationAction: enforce + namespaceSelector: + exclude: ["kube-*"] + include: ["default"] + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: v1 + kind: Secret + metadata: + name: e2esecret2 + type: Opaque + data: + USER_NAME: YWRtaW4= + PASSWORD: '{{ fromSecret "default" "e2esecret" "PASSWORD" }}'