Skip to content

Commit

Permalink
Implement new complianceConfig field
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
JeffeyL committed Jun 5, 2024
1 parent 324a374 commit 6dba49a
Show file tree
Hide file tree
Showing 8 changed files with 514 additions and 68 deletions.
51 changes: 33 additions & 18 deletions api/v1beta1/operatorpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ import (
policyv1 "open-cluster-management.io/config-policy-controller/api/v1"
)

// StatusConfigAction : StatusMessageOnly or NonCompliant
// +kubebuilder:validation:Enum=StatusMessageOnly;NonCompliant
type StatusConfigAction string
// ComplianceConfigAction : Compliant or NonCompliant
// +kubebuilder:validation:Enum=Compliant;NonCompliant
type ComplianceConfigAction string

// RemovalAction : Keep, Delete, or DeleteIfUnused
type RemovalAction string

const (
// StatusMessageOnly is a StatusConfigAction that only shows the status message
StatusMessageOnly StatusConfigAction = "StatusMessageOnly"
// NonCompliant is a StatusConfigAction that shows the status message and sets
// the compliance to NonCompliant
NonCompliant StatusConfigAction = "NonCompliant"
// Compliant is a ComplianceConfigAction that only shows the status message and
// does not affect the overall compliance
Compliant ComplianceConfigAction = "Compliant"
// NonCompliant is a ComplianceConfigAction that shows the status message and sets
// the overall compliance when the condition is met
NonCompliant ComplianceConfigAction = "NonCompliant"
)

