Skip to content

Commit

Permalink
Add relatedObjs to unamed mustnothave musthave
Browse files Browse the repository at this point in the history
Ref: https://issues.redhat.com/browse/ACM-8782
Signed-off-by: Yi Rae Kim <yikim@redhat.com>
  • Loading branch information
yiraeChristineKim authored and openshift-merge-bot[bot] committed Jan 5, 2024
1 parent 32c59d0 commit 7529c90
Show file tree
Hide file tree
Showing 12 changed files with 607 additions and 29 deletions.
Binary file added __debug_bin2514188118
Binary file not shown.
77 changes: 53 additions & 24 deletions controllers/configurationpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,7 @@ func (r *ConfigurationPolicyReconciler) handleObjects(
}

var existingObj *unstructured.Unstructured
var allResourceNames []string

if objDetails.name != "" { // named object, so checking just for the existence of the specific object
// If the object couldn't be retrieved, this will be handled later on.
Expand All @@ -1521,7 +1522,7 @@ func (r *ConfigurationPolicyReconciler) handleObjects(
log.V(1).Info(
"The object template does not specify a name. Will search for matching objects in the namespace.",
)
objNames = getNamesOfKind(
objNames, allResourceNames = getNamesOfKind(
desiredObj,
mapping.Resource,
objDetails.isNamespaced,
Expand Down Expand Up @@ -1556,6 +1557,8 @@ func (r *ConfigurationPolicyReconciler) handleObjects(

objShouldExist := !strings.EqualFold(string(objectT.ComplianceType), string(policyv1.MustNotHave))

shouldAddCondensedRelatedObj := false

if len(objNames) == 1 {
name := objNames[0]
singObj := singleObject{
Expand Down Expand Up @@ -1598,6 +1601,15 @@ func (r *ConfigurationPolicyReconciler) handleObjects(
} else {
resultEvent.compliant = false
resultEvent.reason = reasonWantFoundDNE
// Length of objNames = 0, complianceType == musthave or mustonlyhave
// Find Noncompliant resources to add to the status.relatedObjects for debugging purpose
shouldAddCondensedRelatedObj = true
if objDetails.kind != "" && objDetails.name == "" {
// Change reason to Resource found but does not match
if len(allResourceNames) > 0 {
resultEvent.reason = reasonWantFoundNoMatch
}
}
}
} else {
if exists {
Expand All @@ -1606,21 +1618,36 @@ func (r *ConfigurationPolicyReconciler) handleObjects(
} else {
resultEvent.compliant = true
resultEvent.reason = reasonWantNotFoundDNE
// Compliant, complianceType == mustnothave
// Find resources in the same namespace to add to the status.relatedObjects for debugging purpose
shouldAddCondensedRelatedObj = true
}
}

result = objectTmplEvalResult{objectNames: objNames, events: []objectTmplEvalEvent{resultEvent}}

relatedObjects = addRelatedObjects(
resultEvent.compliant,
mapping.Resource,
objDetails.kind,
namespace,
objDetails.isNamespaced,
objNames,
resultEvent.reason,
nil,
)
if shouldAddCondensedRelatedObj {
// relatedObjs name is *
relatedObjects = addCondensedRelatedObjs(
mapping.Resource,
resultEvent.compliant,
objDetails.kind,
namespace,
objDetails.isNamespaced,
resultEvent.reason,
)
} else {
relatedObjects = addRelatedObjects(
resultEvent.compliant,
mapping.Resource,
objDetails.kind,
namespace,
objDetails.isNamespaced,
objNames,
resultEvent.reason,
nil,
)
}
}

return relatedObjects, result
Expand Down Expand Up @@ -1962,6 +1989,7 @@ func buildNameList(

// getNamesOfKind returns an array with names of all of the resources found
// matching the GVK specified.
// allResourceList includes names that are under the same namespace and kind.
func getNamesOfKind(
desiredObj unstructured.Unstructured,
rsrc schema.GroupVersionResource,
Expand All @@ -1970,30 +1998,31 @@ func getNamesOfKind(
dclient dynamic.Interface,
complianceType string,
zeroValueEqualsNil bool,
) (kindNameList []string) {
) (kindNameList []string, allResourceList []string) {
var resList *unstructured.UnstructuredList
var err error

if namespaced {
res := dclient.Resource(rsrc).Namespace(ns)

resList, err := res.List(context.TODO(), metav1.ListOptions{})
if err != nil {
log.Error(err, "Could not list resources", "rsrc", rsrc, "namespaced", namespaced)

return kindNameList
}
resList, err = res.List(context.TODO(), metav1.ListOptions{})
} else {
res := dclient.Resource(rsrc)

return buildNameList(desiredObj, complianceType, resList, zeroValueEqualsNil)
resList, err = res.List(context.TODO(), metav1.ListOptions{})
}

res := dclient.Resource(rsrc)

resList, err := res.List(context.TODO(), metav1.ListOptions{})
if err != nil {
log.Error(err, "Could not list resources", "rsrc", rsrc, "namespaced", namespaced)

return kindNameList
return kindNameList, allResourceList
}

for _, res := range resList.Items {
allResourceList = append(allResourceList, res.GetName())
}

return buildNameList(desiredObj, complianceType, resList, zeroValueEqualsNil)
return buildNameList(desiredObj, complianceType, resList, zeroValueEqualsNil), allResourceList
}

// enforceByCreatingOrDeleting can handle the situation where a musthave or mustonlyhave object is
Expand Down
39 changes: 39 additions & 0 deletions controllers/configurationpolicy_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,45 @@ func addRelatedObjects(
return relatedObjects
}

// addCondensedRelatedObjs does not include all of relatedObjs.
// The Name field is "*". The list of objects will be presented on the console.
func addCondensedRelatedObjs(
rsrc schema.GroupVersionResource,
compliant bool,
kind string,
namespace string,
namespaced bool,
reason string,
) (relatedObjects []policyv1.RelatedObject) {
metadata := policyv1.ObjectMetadata{Name: "*"}

if namespaced {
metadata.Namespace = namespace
} else {
metadata.Namespace = ""
}

// Initialize the related object from the object handling
relatedObject := policyv1.RelatedObject{
Reason: reason,
Object: policyv1.ObjectResource{
APIVersion: rsrc.GroupVersion().String(),
Kind: kind,
Metadata: metadata,
},
}

if compliant {
relatedObject.Compliant = string(policyv1.Compliant)
} else {
relatedObject.Compliant = string(policyv1.NonCompliant)
}

relatedObjects = append(relatedObjects, relatedObject)

return relatedObjects
}

// unmarshalFromJSON unmarshals raw JSON data into an object
func unmarshalFromJSON(rawData []byte) (unstructured.Unstructured, error) {
var unstruct unstructured.Unstructured
Expand Down
13 changes: 8 additions & 5 deletions test/e2e/case14_selection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,14 @@ var _ = Describe("Test policy compliance with namespace selection", Ordered, fun
// If an object name is specified in the policy, related objects match those in the template.
// If an object name is not specified in the policy, related objects match those in the
// cluster as this is not enforceable.
if policy.hasObjName {
Expect(checkRelated(plc)).Should(HaveLen(len(testNamespaces) + 1))
} else {
Expect(checkRelated(plc)).Should(HaveLen(len(testNamespaces)))
}
// When hasObjName = false
// compliant: NonCompliant
// metadata:
// name: '*'
// namespace: range3
// reason: Resource not found but should exist
// is attached for range3.
Expect(checkRelated(plc)).Should(HaveLen(len(testNamespaces) + 1))
}
})

Expand Down
Loading

0 comments on commit 7529c90

Please sign in to comment.