Skip to content

Commit a443c94

Browse files
Merge branch 'fix-job-ttl-zero-handling'
2 parents af55e47 + 8961147 commit a443c94

File tree

4 files changed

+116
-4
lines changed

4 files changed

+116
-4
lines changed

.changelog/2596.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
Properly handle Kubernetes Jobs with ttl_seconds_after_finished = 0 to prevent unnecessary recreation.
3+
```

kubernetes/resource_kubernetes_job_v1.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,17 @@ func resourceKubernetesJobV1Read(ctx context.Context, d *schema.ResourceData, me
118118
return diag.FromErr(err)
119119
}
120120
if !exists {
121-
d.SetId("")
122-
return diag.Diagnostics{}
121+
// Check if ttl_seconds_after_finished is set
122+
if ttl, ok := d.GetOk("spec.0.ttl_seconds_after_finished"); ok {
123+
// ttl_seconds_after_finished is set, Job is deleted due to TTL
124+
// We don't need to remove the resource from the state
125+
log.Printf("[INFO] Job %s has been deleted by Kubernetes due to TTL (ttl_seconds_after_finished = %v), keeping resource in state", d.Id(), ttl)
126+
return diag.Diagnostics{}
127+
} else {
128+
// ttl_seconds_after_finished is not set, remove the resource from the state
129+
d.SetId("")
130+
return diag.Diagnostics{}
131+
}
123132
}
124133
conn, err := meta.(KubeClientsets).MainClientset()
125134
if err != nil {
@@ -204,7 +213,6 @@ func resourceKubernetesJobV1Update(ctx context.Context, d *schema.ResourceData,
204213
}
205214
return resourceKubernetesJobV1Read(ctx, d, meta)
206215
}
207-
208216
func resourceKubernetesJobV1Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
209217
conn, err := meta.(KubeClientsets).MainClientset()
210218
if err != nil {

kubernetes/resource_kubernetes_job_v1_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,82 @@ func TestAccKubernetesJobV1_ttl_seconds_after_finished(t *testing.T) {
237237
})
238238
}
239239

240+
func TestAccKubernetesJobV1_customizeDiff_ttlZero(t *testing.T) {
241+
var conf batchv1.Job
242+
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(10))
243+
imageName := busyboxImage
244+
resourceName := "kubernetes_job_v1.test"
245+
246+
resource.ParallelTest(t, resource.TestCase{
247+
PreCheck: func() {
248+
testAccPreCheck(t)
249+
skipIfClusterVersionLessThan(t, "1.21.0")
250+
},
251+
ProviderFactories: testAccProviderFactories,
252+
Steps: []resource.TestStep{
253+
// Step 1: Create the Job
254+
{
255+
Config: testAccKubernetesJobV1Config_Diff(name, imageName, 0),
256+
Check: resource.ComposeAggregateTestCheckFunc(
257+
testAccCheckKubernetesJobV1Exists(resourceName, &conf),
258+
resource.TestCheckResourceAttr(resourceName, "spec.0.ttl_seconds_after_finished", "0"),
259+
),
260+
},
261+
// Step 2: Wait for the Job to complete and be deleted
262+
{
263+
PreConfig: func() {
264+
time.Sleep(30 * time.Second)
265+
},
266+
Config: testAccKubernetesJobV1Config_Diff(name, imageName, 0),
267+
PlanOnly: true,
268+
ExpectNonEmptyPlan: false,
269+
},
270+
},
271+
})
272+
}
273+
274+
func TestAccKubernetesJobV1_updateTTLFromZero(t *testing.T) {
275+
var conf batchv1.Job
276+
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(10))
277+
imageName := busyboxImage
278+
resourceName := "kubernetes_job_v1.test"
279+
280+
resource.ParallelTest(t, resource.TestCase{
281+
PreCheck: func() {
282+
testAccPreCheck(t)
283+
skipIfClusterVersionLessThan(t, "1.21.0")
284+
},
285+
ProviderFactories: testAccProviderFactories,
286+
Steps: []resource.TestStep{
287+
// Step 1: Create the Job with ttl_seconds_after_finished = 0
288+
{
289+
Config: testAccKubernetesJobV1Config_Diff(name, imageName, 0),
290+
Check: resource.ComposeAggregateTestCheckFunc(
291+
testAccCheckKubernetesJobV1Exists(resourceName, &conf),
292+
resource.TestCheckResourceAttr(resourceName, "spec.0.ttl_seconds_after_finished", "0"),
293+
),
294+
},
295+
// Step 2: Wait for the Job to complete and be deleted
296+
{
297+
PreConfig: func() {
298+
time.Sleep(30 * time.Second)
299+
},
300+
Config: testAccKubernetesJobV1Config_Diff(name, imageName, 0),
301+
PlanOnly: true,
302+
ExpectNonEmptyPlan: false,
303+
},
304+
// Step 3: Update the Job to ttl_seconds_after_finished = 5
305+
{
306+
Config: testAccKubernetesJobV1Config_Diff(name, imageName, 5),
307+
Check: resource.ComposeAggregateTestCheckFunc(
308+
testAccCheckKubernetesJobV1Exists(resourceName, &conf),
309+
resource.TestCheckResourceAttr(resourceName, "spec.0.ttl_seconds_after_finished", "5"),
310+
),
311+
},
312+
},
313+
})
314+
}
315+
240316
func testAccCheckJobV1Waited(minDuration time.Duration) func(*terraform.State) error {
241317
// NOTE this works because this function is called when setting up the test
242318
// and the function it returns is called after the resource has been created
@@ -516,3 +592,28 @@ func testAccKubernetesJobV1Config_modified(name, imageName string) string {
516592
wait_for_completion = false
517593
}`, name, imageName)
518594
}
595+
596+
func testAccKubernetesJobV1Config_Diff(name, imageName string, ttl int) string {
597+
return fmt.Sprintf(`
598+
resource "kubernetes_job_v1" "test" {
599+
metadata {
600+
name = "%s"
601+
}
602+
spec {
603+
ttl_seconds_after_finished = %d
604+
template {
605+
metadata {}
606+
spec {
607+
container {
608+
name = "wait-test"
609+
image = "%s"
610+
command = ["sleep", "20"]
611+
}
612+
restart_policy = "Never"
613+
}
614+
}
615+
}
616+
wait_for_completion = false
617+
}
618+
`, name, ttl, imageName)
619+
}

kubernetes/schema_job_spec.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func jobSpecFields(specUpdatable bool) map[string]*schema.Schema {
235235
"ttl_seconds_after_finished": {
236236
Type: schema.TypeString,
237237
Optional: true,
238-
ForceNew: false,
238+
ForceNew: true,
239239
ValidateFunc: func(value interface{}, key string) ([]string, []error) {
240240
v, err := strconv.Atoi(value.(string))
241241
if err != nil {

0 commit comments

Comments
 (0)