Repository: hashicorp/terraform-provider-kubernetes

Issue:
Regression in Job deployment caused by #2596
### Terraform Version, Provider Version and Kubernetes Version
<!--- Run `terraform -v` to show the version. If you are not running the latest version of Terraform, please upgrade because your issue may have already been fixed. --->
```
Terraform version:
Kubernetes provider version: v2.34.0
Kubernetes version: AKS 1.31.1
```

### Affected Resource(s)
- `kubernetes_job`

### Terraform Configuration Files
What do you mean by "configuration"? Certainly you don't mean the entire terraform module.

### Debug Output
> Working on this, will attach soon.

### Panic Output
`N/A`

### Steps to Reproduce
1. Use kuberenetes provivder `v2.34.0` or greater.
2. Create a `kubernetes_job` resource which does not have `ttl_seconds_after_finished` set.

### Expected Behavior
1. The job should be recreated on every deployment
2. The deployment should succeed

### Actual Behavior
1. The job is created and the job pod runs successuflly
2. Terraform returns a non-zero exit code and reports the Job as failing.

### Important Factoids
This code has been running fine for a long time and the issue may be caused by this PR that was just merged #2596

Also, and I don't fully understand the PR creators scenario but this assumption seems bad to me:

> This can cause Terraform to plan the recreation of the Job in subsequent runs, which is sort of undesirable behavior. 

In fact this is _highly desirable and required_ behavior for us. We explicitly want the Job to be re-created on every single deployment.

So is this change a regression? Is there some setting I can set it to that will cause it to be recreated on every deployment?

Regardless, having it fail even though the pod is succeeding seems like a bug.


### References
- #2596

### Community Note
<!--- Please keep this note for the community --->
* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request
* If you are interested in working on this issue or have submitted a pull request, please leave a comment


Hints from issue comments:
@justinmchase: We were able to rollback to version `2.33.0` and it resolved our issue, so its definitely a recent issue probably this PR specifically.@github-actions: Marking this issue as stale due to inactivity. If this issue receives no comments in the next 30 days it will automatically be closed. If this issue was automatically closed and you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. This helps our maintainers find and focus on the active issues. Maintainers may also remove the stale label at their discretion. Thank you!

