Skip to content

Commit 03bd852

Browse files
JeffeyLopenshift-merge-robot
authored andcommitted
Fix bug where user error validation was being ignored
Regex formatting changed for template sync to be read in policy status sync and policy template evaluation changed to evaluate erroneous policy templates Signed-off-by: Jeffrey Luo <[email protected]>
1 parent 2df23d8 commit 03bd852

File tree

5 files changed

+196
-8
lines changed

5 files changed

+196
-8
lines changed

controllers/statussync/policy_status_sync.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,17 +215,23 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
215215

216216
reqLogger.Info("Updating status for policy templates")
217217

218-
for _, policyT := range instance.Spec.PolicyTemplates {
218+
for i, policyT := range instance.Spec.PolicyTemplates {
219+
existingDpt := &policiesv1.DetailsPerTemplate{}
220+
221+
var tName string
222+
219223
object, _, err := unstructured.UnstructuredJSONScheme.Decode(policyT.ObjectDefinition.Raw, nil, nil)
220224
if err != nil {
221225
// failed to decode PolicyTemplate, skipping it
222226
reqLogger.Error(err, "Failed to decode policy template, skipping it")
223227

224-
break
228+
existingDpt.ComplianceState = policiesv1.NonCompliant
229+
newStatus.Details = append(newStatus.Details, existingDpt)
230+
tName = fmt.Sprintf("template-%v", i) // template-sync emits this name on error
231+
} else {
232+
tName = object.(metav1.Object).GetName()
225233
}
226234

227-
tName := object.(metav1.Object).GetName()
228-
existingDpt := &policiesv1.DetailsPerTemplate{}
229235
// retrieve existingDpt from instance.status.details field
230236
found := false
231237

controllers/templatesync/template_sync.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
173173
reqLogger.Info(msg)
174174

175175
for tIndex := range instance.Spec.PolicyTemplates {
176-
_ = r.emitTemplateError(ctx, instance, tIndex, fmt.Sprintf("[template %v]", tIndex), false, msg)
176+
_ = r.emitTemplateError(ctx, instance, tIndex, fmt.Sprintf("template-%v", tIndex), false, msg)
177177
}
178178

179179
return reconcile.Result{}, nil
@@ -276,7 +276,7 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
276276
resultError = err
277277
errMsg := fmt.Sprintf("Failed to decode policy template with err: %s", err)
278278

279-
_ = r.emitTemplateError(ctx, instance, tIndex, fmt.Sprintf("[template %v]", tIndex), false, errMsg)
279+
_ = r.emitTemplateError(ctx, instance, tIndex, fmt.Sprintf("template-%v", tIndex), false, errMsg)
280280

281281
reqLogger.Error(resultError, "Failed to decode the policy template", "templateIndex", tIndex)
282282

@@ -326,7 +326,7 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
326326
errMsg := fmt.Sprintf("Failed to decode policy template with err: %s", resultError)
327327

328328
_ = r.emitTemplateError(ctx, instance, tIndex,
329-
fmt.Sprintf("[template %v]", tIndex), isClusterScoped, errMsg)
329+
fmt.Sprintf("template-%v", tIndex), isClusterScoped, errMsg)
330330

331331
reqLogger.Error(resultError, "Failed to decode the policy template", "templateIndex", tIndex)
332332

@@ -356,7 +356,7 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
356356
resultError = k8serrors.NewBadRequest(errMsg)
357357

358358
_ = r.emitTemplateError(ctx, instance, tIndex,
359-
fmt.Sprintf("[template %v]", tIndex), isClusterScoped, errMsg)
359+
fmt.Sprintf("template-%v", tIndex), isClusterScoped, errMsg)
360360

