Skip to content

Fix kubernetes_node_taint so that taints are unique over key and effect and not just key #2611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
5ff7110
Fix kubernetes_node_taint to be unique over effect and key, not just key
xinkechen-evernorth Oct 30, 2024
4783ee8
forgot to add example
xinkechen-evernorth Oct 30, 2024
b770847
Merge remote-tracking branch 'origin/main' into node-taint-unique-by-…
xinkechen-evernorth Oct 31, 2024
360bbcc
add changelog entry for PR
xinkechen-evernorth Oct 31, 2024
586c4be
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Dec 2, 2024
7c61b0c
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Dec 9, 2024
0f58d5a
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Dec 12, 2024
7f04795
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Dec 17, 2024
3e268cb
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Dec 19, 2024
06cbd81
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Jan 9, 2025
e7e8964
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Mar 2, 2025
4e95bf9
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Mar 25, 2025
e52aa3b
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Apr 1, 2025
daa4261
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth Apr 24, 2025
d8045f0
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth May 9, 2025
3566f5d
Merge branch 'main' into node-taint-unique-by-key-and-effect
xinkechen-evernorth May 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/2611.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
`resource/kubernetes_node_taint`: Fix taint uniqueness check so it is enforced over key and effect and not solely key alone.
```
15 changes: 15 additions & 0 deletions examples/resources/node_taint/example_2.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
resource "kubernetes_node_taint" "example" {
metadata {
name = "my-node.my-cluster.k8s.local"
}
taint {
key = "node-role.kubernetes.io/example"
value = "dedicated"
effect = "NoSchedule"
}
taint {
key = "node-role.kubernetes.io/example"
value = "dedicated"
effect = "NoExecute"
}
}
8 changes: 6 additions & 2 deletions kubernetes/resource_kubernetes_node_taint.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package kubernetes
import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -33,11 +34,14 @@ func resourceKubernetesNodeTaint() *schema.Resource {
for _, t := range rd.Get("taint").([]interface{}) {
taint := t.(map[string]interface{})
key := taint["key"].(string)
taintkeys[key] = taintkeys[key] + 1
effect := taint["effect"].(string)
taintkey := fmt.Sprintf("%s:%s", key, effect)
taintkeys[taintkey] = taintkeys[taintkey] + 1
}
for k, v := range taintkeys {
if v > 1 {
return fmt.Errorf("taint: duplicate taint key %q: taint keys must be unique", k)
s := strings.Split(k, ":")
return fmt.Errorf("taint: duplicate taint for key %q and effect %q; taints must be unique over key and effect.", s[0], s[1])
}
}
return nil
Expand Down
89 changes: 89 additions & 0 deletions kubernetes/resource_kubernetes_node_taint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package kubernetes
import (
"context"
"fmt"
"regexp"
"strings"
"testing"

Expand Down Expand Up @@ -106,6 +107,50 @@ func TestAccKubernetesResourceNodeTaint_MultipleBasic(t *testing.T) {
})
}

func TestAccKubernetesResourceNodeTaint_MultipleSameKeyDifferentEffect(t *testing.T) {
resourceName := "kubernetes_node_taint.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: resourceName,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccKubernetesNodeTaintDestroy,
Steps: []resource.TestStep{
{
Config: testAccKubernetesNodeTaintConfig_multipleSameKeyDifferentEffect(),
Check: resource.ComposeAggregateTestCheckFunc(
testAccKubernetesNodeTaintExists(resourceName),
resource.TestCheckResourceAttrSet(resourceName, "metadata.0.name"),
resource.TestCheckResourceAttr(resourceName, "taint.0.key", taintKey),
resource.TestCheckResourceAttr(resourceName, "taint.0.value", taintValue),
resource.TestCheckResourceAttr(resourceName, "taint.0.effect", "NoSchedule"),
resource.TestCheckResourceAttr(resourceName, "taint.1.key", taintKey),
resource.TestCheckResourceAttr(resourceName, "taint.1.value", taintValue),
resource.TestCheckResourceAttr(resourceName, "taint.1.effect", "NoExecute"),
),
},
},
})
}

func TestAccKubernetesResourceNodeTaint_DuplicateTaintKeyAndEffectExpectError(t *testing.T) {
resourceName := "kubernetes_node_taint.test"

expectPattern := "duplicate taint for key .* and effect \"\\w*\"; taints must be unique over key and effect"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: resourceName,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccKubernetesNodeTaintDestroy,
Steps: []resource.TestStep{
{
Config: testAccKubernetesNodeTaintConfig_duplicateKeyAndEffect(),
ExpectError: regexp.MustCompile(expectPattern),
},
},
})
}

func testAccKubernetesCheckNodeTaint(rs *terraform.ResourceState) error {
nodeName, taint, err := idToNodeTaint(rs.Primary.ID)
if err != nil {
Expand Down Expand Up @@ -169,6 +214,50 @@ resource "kubernetes_node_taint" "test" {
`, taintKey, taintValue, taintEffect, fieldManager)
}

func testAccKubernetesNodeTaintConfig_multipleSameKeyDifferentEffect() string {
return fmt.Sprintf(`data "kubernetes_nodes" "test" {}

resource "kubernetes_node_taint" "test" {
metadata {
name = data.kubernetes_nodes.test.nodes.0.metadata.0.name
}
taint {
key = %q
value = %q
effect = %q
}
taint {
key = %q
value = %q
effect = %q
}
field_manager = %q
}
`, taintKey, taintValue, "NoSchedule", taintKey, taintValue, "NoExecute", fieldManager)
}

func testAccKubernetesNodeTaintConfig_duplicateKeyAndEffect() string {
return fmt.Sprintf(`data "kubernetes_nodes" "test" {}

resource "kubernetes_node_taint" "test" {
metadata {
name = data.kubernetes_nodes.test.nodes.0.metadata.0.name
}
taint {
key = %q
value = %q
effect = %q
}
taint {
key = %q
value = %q
effect = %q
}
field_manager = %q
}
`, taintKey, taintValue, "NoSchedule", taintKey, "dedicated", "NoSchedule", fieldManager)
}

func testAccKubernetesNodeTaintConfig_multipleBasic() string {
return fmt.Sprintf(`data "kubernetes_nodes" "test" {}

Expand Down
6 changes: 6 additions & 0 deletions templates/resources/node_taint.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ description: |-

## Example Usage

### Single Taint

{{tffile "examples/resources/node_taint/example_1.tf"}}

### Multiple Taints Using the Same Key and Different Effects

{{tffile "examples/resources/node_taint/example_2.tf"}}

## Import

This resource does not support the `import` command. As this resource operates on Kubernetes resources that already exist, creating the resource is equivalent to importing it.