diff --git a/controllers/templatesync/template_sync.go b/controllers/templatesync/template_sync.go index e630de40..c0c4a727 100644 --- a/controllers/templatesync/template_sync.go +++ b/controllers/templatesync/template_sync.go @@ -1193,10 +1193,7 @@ func generatePendingMsg(dependencyFailures []depclient.ObjectIdentifier) string func overrideRemediationAction(instance *policiesv1.Policy, tObjectUnstructured *unstructured.Unstructured) { // override RemediationAction only when it is set on parent - if instance.Spec.RemediationAction == "" { - return - } - + // or when a policy is set to informonly if tObjectUnstructured.GroupVersionKind().Group == utils.GConstraint { var enforcementAction string @@ -1210,21 +1207,39 @@ func overrideRemediationAction(instance *policiesv1.Policy, tObjectUnstructured } if spec, ok := tObjectUnstructured.Object["spec"]; ok { - specObject, ok := spec.(map[string]interface{}) - if ok { + if specObject, ok := spec.(map[string]interface{}); ok { specObject["enforcementAction"] = enforcementAction } } + + return } else if tObjectUnstructured.GroupVersionKind().Group == utils.GvkConstraintTemplate.Group { // Don't override anything if it's a ConstraintTemplate return - } else { - if spec, ok := tObjectUnstructured.Object["spec"]; ok { - specObject, ok := spec.(map[string]interface{}) - if ok { - specObject["remediationAction"] = string(instance.Spec.RemediationAction) + } + + spec, ok := tObjectUnstructured.Object["spec"] + if !ok { + return + } + + specObject, ok := spec.(map[string]interface{}) + if !ok { + return + } + + if remediationAction, ok := specObject["remediationAction"]; ok { + if _, ok := remediationAction.(string); ok { + if strings.EqualFold(specObject["remediationAction"].(string), "informonly") { + specObject["remediationAction"] = strings.ToLower(string(policiesv1.Inform)) + + return } } + + if instance.Spec.RemediationAction != "" { + specObject["remediationAction"] = string(instance.Spec.RemediationAction) + } } } diff --git a/test/e2e/case20_informonly_test.go b/test/e2e/case20_informonly_test.go new file mode 100644 index 00000000..4701d523 --- /dev/null +++ b/test/e2e/case20_informonly_test.go @@ -0,0 +1,69 @@ +// Copyright (c) 2023 Red Hat, Inc. +// Copyright Contributors to the Open Cluster Management project + +package e2e + +import ( + "errors" + "os/exec" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "open-cluster-management.io/config-policy-controller/test/utils" +) + +const ( + case20PolicyName string = "case20-policy-informonly" + case20PolicyYaml string = "../resources/case20_policy_informonly/case20-parent-policy.yaml" + case20ConfigPlcName string = "create-configmap" + case20ConfigPlcNoRemediationName string = "create-configmap-no-remediationaction" + case20PolicyNoRemediationName string = "case20-policy-informonly-no-remediationaction" + case20PolicyNoRemediationYaml string = "../resources/case20_policy_informonly/" + + "case20-parent-policy-noremediation.yaml" +) + +func checkInformAction(cfplc string) { + By("Checking template policy remediationAction") + Eventually(func() interface{} { + plc := utils.GetWithTimeout(clientManagedDynamic, gvrConfigurationPolicy, + cfplc, clusterNamespace, true, defaultTimeoutSeconds) + + return plc.Object["spec"].(map[string]interface{})["remediationAction"] + }, defaultTimeoutSeconds, 1).Should(Equal("inform")) +} + +var _ = Describe("Test 'InformOnly' ConfigurationPolicies", Ordered, func() { + AfterAll(func() { + By("Deleting all policies on the hub in ns:" + clusterNamespaceOnHub) + _, err := kubectlHub("delete", "-f", case20PolicyYaml, "-n", clusterNamespaceOnHub, + "--ignore-not-found") + var e *exec.ExitError + if !errors.As(err, &e) { + Expect(err).ShouldNot(HaveOccurred()) + } + + _, err = kubectlHub("delete", "-f", case20PolicyNoRemediationYaml, "-n", clusterNamespaceOnHub, + "--ignore-not-found") + if !errors.As(err, &e) { + Expect(err).ShouldNot(HaveOccurred()) + } + }) + + Describe("Override remediationAction in spec", func() { + Context("When parent policy have remediationAction=enforce", func() { + It("Should have remediationAction=inform", func() { + By("Applying parent policy " + case20PolicyName + " in hub ns: " + clusterNamespaceOnHub) + hubApplyPolicy(case20PolicyName, case20PolicyYaml) + checkInformAction(case20ConfigPlcName) + }) + }) + + Context("When parent policy have no remediationAction field set", func() { + It("Should have remediationAction=inform", func() { + By("Applying parent policy " + case20PolicyNoRemediationName + " in hub ns: " + clusterNamespaceOnHub) + hubApplyPolicy(case20PolicyNoRemediationName, case20PolicyNoRemediationYaml) + checkInformAction(case20ConfigPlcNoRemediationName) + }) + }) + }) +}) diff --git a/test/resources/case20_policy_informonly/case20-parent-policy-noremediation.yaml b/test/resources/case20_policy_informonly/case20-parent-policy-noremediation.yaml new file mode 100644 index 00000000..962abae3 --- /dev/null +++ b/test/resources/case20_policy_informonly/case20-parent-policy-noremediation.yaml @@ -0,0 +1,26 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: case20-policy-informonly-no-remediationaction + labels: + policy.open-cluster-management.io/cluster-name: managed + policy.open-cluster-management.io/cluster-namespace: managed + policy.open-cluster-management.io/root-policy: policy-informonly +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: create-configmap-no-remediationaction + spec: + remediationAction: InformOnly + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: v1 + kind: ConfigMap + metadata: + name: test-config + namespace: managed diff --git a/test/resources/case20_policy_informonly/case20-parent-policy.yaml b/test/resources/case20_policy_informonly/case20-parent-policy.yaml new file mode 100644 index 00000000..b6c5aa18 --- /dev/null +++ b/test/resources/case20_policy_informonly/case20-parent-policy.yaml @@ -0,0 +1,27 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: case20-policy-informonly + labels: + policy.open-cluster-management.io/cluster-name: managed + policy.open-cluster-management.io/cluster-namespace: managed + policy.open-cluster-management.io/root-policy: policy-informonly +spec: + remediationAction: enforce + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: create-configmap + spec: + remediationAction: InformOnly + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: v1 + kind: ConfigMap + metadata: + name: test-config + namespace: managed