Skip to content

Commit e4432d1

Browse files
committed
fix(484): add a validation on taint nested object of the nodepool template
fix(review): add title to link un MD
1 parent 9221645 commit e4432d1

4 files changed

+184
-4
lines changed

ovh/resource_cloud_project_kube_nodepool.go

+20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ovh
22

33
import (
4+
"errors"
45
"fmt"
56
"log"
67
"strings"
@@ -203,6 +204,25 @@ func resourceCloudProjectKubeNodePool() *schema.Resource {
203204
Elem: &schema.Schema{
204205
Type: schema.TypeMap,
205206
Set: schema.HashString,
207+
ValidateFunc: func(taintInterface interface{}, path string) (warning []string, errorList []error) {
208+
taint := taintInterface.(map[string]interface{})
209+
210+
if taint["key"] == nil {
211+
return nil, []error{errors.New(fmt.Sprintf("key attribute is mandatory for taint: %s", path))}
212+
}
213+
214+
if taint["effect"] == nil {
215+
return nil, []error{errors.New(fmt.Sprintf("effect attribute is mandatory for taint: %s", path))}
216+
}
217+
218+
effectString := taint["effect"].(string)
219+
effect := TaintEffecTypeToID[effectString]
220+
if effect == NotATaint {
221+
return nil, []error{fmt.Errorf("effect: %s is not a allowable taint %#v", effectString, TaintEffecTypeToID)}
222+
}
223+
224+
return nil, nil
225+
},
206226
},
207227
},
208228
},

ovh/resource_cloud_project_kube_nodepool_test.go

+153
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"log"
66
"os"
7+
"regexp"
78
"strings"
89
"testing"
910
"time"
@@ -13,6 +14,12 @@ import (
1314
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
1415
)
1516

