Repository: hashicorp/terraform-provider-kubernetes

Issue:
Deployment tolerations using keys matching k8s node taints are being ignored for the tfstate
Overriding the default `tolerationSeconds` value for the pods of any given Deployment is totally valid necessity
and should be a supported scenario by this provider IMO.

By not properly supporting this we get into this "perpetual diff" situation for a resource/object configuration that's completely acceptable within Kubernetes.


### Terraform Version, Provider Version and Kubernetes Version
```
Terraform version: 1.4.6
Kubernetes provider version: 2.24.0
Kubernetes version: 1.26.8
```

### Affected Resource(s)
- kubernetes_deployment
- kubernetes_deployment_v1

### Steps to Reproduce
1. Add a toleration inside `spec.template.spec` on your `kubernetes_deployment` resource. Using as key one of k8s `"node.kubernetes.io/*"` taints (e.g: `"node.kubernetes.io/unreachable"`).
2. terraform apply
3. terraform plan (after the successful apply)

### Expected Behavior
What should have happened?

The terraform plan should not show any changes to be performed after a successful apply has executed.

### Actual Behavior
What actually happened?

The terraform plan keeps showing tolerations as required to be added to the deployment:
```
Terraform will perform the following actions:

  # module.envoy-global.kubernetes_deployment_v1.envoy will be updated in-place
  ~ resource "kubernetes_deployment_v1" "envoy" {
        id               = "egress/envoy"
        # (1 unchanged attribute hidden)

      ~ spec {
            # (5 unchanged attributes hidden)

          ~ template {
              ~ spec {
                    # (12 unchanged attributes hidden)

                  + toleration {
                      + effect             = "NoExecute"
                      + key                = "node.kubernetes.io/not-ready"
                      + operator           = "Exists"
                      + toleration_seconds = "150"
                    }
                  + toleration {
                      + effect             = "NoExecute"
                      + key                = "node.kubernetes.io/unreachable"
                      + operator           = "Exists"
                      + toleration_seconds = "90"
                    }

                    # (5 unchanged blocks hidden)
                }

                # (1 unchanged block hidden)
            }

            # (2 unchanged blocks hidden)
        }

        # (1 unchanged block hidden)
    }
```

