Skip to content

Commit 2766dfa

Browse files
JustinKuliopenshift-merge-robot
authored andcommitted
Set state as Compliant when ignorePending is true
Previously, individual templates were always marked as "Pending" if they had an unsatisfied dependency. The `ignorePending` field was only considered when calculating the overall compliance of a Policy. But that meant that it was not possible to correctly calculate the overall state with just the status object, which is confusing. Now, the `ignorePending` field is considered when marking the compliance of each template. This makes how the overall compliance is calculated more clear, and the new messages may be more helpful for users. Refs: - https://issues.redhat.com/browse/ACM-2101 Signed-off-by: Justin Kulikauskas <[email protected]>
1 parent b9b14bd commit 2766dfa

File tree

4 files changed

+129
-42
lines changed

4 files changed

+129
-42
lines changed

controllers/statussync/policy_status_sync.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,6 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
205205

206206
reqLogger.Info("Updating status for policy templates")
207207

208-
shouldSkipPending := map[*policiesv1.DetailsPerTemplate]bool{}
209-
210208
for _, policyT := range instance.Spec.PolicyTemplates {
211209
object, _, err := unstructured.UnstructuredJSONScheme.Decode(policyT.ObjectDefinition.Raw, nil, nil)
212210
if err != nil {
@@ -344,9 +342,6 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
344342
// append existingDpt to status
345343
newStatus.Details = append(newStatus.Details, existingDpt)
346344

347-
// build a map to determine whether to skip pending status from this template
348-
shouldSkipPending[existingDpt] = policyT.IgnorePending
349-
350345
reqLogger.Info("Status update complete", "PolicyTemplate", tName)
351346
}
352347

@@ -360,7 +355,7 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
360355
isCompliant = false
361356

362357
break
363-
} else if dpt.ComplianceState == "Pending" && !shouldSkipPending[dpt] {
358+
} else if dpt.ComplianceState == "Pending" {
364359
instance.Status.ComplianceState = policiesv1.Pending
365360
isCompliant = false
366361
} else if dpt.ComplianceState == "" {

controllers/templatesync/template_sync.go

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,7 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
299299
if err != nil {
300300
if len(dependencyFailures) > 0 {
301301
// template must be pending, do not create it
302-
pendingErr := generatePendingErr(dependencyFailures)
303-
resultError = pendingErr
304-
errMsg := fmt.Sprintf("Dependencies were not satisfied: %s", pendingErr)
305-
306-
r.emitTemplatePending(instance, tIndex, tName, errMsg)
302+
r.emitTemplatePending(instance, tIndex, tName, generatePendingMsg(dependencyFailures))
307303
tLogger.Info("Dependencies were not satisfied for the policy template",
308304
"namespace", instance.GetNamespace(),
309305
"kind", gvk.Kind,
@@ -378,11 +374,7 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
378374

379375
if len(dependencyFailures) > 0 {
380376
// template must be pending, need to delete it and error
381-
pendingErr := generatePendingErr(dependencyFailures)
382-
resultError = pendingErr
383-
errMsg := fmt.Sprintf("Dependencies were not satisfied: %s", pendingErr)
384-
385-
r.emitTemplatePending(instance, tIndex, tName, errMsg)
377+
r.emitTemplatePending(instance, tIndex, tName, generatePendingMsg(dependencyFailures))
386378
tLogger.Info("Dependencies were not satisfied for the policy template",
387379
"namespace", instance.GetNamespace(),
388380
"kind", gvk.Kind,
@@ -394,6 +386,8 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
394386
"namespace", instance.GetNamespace(),
395387
"name", tName,
396388
)
389+
390+
resultError = err
397391
}
398392

399393
continue
@@ -555,20 +549,22 @@ func (r *PolicyReconciler) processDependencies(ctx context.Context, dClient dyna
555549
return dependencyFailures
556550
}
557551

558-
// generatePendingErr formats the list of failed dependencies into a readable error
559-
func generatePendingErr(dependencyFailures []depclient.ObjectIdentifier) error {
552+
// generatePendingMsg formats the list of failed dependencies into a readable error.
553+
// Example: `Dependencies were not satisfied: 1 is still pending (FooPolicy foo)`
554+
func generatePendingMsg(dependencyFailures []depclient.ObjectIdentifier) string {
560555
names := make([]string, len(dependencyFailures))
561556
for i, dep := range dependencyFailures {
562557
names[i] = fmt.Sprintf("%s %s", dep.Kind, dep.Name)
563558
}
564559

565560
nameStr := strings.Join(names, ", ")
566561

567-
return fmt.Errorf(
568-
"%d dependencies are still pending (%s)",
569-
len(dependencyFailures),
570-
nameStr,
571-
)
562+
fmtStr := "Dependencies were not satisfied: %d are still pending (%s)"
563+
if len(dependencyFailures) == 1 {
564+
fmtStr = "Dependencies were not satisfied: %d is still pending (%s)"
565+
}
566+
567+
return fmt.Sprintf(fmtStr, len(dependencyFailures), nameStr)
572568
}
573569

574570
func overrideRemediationAction(instance *policiesv1.Policy, tObjectUnstructured *unstructured.Unstructured) {
@@ -600,21 +596,29 @@ func (r *PolicyReconciler) emitTemplateError(pol *policiesv1.Policy, tIndex int,
600596
r.Recorder.Event(pol, "Warning", "PolicyTemplateSync", errMsg)
601597
}
602598

603-
// emitTemplatePending performs actions that ensure correct reporting of dependency errors in the
604-
// policy framework. If the policy's status already reflects the current error, then no actions
599+
// emitTemplatePending performs actions that ensure correct reporting of pending dependencies in the
600+
// policy framework. If the policy's status already reflects the current status, then no actions
605601
// are taken.
606-
func (r *PolicyReconciler) emitTemplatePending(pol *policiesv1.Policy, tIndex int, tName, errMsg string) {
602+
func (r *PolicyReconciler) emitTemplatePending(pol *policiesv1.Policy, tIndex int, tName, msg string) {
603+
statusMsg := "Pending; " + msg
604+
eventType := "Warning"
605+
606+
if pol.Spec.PolicyTemplates[tIndex].IgnorePending {
607+
statusMsg = "Compliant; " + msg + " but ignorePending is true"
608+
eventType = "Normal"
609+
}
610+
607611
// check if the error is already present in the policy status - if so, return early
608-
if strings.Contains(getLatestStatusMessage(pol, tIndex), errMsg) {
612+
if strings.Contains(getLatestStatusMessage(pol, tIndex), statusMsg) {
609613
return
610614
}
611615

612616
// emit the non-compliance event
613617
policyComplianceReason := fmt.Sprintf(policyFmtStr, pol.GetNamespace(), tName)
614-
r.Recorder.Event(pol, "Warning", policyComplianceReason, "Pending; template-error; "+errMsg)
618+
r.Recorder.Event(pol, eventType, policyComplianceReason, statusMsg)
615619

616620
// emit an informational event
617-
r.Recorder.Event(pol, "Warning", "PolicyTemplateSync", errMsg)
621+
r.Recorder.Event(pol, eventType, "PolicyTemplateSync", statusMsg)
618622
}
619623

620624
// handleSyncSuccess performs common actions that should be run whenever a template is in sync,

test/e2e/case12_ordering_test.go

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,20 @@ import (
1111
)
1212

1313
const (
14-
case12PolicyName string = "case12-test-policy"
15-
case12PolicyYaml string = "../resources/case12_ordering/case12-plc.yaml"
16-
case12PolicyNameInvalid string = "case12-test-policy-invalid"
17-
case12PolicyYamlInvalid string = "../resources/case12_ordering/case12-plc-invalid-dep.yaml"
18-
case12ExtraDepsPolicyName string = "case12-test-policy-multi"
19-
case12ExtraDepsPolicyYaml string = "../resources/case12_ordering/case12-plc-multiple-deps.yaml"
20-
case12Plc2TemplatesName string = "case12-test-policy-2-templates"
21-
case12Plc2TemplatesYaml string = "../resources/case12_ordering/case12-plc-2-template.yaml"
22-
case12DepName string = "namespace-foo-setup-policy"
23-
case12DepYaml string = "../resources/case12_ordering/case12-dependency.yaml"
24-
case12DepBName string = "namespace-foo-setup-policy-b"
25-
case12DepBYaml string = "../resources/case12_ordering/case12-dependency-b.yaml"
14+
case12PolicyName string = "case12-test-policy"
15+
case12PolicyYaml string = "../resources/case12_ordering/case12-plc.yaml"
16+
case12PolicyIgnorePendingName string = "case12-test-policy-ignorepending"
17+
case12PolicyIgnorePendingYaml string = "../resources/case12_ordering/case12-plc-ignorepending.yaml"
18+
case12PolicyNameInvalid string = "case12-test-policy-invalid"
19+
case12PolicyYamlInvalid string = "../resources/case12_ordering/case12-plc-invalid-dep.yaml"
20+
case12ExtraDepsPolicyName string = "case12-test-policy-multi"
21+
case12ExtraDepsPolicyYaml string = "../resources/case12_ordering/case12-plc-multiple-deps.yaml"
22+
case12Plc2TemplatesName string = "case12-test-policy-2-templates"
23+
case12Plc2TemplatesYaml string = "../resources/case12_ordering/case12-plc-2-template.yaml"
24+
case12DepName string = "namespace-foo-setup-policy"
25+
case12DepYaml string = "../resources/case12_ordering/case12-dependency.yaml"
26+
case12DepBName string = "namespace-foo-setup-policy-b"
27+
case12DepBYaml string = "../resources/case12_ordering/case12-dependency-b.yaml"
2628
)
2729

2830
// Helper function to create events
@@ -127,7 +129,8 @@ var _ = Describe("Test dependency logic in template sync", Ordered, func() {
127129
true,
128130
defaultTimeoutSeconds)
129131
Expect(hubPlc).NotTo(BeNil())
130-
By("Generating a noncompliant event on the policy")
132+
133+
By("Generating a noncompliant event on the dependency")
131134
generateEventOnPolicy(
132135
case12DepName,
133136
"managed/namespace-foo-setup-configpolicy",
@@ -149,6 +152,53 @@ var _ = Describe("Test dependency logic in template sync", Ordered, func() {
149152
_, err = kubectlHub("delete", "-f", case12PolicyYaml, "-n", clusterNamespaceOnHub)
150153
Expect(err).To(BeNil())
151154
})
155+
It("Should set to Compliant when dep status is NonCompliant and ignorePending is true", func() {
156+
By("Creating a dep on hub cluster in ns:" + clusterNamespaceOnHub)
157+
_, err := kubectlHub("apply", "-f", case12DepYaml, "-n", clusterNamespaceOnHub)
158+
Expect(err).To(BeNil())
159+
hubPlc := utils.GetWithTimeout(
160+
clientHubDynamic,
161+
gvrPolicy,
162+
case12DepName,
163+
clusterNamespaceOnHub,
164+
true,
165+
defaultTimeoutSeconds)
166+
Expect(hubPlc).NotTo(BeNil())
167+
168+
By("Creating a policy on hub cluster in ns:" + clusterNamespaceOnHub)
169+
_, err = kubectlHub("apply", "-f", case12PolicyIgnorePendingYaml, "-n", clusterNamespaceOnHub)
170+
Expect(err).To(BeNil())
171+
hubPlc = utils.GetWithTimeout(
172+
clientHubDynamic,
173+
gvrPolicy,
174+
case12PolicyIgnorePendingName,
175+
clusterNamespaceOnHub,
176+
true,
177+
defaultTimeoutSeconds)
178+
Expect(hubPlc).NotTo(BeNil())
179+
180+
By("Generating a noncompliant event on the dependency")
181+
generateEventOnPolicy(
182+
case12DepName,
183+
"managed/namespace-foo-setup-configpolicy",
184+
"Warning",
185+
"NonCompliant; there is violation",
186+
)
187+
188+
By("Checking if dependency status is noncompliant")
189+
Eventually(checkCompliance(case12DepName), defaultTimeoutSeconds, 1).Should(Equal("NonCompliant"))
190+
191+
By("Checking if policy status is pending")
192+
Eventually(checkCompliance(case12PolicyIgnorePendingName), defaultTimeoutSeconds, 1).Should(Equal("Compliant"))
193+
194+
By("Deleting dependency on hub cluster in ns:" + clusterNamespaceOnHub)
195+
_, err = kubectlHub("delete", "-f", case12DepYaml, "-n", clusterNamespaceOnHub)
196+
Expect(err).To(BeNil())
197+
198+
By("Deleting the policy on hub cluster in ns:" + clusterNamespaceOnHub)
199+
_, err = kubectlHub("delete", "-f", case12PolicyIgnorePendingYaml, "-n", clusterNamespaceOnHub)
200+
Expect(err).To(BeNil())
201+
})
152202
It("Should set to Compliant when dep status is resolved", func() {
153203
By("Creating a dep on hub cluster in ns:" + clusterNamespaceOnHub)
154204
_, err := kubectlHub("apply", "-f", case12DepYaml, "-n", clusterNamespaceOnHub)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
apiVersion: policy.open-cluster-management.io/v1
2+
kind: Policy
3+
metadata:
4+
name: case12-test-policy-ignorepending
5+
labels:
6+
policy.open-cluster-management.io/cluster-name: managed
7+
policy.open-cluster-management.io/cluster-namespace: managed
8+
policy.open-cluster-management.io/root-policy: case12-test-policy
9+
spec:
10+
remediationAction: inform
11+
disabled: false
12+
dependencies:
13+
- apiVersion: policy.open-cluster-management.io/v1
14+
kind: Policy
15+
name: namespace-foo-setup-policy
16+
namespace: ""
17+
compliance: Compliant
18+
policy-templates:
19+
- ignorePending: true
20+
objectDefinition:
21+
apiVersion: policy.open-cluster-management.io/v1
22+
kind: ConfigurationPolicy
23+
metadata:
24+
name: case12-config-policy
25+
spec:
26+
remediationAction: inform
27+
object-templates:
28+
- complianceType: musthave
29+
objectDefinition:
30+
apiVersion: v1
31+
kind: Pod
32+
metadata:
33+
name: nginx-pod-e2e
34+
namespace: default
35+
spec:
36+
containers:
37+
- name: nginx
38+

0 commit comments

Comments
 (0)