Skip to content

Commit

Permalink
CMP-2132: Implement suspend and resume scan schedule
Browse files Browse the repository at this point in the history
This commit implements the logic and tests necessary to suspend and
resume scan schedules using the `ScanSetting` custom resource.

You can find more details on the overall justification, use cases, and
implementation details in the enhancement:

  #375
  • Loading branch information
rhmdnd committed Oct 6, 2023
1 parent 560273b commit b4fedde
Show file tree
Hide file tree
Showing 20 changed files with 490 additions and 16 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ Versioning](https://semver.org/spec/v2.0.0.html).

### Enhancements

-
- Users can now pause scan schedules by setting the `ScanSetting.suspend`
attribute to `True`. This allows users to suspend a scan, and reactivate it
without having to delete and recreate the `ScanSettingBinding`, making it
more ergonomic to pause scans during maintenance periods. See the
[enhancement](https://github.com/ComplianceAsCode/compliance-operator/pull/375)
for more details.

### Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: compliancecheckresults.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: complianceremediations.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: compliancescans.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: compliancesuites.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down Expand Up @@ -323,6 +323,11 @@ spec:
scheduled scans will start running only after the initial results
are ready.
type: string
suspend:
default: false
description: Defines if a schedule should be suspended and is a boolean
value, defaulting to False.
type: boolean
required:
- scans
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: profilebundles.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down
2 changes: 1 addition & 1 deletion config/crd/bases/compliance.openshift.io_profiles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: profiles.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down
2 changes: 1 addition & 1 deletion config/crd/bases/compliance.openshift.io_rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: rules.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: scansettingbindings.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand All @@ -16,7 +16,11 @@ spec:
singular: scansettingbinding
scope: Namespaced
versions:
- name: v1alpha1
- additionalPrinterColumns:
- jsonPath: .status.phase
name: Status
type: string
name: v1alpha1
schema:
openAPIV3Schema:
description: ScanSettingBinding is the Schema for the scansettingbindings
Expand Down Expand Up @@ -124,6 +128,8 @@ spec:
- name
type: object
x-kubernetes-map-type: atomic
phase:
type: string
type: object
type: object
served: true
Expand Down
7 changes: 6 additions & 1 deletion config/crd/bases/compliance.openshift.io_scansettings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: scansettings.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down Expand Up @@ -247,6 +247,11 @@ spec:
be strict and error out. `false` means that we don't need to be strict
and we can proceed.
type: boolean
suspend:
default: false
description: Defines if a schedule should be suspended and is a boolean
value, defaulting to False.
type: boolean
timeout:
default: 30m
description: Timeout is the maximum amount of time the scan can run. If
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: tailoredprofiles.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down
2 changes: 1 addition & 1 deletion config/crd/bases/compliance.openshift.io_variables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.12.0
controller-gen.kubebuilder.io/version: v0.13.0
name: variables.compliance.openshift.io
spec:
group: compliance.openshift.io
Expand Down
47 changes: 47 additions & 0 deletions doc/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,53 @@ or `ocp4-var-role-worker`:
`oc get ccr -n openshift-compliance -o yaml | jq '.items[] | select(.valuesUsed | contains("ocp4-var-role-master") or contains("ocp4-var-role-worker"))'`


## Suspending and resuming scan schedules

The `ScanSetting` CRD exposes a `schedule` attribute that allows you to
schedule compliance scans as a cron job syntax. The Compliance Operator uses
Kubernetes `CronJob` resources to implement the schedule for a scan suite,
which is sometimes referred to as a suite rerunner.

Scan schedules are associated with a `ComplianceSuite`, which may contain at
least one `ComplianceScan`. This means the schedule associated with a
`ComplianceSuite` applies to all `ComplianceScan` objects within that suite.
This may be useful to prevent scans from happening during planned maintenance
windows, where results might be inaccurate depending on the state of the
cluster.

You can suspend a `ComplianceSuite` by updating the `ScanSetting` you used when
you created the `ScanSettingBinding`.

```
$ oc patch ss/default -p 'suspend: true' --type merge
```
Any `ScanSettingBinding` using the suspended `ScanSetting` will show a
`SUSPENDED` status:
```
$ oc get ssb
NAME STATUS
cis-node SUSPENDED
```
You can disable the `suspend` attribute to resume the scan schedule:
```
$ oc patch ss/default -p 'suspend: false' --type merge
```
The `ScanSettingBinding` will return to a `READY` state:
```
$ oc get ssb
NAME STATUS
cis-node READY
```
Note that this functionality does not pause, suspend, or stop a scan that is
already in progress.
## Extracting raw results
The scans provide two kinds of raw results: the full report in the ARF format
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/compliance/v1alpha1/compliancesuite_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ type ComplianceSuiteSettings struct {
// Note the scan will still be triggered immediately, and the scheduled
// scans will start running only after the initial results are ready.
Schedule string `json:"schedule,omitempty"`
// Defines if a schedule should be suspended and is a boolean value,
// defaulting to False.
// +kubebuilder:default=false
Suspend bool `json:"suspend,omitempty"`
}

// ComplianceSuiteSpec defines the desired state of ComplianceSuite
Expand Down
20 changes: 20 additions & 0 deletions pkg/apis/compliance/v1alpha1/scansettingbinding_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type ScanSettingBindingStatusPhase string

const (
ScanSettingBindingPhasePending ScanSettingBindingStatusPhase = "PENDING"
ScanSettingBindingPhaseReady ScanSettingBindingStatusPhase = "READY"
ScanSettingBindingPhaseInvalid ScanSettingBindingStatusPhase = "INVALID"
ScanSettingBindingPhaseSuspended ScanSettingBindingStatusPhase = "SUSPENDED"
)

type NamedObjectReference struct {
Name string `json:"name,omitempty"`
Kind string `json:"kind,omitempty"`
Expand All @@ -16,6 +25,7 @@ type NamedObjectReference struct {
// ScanSettingBinding is the Schema for the scansettingbindings API
// +kubebuilder:subresource:status
// +kubebuilder:resource:path=scansettingbindings,scope=Namespaced,shortName=ssb
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=`.status.phase`
type ScanSettingBinding struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand All @@ -32,6 +42,7 @@ type ScanSettingBinding struct {
type ScanSettingBindingSpec struct{}

type ScanSettingBindingStatus struct {
Phase ScanSettingBindingStatusPhase `json:"phase,omitempty"`
// +optional
Conditions Conditions `json:"conditions,omitempty"`
// Reference to the object generated from this ScanSettingBinding
Expand Down Expand Up @@ -76,6 +87,15 @@ func (s *ScanSettingBindingStatus) SetConditionReady() {
})
}

func (s *ScanSettingBindingStatus) SetConditionSuspended() {
s.Conditions.SetCondition(Condition{
Type: "Ready",
Status: corev1.ConditionFalse,
Reason: "Suspended",
Message: "The scan setting binding uses a scan setting that is suspended",
})
}

func init() {
SchemeBuilder.Register(&ScanSettingBinding{}, &ScanSettingBindingList{})
}
1 change: 0 additions & 1 deletion pkg/apis/compliance/v1alpha1/zz_generated.deepcopy.go

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

3 changes: 2 additions & 1 deletion pkg/controller/compliancesuite/suitererunner_cron_compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ func (r *ReconcileComplianceSuite) cronJobCompatCreate(
if !ok {
return fmt.Errorf("failed to cast object to v1 CronJob")
}
if getObjTyped.Spec.Schedule == suite.Spec.Schedule {
if getObjTyped.Spec.Schedule == suite.Spec.Schedule && getObjTyped.Spec.Suspend == &suite.Spec.Suspend {
return nil
}
cronJobCopy := getObjTyped.DeepCopy()
cronJobCopy.Spec.Schedule = suite.Spec.Schedule
cronJobCopy.Spec.Suspend = &suite.Spec.Suspend
logger.Info("Updating v1 rerunner", "CronJob.Name", cronJobCopy.GetName())
return r.Client.Update(context.TODO(), cronJobCopy)
}
Expand Down
Loading

0 comments on commit b4fedde

Please sign in to comment.