### Important Factoids
<!-- Are there anything atypical about your accounts that we should know? For example: Running in EC2 Classic? Custom version of OpenStack? Tight ACLs?-->
A similar issue was raised in the past (1) and got a fix (2), but it only addressed `node.kubernetes.io` prefixed toleration keys that are not part of the [well-known node taints](https://github.com/kubernetes/kubernetes/blob/v1.26.8/staging/src/k8s.io/api/core/v1/well_known_taints.go).

I believe it should be supported to properly manage any toleration key at the Deployment resource (I understand Pod may need to be left as is).

Actually, a fair point about this was already made here: https://github.com/hashicorp/terraform-provider-kubernetes/issues/955#issuecomment-681022027.

Also, (3) seems to propose a fair attempt at sorting this, but appears to have become stale and eventually (auto-)closed. I think we should recover this.

### References
- (1) GH-955
- (2) GH-978
- (3) GH-1012

### 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:
@arybolovlev: Hi @Restless-ET,

Thank you for raising this issue. I think it makes sense to strip well-known tolerations only when we flatten a pod object spec, in all other cases, when it is a template, we could keep them. The same approach we use for labels and annotations. You are right, it looks like #1012 introduced a similar fix but for whatever reason didn't get much attention. I will raise this proposal during our next triage session and let you know about the decision here.

Happy New Year! 🎉@Restless-ET: Hello @arybolovlev and HNY 😄 

Thank you for the feedback.
I can see there's already an open PR for the fix so thanks again for the quick action.@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!@dghubble: Still relevant, don't stale close please

Solution patch:
diff --git a/.changelog/2380.txt b/.changelog/2380.txt
new file mode 100644
index 00000000..9da0feff
--- /dev/null
+++ b/.changelog/2380.txt
@@ -0,0 +1,59 @@
+```release-note:note
+We have updated the logic of resources that use the Pod specification template, such as `kubernetes_deployment_v1`, `kubernetes_stateful_set_v1`, etc, and now the provider will keep all tolerations(`spec.toleration`) returned by Kubernetes. The same is applicable for the data sources `kubernetes_pod_v1` and `kubernetes_pod`. The behavior of resources `kubernetes_pod_v1` and `kubernetes_pod` remains unchanged, i.e. the provider will keep removing tolerations with well-known [taints](https://kubernetes.io/docs/reference/labels-annotations-taints/) since they might be attached to the object by Kubernetes controller and could lead to a perpetual diff.
+```
+
+```release-note:bug
+`resource/kubernetes_replication_controller`: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_replication_controller_v1`: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_stateful_set: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_stateful_set_v1: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_deployment: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_deployment_v1: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_daemonset: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_daemon_set_v1: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_cron_job: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_cron_job_v1: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_job: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`resource/kubernetes_job_v1: fix an issue when the provider cuts out toleration under pod spec template(`*.template.spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/). That could lead to a perpetual diff behavior.
+```
+
+```release-note:bug
+`data_source/kubernetes_pod`: fix an issue when the provider cuts out toleration under pod spec(`spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/).
+```
+
+```release-note:bug
+`data_source/kubernetes_pod_v1`: fix an issue when the provider cuts out toleration under pod spec(`spec.toleration`) if it uses a well-known [taint](https://kubernetes.io/docs/reference/labels-annotations-taints/).
+```
diff --git a/kubernetes/data_source_kubernetes_pod_v1.go b/kubernetes/data_source_kubernetes_pod_v1.go
index a7878d93..a0bc6f41 100644
--- a/kubernetes/data_source_kubernetes_pod_v1.go
+++ b/kubernetes/data_source_kubernetes_pod_v1.go
@@ -70,7 +70,8 @@ func dataSourceKubernetesPodV1Read(ctx context.Context, d *schema.ResourceData,
 		return diag.FromErr(err)
 	}
 
-	podSpec, err := flattenPodSpec(pod.Spec)
+	// isTemplate argument here is equal to 'true' because we want to keep all attributes that Kubernetes unchanged.
+	podSpec, err := flattenPodSpec(pod.Spec, true)
 	if err != nil {
 		return diag.FromErr(err)
 	}
diff --git a/kubernetes/resource_kubernetes_pod_v1.go b/kubernetes/resource_kubernetes_pod_v1.go
index e2947b79..20717666 100644
--- a/kubernetes/resource_kubernetes_pod_v1.go
+++ b/kubernetes/resource_kubernetes_pod_v1.go
@@ -201,7 +201,7 @@ func resourceKubernetesPodV1Read(ctx context.Context, d *schema.ResourceData, me
 		return diag.FromErr(err)
 	}
 
-	podSpec, err := flattenPodSpec(pod.Spec)
+	podSpec, err := flattenPodSpec(pod.Spec, false)
 	if err != nil {
 		return diag.FromErr(err)
 	}
diff --git a/kubernetes/structures_daemonset.go b/kubernetes/structures_daemonset.go
index 7dc5eec0..d3f152a2 100644
--- a/kubernetes/structures_daemonset.go
+++ b/kubernetes/structures_daemonset.go
@@ -24,7 +24,7 @@ func flattenDaemonSetSpec(in appsv1.DaemonSetSpec, d *schema.ResourceData, meta
 		att["selector"] = flattenLabelSelector(in.Selector)
 	}
 
-	podSpec, err := flattenPodSpec(in.Template.Spec)
+	podSpec, err := flattenPodSpec(in.Template.Spec, true)
 	if err != nil {
 		return nil, err
 	}
diff --git a/kubernetes/structures_deployment.go b/kubernetes/structures_deployment.go
index 689b4c86..a8f9e934 100644
--- a/kubernetes/structures_deployment.go
+++ b/kubernetes/structures_deployment.go
@@ -35,7 +35,7 @@ func flattenDeploymentSpec(in appsv1.DeploymentSpec, d *schema.ResourceData, met
 
 	att["strategy"] = flattenDeploymentStrategy(in.Strategy)
 
-	podSpec, err := flattenPodSpec(in.Template.Spec)
+	podSpec, err := flattenPodSpec(in.Template.Spec, true)
 	if err != nil {
 		return nil, err
 	}
diff --git a/kubernetes/structures_pod.go b/kubernetes/structures_pod.go
index 6ab2427d..808d1efc 100644
--- a/kubernetes/structures_pod.go
+++ b/kubernetes/structures_pod.go
@@ -38,7 +38,7 @@ func flattenOS(in v1.PodOS) []interface{} {
 	return []interface{}{att}
 }
 
-func flattenPodSpec(in v1.PodSpec) ([]interface{}, error) {
+func flattenPodSpec(in v1.PodSpec, isTemplate bool) ([]interface{}, error) {
 	att := make(map[string]interface{})
 	if in.ActiveDeadlineSeconds != nil {
 		att["active_deadline_seconds"] = *in.ActiveDeadlineSeconds
@@ -141,7 +141,7 @@ func flattenPodSpec(in v1.PodSpec) ([]interface{}, error) {
 	}
 
 	if len(in.Tolerations) > 0 {
-		att["toleration"] = flattenTolerations(in.Tolerations)
+		att["toleration"] = flattenTolerations(in.Tolerations, isTemplate)
 	}
 
 	if len(in.TopologySpreadConstraints) > 0 {
@@ -293,11 +293,12 @@ func flattenSysctls(sysctls []v1.Sysctl) []interface{} {
 	return att
 }
 
-func flattenTolerations(tolerations []v1.Toleration) []interface{} {
+func flattenTolerations(tolerations []v1.Toleration, isTemplate bool) []interface{} {
 	att := []interface{}{}
 	for _, v := range tolerations {
 		// The API Server may automatically add several Tolerations to pods, strip these to avoid TF diff.
-		if _, ok := builtInTolerations[v.Key]; ok {
+		// Keep all tolerations if we flatten the Pod spec template.
+		if _, ok := builtInTolerations[v.Key]; ok && !isTemplate {
 			log.Printf("[INFO] ignoring toleration with key: %s", v.Key)
 			continue
 		}
diff --git a/kubernetes/structures_replication_controller.go b/kubernetes/structures_replication_controller.go
index 723caf7c..54fbf1fc 100644
--- a/kubernetes/structures_replication_controller.go
+++ b/kubernetes/structures_replication_controller.go
@@ -22,7 +22,7 @@ func flattenReplicationControllerSpec(in corev1.ReplicationControllerSpec, d *sc
 	}
 
 	if in.Template != nil {
-		podSpec, err := flattenPodSpec(in.Template.Spec)
+		podSpec, err := flattenPodSpec(in.Template.Spec, true)
 		if err != nil {
 			return nil, err
 		}
diff --git a/kubernetes/structures_stateful_set.go b/kubernetes/structures_stateful_set.go
index a2361ef2..81dc1c82 100644
--- a/kubernetes/structures_stateful_set.go
+++ b/kubernetes/structures_stateful_set.go
@@ -193,7 +193,7 @@ func flattenPodTemplateSpec(t corev1.PodTemplateSpec) ([]interface{}, error) {
 	template := make(map[string]interface{})
 
 	template["metadata"] = flattenMetadataFields(t.ObjectMeta)
-	spec, err := flattenPodSpec(t.Spec)
+	spec, err := flattenPodSpec(t.Spec, true)
 	if err != nil {
 		return []interface{}{template}, err
 	}



Test patch:
diff --git a/kubernetes/data_source_kubernetes_pod_v1_test.go b/kubernetes/data_source_kubernetes_pod_v1_test.go
index 40adfc01..346b3f7e 100644
--- a/kubernetes/data_source_kubernetes_pod_v1_test.go
+++ b/kubernetes/data_source_kubernetes_pod_v1_test.go
@@ -5,6 +5,7 @@ package kubernetes
 
 import (
 	"fmt"
+	"regexp"
 	"testing"
 
 	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
@@ -16,6 +17,7 @@ func TestAccKubernetesDataSourcePodV1_basic(t *testing.T) {
 	dataSourceName := "data.kubernetes_pod_v1.test"
 	name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
 	imageName := busyboxImage
+	oneOrMore := regexp.MustCompile(`^[1-9][0-9]*$`)
 
 	resource.ParallelTest(t, resource.TestCase{
 		PreCheck:          func() { testAccPreCheck(t) },
@@ -34,6 +36,7 @@ func TestAccKubernetesDataSourcePodV1_basic(t *testing.T) {
 				Check: resource.ComposeAggregateTestCheckFunc(
 					resource.TestCheckResourceAttr(dataSourceName, "metadata.0.name", name),
 					resource.TestCheckResourceAttr(dataSourceName, "spec.0.container.0.image", imageName),
+					resource.TestMatchResourceAttr(dataSourceName, "spec.0.toleration.#", oneOrMore),
 				),
 			},
 		},
diff --git a/kubernetes/resource_kubernetes_deployment_v1_test.go b/kubernetes/resource_kubernetes_deployment_v1_test.go
index 9b9fb19d..c6599198 100644
--- a/kubernetes/resource_kubernetes_deployment_v1_test.go
+++ b/kubernetes/resource_kubernetes_deployment_v1_test.go
@@ -316,6 +316,7 @@ func TestAccKubernetesDeploymentV1_with_tolerations(t *testing.T) {
 	deploymentName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
 	resourceName := "kubernetes_deployment_v1.test"
 	imageName := busyboxImage
+	key := "myKey"
 	tolerationSeconds := 6000
 	operator := "Equal"
 
@@ -325,11 +326,11 @@ func TestAccKubernetesDeploymentV1_with_tolerations(t *testing.T) {
 		CheckDestroy:      testAccCheckKubernetesDeploymentV1Destroy,
 		Steps: []resource.TestStep{
 			{
-				Config: testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageName, &tolerationSeconds, operator, nil),
+				Config: testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageName, key, operator, "", &tolerationSeconds),
 				Check: resource.ComposeAggregateTestCheckFunc(
 					testAccCheckKubernetesDeploymentV1Exists(resourceName, &conf),
 					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.effect", "NoExecute"),
-					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.key", "myKey"),
+					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.key", key),
 					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.operator", operator),
 					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.toleration_seconds", "6000"),
 					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.value", ""),
@@ -345,6 +346,7 @@ func TestAccKubernetesDeploymentV1_with_tolerations_unset_toleration_seconds(t *
 	deploymentName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
 	resourceName := "kubernetes_deployment_v1.test"
 	imageName := busyboxImage
+	key := "myKey"
 	operator := "Equal"
 	value := "value"
 
@@ -354,11 +356,11 @@ func TestAccKubernetesDeploymentV1_with_tolerations_unset_toleration_seconds(t *
 		CheckDestroy:      testAccCheckKubernetesDeploymentV1Destroy,
 		Steps: []resource.TestStep{
 			{
-				Config: testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageName, nil, operator, &value),
+				Config: testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageName, key, operator, value, nil),
 				Check: resource.ComposeAggregateTestCheckFunc(
 					testAccCheckKubernetesDeploymentV1Exists(resourceName, &conf),
 					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.effect", "NoExecute"),
-					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.key", "myKey"),
+					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.key", key),
 					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.operator", operator),
 					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.value", "value"),
 					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.toleration_seconds", ""),
@@ -368,6 +370,36 @@ func TestAccKubernetesDeploymentV1_with_tolerations_unset_toleration_seconds(t *
 	})
 }
 
+func TestAccKubernetesDeploymentV1_with_well_known_tolerations(t *testing.T) {
+	var conf appsv1.Deployment
+
+	deploymentName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
+	resourceName := "kubernetes_deployment_v1.test"
+	imageName := busyboxImage
+	key := "node.kubernetes.io/unreachable"
+	tolerationSeconds := 6000
+	operator := "Exists"
+
+	resource.ParallelTest(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		ProviderFactories: testAccProviderFactories,
+		CheckDestroy:      testAccCheckKubernetesDeploymentV1Destroy,
+		Steps: []resource.TestStep{
+			{
+				Config: testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageName, key, operator, "", &tolerationSeconds),
+				Check: resource.ComposeAggregateTestCheckFunc(
+					testAccCheckKubernetesDeploymentV1Exists(resourceName, &conf),
+					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.effect", "NoExecute"),
+					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.key", key),
+					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.operator", operator),
+					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.toleration_seconds", "6000"),
+					resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.toleration.0.value", ""),
+				),
+			},
+		},
+	})
+}
+
 func TestAccKubernetesDeploymentV1_with_container_liveness_probe_using_exec(t *testing.T) {
 	var conf appsv1.Deployment
 
@@ -1851,14 +1883,14 @@ func testAccKubernetesDeploymentV1ConfigWithSecurityContextSysctl(deploymentName
 `, deploymentName, imageName)
 }
 
-func testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageName string, tolerationSeconds *int, operator string, value *string) string {
+func testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageName, key, operator, value string, tolerationSeconds *int) string {
 	tolerationDuration := ""
 	if tolerationSeconds != nil {
 		tolerationDuration = fmt.Sprintf("toleration_seconds = %d", *tolerationSeconds)
 	}
 	valueString := ""
-	if value != nil {
-		valueString = fmt.Sprintf("value = \"%s\"", *value)
+	if value != "" {
+		valueString = fmt.Sprintf("value = \"%s\"", value)
 	}
 
 	return fmt.Sprintf(`resource "kubernetes_deployment_v1" "test" {
@@ -1887,7 +1919,7 @@ func testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageNam
       spec {
         toleration {
           effect   = "NoExecute"
-          key      = "myKey"
+          key      = "%s"
           operator = "%s"
           %s
           %s
@@ -1896,14 +1928,14 @@ func testAccKubernetesDeploymentV1ConfigWithTolerations(deploymentName, imageNam
         container {
           image   = "%s"
           name    = "containername"
-          command = ["sleep", "300"]
+          command = ["sleep", "infinity"]
         }
         termination_grace_period_seconds = 1
       }
     }
   }
 }
-`, deploymentName, operator, valueString, tolerationDuration, imageName)
+`, deploymentName, key, operator, valueString, tolerationDuration, imageName)
 }
 
 func testAccKubernetesDeploymentV1ConfigWithLivenessProbeUsingExec(deploymentName, imageName string) string {
diff --git a/kubernetes/structures_pod_test.go b/kubernetes/structures_pod_test.go
index ca35e159..a9a5bbdd 100644
--- a/kubernetes/structures_pod_test.go
+++ b/kubernetes/structures_pod_test.go
@@ -16,6 +16,7 @@ import (
 func TestFlattenTolerations(t *testing.T) {
 	cases := []struct {
 		Input          []corev1.Toleration
+		isTemplate     bool
 		ExpectedOutput []interface{}
 	}{
 		{
@@ -25,6 +26,7 @@ func TestFlattenTolerations(t *testing.T) {
 					Value: "true",
 				},
 			},
+			false,
 			[]interface{}{
 				map[string]interface{}{
 					"key":   "node-role.kubernetes.io/spot-worker",
@@ -43,6 +45,7 @@ func TestFlattenTolerations(t *testing.T) {
 					Value: "true",
 				},
 			},
+			false,
 			[]interface{}{
 				map[string]interface{}{
 					"key":      "node-role.kubernetes.io/other-worker",
@@ -61,6 +64,7 @@ func TestFlattenTolerations(t *testing.T) {
 					TolerationSeconds: ptr.To(int64(120)),
 				},
 			},
+			false,
 			[]interface{}{
 				map[string]interface{}{
 					"effect":             "NoExecute",
@@ -68,14 +72,51 @@ func TestFlattenTolerations(t *testing.T) {
 				},
 			},
 		},
+		{
+			[]corev1.Toleration{
+				{
+					Effect:            "NoExecute",
+					Key:               "node.kubernetes.io/unreachable",
+					Operator:          "Exists",
+					TolerationSeconds: ptr.To(int64(120)),
+				},
+			},
+			false,
+			[]interface{}{},
+		},
 		{
 			[]corev1.Toleration{},
+			false,
 			[]interface{}{},
 		},
+		{
+			[]corev1.Toleration{},
+			true,
+			[]interface{}{},
+		},
+		{
+			[]corev1.Toleration{
+				{
+					Effect:            "NoExecute",
+					Key:               "node.kubernetes.io/unreachable",
+					Operator:          "Exists",
+					TolerationSeconds: ptr.To(int64(120)),
+				},
+			},
+			true,
+			[]interface{}{
+				map[string]interface{}{
+					"effect":             "NoExecute",
+					"key":                "node.kubernetes.io/unreachable",
+					"operator":           "Exists",
+					"toleration_seconds": "120",
+				},
+			},
+		},
 	}
 
 	for _, tc := range cases {
-		output := flattenTolerations(tc.Input)
+		output := flattenTolerations(tc.Input, tc.isTemplate)
 		if !reflect.DeepEqual(output, tc.ExpectedOutput) {
 			t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven:    %#v",
 				tc.ExpectedOutput, output)