const (
Expand Down Expand Up @@ -98,12 +99,20 @@ func (rb RemovalBehavior) ApplyDefaults() RemovalBehavior {
return withDefaults
}

// StatusConfig defines how resource statuses affect the OperatorPolicy status and compliance
type StatusConfig struct {
CatalogSourceUnhealthy StatusConfigAction `json:"catalogSourceUnhealthy,omitempty"`
DeploymentsUnavailable StatusConfigAction `json:"deploymentsUnavailable,omitempty"`
UpgradesAvailable StatusConfigAction `json:"upgradesAvailable,omitempty"`
UpgradesProgressing StatusConfigAction `json:"upgradesProgressing,omitempty"`
// ComplianceConfig defines how resource statuses affect the OperatorPolicy compliance
type ComplianceConfig struct {
//+kubebuilder:default=Compliant
// Specifies how the CatalogSourceUnhealthy typed condition should affect
// overall policy compliance. Defaults to 'Compliant'
CatalogSourceUnhealthy ComplianceConfigAction `json:"catalogSourceUnhealthy,omitempty"`
//+kubebuilder:default=NonCompliant
// Specifies how the DeploymentCompliant typed condition should affect
// overall policy compliance. Defaults to 'NonCompliant'
DeploymentsUnavailable ComplianceConfigAction `json:"deploymentsUnavailable,omitempty"`
//+kubebuilder:default=Compliant
// Specifies how the InstallPlanCompliant typed condition should affect
// overall policy compliance. Defaults to 'Compliant'
UpgradesAvailable ComplianceConfigAction `json:"upgradesAvailable,omitempty"`
}

// OperatorPolicySpec defines the desired state of OperatorPolicy
Expand All @@ -115,15 +124,15 @@ type OperatorPolicySpec struct {
// Include the name, namespace, and any `spec` fields for the OperatorGroup.
// For more info, see `kubectl explain operatorgroup.spec` or
// https://olm.operatorframework.io/docs/concepts/crds/operatorgroup/
// +kubebuilder:pruning:PreserveUnknownFields
// +optional
//+kubebuilder:pruning:PreserveUnknownFields
//+optional
OperatorGroup *runtime.RawExtension `json:"operatorGroup,omitempty"`

// Include the namespace, and any `spec` fields for the Subscription.
// For more info, see `kubectl explain subscription.spec` or
// https://olm.operatorframework.io/docs/concepts/crds/subscription/
// +kubebuilder:validation:Required
// +kubebuilder:pruning:PreserveUnknownFields
//+kubebuilder:validation:Required
//+kubebuilder:pruning:PreserveUnknownFields
Subscription runtime.RawExtension `json:"subscription"`

// Versions is a list of nonempty strings that specifies which installed versions are compliant when
Expand All @@ -143,6 +152,12 @@ type OperatorPolicySpec struct {
// approval is not affected by this setting. This setting has no effect when the policy is in
// 'mustnothave' mode. Allowed values are "None" or "Automatic".
UpgradeApproval string `json:"upgradeApproval"`

//+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 causes the OperatorPolicy to become NonCompliant.
ComplianceConfig ComplianceConfig `json:"complianceConfig,omitempty"`
}

// OperatorPolicyStatus defines the observed state of OperatorPolicy
Expand Down
31 changes: 16 additions & 15 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 17 additions & 10 deletions controllers/operatorpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,7 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
ipsRequiringApproval := make([]unstructured.Unstructured, 0)
anyInstalling := false
currentPlanFailed := false
complianceConfig := policy.Spec.ComplianceConfig.UpgradesAvailable

// Construct the relevant relatedObjects, and collect any that might be considered for approval
for i, installPlan := range ownedInstallPlans {
Expand Down Expand Up @@ -1356,7 +1357,8 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
}
}

relatedInstallPlans = append(relatedInstallPlans, existingInstallPlanObj(&ownedInstallPlans[i], phase))
relatedInstallPlans = append(relatedInstallPlans,
existingInstallPlanObj(&ownedInstallPlans[i], phase, complianceConfig))
}

if currentPlanFailed {
Expand Down Expand Up @@ -1396,9 +1398,8 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
// Only report this status when not approving an InstallPlan, because otherwise it could easily
// oscillate between this and another condition.
if policy.Spec.RemediationAction.IsInform() || (!initialInstall && !autoUpgrade) {
// FUTURE: check policy.spec.statusConfig.upgradesAvailable to determine `compliant`.
// For now this condition assumes it is set to 'NonCompliant'
return updateStatus(policy, installPlanUpgradeCond(allUpgradeVersions, nil), relatedInstallPlans...), nil
return updateStatus(policy, installPlanUpgradeCond(complianceConfig, allUpgradeVersions, nil),
relatedInstallPlans...), nil
}

approvedVersion := "" // this will only be accurate when there is only one approvable InstallPlan
Expand Down Expand Up @@ -1446,8 +1447,11 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
}

if len(approvableInstallPlans) != 1 {
changed := updateStatus(policy,
installPlanUpgradeCond(allUpgradeVersions, approvableInstallPlans), relatedInstallPlans...)
changed := updateStatus(
policy,
installPlanUpgradeCond(complianceConfig, allUpgradeVersions, approvableInstallPlans),
relatedInstallPlans...,
)

return changed, nil
}
Expand Down Expand Up @@ -1644,6 +1648,7 @@ func (r *OperatorPolicyReconciler) handleDeployment(
var relatedObjects []policyv1.RelatedObject
var unavailableDeployments []appsv1.Deployment

complianceConfig := policy.Spec.ComplianceConfig.DeploymentsUnavailable
depNum := 0

for _, dep := range csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs {
Expand Down Expand Up @@ -1680,15 +1685,16 @@ func (r *OperatorPolicyReconciler) handleDeployment(
if policy.Spec.ComplianceType.IsMustNotHave() {
relatedObjects = append(relatedObjects, foundNotApplicableObj(&dep))
} else {
relatedObjects = append(relatedObjects, existingDeploymentObj(&dep))
relatedObjects = append(relatedObjects, existingDeploymentObj(&dep, complianceConfig))
}
}

if policy.Spec.ComplianceType.IsMustNotHave() {
return updateStatus(policy, notApplicableCond("Deployment"), relatedObjects...), nil
}

return updateStatus(policy, buildDeploymentCond(depNum > 0, unavailableDeployments), relatedObjects...), nil
return updateStatus(policy, buildDeploymentCond(complianceConfig, depNum > 0, unavailableDeployments),
relatedObjects...), nil
}

func (r *OperatorPolicyReconciler) handleCRDs(
Expand Down Expand Up @@ -1888,8 +1894,9 @@ func (r *OperatorPolicyReconciler) musthaveCatalogSource(
isUnhealthy = (CatalogSrcState != CatalogSourceReady)
}

changed := updateStatus(policy, catalogSourceFindCond(isUnhealthy, isMissing, catalogName),
catalogSourceObj(catalogName, catalogNS, isUnhealthy, isMissing))
complianceConfig := policy.Spec.ComplianceConfig.CatalogSourceUnhealthy
changed := updateStatus(policy, catalogSourceFindCond(complianceConfig, isUnhealthy, isMissing, catalogName),
catalogSourceObj(catalogName, catalogNS, isUnhealthy, isMissing, complianceConfig))

return changed, nil
}
Expand Down
Loading

0 comments on commit 6dba49a

Please sign in to comment.