Skip to content

Commit c17833d

Browse files
authored
Add new check job-ttl-seconds-after-finished (stackrox#963) (stackrox#964)
* Add new check job-ttl-seconds-after-finished (stackrox#963) The new check advices for - Setting ttlSecondsAfterFinished for standalone Job objects whenever it's not set - Unsetting ttlSecondsAfterFinished for managed Job objects whenever it's set
1 parent c87de4e commit c17833d

File tree

15 files changed

+411
-0
lines changed

15 files changed

+411
-0
lines changed

docs/generated/checks.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,15 @@ minReplicas: 3
277277
**Remediation**: Ensure that port naming is in conjunction with the specification. For more information, please look at the Kubernetes Service specification on this page: https://kubernetes.io/docs/reference/_print/#ServiceSpec. And additional information about IANA Service naming can be found on the following page: https://www.rfc-editor.org/rfc/rfc6335.html#section-5.1.
278278
279279
**Template**: [target-port](templates.md#target-port)
280+
## job-ttl-seconds-after-finished
281+
282+
**Enabled by default**: Yes
283+
284+
**Description**: Indicates when standalone jobs do not set ttlSecondsAfterFinished and when jobs managed by cronjob do set ttlSecondsAfterFinished.
285+
286+
**Remediation**: Set Job.spec.ttlSecondsAfterFinished. Unset CronJob.Spec.JobTemplate.Spec.ttlSecondsAfterFinished.
287+
288+
**Template**: [job-ttl-seconds-after-finished](templates.md#ttlsecondsafterfinished-impact-for-standalone-and-managed-job-objects)
280289
## latest-tag
281290
282291
**Enabled by default**: Yes

docs/generated/templates.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,15 @@ KubeLinter supports the following templates:
414414
type: array
415415
```
416416

417+
## ttlSecondsAfterFinished impact for standalone and managed Job objects
418+
419+
**Key**: `job-ttl-seconds-after-finished`
420+
421+
**Description**: Flag standalone Job objects not setting ttlSecondsAfterFinished. Flag CronJob objects setting ttlSecondsAfterFinished
422+
423+
**Supported Objects**: JobLike
424+
425+
417426
## Latest Tag
418427

419428
**Key**: `latest-tag`

e2etests/bats-tests.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,21 @@ get_value_from() {
394394
[[ "${actual_messages[3]}" == "Deployment: port name \"123456\" in container \"invalid-target-ports\" must contain at least one letter (a-z)" ]]
395395
}
396396

397+
@test "job-ttl-seconds-after-finished" {
398+
tmp="tests/checks/job-ttl-seconds-after-finished.yaml"
399+
cmd="${KUBE_LINTER_BIN} lint --include job-ttl-seconds-after-finished --do-not-auto-add-defaults --format json ${tmp}"
400+
run ${cmd}
401+
402+
message1=$(get_value_from "${lines[0]}" '.Reports[0].Object.K8sObject.GroupVersionKind.Kind + " " + .Reports[0].Object.K8sObject.Name + ": " + .Reports[0].Diagnostic.Message')
403+
message2=$(get_value_from "${lines[0]}" '.Reports[1].Object.K8sObject.GroupVersionKind.Kind + " " + .Reports[1].Object.K8sObject.Name + ": " + .Reports[1].Diagnostic.Message')
404+
405+
[[ "${message1}" == "Job bad-job: Standalone Job does not specify ttlSecondsAfterFinished" ]]
406+
[[ "${message2}" == "CronJob bad-cronjob: Managed Job specifies ttlSecondsAfterFinished which might conflict with successfulJobsHistoryLimit and failedJobsHistoryLimit from CronJob that have default values. Final behaviour is determined by the strictest parameter, and therefore, setting ttlSecondsAfterFinished at the job level can result with unexpected behaviour with regard to finished jobs removal" ]]
407+
408+
count=$(get_value_from "${lines[0]}" '.Reports | length')
409+
[[ "${count}" == "2" ]]
410+
}
411+
397412
@test "latest-tag" {
398413
tmp="tests/checks/latest-tag.yml"
399414
cmd="${KUBE_LINTER_BIN} lint --include latest-tag --do-not-auto-add-defaults --format json ${tmp}"

internal/defaultchecks/default_checks.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var (
1717
"host-network",
1818
"host-pid",
1919
"invalid-target-ports",
20+
"job-ttl-seconds-after-finished",
2021
"latest-tag",
2122
"liveness-port",
2223
"mismatching-selector",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name: "job-ttl-seconds-after-finished"
2+
description: "Indicates when standalone jobs do not set ttlSecondsAfterFinished and when jobs managed by cronjob do set ttlSecondsAfterFinished."
3+
remediation: "Set Job.spec.ttlSecondsAfterFinished. Unset CronJob.Spec.JobTemplate.Spec.ttlSecondsAfterFinished."
4+
scope:
5+
objectKinds:
6+
- JobLike
7+
template: "job-ttl-seconds-after-finished"

pkg/extract/job_spec.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package extract
2+
3+
import (
4+
"golang.stackrox.io/kube-linter/pkg/k8sutil"
5+
batchV1 "k8s.io/api/batch/v1"
6+
)
7+
8+
// JobSpec extracts a job template spec from Job or CronJob objects
9+
func JobSpec(obj k8sutil.Object) (batchV1.JobSpec, string, bool) {
10+
switch obj := obj.(type) {
11+
case *batchV1.Job:
12+
return obj.Spec, "Job", true
13+
case *batchV1.CronJob:
14+
return obj.Spec.JobTemplate.Spec, "CronJob", true
15+
default:
16+
return batchV1.JobSpec{}, "", false
17+
}
18+
}

pkg/lintcontext/mocks/cronjob.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package mocks
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
batchV1 "k8s.io/api/batch/v1"
8+
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
)
10+
11+
// AddMockCronJob adds a mock CronJob to LintContext
12+
func (l *MockLintContext) AddMockCronJob(t *testing.T, name string) {
13+
require.NotEmpty(t, name)
14+
l.objects[name] = &batchV1.CronJob{
15+
ObjectMeta: metaV1.ObjectMeta{Name: name},
16+
}
17+
}
18+
19+
// ModifyCronJob modifies a given CronJob in the context via the passed function
20+
func (l *MockLintContext) ModifyCronJob(t *testing.T, name string, f func(cronjob *batchV1.CronJob)) {
21+
dep, ok := l.objects[name].(*batchV1.CronJob)
22+
require.True(t, ok)
23+
f(dep)
24+
}

pkg/lintcontext/mocks/job.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package mocks
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
batchV1 "k8s.io/api/batch/v1"
8+
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
)
10+
11+
// AddMockJob adds a mock Job to LintContext
12+
func (l *MockLintContext) AddMockJob(t *testing.T, name string) {
13+
require.NotEmpty(t, name)
14+
l.objects[name] = &batchV1.Job{
15+
ObjectMeta: metaV1.ObjectMeta{Name: name},
16+
}
17+
}
18+
19+
// ModifyJob modifies a given Job in the context via the passed function
20+
func (l *MockLintContext) ModifyJob(t *testing.T, name string, f func(job *batchV1.Job)) {
21+
dep, ok := l.objects[name].(*batchV1.Job)
22+
require.True(t, ok)
23+
f(dep)
24+
}

pkg/objectkinds/job_like.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package objectkinds
2+
3+
import (
4+
batchV1 "k8s.io/api/batch/v1"
5+
"k8s.io/apimachinery/pkg/runtime/schema"
6+
)
7+
8+
const (
9+
JobLike = "JobLike"
10+
)
11+
12+
var (
13+
jobGVK = batchV1.SchemeGroupVersion.WithKind("Job")
14+
)
15+
var (
16+
cronJobGVK = batchV1.SchemeGroupVersion.WithKind("CronJob")
17+
)
18+
19+
func init() {
20+
RegisterObjectKind(JobLike, MatcherFunc(func(gvk schema.GroupVersionKind) bool {
21+
return gvk == jobGVK || gvk == cronJobGVK
22+
}))
23+
}

pkg/templates/all/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
_ "golang.stackrox.io/kube-linter/pkg/templates/hostpid"
2626
_ "golang.stackrox.io/kube-linter/pkg/templates/hpareplicas"
2727
_ "golang.stackrox.io/kube-linter/pkg/templates/imagepullpolicy"
28+
_ "golang.stackrox.io/kube-linter/pkg/templates/jobttlsecondsafterfinished"
2829
_ "golang.stackrox.io/kube-linter/pkg/templates/latesttag"
2930
_ "golang.stackrox.io/kube-linter/pkg/templates/livenessport"
3031
_ "golang.stackrox.io/kube-linter/pkg/templates/livenessprobe"

0 commit comments

Comments
 (0)