Skip to content

Commit 3d0d9d3

Browse files
JustinKuliopenshift-merge-robot
authored andcommitted
Correct to Pending status after late events
Previously, if the policy controller sent out a compliance event after the policy transitioned to a Pending state (because things are async), that compliance event would override the Pending state, and might never be corrected. Now, the template-sync should re-reconcile in that case, and apply the Pending state again. Refs: - https://issues.redhat.com/browse/ACM-5022 Signed-off-by: Justin Kulikauskas <[email protected]>
1 parent 3f4bda1 commit 3d0d9d3

File tree

3 files changed

+92
-3
lines changed

3 files changed

+92
-3
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2023 Red Hat, Inc.
2+
// Copyright Contributors to the Open Cluster Management project
3+
4+
package templatesync
5+
6+
import (
7+
policiesv1 "open-cluster-management.io/governance-policy-propagator/api/v1"
8+
"sigs.k8s.io/controller-runtime/pkg/event"
9+
"sigs.k8s.io/controller-runtime/pkg/predicate"
10+
)
11+
12+
// templatePredicates filters out changes to policies that don't need to be
13+
// considered by the template-sync controller.
14+
func templatePredicates() predicate.Funcs {
15+
return predicate.Funcs{
16+
UpdateFunc: func(e event.UpdateEvent) bool {
17+
oldPolicy := e.ObjectOld.(*policiesv1.Policy)
18+
updatedPolicy := e.ObjectNew.(*policiesv1.Policy)
19+
20+
if oldPolicy.Generation != updatedPolicy.Generation {
21+
// The spec changed - templates need to be updated.
22+
return true
23+
}
24+
25+
if hasAnyDependencies(updatedPolicy) {
26+
// if it has dependencies, and it's not currently Pending, then
27+
// it needs to re-calculate if it *should* be Pending.
28+
return updatedPolicy.Status.ComplianceState != "Pending"
29+
}
30+
31+
return false
32+
},
33+
}
34+
}
35+
36+
// hasAnyDependencies returns true if the policy has any Dependencies or if
37+
// any of its templates have any ExtraDependencies.
38+
func hasAnyDependencies(pol *policiesv1.Policy) bool {
39+
if len(pol.Spec.Dependencies) > 0 {
40+
return true
41+
}
42+
43+
for _, tmpl := range pol.Spec.PolicyTemplates {
44+
if len(tmpl.ExtraDependencies) > 0 {
45+
return true
46+
}
47+
}
48+
49+
return false
50+
}

controllers/templatesync/template_sync.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import (
3737
ctrl "sigs.k8s.io/controller-runtime"
3838
"sigs.k8s.io/controller-runtime/pkg/client"
3939
"sigs.k8s.io/controller-runtime/pkg/handler"
40-
"sigs.k8s.io/controller-runtime/pkg/predicate"
4140
"sigs.k8s.io/controller-runtime/pkg/reconcile"
4241
"sigs.k8s.io/controller-runtime/pkg/source"
4342

@@ -62,7 +61,7 @@ func (r *PolicyReconciler) Setup(mgr ctrl.Manager, depEvents *source.Channel) er
6261
return ctrl.NewControllerManagedBy(mgr).
6362
Named(ControllerName).
6463
For(&policiesv1.Policy{}).
65-
WithEventFilter(predicate.GenerationChangedPredicate{}).
64+
WithEventFilter(templatePredicates()).
6665
Watches(depEvents, &handler.EnqueueRequestForObject{}).
6766
Complete(r)
6867
}

test/e2e/case12_ordering_test.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package e2e
55

66
import (
77
"context"
8+
"time"
89

910
. "github.com/onsi/ginkgo/v2"
1011
. "github.com/onsi/gomega"
@@ -338,7 +339,46 @@ var _ = Describe("Test dependency logic in template sync", Ordered, func() {
338339
)
339340

340341
// should be noncompliant - template A is pending and B is noncompliant
341-
By("Checking if policy status is pending")
342+
By("Checking if policy status is noncompliant")
342343
Eventually(checkCompliance(case12Plc2TemplatesName), defaultTimeoutSeconds, 1).Should(Equal("NonCompliant"))
343344
})
345+
It("Should correct a late compliance event while the policy is pending", func() {
346+
By("Creating a dep on hub cluster in ns:" + clusterNamespaceOnHub)
347+
hubPolicyApplyAndDeferCleanup(case12DepYaml, case12DepName)
348+
349+
By("Creating a policy on hub cluster in ns:" + clusterNamespaceOnHub)
350+
hubPolicyApplyAndDeferCleanup(case12PolicyYaml, case12PolicyName)
351+
352+
By("Generating a noncompliant event on the dependency")
353+
generateEventOnPolicy(
354+
case12DepName,
355+
"namespace-foo-setup-configpolicy",
356+
"there is violation",
357+
"NonCompliant",
358+
)
359+
360+
By("Checking if dependency status is noncompliant")
361+
Eventually(checkCompliance(case12DepName), defaultTimeoutSeconds, 1).Should(Equal("NonCompliant"))
362+
363+
By("Checking if policy status is pending")
364+
Eventually(checkCompliance(case12PolicyName), defaultTimeoutSeconds*2, 1).Should(Equal("Pending"))
365+
366+
By("Generating an (incorrect, late) compliance event on the policy")
367+
generateEventOnPolicy(
368+
case12PolicyName,
369+
"case12-config-policy",
370+
"No violation detected",
371+
"Compliant",
372+
)
373+
374+
// Sleep 5 seconds to avoid the Compliant status that only sometimes appears;
375+
// otherwise, the next Eventually might finish *before* that status comes and goes.
376+
time.Sleep(5 * time.Second)
377+
378+
By("Checking if policy status is pending")
379+
Eventually(checkCompliance(case12PolicyName), defaultTimeoutSeconds, 1).Should(Equal("Pending"))
380+
381+
By("Checking if policy status is consistently pending")
382+
Consistently(checkCompliance(case12PolicyName), "15s", 1).Should(Equal("Pending"))
383+
})
344384
})

0 commit comments

Comments
 (0)