Solution patch:
diff --git a/.changelog/2650.txt b/.changelog/2650.txt
new file mode 100644
index 00000000..520e47b7
--- /dev/null
+++ b/.changelog/2650.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+Revert "Handle Jobs with ttl_seconds_after_finished = 0 correctly"
+```
\ No newline at end of file
diff --git a/kubernetes/resource_kubernetes_job_v1.go b/kubernetes/resource_kubernetes_job_v1.go
index cd261551..572635b3 100644
--- a/kubernetes/resource_kubernetes_job_v1.go
+++ b/kubernetes/resource_kubernetes_job_v1.go
@@ -118,17 +118,8 @@ func resourceKubernetesJobV1Read(ctx context.Context, d *schema.ResourceData, me
 		return diag.FromErr(err)
 	}
 	if !exists {
-		// Check if ttl_seconds_after_finished is set
-		if ttl, ok := d.GetOk("spec.0.ttl_seconds_after_finished"); ok {
-			// ttl_seconds_after_finished is set, Job is deleted due to TTL
-			// We don't need to remove the resource from the state
-			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)
-			return diag.Diagnostics{}
-		} else {
-			// ttl_seconds_after_finished is not set, remove the resource from the state
-			d.SetId("")
-			return diag.Diagnostics{}
-		}
+		d.SetId("")
+		return diag.Diagnostics{}
 	}
 	conn, err := meta.(KubeClientsets).MainClientset()
 	if err != nil {
@@ -213,6 +204,7 @@ func resourceKubernetesJobV1Update(ctx context.Context, d *schema.ResourceData,
 	}
 	return resourceKubernetesJobV1Read(ctx, d, meta)
 }
+
 func resourceKubernetesJobV1Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
 	conn, err := meta.(KubeClientsets).MainClientset()
 	if err != nil {
diff --git a/kubernetes/schema_job_spec.go b/kubernetes/schema_job_spec.go
index 243d8aae..1e7157ba 100644
--- a/kubernetes/schema_job_spec.go
+++ b/kubernetes/schema_job_spec.go
@@ -235,7 +235,7 @@ func jobSpecFields(specUpdatable bool) map[string]*schema.Schema {
 		"ttl_seconds_after_finished": {
 			Type:     schema.TypeString,
 			Optional: true,
-			ForceNew: true,
+			ForceNew: false,
 			ValidateFunc: func(value interface{}, key string) ([]string, []error) {
 				v, err := strconv.Atoi(value.(string))
 				if err != nil {



Test patch:
diff --git a/kubernetes/resource_kubernetes_job_v1_test.go b/kubernetes/resource_kubernetes_job_v1_test.go
index 2e85679c..396777de 100644
--- a/kubernetes/resource_kubernetes_job_v1_test.go
+++ b/kubernetes/resource_kubernetes_job_v1_test.go
@@ -237,82 +237,6 @@ func TestAccKubernetesJobV1_ttl_seconds_after_finished(t *testing.T) {
 	})
 }
 
-func TestAccKubernetesJobV1_customizeDiff_ttlZero(t *testing.T) {
-	var conf batchv1.Job
-	name := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(10))
-	imageName := busyboxImage
-	resourceName := "kubernetes_job_v1.test"
-
-	resource.ParallelTest(t, resource.TestCase{
-		PreCheck: func() {
-			testAccPreCheck(t)
-			skipIfClusterVersionLessThan(t, "1.21.0")
-		},
-		ProviderFactories: testAccProviderFactories,
-		Steps: []resource.TestStep{
-			// Step 1: Create the Job
-			{
-				Config: testAccKubernetesJobV1Config_Diff(name, imageName, 0),
-				Check: resource.ComposeAggregateTestCheckFunc(
-					testAccCheckKubernetesJobV1Exists(resourceName, &conf),
-					resource.TestCheckResourceAttr(resourceName, "spec.0.ttl_seconds_after_finished", "0"),
-				),
-			},
-			// Step 2: Wait for the Job to complete and be deleted
-			{
-				PreConfig: func() {
-					time.Sleep(30 * time.Second)
-				},
-				Config:             testAccKubernetesJobV1Config_Diff(name, imageName, 0),
-				PlanOnly:           true,
-				ExpectNonEmptyPlan: false,
-			},
-		},
-	})
-}
-
-func TestAccKubernetesJobV1_updateTTLFromZero(t *testing.T) {
-	var conf batchv1.Job
-	name := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(10))
-	imageName := busyboxImage
-	resourceName := "kubernetes_job_v1.test"
-
-	resource.ParallelTest(t, resource.TestCase{
-		PreCheck: func() {
-			testAccPreCheck(t)
-			skipIfClusterVersionLessThan(t, "1.21.0")
-		},
-		ProviderFactories: testAccProviderFactories,
-		Steps: []resource.TestStep{
-			// Step 1: Create the Job with ttl_seconds_after_finished = 0
-			{
-				Config: testAccKubernetesJobV1Config_Diff(name, imageName, 0),
-				Check: resource.ComposeAggregateTestCheckFunc(
-					testAccCheckKubernetesJobV1Exists(resourceName, &conf),
-					resource.TestCheckResourceAttr(resourceName, "spec.0.ttl_seconds_after_finished", "0"),
-				),
-			},
-			// Step 2: Wait for the Job to complete and be deleted
-			{
-				PreConfig: func() {
-					time.Sleep(30 * time.Second)
-				},
-				Config:             testAccKubernetesJobV1Config_Diff(name, imageName, 0),
-				PlanOnly:           true,
-				ExpectNonEmptyPlan: false,
-			},
-			// Step 3: Update the Job to ttl_seconds_after_finished = 5
-			{
-				Config: testAccKubernetesJobV1Config_Diff(name, imageName, 5),
-				Check: resource.ComposeAggregateTestCheckFunc(
-					testAccCheckKubernetesJobV1Exists(resourceName, &conf),
-					resource.TestCheckResourceAttr(resourceName, "spec.0.ttl_seconds_after_finished", "5"),
-				),
-			},
-		},
-	})
-}
-
 func testAccCheckJobV1Waited(minDuration time.Duration) func(*terraform.State) error {
 	// NOTE this works because this function is called when setting up the test
 	// and the function it returns is called after the resource has been created
@@ -592,28 +516,3 @@ func testAccKubernetesJobV1Config_modified(name, imageName string) string {
   wait_for_completion = false
 }`, name, imageName)
 }
-
-func testAccKubernetesJobV1Config_Diff(name, imageName string, ttl int) string {
-	return fmt.Sprintf(`
-resource "kubernetes_job_v1" "test" {
-  metadata {
-    name = "%s"
-  }
-  spec {
-    ttl_seconds_after_finished = %d
-    template {
-      metadata {}
-      spec {
-        container {
-          name    = "wait-test"
-          image   = "%s"
-          command = ["sleep", "20"]
-        }
-        restart_policy = "Never"
-      }
-    }
-  }
-  wait_for_completion = false
-}
-`, name, ttl, imageName)
-}