Repository: zegl/kube-score
Pull request #474 (2022-05-31 19:38:55)

Bugfix/cronjob restartpolicy check

```
RELNOTE: Implement New Rule: CronJob resource requires Pod restartPolicy set to Never or OnFailure #471
```



Patch:
diff --git a/domain/kube-score.go b/domain/kube-score.go
index 17dab41..6e54d1b 100644
--- a/domain/kube-score.go
+++ b/domain/kube-score.go
@@ -121,6 +121,7 @@ type CronJob interface {
 	GetTypeMeta() metav1.TypeMeta
 	GetObjectMeta() metav1.ObjectMeta
 	StartingDeadlineSeconds() *int64
+	GetPodTemplateSpec() corev1.PodTemplateSpec
 	FileLocationer
 }
 
diff --git a/score/cronjob/cronjob.go b/score/cronjob/cronjob.go
index 39d39bd..fdb8ab3 100644
--- a/score/cronjob/cronjob.go
+++ b/score/cronjob/cronjob.go
@@ -8,6 +8,7 @@ import (
 
 func Register(allChecks *checks.Checks) {
 	allChecks.RegisterCronJobCheck("CronJob has deadline", `Makes sure that all CronJobs has a configured deadline`, cronJobHasDeadline)
+	allChecks.RegisterCronJobCheck("CronJob RestartPolicy", `Makes sure CronJobs have a valid RestartPolicy`, cronJobHasRestartPolicy)
 }
 
 func cronJobHasDeadline(job ks.CronJob) (score scorecard.TestScore) {
@@ -21,3 +22,26 @@ func cronJobHasDeadline(job ks.CronJob) (score scorecard.TestScore) {
 	score.Grade = scorecard.GradeAllOK
 	return
 }
+
+// CronJob restartPolicy must be "OnFailure" or "Never". It cannot be empty (unspecified)
+func cronJobHasRestartPolicy(job ks.CronJob) (score scorecard.TestScore) {
+
+	podTmpl := job.GetPodTemplateSpec()
+	restartPolicy := podTmpl.Spec.RestartPolicy
+
+	if len(restartPolicy) > 0 {
+		if restartPolicy == "Never" || restartPolicy == "OnFailure" {
+			score.Grade = scorecard.GradeAllOK
+		} else {
+			score.Grade = scorecard.GradeCritical
+			score.AddComment("", "The CronJob must have a valid RestartPolicy configured",
+				"Valid CronJob RestartPolicy settings are Never or OnFailure")
+		}
+	} else {
+		score.Grade = scorecard.GradeCritical
+		score.AddComment("", "The CronJob is missing a valid RestartPolicy",
+			"Valid CronJob RestartPolicy settings are Never or OnFailure")
+	}
+
+	return
+}


Test patch:
diff --git a/score/cronjob_test.go b/score/cronjob_test.go
index bdcb1b5..f8f65c9 100644
--- a/score/cronjob_test.go
+++ b/score/cronjob_test.go
@@ -35,3 +35,33 @@ func TestProbesPodCronMissingReady(t *testing.T) {
 		})
 	}
 }
+
+func TestCronJobHasRestartPolicyMissing(t *testing.T) {
+	t.Parallel()
+
+	for _, v := range []string{"batchv1beta1", "batchv1"} {
+		t.Run(v, func(t *testing.T) {
+			testExpectedScore(t, "cronjob-"+v+"-restartpolicy-not-set.yaml", "CronJob RestartPolicy", scorecard.GradeCritical)
+		})
+	}
+}
+
+func TestCronJobHasRestartPolicyInvalid(t *testing.T) {
+	t.Parallel()
+
+	for _, v := range []string{"batchv1beta1", "batchv1"} {
+		t.Run(v, func(t *testing.T) {
+			testExpectedScore(t, "cronjob-"+v+"-restartpolicy-invalid.yaml", "CronJob RestartPolicy", scorecard.GradeCritical)
+		})
+	}
+}
+
+func TestCronJobHasRestartPolicyValid(t *testing.T) {
+	t.Parallel()
+
+	for _, v := range []string{"batchv1beta1", "batchv1"} {
+		t.Run(v, func(t *testing.T) {
+			testExpectedScore(t, "cronjob-"+v+"-restartpolicy-valid.yaml", "CronJob RestartPolicy", scorecard.GradeAllOK)
+		})
+	}
+}
diff --git a/score/testdata/cronjob-batchv1-restartpolicy-invalid.yaml b/score/testdata/cronjob-batchv1-restartpolicy-invalid.yaml
new file mode 100644
index 0000000..56d60f6
--- /dev/null
+++ b/score/testdata/cronjob-batchv1-restartpolicy-invalid.yaml
@@ -0,0 +1,28 @@
+kind: CronJob
+apiVersion: batch/v1
+metadata:
+  namespace: cronjobs
+  name: pwsh-test
+spec:
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+          - name: pwsh
+            imagePullPolicy: Always
+            image: mcr.microsoft.com/powershell:7
+            command:
+            - pwsh
+            - -Command
+            - Start-Sleep -Seconds 5
+            securityContext:
+              readOnlyRootFilesystem: true
+            resources:
+              limits:
+                ephemeral-storage: 50Mi
+              requests:
+                ephemeral-storage: 50Mi
+          RestartPolicy: Once
+  schedule: '0/1 * * * *'
+  startingDeadlineSeconds: 5
diff --git a/score/testdata/cronjob-batchv1-restartpolicy-not-set.yaml b/score/testdata/cronjob-batchv1-restartpolicy-not-set.yaml
new file mode 100644
index 0000000..b8adec7
--- /dev/null
+++ b/score/testdata/cronjob-batchv1-restartpolicy-not-set.yaml
@@ -0,0 +1,18 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+  name: hello
+spec:
+  schedule: "* * * * *"
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+          - name: hello
+            image: busybox:1.28
+            imagePullPolicy: IfNotPresent
+            command:
+            - /bin/sh
+            - -c
+            - date; echo Hello from the Kubernetes cluster
diff --git a/score/testdata/cronjob-batchv1-restartpolicy-valid.yaml b/score/testdata/cronjob-batchv1-restartpolicy-valid.yaml
new file mode 100644
index 0000000..78d0e2d
--- /dev/null
+++ b/score/testdata/cronjob-batchv1-restartpolicy-valid.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+  name: hello
+spec:
+  schedule: "* * * * *"
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+          - name: hello
+            image: busybox:1.28
+            imagePullPolicy: IfNotPresent
+            command:
+            - /bin/sh
+            - -c
+            - date; echo Hello from the Kubernetes cluster
+          restartPolicy: OnFailure
diff --git a/score/testdata/cronjob-batchv1beta1-restartpolicy-invalid.yaml b/score/testdata/cronjob-batchv1beta1-restartpolicy-invalid.yaml
new file mode 100644
index 0000000..5c6e569
--- /dev/null
+++ b/score/testdata/cronjob-batchv1beta1-restartpolicy-invalid.yaml
@@ -0,0 +1,28 @@
+kind: CronJob
+apiVersion: batch/v1beta1
+metadata:
+  namespace: cronjobs
+  name: pwsh-test
+spec:
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+          - name: pwsh
+            imagePullPolicy: Always
+            image: mcr.microsoft.com/powershell:7
+            command:
+            - pwsh
+            - -Command
+            - Start-Sleep -Seconds 5
+            securityContext:
+              readOnlyRootFilesystem: true
+            resources:
+              limits:
+                ephemeral-storage: 50Mi
+              requests:
+                ephemeral-storage: 50Mi
+          RestartPolicy: OnFailure 
+schedule: '0/1 * * * *'
+startingDeadlineSeconds: 5
diff --git a/score/testdata/cronjob-batchv1beta1-restartpolicy-not-set.yaml b/score/testdata/cronjob-batchv1beta1-restartpolicy-not-set.yaml
new file mode 100644
index 0000000..ee2b583
--- /dev/null
+++ b/score/testdata/cronjob-batchv1beta1-restartpolicy-not-set.yaml
@@ -0,0 +1,18 @@
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+  name: hello
+spec:
+  schedule: "* * * * *"
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+          - name: hello
+            image: busybox:1.28
+            imagePullPolicy: IfNotPresent
+            command:
+            - /bin/sh
+            - -c
+            - date; echo Hello from the Kubernetes cluster
diff --git a/score/testdata/cronjob-batchv1beta1-restartpolicy-valid.yaml b/score/testdata/cronjob-batchv1beta1-restartpolicy-valid.yaml
new file mode 100644
index 0000000..f7546fa
--- /dev/null
+++ b/score/testdata/cronjob-batchv1beta1-restartpolicy-valid.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+  name: hello
+spec:
+  schedule: "* * * * *"
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+          - name: hello
+            image: busybox:1.28
+            imagePullPolicy: IfNotPresent
+            command:
+            - /bin/sh
+            - -c
+            - date; echo Hello from the Kubernetes cluster
+          restartPolicy: OnFailure