361361
reqLogger.Error(resultError, "Failed to process the policy template", "templateIndex", tIndex)
362362

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) 2023 Red Hat, Inc.
2+
// Copyright Contributors to the Open Cluster Management project
3+
4+
package e2e
5+
6+
import (
7+
. "github.com/onsi/ginkgo/v2"
8+
. "github.com/onsi/gomega"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/apimachinery/pkg/runtime"
11+
"open-cluster-management.io/config-policy-controller/test/utils"
12+
policiesv1 "open-cluster-management.io/governance-policy-propagator/api/v1"
13+
policyUtils "open-cluster-management.io/governance-policy-propagator/test/utils"
14+
)
15+
16+
var _ = Describe("Test proper metrics handling on syntax error", Ordered, func() {
17+
case22ErrPolicyName := "case22-err"
18+
case22ErrYaml := "../resources/case22_user_validation_error/case22-test-err.yaml"
19+
case22CorrectPolicyName := "case22-correct"
20+
case22CorrectYaml := "../resources/case22_user_validation_error/case22-test-correct.yaml"
21+
22+
cleanup := func() {
23+
By("Deleting test policies on hub cluster in ns:" + clusterNamespaceOnHub)
24+
// Clean up and ignore any errors (in case it was deleted previously)
25+
_, _ = kubectlHub("delete", "-f", case22ErrYaml, "-n", clusterNamespaceOnHub, "--ignore-not-found")
26+
_, _ = kubectlHub("delete", "-f", case22CorrectYaml, "-n", clusterNamespaceOnHub, "--ignore-not-found")
27+
opt := metav1.ListOptions{}
28+
policyUtils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, true, defaultTimeoutSeconds)
29+
policyUtils.ListWithTimeout(clientManagedDynamic, gvrPolicy, opt, 0, true, defaultTimeoutSeconds)
30+
}
31+
32+
AfterAll(cleanup)
33+
34+
It("Verifies NonCompliant status for non-decodable policy", func() {
35+
hubApplyPolicy(case22ErrPolicyName, case22ErrYaml)
36+
37+
By("Waiting for " + case22ErrPolicyName + " to become NonCompliant")
38+
Eventually(func() interface{} {
39+
plc := utils.GetWithTimeout(
40+
clientHubDynamic, gvrPolicy,
41+
case22ErrPolicyName, clusterNamespaceOnHub,
42+
true, defaultTimeoutSeconds,
43+
)
44+
45+
return utils.GetComplianceState(plc)
46+
}, defaultTimeoutSeconds, 1).Should(Equal("NonCompliant"))
47+
})
48+
49+
It("Verifies that validation errors are shown", func() {
50+
By("Checking message on " + case22ErrPolicyName)
51+
var plc *policiesv1.Policy
52+
Eventually(func(g Gomega) interface{} {
53+
managedPlc := utils.GetWithTimeout(
54+
clientManagedDynamic,
55+
gvrPolicy,
56+
case22ErrPolicyName,
57+
clusterNamespace,
58+
true,
59+
defaultTimeoutSeconds)
60+
err := runtime.DefaultUnstructuredConverter.FromUnstructured(managedPlc.Object, &plc)
61+
g.Expect(err).ToNot(HaveOccurred())
62+
if len(plc.Status.Details) < 1 {
63+
return ""
64+
}
65+
66+
return plc.Status.Details[1].History[0].Message
67+
}, defaultTimeoutSeconds, 1).Should(ContainSubstring("NonCompliant; template-error;"))
68+
})
69+
70+
It("Verifies correct policy does not become NonCompliant", func() {
71+
hubApplyPolicy(case22CorrectPolicyName, case22CorrectYaml)
72+
73+
By("Checking that " + case22CorrectPolicyName + " does not become NonCompliant")
74+
Consistently(func() interface{} {
75+
plc := utils.GetWithTimeout(
76+
clientHubDynamic, gvrPolicy,
77+
case22CorrectPolicyName, clusterNamespaceOnHub,
78+
true, defaultTimeoutSeconds,
79+
)
80+
81+
return utils.GetComplianceState(plc)
82+
}, defaultTimeoutSeconds, 1).ShouldNot(Equal("NonCompliant"))
83+
})
84+
})
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
apiVersion: policy.open-cluster-management.io/v1
2+
kind: Policy
3+
metadata:
4+
name: case22-correct
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: case22-correct
9+
spec:
10+
disabled: false
11+
policy-templates:
12+
- objectDefinition:
13+
apiVersion: policy.open-cluster-management.io/v1
14+
kind: ConfigurationPolicy
15+
metadata:
16+
name: checkfailednodes
17+
spec:
18+
object-templates-raw: |
19+
{{- range $node := (lookup "v1" "Node" "" "").items }}
20+
- complianceType: musthave
21+
objectDefinition:
22+
apiVersion: v1
23+
kind: Node
24+
metadata:
25+
name: test-node
26+
status:
27+
conditions:
28+
- message: kubelet has sufficient memory available
29+
reason: KubeletHasSufficientMemory
30+
status: "False"
31+
type: MemoryPressure
32+
- message: kubelet has no disk pressure
33+
reason: KubeletHasNoDiskPressure
34+
status: "False"
35+
type: DiskPressure
36+
- message: kubelet has sufficient PID available
37+
reason: KubeletHasSufficientPID
38+
status: "False"
39+
type: PIDPressure
40+
- message: kubelet is posting ready status
41+
reason: KubeletReady
42+
status: "True"
43+
type: Ready
44+
{{- end }}
45+
remediationAction: inform
46+
severity: low
47+
remediationAction: inform
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
apiVersion: policy.open-cluster-management.io/v1
2+
kind: Policy
3+
metadata:
4+
name: case22-err
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: case22-err
9+
creationTimestamp: 2023-08-07T09:21:13Z
10+
generation: 4
11+
managedFields:
12+
resourceVersion: "168475"
13+
uid: d40e4a53-919a-4d5e-a23e-de32eb9ae710
14+
spec:
15+
disabled: false
16+
policy-templates:
17+
- objectDefinition:
18+
spec:
19+
apiVersion: policy.open-cluster-management.io/v1
20+
kind: ConfigurationPolicy
21+
metadata:
22+
name: checkfailednodes
23+
severity: low
24+
spec:
25+
object-templates-raw: |
26+
{{- /* loop over nodes*/ -}}
27+
{{- range $node := (lookup "v1" "Node" "").items }}
28+
- complianceType: musthave
29+
objectDefinition:
30+
apiVersion: v1
31+
kind: Node
32+
metadata:
33+
name: {{ $node }}
34+
status:
35+
conditions:
36+
- message: kubelet has sufficient memory available
37+
reason: KubeletHasSufficientMemory
38+
status: "False"
39+
type: MemoryPressure
40+
remediationAction: inform
41+
severity: high
42+
remediationAction: inform
43+
status:
44+
compliant: Compliant
45+
placement:
46+
- placement: testix-placement
47+
placementBinding: testix-placement
48+
status:
49+
- clustername: local-cluster
50+
clusternamespace: local-cluster
51+
compliant: Compliant

0 commit comments

Comments
 (0)