From f8a5b4f84a727a3ee445ac95545a8fc9f3ddfdfd Mon Sep 17 00:00:00 2001 From: mehrdadbn9 Date: Sat, 21 Feb 2026 06:18:50 +0330 Subject: [PATCH] fix: skip waiting for Jobs with TTL in status watcher Jobs with ttlSecondsAfterFinished set will be automatically deleted after completion. The kstatus watcher would get stuck waiting for these Jobs when they become NotFound after the TTL controller deletes them. This fix skips waiting for Jobs that have TTLSecondsAfterFinished set, similar to how paused Deployments are skipped. This matches the behavior from the legacy Helm 3 waiter which ignored deleted hooks. Fixes #31786 Signed-off-by: mehrdadbn9 --- pkg/kube/statuswait.go | 5 +++++ pkg/kube/statuswait_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/pkg/kube/statuswait.go b/pkg/kube/statuswait.go index 01024afa6..bb9b904d9 100644 --- a/pkg/kube/statuswait.go +++ b/pkg/kube/statuswait.go @@ -33,6 +33,7 @@ import ( "github.com/fluxcd/cli-utils/pkg/kstatus/watcher" "github.com/fluxcd/cli-utils/pkg/object" appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/dynamic" @@ -179,6 +180,10 @@ func (w *statusWaiter) wait(ctx context.Context, resourceList ResourceList, sw w if value.Spec.Paused { continue } + case *batchv1.Job: + if value.Spec.TTLSecondsAfterFinished != nil { + continue + } } obj, err := object.RuntimeToObjMeta(resource.Object) if err != nil { diff --git a/pkg/kube/statuswait_test.go b/pkg/kube/statuswait_test.go index d2dd57872..9a7c4fb34 100644 --- a/pkg/kube/statuswait_test.go +++ b/pkg/kube/statuswait_test.go @@ -123,6 +123,23 @@ status: message: "Job has reached the specified backoff limit" ` +var jobWithTTLManifest = ` +apiVersion: batch/v1 +kind: Job +metadata: + name: job-with-ttl + namespace: default + generation: 1 +spec: + ttlSecondsAfterFinished: 0 +status: + succeeded: 1 + active: 0 + conditions: + - type: Complete + status: "True" +` + var podCompleteManifest = ` apiVersion: v1 kind: Pod @@ -412,6 +429,10 @@ func TestStatusWait(t *testing.T) { name: "paused deployment passes", objManifests: []string{pausedDeploymentManifest}, }, + { + name: "job with TTL is skipped", + objManifests: []string{jobWithTTLManifest}, + }, } for _, tt := range tests { @@ -471,6 +492,10 @@ func TestWaitForJobComplete(t *testing.T) { objManifests: []string{jobReadyManifest}, expectErrStrs: []string{"resource Job/default/ready-not-complete not ready. status: InProgress", "context deadline exceeded"}, }, + { + name: "job with TTL is skipped", + objManifests: []string{jobWithTTLManifest}, + }, } for _, tt := range tests { @@ -532,6 +557,10 @@ func TestWatchForReady(t *testing.T) { objManifests: []string{podCurrentManifest}, expectErrStrs: []string{"resource Pod/ns/current-pod not ready. status: InProgress", "context deadline exceeded"}, }, + { + name: "job with TTL is skipped", + objManifests: []string{jobWithTTLManifest}, + }, } for _, tt := range tests {