Skip to content

Commit f580087

Browse files
BBBmaujrhouston
andauthored
Add PodFailurePolicy for Jobs (#2394)
* initial schema creation * add expander functions * add flattener functions * WIP: podFailurePolicy tests * finish pod_failure_policy in jobs * remove typo * add changelog-entry * add cronjob podFailurePolicy test * add requested changes * changelog-entry * fix lints * add podFailurePolicy to uJobv1_update test * fix jobv1_update test * lint-fix * add value check in tests cronjobs/jobs * add value check * update cronjobs/jobs docs * update in docs to be required * use TypeList for values field in on_exit_codes * WIP: values is empty in fflatten function * fix flatten/expand of exit codes list * remove sort function * update values in tests to be in order * update docs / remove unused functions * add pod-failure-policy to patchSpec function * path typo * forceNew * add TestAccKubernetesCronJobV1_minimalWithPodFailurePolicy * tests-lint-fix --------- Co-authored-by: John Houston <[email protected]>
1 parent 4db62a7 commit f580087

File tree

9 files changed

+507
-5
lines changed

9 files changed

+507
-5
lines changed

.changelog/2394.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
`resource/kubernetes_job_v1`: add new attribute `spec.pod_failure_policy` to job spec
3+
```

kubernetes/resource_kubernetes_cron_job_v1_test.go

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,6 @@ func TestAccKubernetesCronJobV1_basic(t *testing.T) {
7575
resource.TestCheckResourceAttr(resourceName, "spec.0.starting_deadline_seconds", "0"),
7676
resource.TestCheckResourceAttr(resourceName, "spec.0.successful_jobs_history_limit", "3"),
7777
resource.TestCheckResourceAttr(resourceName, "spec.0.suspend", "false"),
78-
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.parallelism", "2"),
79-
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.backoff_limit", "6"),
80-
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.template.0.spec.0.container.0.name", "hello"),
81-
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.template.0.metadata.#", "1"),
82-
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.template.0.metadata.0.labels.%", "1"),
8378
testAccCheckKubernetesCronJobV1ForceNew(&conf1, &conf2, false),
8479
),
8580
},
@@ -174,6 +169,56 @@ func TestAccKubernetesCronJobV1_minimalWithTemplateNamespace(t *testing.T) {
174169
})
175170
}
176171

172+
func TestAccKubernetesCronJobV1_minimalWithPodFailurePolicy(t *testing.T) {
173+
var conf1, conf2 batchv1.CronJob
174+
175+
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
176+
resourceName := "kubernetes_cron_job_v1.test"
177+
imageName := busyboxImage
178+
179+
resource.ParallelTest(t, resource.TestCase{
180+
PreCheck: func() { testAccPreCheck(t) },
181+
IDRefreshName: resourceName,
182+
IDRefreshIgnore: []string{"metadata.0.resource_version"},
183+
ProviderFactories: testAccProviderFactories,
184+
CheckDestroy: testAccCheckKubernetesCronJobV1Destroy,
185+
Steps: []resource.TestStep{
186+
{
187+
Config: testAccKubernetesCronJobV1ConfigMinimal(name, imageName),
188+
Check: resource.ComposeAggregateTestCheckFunc(
189+
testAccCheckKubernetesCronJobV1Exists(resourceName, &conf1),
190+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.generation"),
191+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.resource_version"),
192+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.uid"),
193+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.namespace"),
194+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.metadata.0.namespace", ""),
195+
),
196+
},
197+
{
198+
Config: testAccKubernetesCronJobV1ConfigMinimalWithPodFailurePolicy(name, imageName),
199+
Check: resource.ComposeAggregateTestCheckFunc(
200+
testAccCheckKubernetesCronJobV1Exists(resourceName, &conf2),
201+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.generation"),
202+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.resource_version"),
203+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.uid"),
204+
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.namespace"),
205+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.#", "2"),
206+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.0.action", "FailJob"),
207+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.container_name", "test"),
208+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.#", "3"),
209+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.0", "1"),
210+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.1", "2"),
211+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.2", "42"),
212+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.1.action", "Ignore"),
213+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.1.on_pod_condition.0.type", "DisruptionTarget"),
214+
resource.TestCheckResourceAttr(resourceName, "spec.0.job_template.0.spec.0.pod_failure_policy.0.rule.1.on_pod_condition.0.status", "False"),
215+
testAccCheckKubernetesCronJobV1ForceNew(&conf1, &conf2, true),
216+
),
217+
},
218+
},
219+
})
220+
}
221+
177222
func testAccCheckKubernetesCronJobV1Destroy(s *terraform.State) error {
178223
conn, err := testAccProvider.Meta().(KubeClientsets).MainClientset()
179224

@@ -413,6 +458,52 @@ func testAccKubernetesCronJobV1ConfigMinimal(name, imageName string) string {
413458
`, name, imageName)
414459
}
415460

461+
func testAccKubernetesCronJobV1ConfigMinimalWithPodFailurePolicy(name, imageName string) string {
462+
return fmt.Sprintf(`resource "kubernetes_cron_job_v1" "test" {
463+
metadata {
464+
name = "%s"
465+
}
466+
spec {
467+
schedule = "*/1 * * * *"
468+
job_template {
469+
metadata {}
470+
spec {
471+
pod_failure_policy {
472+
rule {
473+
action = "FailJob"
474+
on_exit_codes {
475+
container_name = "test"
476+
operator = "In"
477+
values = [1, 2, 42]
478+
}
479+
}
480+
rule {
481+
action = "Ignore"
482+
on_pod_condition {
483+
status = "False"
484+
type = "DisruptionTarget"
485+
}
486+
}
487+
}
488+
template {
489+
metadata {}
490+
spec {
491+
492+
container {
493+
name = "test"
494+
image = "%s"
495+
command = ["sleep", "5"]
496+
}
497+
termination_grace_period_seconds = 1
498+
}
499+
}
500+
}
501+
}
502+
}
503+
}
504+
`, name, imageName)
505+
}
506+
416507
func testAccKubernetesCronJobV1ConfigMinimalWithJobTemplateNamespace(name, imageName string) string {
417508
return fmt.Sprintf(`resource "kubernetes_cron_job_v1" "test" {
418509
metadata {

kubernetes/resource_kubernetes_job_v1_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ func TestAccKubernetesJobV1_basic(t *testing.T) {
7777
resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.container.0.name", "hello"),
7878
resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.container.0.image", imageName),
7979
resource.TestCheckResourceAttr(resourceName, "wait_for_completion", "false"),
80+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.#", "2"),
81+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.action", "FailJob"),
82+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.container_name", "hello"),
83+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.#", "3"),
84+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.0", "1"),
85+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.1", "2"),
86+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.2", "42"),
87+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.1.action", "Ignore"),
88+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.1.on_pod_condition.0.type", "DisruptionTarget"),
89+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.1.on_pod_condition.0.status", "False"),
8090
),
8191
},
8292
{
@@ -131,6 +141,16 @@ func TestAccKubernetesJobV1_update(t *testing.T) {
131141
resource.TestCheckResourceAttr(resourceName, "spec.0.template.0.spec.0.container.0.image", imageName),
132142
resource.TestCheckResourceAttr(resourceName, "wait_for_completion", "false"),
133143
resource.TestCheckResourceAttr(resourceName, "spec.0.manual_selector", "false"),
144+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.#", "2"),
145+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.action", "FailJob"),
146+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.container_name", "hello"),
147+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.#", "3"),
148+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.0", "1"),
149+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.1", "2"),
150+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.0.on_exit_codes.0.values.2", "42"),
151+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.1.action", "Ignore"),
152+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.1.on_pod_condition.0.type", "DisruptionTarget"),
153+
resource.TestCheckResourceAttr(resourceName, "spec.0.pod_failure_policy.0.rule.1.on_pod_condition.0.status", "False"),
134154
),
135155
},
136156
{
@@ -307,6 +327,23 @@ func testAccKubernetesJobV1Config_basic(name, imageName string) string {
307327
backoff_limit = 10
308328
completions = 4
309329
parallelism = 2
330+
pod_failure_policy {
331+
rule {
332+
action = "FailJob"
333+
on_exit_codes {
334+
container_name = "hello"
335+
operator = "In"
336+
values = [1, 2, 42]
337+
}
338+
}
339+
rule {
340+
action = "Ignore"
341+
on_pod_condition {
342+
status = "False"
343+
type = "DisruptionTarget"
344+
}
345+
}
346+
}
310347
template {
311348
metadata {}
312349
spec {
@@ -334,6 +371,23 @@ func testAccKubernetesJobV1Config_updateMutableFields(name, imageName, activeDea
334371
completions = 4
335372
manual_selector = %s
336373
parallelism = %s
374+
pod_failure_policy {
375+
rule {
376+
action = "FailJob"
377+
on_exit_codes {
378+
container_name = "hello"
379+
operator = "In"
380+
values = [1, 2, 42]
381+
}
382+
}
383+
rule {
384+
action = "Ignore"
385+
on_pod_condition {
386+
status = "False"
387+
type = "DisruptionTarget"
388+
}
389+
}
390+
}
337391
template {
338392
metadata {}
339393
spec {

kubernetes/schema_job_spec.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,72 @@ func jobSpecFields(specUpdatable bool) map[string]*schema.Schema {
9191
ValidateFunc: validateNonNegativeInteger,
9292
Description: "Specifies the maximum desired number of pods the job should run at any given time. The actual number of pods running in steady state will be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), i.e. when the work left to do is less than max parallelism. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
9393
},
94+
"pod_failure_policy": {
95+
Type: schema.TypeList,
96+
Optional: true,
97+
ForceNew: true,
98+
MaxItems: 1,
99+
Description: "Specifies the maximum desired number of pods the job should run at any given time. The actual number of pods running in steady state will be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), i.e. when the work left to do is less than max parallelism. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
100+
Elem: &schema.Resource{
101+
Schema: map[string]*schema.Schema{
102+
"rule": {
103+
Type: schema.TypeList,
104+
Description: "A label query over volumes to consider for binding.",
105+
Required: true,
106+
Elem: &schema.Resource{
107+
Schema: map[string]*schema.Schema{
108+
"action": {
109+
Type: schema.TypeString,
110+
Optional: true,
111+
},
112+
"on_exit_codes": {
113+
Type: schema.TypeList,
114+
Optional: true,
115+
MaxItems: 1,
116+
Elem: &schema.Resource{
117+
Schema: map[string]*schema.Schema{
118+
"container_name": {
119+
Type: schema.TypeString,
120+
Optional: true,
121+
},
122+
"operator": {
123+
Type: schema.TypeString,
124+
Optional: true,
125+
},
126+
"values": {
127+
Type: schema.TypeList,
128+
Required: true,
129+
MinItems: 1,
130+
MaxItems: 255,
131+
Elem: &schema.Schema{Type: schema.TypeInt,
132+
ValidateFunc: validation.IntNotInSlice([]int{0})},
133+
},
134+
},
135+
},
136+
},
137+
"on_pod_condition": {
138+
Type: schema.TypeList,
139+
Optional: true,
140+
Elem: &schema.Resource{
141+
Schema: map[string]*schema.Schema{
142+
"status": {
143+
Type: schema.TypeString,
144+
Optional: true,
145+
Default: "True",
146+
},
147+
"type": {
148+
Type: schema.TypeString,
149+
Optional: true,
150+
},
151+
},
152+
},
153+
},
154+
},
155+
},
156+
},
157+
},
158+
},
159+
},
94160
// This field is immutable in Jobs.
95161
"selector": {
96162
Type: schema.TypeList,

0 commit comments

Comments
 (0)