Skip to content

Commit 927c705

Browse files
BBBmaujrhouston
andauthored
Remove limit for taints in kubernetes_node_taint resource (#2046)
Co-authored-by: John Houston <[email protected]>
1 parent 26adb1f commit 927c705

File tree

4 files changed

+202
-127
lines changed

4 files changed

+202
-127
lines changed

.changelog/2046.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
`kubernetes/resource_kubernetes_node_taint.go`: Remove MaxItems from taint attribute
3+
```

kubernetes/resource_kubernetes_node_taint.go

Lines changed: 31 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ package kubernetes
66
import (
77
"context"
88
"fmt"
9-
"log"
10-
"strings"
119

1210
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1311
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -17,8 +15,6 @@ import (
1715
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1816
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1917
"k8s.io/apimachinery/pkg/types"
20-
"k8s.io/kubernetes/pkg/apis/core/helper"
21-
"k8s.io/kubernetes/pkg/util/taints"
2218
)
2319

2420
var taintMap = map[string]v1.TaintEffect{
@@ -33,6 +29,24 @@ func resourceKubernetesNodeTaint() *schema.Resource {
3329
ReadContext: resourceKubernetesNodeTaintRead,
3430
UpdateContext: resourceKubernetesNodeTaintUpdate,
3531
DeleteContext: resourceKubernetesNodeTaintDelete,
32+
CustomizeDiff: func(ctx context.Context, rd *schema.ResourceDiff, i interface{}) error {
33+
if !rd.HasChange("taint") {
34+
return nil
35+
}
36+
// check for duplicate taint keys
37+
taintkeys := map[string]int{}
38+
for _, t := range rd.Get("taint").([]interface{}) {
39+
taint := t.(map[string]interface{})
40+
key := taint["key"].(string)
41+
taintkeys[key] = taintkeys[key] + 1
42+
}
43+
for k, v := range taintkeys {
44+
if v > 1 {
45+
return fmt.Errorf("taint: duplicate taint key %q: taint keys must be unique", k)
46+
}
47+
}
48+
return nil
49+
},
3650
Schema: map[string]*schema.Schema{
3751
"metadata": {
3852
Type: schema.TypeList,
@@ -64,7 +78,6 @@ func resourceKubernetesNodeTaint() *schema.Resource {
6478
"taint": {
6579
Type: schema.TypeList,
6680
Required: true,
67-
MaxItems: 1,
6881
Elem: &schema.Resource{
6982
Schema: nodeTaintFields(),
7083
},
@@ -89,10 +102,8 @@ func resourceKubernetesNodeTaintDelete(ctx context.Context, d *schema.ResourceDa
89102
}
90103

91104
func resourceKubernetesNodeTaintRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
92-
nodeName, idTaint, err := idToNodeTaint(d.Id())
93-
if err != nil {
94-
return diag.FromErr(err)
95-
}
105+
meta := expandMetadata(d.Get("metadata").([]interface{}))
106+
nodeName := meta.Name
96107

97108
conn, err := m.(KubeClientsets).MainClientset()
98109
if err != nil {
@@ -109,11 +120,8 @@ func resourceKubernetesNodeTaintRead(ctx context.Context, d *schema.ResourceData
109120
d.SetId("")
110121
return nil
111122
}
112-
if !hasTaint(nodeTaints, idTaint) {
113-
d.SetId("")
114-
return nil
115-
}
116-
d.Set("taint", flattenNodeTaints(*idTaint))
123+
124+
d.Set("taint", flattenNodeTaints(nodeTaints...))
117125
return nil
118126
}
119127

@@ -127,7 +135,7 @@ func resourceKubernetesNodeTaintUpdate(ctx context.Context, d *schema.ResourceDa
127135
}
128136
nodeApi := conn.CoreV1().Nodes()
129137

130-
node, err := nodeApi.Get(ctx, nodeName, metav1.GetOptions{})
138+
_, err = nodeApi.Get(ctx, nodeName, metav1.GetOptions{})
131139
if err != nil {
132140
if d.Id() == "" {
133141
if statusErr, ok := err.(*errors.StatusError); ok && errors.IsNotFound(statusErr) {
@@ -139,28 +147,9 @@ func resourceKubernetesNodeTaintUpdate(ctx context.Context, d *schema.ResourceDa
139147
}
140148

141149
taints := d.Get("taint").([]interface{})
142-
newTaint, err := expandNodeTaint(taints[0].(map[string]interface{}))
143-
if err != nil {
144-
return diag.FromErr(err)
145-
}
146-
var newNode *v1.Node
147150
if d.Id() == "" {
148-
var removed bool
149-
newNode, removed = removeTaint(node, newTaint)
150-
if !removed {
151-
return diag.Diagnostics{{
152-
Severity: diag.Warning,
153-
Summary: "Resource deleted",
154-
Detail: fmt.Sprintf("Node %s does not have taint %+v. You should re-create it, or remove this resource from your configuration", nodeName, newTaint),
155-
}}
156-
}
157-
} else {
158-
log.Printf("[INFO] adding taint %+v to node %s", newTaint, nodeName)
159-
var updated bool
160-
newNode, updated = addOrUpdateTaint(node, newTaint)
161-
if !updated {
162-
return diag.Errorf("Node %s already has taint %+v", nodeName, newTaint)
163-
}
151+
// make taints an empty list if we're deleting the resource
152+
taints = []interface{}{}
164153
}
165154
patchObj := map[string]interface{}{
166155
"apiVersion": "v1",
@@ -169,7 +158,7 @@ func resourceKubernetesNodeTaintUpdate(ctx context.Context, d *schema.ResourceDa
169158
"name": nodeName,
170159
},
171160
"spec": map[string]interface{}{
172-
"taints": flattenNodeTaints(newNode.Spec.Taints...),
161+
"taints": taints,
173162
},
174163
}
175164
patch := unstructured.Unstructured{
@@ -197,93 +186,14 @@ func resourceKubernetesNodeTaintUpdate(ctx context.Context, d *schema.ResourceDa
197186
if d.Id() == "" {
198187
return nil
199188
}
200-
d.SetId(nodeTaintToId(nodeName, taints))
201189
return resourceKubernetesNodeTaintRead(ctx, d, m)
202190
}
203191

204-
func addOrUpdateTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool) {
205-
nodeTaints := node.Spec.Taints
206-
newTaints := []v1.Taint{}
207-
updated := false
208-
for i := range nodeTaints {
209-
log.Printf("[INFO] Checking taint: %+v", nodeTaints[i])
210-
if taint.MatchTaint(&nodeTaints[i]) {
211-
if helper.Semantic.DeepEqual(*taint, nodeTaints[i]) {
212-
return node, false
213-
}
214-
newTaints = append(newTaints, *taint)
215-
updated = true
216-
continue
217-
}
218-
newTaints = append(newTaints, nodeTaints[i])
219-
}
220-
if !updated {
221-
newTaints = append(newTaints, *taint)
222-
log.Printf("[INFO] appended taint: %+v", taint)
223-
updated = true
224-
}
225-
newNode := node.DeepCopy()
226-
newNode.Spec.Taints = newTaints
227-
return newNode, updated
228-
}
229-
230-
func removeTaint(node *v1.Node, delTaint *v1.Taint) (*v1.Node, bool) {
231-
taints := node.Spec.Taints
232-
newTaints := []v1.Taint{}
233-
deleted := false
234-
for i := range taints {
235-
if delTaint.MatchTaint(&taints[i]) {
236-
deleted = true
237-
continue
238-
}
239-
newTaints = append(newTaints, taints[i])
240-
}
241-
if !deleted {
242-
return node, false
243-
}
244-
newNode := node.DeepCopy()
245-
newNode.Spec.Taints = newTaints
246-
return newNode, deleted
247-
}
248-
249-
func hasTaint(taints []v1.Taint, taint *v1.Taint) bool {
250-
for i := range taints {
251-
if taint.MatchTaint(&taints[i]) {
252-
return true
253-
}
254-
}
255-
return false
256-
}
257-
258-
func expandNodeTaint(t map[string]interface{}) (*v1.Taint, error) {
259-
tt := expandStringMap(t)
260-
taintEffect, ok := taintMap[tt["effect"]]
261-
if !ok {
262-
return nil, fmt.Errorf("Invalid taint effect '%s'", tt["effect"])
263-
}
264-
taint := &v1.Taint{
265-
Key: tt["key"],
266-
Value: tt["value"],
267-
Effect: taintEffect,
268-
}
269-
return taint, nil
270-
}
271-
272192
func nodeTaintToId(nodeName string, taints []interface{}) string {
273-
t := taints[0].(map[string]interface{})
274-
return fmt.Sprintf("%s,%s=%s:%s", nodeName, t["key"], t["value"], t["effect"])
275-
}
276-
277-
func idToNodeTaint(id string) (string, *v1.Taint, error) {
278-
idVals := strings.Split(id, ",")
279-
nodeName := idVals[0]
280-
taintStr := idVals[1]
281-
taints, _, err := taints.ParseTaints([]string{taintStr})
282-
if err != nil {
283-
return "", nil, err
284-
}
285-
if len(taints) == 0 {
286-
return "", nil, fmt.Errorf("failed to parse taint %s", taintStr)
193+
var id string = fmt.Sprintf("%s", nodeName)
194+
for _, t := range taints {
195+
taint := t.(map[string]interface{})
196+
id += fmt.Sprintf(",%s=%s:%s", taint["key"], taint["value"], taint["effect"])
287197
}
288-
return nodeName, &taints[0], nil
198+
return id
289199
}

0 commit comments

Comments
 (0)