17+
var (
18+
effectTaintsErrorRegex = regexp.MustCompile("(.)*effect attribute is mandatory for taint(.)*")
19+
keyTaintsErrorRegex = regexp.MustCompile("(.)*key attribute is mandatory for taint(.)*")
20+
valueNoCrashTaintsErrorRegex = regexp.MustCompile("(.)*This service does not exist(.)*")
21+
)
22+
1623
func init() {
1724
resource.AddTestSweepers("ovh_cloud_project_kube_nodepool", &resource.Sweeper{
1825
Name: "ovh_cloud_project_kube_nodepool",
@@ -73,6 +80,105 @@ func testSweepCloudProjectKubeNodePool(region string) error {
7380
return nil
7481
}
7582

83+
var testAccCloudProjectKubeNodePoolConfigEffectMissingInTaint = `
84+
resource "ovh_cloud_project_kube_nodepool" "pool" {
85+
service_name = "xxx"
86+
kube_id = "xxx"
87+
name = "xxx"
88+
flavor_name = "b2-7"
89+
desired_nodes = 1
90+
min_nodes = 0
91+
max_nodes = 1
92+
template {
93+
metadata {
94+
annotations = {
95+
a1 = "av1"
96+
}
97+
finalizers = ["finalizer.extensions/v1beta1"]
98+
labels = {
99+
l1 = "lv1"
100+
}
101+
}
102+
spec {
103+
unschedulable = false
104+
taints = [
105+
{
106+
#effect = "PreferNoSchedule"
107+
key = "t1"
108+
value = "tv1"
109+
}
110+
]
111+
}
112+
}
113+
}
114+
`
115+
116+
var testAccCloudProjectKubeNodePoolConfigKeyMissingInTaint = `
117+
resource "ovh_cloud_project_kube_nodepool" "pool" {
118+
service_name = "xxx"
119+
kube_id = "xxx"
120+
name = "xxx"
121+
flavor_name = "b2-7"
122+
desired_nodes = 1
123+
min_nodes = 0
124+
max_nodes = 1
125+
template {
126+
metadata {
127+
annotations = {
128+
a1 = "av1"
129+
}
130+
finalizers = ["finalizer.extensions/v1beta1"]
131+
labels = {
132+
l1 = "lv1"
133+
}
134+
}
135+
spec {
136+
unschedulable = false
137+
taints = [
138+
{
139+
effect = "PreferNoSchedule"
140+
#key = "t1"
141+
value = "tv1"
142+
}
143+
]
144+
}
145+
}
146+
}
147+
`
148+
149+
var testAccCloudProjectKubeNodePoolConfigValueMissingInTaint = `
150+
resource "ovh_cloud_project_kube_nodepool" "pool" {
151+
service_name = "xxx"
152+
kube_id = "xxx"
153+
name = "xxx"
154+
flavor_name = "b2-7"
155+
desired_nodes = 1
156+
min_nodes = 0
157+
max_nodes = 1
158+
template {
159+
metadata {
160+
annotations = {
161+
a1 = "av1"
162+
}
163+
finalizers = ["finalizer.extensions/v1beta1"]
164+
labels = {
165+
l1 = "lv1"
166+
}
167+
}
168+
spec {
169+
unschedulable = false
170+
taints = [
171+
{
172+
effect = "PreferNoSchedule"
173+
key = "t1"
174+
#value = "tv1"
175+
}
176+
]
177+
}
178+
}
179+
}
180+
`
181+
76182
var testAccCloudProjectKubeNodePoolConfig = `
77183
resource "ovh_cloud_project_kube" "cluster" {
78184
service_name = "%s"
@@ -297,3 +403,50 @@ func TestAccCloudProjectKubeNodePool(t *testing.T) {
297403
},
298404
})
299405
}
406+
407+
func TestAccCloudProjectKubeNodePoolTaints(t *testing.T) {
408+
resource.Test(t, resource.TestCase{
409+
PreCheck: func() {
410+
testAccPreCheckCloud(t)
411+
testAccCheckCloudProjectExists(t)
412+
testAccPreCheckKubernetes(t)
413+
},
414+
Providers: testAccProviders,
415+
Steps: []resource.TestStep{
416+
{
417+
Config: testAccCloudProjectKubeNodePoolConfigEffectMissingInTaint,
418+
ExpectError: effectTaintsErrorRegex,
419+
},
420+
},
421+
})
422+
423+
resource.Test(t, resource.TestCase{
424+
PreCheck: func() {
425+
testAccPreCheckCloud(t)
426+
testAccCheckCloudProjectExists(t)
427+
testAccPreCheckKubernetes(t)
428+
},
429+
Providers: testAccProviders,
430+
Steps: []resource.TestStep{
431+
{
432+
Config: testAccCloudProjectKubeNodePoolConfigKeyMissingInTaint,
433+
ExpectError: keyTaintsErrorRegex,
434+
},
435+
},
436+
})
437+
438+
resource.Test(t, resource.TestCase{
439+
PreCheck: func() {
440+
testAccPreCheckCloud(t)
441+
testAccCheckCloudProjectExists(t)
442+
testAccPreCheckKubernetes(t)
443+
},
444+
Providers: testAccProviders,
445+
Steps: []resource.TestStep{
446+
{
447+
Config: testAccCloudProjectKubeNodePoolConfigValueMissingInTaint,
448+
ExpectError: valueNoCrashTaintsErrorRegex,
449+
},
450+
},
451+
})
452+
}

ovh/types_cloud_project_kube_nodepool.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,15 @@ func loadNodelPoolTemplateFromResource(i interface{}) (*CloudProjectKubeNodePool
196196
return nil, fmt.Errorf("effect: %s is not a allowable taint %#v", effectString, TaintEffecTypeToID)
197197
}
198198

199-
template.Spec.Taints = append(template.Spec.Taints, Taint{
199+
taintObject := Taint{
200200
Effect: effect,
201201
Key: taint.(map[string]interface{})["key"].(string),
202-
Value: taint.(map[string]interface{})["value"].(string),
203-
})
202+
}
203+
if taint.(map[string]interface{})["value"] != nil {
204+
taintObject.Value = taint.(map[string]interface{})["value"].(string)
205+
}
206+
207+
template.Spec.Taints = append(template.Spec.Taints, taintObject)
204208
}
205209

206210
// spec.unschedulable

website/docs/r/cloud_project_kube_nodepool.html.markdown

+4-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,10 @@ The following arguments are supported:
8080
* `finalizers` - Finalizers to apply to each node. A finalizer name must be fully qualified, e.g. kubernetes.io/pv-protection , where you prefix it with hostname of your service which is related to the controller responsible for the finalizer.
8181
* `labels` - Labels to apply to each node
8282
* `spec` - Spec of each node in the pool
83-
* `taints` - Taints to apply to each node
83+
* `taints` - Taints to apply to each node [NodeSpec kubernetes documentation](https://kubernetes.io/docs/reference/kubernetes-api/cluster-resources/node-v1/#NodeSpec)
84+
* `effect` - mandatory possible values: NoExecute, NoSchedule, PreferNoSchedule
85+
* `key` - mandatory
86+
* `value` - (Optional)
8487
* `unschedulable` - If true, set nodes as un-schedulable
8588

8689
## Attributes Reference

0 commit comments

Comments
 (0)