Skip to content

Commit 1fef571

Browse files
Handle Jobs with ttl_seconds_after_finished = 0 correctly
1 parent 9d6074c commit 1fef571

File tree

2 files changed

+107
-2
lines changed

2 files changed

+107
-2
lines changed

kubernetes/resource_kubernetes_job_v1.go

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func resourceKubernetesJobV1() *schema.Resource {
2828
ReadContext: resourceKubernetesJobV1Read,
2929
UpdateContext: resourceKubernetesJobV1Update,
3030
DeleteContext: resourceKubernetesJobV1Delete,
31+
CustomizeDiff: resourceKubernetesJobV1CustomizeDiff,
3132
Importer: &schema.ResourceImporter{
3233
StateContext: schema.ImportStatePassthroughContext,
3334
},
@@ -48,6 +49,42 @@ func resourceKubernetesJobV1() *schema.Resource {
4849
}
4950
}
5051

52+
func resourceKubernetesJobV1CustomizeDiff(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error {
53+
if d.Id() == "" {
54+
log.Printf("[DEBUG] Resource ID is empty, resource not created yet.")
55+
return nil
56+
}
57+
58+
conn, err := meta.(KubeClientsets).MainClientset()
59+
if err != nil {
60+
return err
61+
}
62+
63+
namespace, name, err := idParts(d.Id())
64+
if err != nil {
65+
return err
66+
}
67+
68+
ttlAttr := d.Get("spec.0.ttl_seconds_after_finished")
69+
ttlSeconds, ok := ttlAttr.(int)
70+
if !ok || ttlSeconds != 0 {
71+
return nil
72+
}
73+
74+
// getting the job
75+
_, err = conn.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{})
76+
if err != nil {
77+
if errors.IsNotFound(err) {
78+
// Suppress diff
79+
d.Clear("spec")
80+
d.Clear("metadata")
81+
return nil
82+
}
83+
return err
84+
}
85+
return nil
86+
}
87+
5188
func resourceKubernetesJobV1Schema() map[string]*schema.Schema {
5289
return map[string]*schema.Schema{
5390
"metadata": jobMetadataSchema(),
@@ -118,8 +155,17 @@ func resourceKubernetesJobV1Read(ctx context.Context, d *schema.ResourceData, me
118155
return diag.FromErr(err)
119156
}
120157
if !exists {
121-
d.SetId("")
122-
return diag.Diagnostics{}
158+
// Check if ttl_seconds_after_finished is set
159+
if ttl, ok := d.GetOk("spec.0.ttl_seconds_after_finished"); ok {
160+
// ttl_seconds_after_finished is set, Job is deleted due to TTL
161+
// We don't need to remove the resource from the state
162+
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)
163+
return diag.Diagnostics{}
164+
} else {
165+
// ttl_seconds_after_finished is not set, remove the resource from the state
166+
d.SetId("")
167+
return diag.Diagnostics{}
168+
}
123169
}
124170
conn, err := meta.(KubeClientsets).MainClientset()
125171
if err != nil {

kubernetes/resource_kubernetes_job_v1_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,40 @@ 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_customizeDiff_ttlZero(name, imageName),
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(70 * time.Second)
265+
},
266+
Config: testAccKubernetesJobV1Config_customizeDiff_ttlZero(name, imageName),
267+
PlanOnly: true,
268+
ExpectNonEmptyPlan: false,
269+
},
270+
},
271+
})
272+
}
273+
240274
func testAccCheckJobV1Waited(minDuration time.Duration) func(*terraform.State) error {
241275
// NOTE this works because this function is called when setting up the test
242276
// and the function it returns is called after the resource has been created
@@ -516,3 +550,28 @@ func testAccKubernetesJobV1Config_modified(name, imageName string) string {
516550
wait_for_completion = false
517551
}`, name, imageName)
518552
}
553+
554+
func testAccKubernetesJobV1Config_customizeDiff_ttlZero(name, imageName string) string {
555+
return fmt.Sprintf(`
556+
resource "kubernetes_job_v1" "test" {
557+
metadata {
558+
name = "%s"
559+
}
560+
spec {
561+
ttl_seconds_after_finished = 0
562+
template {
563+
metadata {}
564+
spec {
565+
container {
566+
name = "wait-test"
567+
image = "%s"
568+
command = ["sleep", "60"]
569+
}
570+
restart_policy = "Never"
571+
}
572+
}
573+
}
574+
wait_for_completion = false
575+
}
576+
`, name, imageName)
577+
}

0 commit comments

Comments
 (0)