Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new ComplianceConfig field #252

Merged

Conversation

zyjjay
Copy link
Contributor

@zyjjay zyjjay commented May 23, 2024

Users can define how specific resource statuses affect the overall OperatorPolicy compliance events.

ref: https://issues.redhat.com/browse/ACM-11023

Copy link
Member

@JustinKuli JustinKuli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall to me! I think the one e2e test, combined with the unit tests is sufficient for verifying the behavior.

I think we're considering changing the default behaviors, which look easy to adjust here.

Copy link
Member

@JustinKuli JustinKuli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some early comments - they might be things you're already looking at changing.

Comment on lines 683 to 685
// FUTURE: check policy.spec.statusConfig.upgradesAvailable to determine `compliant`.
// For now this condition assumes it is set to 'NonCompliant'
canModifyComp := complianceConfig == "NonCompliant"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd prefer using complianceConfig == "NonCompliant" directly in the condition below, it might make it easier in the future if we add other options. Also just a reminder to remove the // FUTURE comment.

@@ -775,6 +794,11 @@ func buildDeploymentCond(
message = fmt.Sprintf("the deployments %s do not have their minimum availability", names)
}

if !canModifyComp {
status = metav1.ConditionTrue
message += " - ignore, compliance overridden by complianceConfig"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a conditional to only add this message if it is overriding the status? It looks to me like it would be adding this even if all of the deployments are available.

@@ -1044,7 +1079,7 @@ func noInstallPlansObj(namespace string) policyv1.RelatedObject {
// existingInstallPlanObj returns a RelatedObject for the InstallPlan, with a reason
// like 'The InstallPlan is ____' based on the phase. When the InstallPlan is in phase
// 'Complete', the object will be Compliant, otherwise it will be NonCompliant.
func existingInstallPlanObj(ip client.Object, phase string) policyv1.RelatedObject {
func existingInstallPlanObj(ip client.Object, phase string, complianceConfig string) policyv1.RelatedObject {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if this took type policyv1beta1.ComplianceConfigAction, there are two conversions to string that would be unnecessary.

@JeffeyL JeffeyL force-pushed the ACM-11023 branch 4 times, most recently from fedc6e1 to 28b795e Compare May 30, 2024 20:17
@zyjjay zyjjay marked this pull request as ready for review May 30, 2024 21:08
@openshift-ci openshift-ci bot requested review from gparvin and mprahl May 30, 2024 21:09
@mprahl
Copy link
Member

mprahl commented May 31, 2024

Could you please squash the commits and update the PR title and commit title to mention complianceConfig instead of statusConfig?

Comment on lines 23 to 24
// Compliant is a ComplianceConfigAction that only shows the status message and
// sets thje compliance to Compliant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Compliant is a ComplianceConfigAction that only shows the status message and
// sets thje compliance to Compliant
// Compliant is a ComplianceConfigAction that only shows the status message and
// does not affect the overall compliance.

Comment on lines 26 to 27
// NonCompliant is a ComplianceConfigAction that shows the status message and sets
// the compliance to NonCompliant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// NonCompliant is a ComplianceConfigAction that shows the status message and sets
// the compliance to NonCompliant
// NonCompliant is a ComplianceConfigAction that shows the status message and sets
// the overall compliance to NonCompliant when the condition is met

DeploymentsUnavailable StatusConfigAction `json:"deploymentsUnavailable,omitempty"`
UpgradesAvailable StatusConfigAction `json:"upgradesAvailable,omitempty"`
UpgradesProgressing StatusConfigAction `json:"upgradesProgressing,omitempty"`
// ComplianceConfig defines how resource statuses affect the OperatorPolicy status and compliance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// ComplianceConfig defines how resource statuses affect the OperatorPolicy status and compliance
// ComplianceConfig defines how resource statuses affect the OperatorPolicy compliance

UpgradesProgressing StatusConfigAction `json:"upgradesProgressing,omitempty"`
// ComplianceConfig defines how resource statuses affect the OperatorPolicy status and compliance
type ComplianceConfig struct {
// +kubebuilder:default=Compliant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of having a default, but this does mean the template sync equivalentPolicies will have to be modified to not think the OperatorPolicy on the cluster is different than the one specified in the Policy object if the defaults aren't specified in the Policy object. See how this is handled for ConfigurationPolicy:
https://github.com/open-cluster-management-io/governance-policy-framework-addon/blob/c34eec6923b9f4079977c116ecd513f1eb9f22b7/controllers/templatesync/template_sync.go#L958

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like I'll need to do some similar changes like this for some other fields, sorry I missed it!

@@ -130,7 +133,7 @@ type OperatorPolicySpec struct {
// in 'inform' mode, and which installPlans are approved when in 'enforce' mode
Versions []policyv1.NonEmptyString `json:"versions,omitempty"`

//+kubebuilder:default={}
// +kubebuilder:default={}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, comments related to autogenerating code don't have a space after // but I'm not strict about this. Some others on the team may be 😉

Comment on lines 151 to 153
// ComplianceConfig defines how resource statuses affect the OperatorPolicy status and compliance.
// Options include Compliant, which will essentially ignore NonCompliance for certain cases,
// and NonCompliant, which will report NonCompliance for those cases.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// ComplianceConfig defines how resource statuses affect the OperatorPolicy status and compliance.
// Options include Compliant, which will essentially ignore NonCompliance for certain cases,
// and NonCompliant, which will report NonCompliance for those cases.
// ComplianceConfig defines how resource statuses affect the OperatorPolicy compliance.
// When set to Compliant, the condition does not impact the OperatorPolicy compliance. When
// set to NonCompliant, the condition causes the OperatorPolicy to become NonComplaint.

@@ -1356,7 +1356,9 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
}
}

relatedInstallPlans = append(relatedInstallPlans, existingInstallPlanObj(&ownedInstallPlans[i], phase))
complianceConfig := policy.Spec.ComplianceConfig.UpgradesAvailable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you set this once outside of the loop so it's not redefined every loop iteration and the code below can reference it as well?

@@ -1680,15 +1685,19 @@ func (r *OperatorPolicyReconciler) handleDeployment(
if policy.Spec.ComplianceType.IsMustNotHave() {
relatedObjects = append(relatedObjects, foundNotApplicableObj(&dep))
} else {
relatedObjects = append(relatedObjects, existingDeploymentObj(&dep))
complianceConfig := policy.Spec.ComplianceConfig.DeploymentsUnavailable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider defining this once outside of the loop.

@@ -669,12 +675,13 @@ var installPlansNoApprovals = metav1.Condition{

// installPlanUpgradeCond is a NonCompliant condition with Reason 'InstallPlanRequiresApproval'
// and a message detailing which possible updates are available
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring needs to be updated to mention the new argument.

@@ -693,6 +700,13 @@ func installPlanUpgradeCond(versions []string, approvableIPs []unstructured.Unst
cond.Message += " but multiple of those match the versions specified in the policy"
}

if complianceConfig == "NonCompliant" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: It doesn't really matter in this case because there are only two values, but I prefer checking specifically for "Compliant" and if it's not, assume it's "NonCompliant". If we add additional options in the future, this is clearer.

cond.Status = metav1.ConditionFalse
} else {
cond.Status = metav1.ConditionTrue
cond.Message += " - ignore, compliance overridden by complianceConfig"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this additional message is required. Now that the default is "Compliant", I don't think overridden is the correct term.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think because this condition is a NonCompliant condition, it would make sense to to say it was overridden. Especially since the condition message makes it to the final policy compliance event, it might be useful to see this detail.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I somehow agree with both of you 😆 - saying its overriden doesn't feel right, but I don't want to not mention that the possible upgrade is being ignored.

Maybe a rephrasing would help, something like " - not triggering noncompliance because of complianceConfig".

Copy link
Member

@JustinKuli JustinKuli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good overall, I'd be ok merging this if Matt's discussions are all resolved... I do have some nits, and I'm wondering if we should add info to the related objects when their compliance is affected by the complianceConfig. But that's not strictly necessary to do now.

controllers/operatorpolicy_status.go Show resolved Hide resolved
controllers/operatorpolicy_status.go Outdated Show resolved Hide resolved
controllers/operatorpolicy_status.go Show resolved Hide resolved
@JeffeyL
Copy link
Contributor

JeffeyL commented Jun 5, 2024

Per Matt's previous mention, this PR (open-cluster-management-io/governance-policy-framework-addon#145) in the framework-addon addresses the template sync for default values of complianceConfig

JustinKuli
JustinKuli previously approved these changes Jun 5, 2024
Copy link
Member

@JustinKuli JustinKuli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/hold for @mprahl

LGTM

//+kubebuilder:default={}
// ComplianceConfig defines how resource statuses affect the OperatorPolicy status and compliance.
// When set to Compliant, the condition does not impact the OperatorPolicy compliance.
// When set to NonCompliant, the condition cause the OperatorPolicy to become NonCompliant.
Copy link
Member

@mprahl mprahl Jun 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// When set to NonCompliant, the condition cause the OperatorPolicy to become NonCompliant.
// When set to NonCompliant, the condition causes the OperatorPolicy to become NonCompliant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I assume you meant "causes"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, you caught it before the edit 😆

relObj.Compliant = string(policyv1.NonCompliant)
} else {
relObj.Compliant = string(policyv1.Compliant)
relObj.Reason += " (policy compliance is not impacted due to spec.complianceConfig.upgradesAvailable)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this message to be quite noisy for a default behavior. My thought is that we only need to include a message such as this when the default is overridden.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JustinKuli what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's prohibitively noisy, but I see what you mean with default behaviors. So then should we have a message on the NonCompliant case? Maybe "(in violation due to spec.complianceConfig.upgradesAvailable)"?

relObj.Compliant = string(policyv1.NonCompliant)
} else {
relObj.Compliant = string(policyv1.Compliant)
relObj.Reason += " (policy compliance is not impacted due to spec.complianceConfig.upgradesAvailable)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

if complianceConfig != "Compliant" {
compliance = string(policyv1.NonCompliant)
} else {
reason += " (policy compliance is not impacted due to spec.complianceConfig.catalogSourceUnhealthy)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mprahl how do you feel about this one. I think "___ exists but is unhealthy" on its own in a Compliant object could be confusing. It is the default behavior, but I feel like mentioning why "unhealthy" is ok in this case is good.

Users can define how specific resource statuses affect the overall OperatorPolicy status and compliance events.

ref: https://issues.redhat.com/browse/ACM-11023
Signed-off-by: Jason Zhang <jaszhang@redhat.com>
Copy link
Member

@JustinKuli JustinKuli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/unhold

LGTM, I think you covered Matt's suggestions, thanks

Copy link

openshift-ci bot commented Jun 5, 2024

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: JustinKuli, zyjjay

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants