Repository: helm/helm (go)

Issue:
--wait-for-jobs does not work with backOffLimit = 0
Using the new `--wait-for-jobs` flag, we encountered a bit of strange behavior when `backOffLimit` is set to zero. Setting the backoff to 0 as well as ` restartPolicy: Never` ensures that a job is only run once.

[The following check](https://github.com/helm/helm/blob/master/pkg/kube/wait.go#L193) validates failed runs are greater than or equal to 0. This condition will always return true when a job with `backOffLimit: 0` completes, because the `job.Status.Failed` will have a zero value (the field will not exist on job status).


Pull request description:
wait-for-job with backoff limit 0
Because backOffLimit can be 0, a zero value for pod status failed will
always cause the condition to return true.

Signed-off-by: James McElwain <jmcelwain@gmail.com>

- [ ] this PR contains documentation
- [x] this PR contains unit tests
- [ ] this PR has been tested for backwards compatibility


Patch:
diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go
index 40f7b7a6e..489dd8132 100644
--- a/pkg/kube/wait.go
+++ b/pkg/kube/wait.go
@@ -190,7 +190,7 @@ func (w *waiter) isPodReady(pod *corev1.Pod) bool {
 }
 
 func (w *waiter) jobReady(job *batchv1.Job) bool {
-	if job.Status.Failed >= *job.Spec.BackoffLimit {
+	if job.Status.Failed > *job.Spec.BackoffLimit {
 		w.log("Job is failed: %s/%s", job.GetNamespace(), job.GetName())
 		return false
 	}


Test patch:
diff --git a/pkg/kube/wait_test.go b/pkg/kube/wait_test.go
index 3f7b86710..7864f5e00 100644
--- a/pkg/kube/wait_test.go
+++ b/pkg/kube/wait_test.go
@@ -266,6 +266,26 @@ func Test_waiter_jobReady(t *testing.T) {
 			args: args{job: newJob("foo", 1, 1, 0, 1)},
 			want: false,
 		},
+		{
+			name: "job is completed with retry",
+			args: args{job: newJob("foo", 1, 1, 1, 1)},
+			want: true,
+		},
+		{
+			name: "job is failed with retry",
+			args: args{job: newJob("foo", 1, 1, 0, 2)},
+			want: false,
+		},
+		{
+			name: "job is completed single run",
+			args: args{job: newJob("foo", 0, 1, 1, 0)},
+			want: true,
+		},
+		{
+			name: "job is failed single run",
+			args: args{job: newJob("foo", 0, 1, 0, 1)},
+			want: false,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {