Skip to content
Merged
11 changes: 11 additions & 0 deletions documentation/docs/api/crds/scan.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,17 @@ resources:
memory: 4Gi
```

### TTLSecondsAfterFinished
`ttlSecondsAfterFinished` deletes the scan after a specified duration.

```yaml
ttlSecondsAfterFinished: 30 #deletes the scan after 30 seconds after completion
```

:::note
ttlSecondsAfterFinished can also be set for the scan (as part of the [jobTemplate](https://www.securecodebox.io/docs/api/crds/scan-type#jobtemplate-required)), [parser](https://www.securecodebox.io/docs/api/crds/parse-definition) and [hook](https://www.securecodebox.io/docs/api/crds/scan-completion-hook#ttlsecondsafterfinished-optional) jobs individually. Setting these will only deleted the jobs not the entire scan.
:::

## Metadata

Metadata is a standard field on Kubernetes resources. It contains multiple relevant fields, e.g. the name of the resource, its namespace and a `creationTimestamp` of the resource. See more on the [Kubernetes Docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/) and the [Kubernetes API Reference](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/object-meta/).
Expand Down
4 changes: 3 additions & 1 deletion operator/apis/execution/v1/scan_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ type ScanSpec struct {

// Resources lets you control resource limits and requests for the parser container. See https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
// ttlSecondsAfterFinished limits the lifetime of a Scan that has finished execution (either Done or Errored). If this field is set ttlSecondsAfterFinished after the Scan finishes, it is eligible to be automatically deleted. When the Scan is being deleted, its lifecycle guarantees (e.g. finalizers) will be honored. If this field is unset, the Scan won't be automatically deleted. If this is set to zero, the Scan becomes eligible to be deleted immediately after it finishes.
TTLSecondsAfterFinished *int32 `json:"ttlSecondsAfterFinished,omitempty"`
}

type ScanState string
Expand All @@ -168,7 +170,7 @@ const (
type ScanStatus struct {
State ScanState `json:"state,omitempty"`

// FinishedAt contains the time where the scan (including parser & hooks) has been marked as "Done"
// FinishedAt contains the time where the scan (including parser & hooks) has been marked as "Done", or "Errored"
FinishedAt *metav1.Time `json:"finishedAt,omitempty"`
ErrorDescription string `json:"errorDescription,omitempty"`

Expand Down
5 changes: 5 additions & 0 deletions operator/apis/execution/v1/zz_generated.deepcopy.go

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

20 changes: 20 additions & 0 deletions operator/controllers/execution/scans/scan_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,28 @@ func (r *ScanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.
err = r.setHookStatus(&scan)
case executionv1.ScanStateHookProcessing:
err = r.executeHooks(&scan)
case executionv1.ScanStateErrored:
if r.checkIfTTLSecondsAfterFinishedisCompleted(&scan) {
err = r.deleteScan(&scan)
}
case executionv1.ScanStateDone:
if r.checkIfTTLSecondsAfterFinishedisCompleted(&scan) {
err = r.deleteScan(&scan)
}
case executionv1.ScanStateReadAndWriteHookProcessing:
fallthrough
case executionv1.ScanStateReadAndWriteHookCompleted:
fallthrough
case executionv1.ScanStateReadOnlyHookProcessing:
err = r.migrateHookStatus(&scan)
}

if scan.Spec.TTLSecondsAfterFinished != nil && (scan.Status.State == executionv1.ScanStateDone || scan.Status.State == executionv1.ScanStateErrored) {
return ctrl.Result{
Requeue: true,
RequeueAfter: time.Duration(*scan.Spec.TTLSecondsAfterFinished) * time.Second,
}, err
}
if err != nil {
return ctrl.Result{}, err
}
Expand Down Expand Up @@ -241,6 +256,11 @@ func updateScanStateMetrics(scan executionv1.Scan) {

func (r *ScanReconciler) updateScanStatus(ctx context.Context, scan *executionv1.Scan) error {
updateScanStateMetrics(*scan)
if scan.Status.State == executionv1.ScanStateDone || scan.Status.State == executionv1.ScanStateErrored {
if scan.Status.FinishedAt == nil {
scan.Status.FinishedAt = &metav1.Time{Time: time.Now()}
}
}

if err := r.Status().Update(ctx, scan); err != nil {
r.Log.Error(err, "unable to update Scan status")
Expand Down
32 changes: 32 additions & 0 deletions operator/controllers/execution/scans/scan_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
resource "k8s.io/apimachinery/pkg/api/resource"

apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -416,3 +417,34 @@ func (r *ScanReconciler) constructJobForScan(scan *executionv1.Scan, scanTypeSpe

return job, nil
}

func (r *ScanReconciler) checkIfTTLSecondsAfterFinishedisCompleted(scan *executionv1.Scan) bool {
if scan.Spec.TTLSecondsAfterFinished == nil {
return false
}
interval := time.Duration(*scan.Spec.TTLSecondsAfterFinished) * time.Second
if scan.Status.FinishedAt != nil {
scanTimeout := scan.Status.FinishedAt.Add(interval)
now := time.Now()
if now.After(scanTimeout) {
return true
}
}
return false
}

func (r *ScanReconciler) deleteScan(scan *executionv1.Scan) error {
ctx := context.Background()
err := r.Client.Delete(ctx, scan)
if err != nil {
if apierrors.IsNotFound(err) {
r.Log.Info("Scan was already deleted, nothing to do")
} else {
r.Log.Error(err, "Unexpected error while trying to delete Scan")
return err
}
} else {
r.Log.Info("Scan was deleted successfully", "scan", scan.Name)
}
return nil
}
7 changes: 7 additions & 0 deletions operator/crds/cascading.securecodebox.io_cascadingrules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2684,6 +2684,13 @@ spec:
type: string
type: object
type: array
ttlSecondsAfterFinished:
description: ttlSecondsAfterFinished limits the lifetime of a
Scan that has finished execution (either Done or Errored). If
this field is set ttlSecondsAfterFinished after the Scan finishes,
it is eligible to be automatically deleted.
format: int32
type: integer
volumeMounts:
description: VolumeMounts allows to specify volume mounts for
the scan container.
Expand Down
9 changes: 8 additions & 1 deletion operator/crds/execution.securecodebox.io_scans.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2623,6 +2623,13 @@ spec:
type: string
type: object
type: array
ttlSecondsAfterFinished:
description: ttlSecondsAfterFinished limits the lifetime of a Scan
that has finished execution (either Done or Errored). If this field
is set ttlSecondsAfterFinished after the Scan finishes, it is eligible
to be automatically deleted.
format: int32
type: integer
volumeMounts:
description: VolumeMounts allows to specify volume mounts for the
scan container.
Expand Down Expand Up @@ -4277,7 +4284,7 @@ spec:
type: object
finishedAt:
description: FinishedAt contains the time where the scan (including
parser & hooks) has been marked as "Done"
parser & hooks) has been marked as "Done", or "Errored"
format: date-time
type: string
orderedHookStatuses:
Expand Down
7 changes: 7 additions & 0 deletions operator/crds/execution.securecodebox.io_scheduledscans.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2678,6 +2678,13 @@ spec:
type: string
type: object
type: array
ttlSecondsAfterFinished:
description: ttlSecondsAfterFinished limits the lifetime of a
Scan that has finished execution (either Done or Errored). If
this field is set ttlSecondsAfterFinished after the Scan finishes,
it is eligible to be automatically deleted.
format: int32
type: integer
volumeMounts:
description: VolumeMounts allows to specify volume mounts for
the scan container.
Expand Down