Skip to content

Commit

Permalink
Fire event on object update
Browse files Browse the repository at this point in the history
Signed-off-by: Will Kutler <wkutler@redhat.com>
  • Loading branch information
willkutler committed Jan 6, 2023
1 parent 1f2a2e8 commit 74add6a
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 12 deletions.
37 changes: 25 additions & 12 deletions controllers/configurationpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1514,7 +1514,7 @@ func (r *ConfigurationPolicyReconciler) handleSingleObj(

before := time.Now().UTC()

throwSpecViolation, msg, pErr := r.checkAndUpdateResource(obj, compType, mdCompType, remediation)
throwSpecViolation, msg, pErr, updatedObj := r.checkAndUpdateResource(obj, compType, mdCompType, remediation)

duration := time.Now().UTC().Sub(before)
seconds := float64(duration) / float64(time.Second)
Expand All @@ -1538,8 +1538,19 @@ func (r *ConfigurationPolicyReconciler) handleSingleObj(
// it is a must have and it does exist, so it is compliant
compliant = true
if strings.EqualFold(string(remediation), string(policyv1.Enforce)) {
statusUpdateNeeded = createStatus("", obj.gvr.Resource, compliantObject, obj.namespaced, obj.policy,
obj.index, compliant, true)
if updatedObj {
// object updated in checkAndUpdateResource, send event

log.Info("Updated must have object", "resource", obj.gvr.Resource, "name", obj.name)
reason := "K8s update success"
idStr := identifierStr([]string{obj.name}, obj.namespace, obj.namespaced)
msg := fmt.Sprintf("%v %v was updated successfully", obj.gvr.Resource, idStr)

statusUpdateNeeded = addConditionToStatus(obj.policy, obj.index, true, reason, msg)
} else {
statusUpdateNeeded = createStatus("", obj.gvr.Resource, compliantObject, obj.namespaced, obj.policy,
obj.index, compliant, true)
}
created := false
creationInfo = &policyv1.ObjectProperties{
CreatedByPolicy: &created,
Expand Down Expand Up @@ -2325,15 +2336,15 @@ func (r *ConfigurationPolicyReconciler) checkAndUpdateResource(
complianceType string,
mdComplianceType string,
remediation policyv1.RemediationAction,
) (throwSpecViolation bool, message string, processingErr bool) {
) (throwSpecViolation bool, message string, processingErr bool, updatedObj bool) {
log := log.WithValues(
"policy", obj.policy.Name, "name", obj.name, "namespace", obj.namespace, "resource", obj.gvr.Resource,
)

if obj.object == nil {
log.Info("Skipping update: Previous object retrieval from the API server failed")

return false, "", false
return false, "", false, false
}

var res dynamic.ResourceInterface
Expand All @@ -2347,6 +2358,8 @@ func (r *ConfigurationPolicyReconciler) checkAndUpdateResource(
var updateNeeded bool
var statusUpdated bool

updatedObj = false

for key := range obj.unstruct.Object {
isStatus := key == "status"

Expand All @@ -2363,7 +2376,7 @@ func (r *ConfigurationPolicyReconciler) checkAndUpdateResource(
if errorMsg != "" {
log.Info(errorMsg)

return false, errorMsg, true
return false, errorMsg, true, false
}

if mergedObj == nil && skipped {
Expand All @@ -2382,7 +2395,7 @@ func (r *ConfigurationPolicyReconciler) checkAndUpdateResource(

if keyUpdateNeeded {
if strings.EqualFold(string(remediation), string(policyv1.Inform)) {
return true, "", false
return true, "", false, false
} else if isStatus {
statusUpdated = true
log.Info("Ignoring an update to the object status", "key", key)
Expand All @@ -2399,26 +2412,26 @@ func (r *ConfigurationPolicyReconciler) checkAndUpdateResource(
if err := r.validateObject(obj.object); err != nil {
message := fmt.Sprintf("Error validating the object %s, the error is `%v`", obj.name, err)

return false, message, true
return false, message, true, false
}

_, err = res.Update(context.TODO(), obj.object, metav1.UpdateOptions{})
if k8serrors.IsNotFound(err) {
message := fmt.Sprintf("`%v` is not present and must be created", obj.object.GetKind())

return false, message, true
return false, message, true, false
}

if err != nil {
message := fmt.Sprintf("Error updating the object `%v`, the error is `%v`", obj.name, err)

return false, message, true
return false, message, true, false
}

log.Info("Updated the object based on the template definition")
updatedObj = true
}

return statusUpdated, "", false
return statusUpdated, "", false, updatedObj
}

// AppendCondition check and appends conditions to the policy status
Expand Down
52 changes: 52 additions & 0 deletions test/e2e/case27_showupdateinstatus_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2020 Red Hat, Inc.
// Copyright Contributors to the Open Cluster Management project

package e2e

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"open-cluster-management.io/config-policy-controller/test/utils"
)

const (
case27ConfigPolicyName string = "policy-pod-create"
case27CreateYaml string = "../resources/case27_showupdateinstatus/case27-create-pod-policy.yaml"
case27UpdateYaml string = "../resources/case27_showupdateinstatus/case27-update-pod-policy.yaml"
)

var _ = Describe("Test cluster version obj template handling", func() {
Describe("enforce patch on unnamespaced resource clusterversion "+testNamespace, func() {
It("should be created properly on the managed cluster", func() {
By("Creating " + case27ConfigPolicyName + " on managed")
utils.Kubectl("apply", "-f", case27CreateYaml, "-n", testNamespace)
plc := utils.GetWithTimeout(clientManagedDynamic, gvrConfigPolicy,
case27ConfigPolicyName, testNamespace, true, defaultTimeoutSeconds)
Expect(plc).NotTo(BeNil())
Eventually(func() interface{} {
managedPlc := utils.GetWithTimeout(clientManagedDynamic, gvrConfigPolicy,
case27ConfigPolicyName, testNamespace, true, defaultTimeoutSeconds)

return utils.GetStatusMessage(managedPlc)
}, 120, 1).Should(Equal(
"pods [nginx-pod-e2e] in namespace default found as specified, " +
"therefore this Object template is compliant"))
})
It("should be updated properly on the managed cluster", func() {
By("Creating " + case27ConfigPolicyName + " on managed")
utils.Kubectl("apply", "-f", case27UpdateYaml, "-n", testNamespace)
Eventually(func() interface{} {
managedPlc := utils.GetWithTimeout(clientManagedDynamic, gvrConfigPolicy,
case27ConfigPolicyName, testNamespace, true, defaultTimeoutSeconds)

return utils.GetStatusMessage(managedPlc)
}, 30, 0.5).Should(Equal(
"pods [nginx-pod-e2e] in namespace default was updated successfully"))
})
It("Cleans up", func() {
deleteConfigPolicies([]string{case27ConfigPolicyName})
utils.Kubectl("delete", "pod", "nginx-pod-e2e")
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: policy.open-cluster-management.io/v1
kind: ConfigurationPolicy
metadata:
name: policy-pod-create
spec:
remediationAction: enforce
namespaceSelector:
exclude: ["kube-*"]
include: ["default"]
object-templates:
- complianceType: musthave
objectDefinition:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod-e2e
spec:
containers:
- image: nginx:1.7.9
name: nginx
ports:
- containerPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: policy.open-cluster-management.io/v1
kind: ConfigurationPolicy
metadata:
name: policy-pod-create
spec:
remediationAction: enforce
namespaceSelector:
exclude: ["kube-*"]
include: ["default"]
object-templates:
- complianceType: musthave
objectDefinition:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod-e2e
labels:
test: test
spec:
containers:
- image: nginx:1.7.9
name: nginx
ports:
- containerPort: 80

0 comments on commit 74add6a

Please sign in to comment.