Skip to content

Commit 3aced86

Browse files
committed
Adds network regex webhook validation for powervscluster
1 parent 3bf33db commit 3aced86

File tree

3 files changed

+211
-0
lines changed

3 files changed

+211
-0
lines changed

api/v1beta2/common.go

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v1beta2
1818

1919
import (
20+
"regexp"
2021
"strconv"
2122

2223
"k8s.io/apimachinery/pkg/util/intstr"
@@ -42,16 +43,24 @@ func validateIBMPowerVSResourceReference(res IBMPowerVSResourceReference, resTyp
4243
if res.ID != nil && res.Name != nil {
4344
return false, field.Invalid(field.NewPath("spec", resType), res, "Only one of "+resType+" - ID or Name may be specified")
4445
}
46+
4547
return true, nil
4648
}
4749

4850
func validateIBMPowerVSNetworkReference(res IBMPowerVSResourceReference) (bool, *field.Error) {
51+
// Ensure only one of ID, Name, or RegEx is specified
4952
if (res.ID != nil && res.Name != nil) || (res.ID != nil && res.RegEx != nil) || (res.Name != nil && res.RegEx != nil) {
5053
return false, field.Invalid(field.NewPath("spec", "Network"), res, "Only one of Network - ID, Name or RegEx can be specified")
5154
}
5255
return true, nil
5356
}
5457

58+
// regexMatches validates if a given regex matches the target string.
59+
func regexMatches(pattern, target string) bool {
60+
matched, err := regexp.MatchString(pattern, target)
61+
return err == nil && matched
62+
}
63+
5564
func validateIBMPowerVSMemoryValues(resValue int32) bool {
5665
if val := float64(resValue); val < 2 {
5766
return false

api/v1beta2/ibmpowervscluster_webhook.go

+38
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,48 @@ func (r *IBMPowerVSCluster) validateIBMPowerVSCluster() (admission.Warnings, err
9595
r.Name, allErrs)
9696
}
9797

98+
func (r *IBMPowerVSCluster) validateNetworkRegex() (bool, *field.Error) {
99+
if r.Spec.Network.RegEx == nil {
100+
return true, nil
101+
}
102+
var targetName string
103+
var validationMessage string
104+
105+
// If only spec.Network.RegEx is set and no other network resources are specified,
106+
// the controller will create a DHCP server and the corresponding network in the format:
107+
// DHCPSERVER<dhcp_server_name>_Private.
108+
if r.Spec.DHCPServer != nil && *r.Spec.DHCPServer.Name != "" {
109+
targetName = *r.Spec.DHCPServer.Name
110+
validationMessage = "The RegEx should match the DHCP server name when the DHCP server is set"
111+
} else {
112+
if r.GetObjectMeta().GetName() == "" {
113+
return false, field.Required(
114+
field.NewPath("metadata", "name"),
115+
"Cluster name must be set when Network.RegEx is provided and DHCP server name is not set",
116+
)
117+
}
118+
targetName = r.GetObjectMeta().GetName()
119+
validationMessage = "The RegEx should match the cluster name when the DHCP server is not set"
120+
}
121+
122+
if !regexMatches(*r.Spec.Network.RegEx, targetName) {
123+
return false, field.Invalid(
124+
field.NewPath("spec", "Network", "RegEx"),
125+
r.Spec.Network.RegEx,
126+
validationMessage,
127+
)
128+
}
129+
130+
return true, nil
131+
}
132+
98133
func (r *IBMPowerVSCluster) validateIBMPowerVSClusterNetwork() *field.Error {
99134
if res, err := validateIBMPowerVSNetworkReference(r.Spec.Network); !res {
100135
return err
101136
}
137+
if res, err := r.validateNetworkRegex(); !res {
138+
return err
139+
}
102140
return nil
103141
}
104142

api/v1beta2/ibmpowervscluster_webhook_test.go

+164
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,63 @@ func TestIBMPowerVSCluster_create(t *testing.T) {
6868
},
6969
wantErr: true,
7070
},
71+
{
72+
name: "Should error network regex and dhcp server name is set but does not match dhcp server name",
73+
powervsCluster: &IBMPowerVSCluster{
74+
Spec: IBMPowerVSClusterSpec{
75+
ServiceInstanceID: "capi-si-id",
76+
Network: IBMPowerVSResourceReference{
77+
RegEx: ptr.To("^capi$"),
78+
},
79+
DHCPServer: &DHCPServer{
80+
Name: ptr.To("test"),
81+
},
82+
},
83+
},
84+
wantErr: true,
85+
},
86+
{
87+
name: "Should allow if network regex, dhcp server name is set and matches dhcp server name",
88+
powervsCluster: &IBMPowerVSCluster{
89+
Spec: IBMPowerVSClusterSpec{
90+
ServiceInstanceID: "capi-si-id",
91+
Network: IBMPowerVSResourceReference{
92+
RegEx: ptr.To("^capi$"),
93+
},
94+
DHCPServer: &DHCPServer{
95+
Name: ptr.To("capi"),
96+
},
97+
},
98+
},
99+
wantErr: false,
100+
},
101+
{
102+
name: "Should error if only network regex is set, dhcp server name is not set and does not match cluster name",
103+
powervsCluster: &IBMPowerVSCluster{
104+
Spec: IBMPowerVSClusterSpec{
105+
ServiceInstanceID: "capi-si-id",
106+
Network: IBMPowerVSResourceReference{
107+
RegEx: ptr.To("^capi$"),
108+
},
109+
},
110+
ObjectMeta: metav1.ObjectMeta{
111+
Name: "test",
112+
},
113+
},
114+
wantErr: true,
115+
},
116+
{
117+
name: "Should allow if network regex is set, dhcp server name is not set and matches cluster name",
118+
powervsCluster: &IBMPowerVSCluster{
119+
Spec: IBMPowerVSClusterSpec{
120+
ServiceInstanceID: "capi-si-id",
121+
Network: IBMPowerVSResourceReference{
122+
RegEx: ptr.To("^capi-cluster-.*"),
123+
},
124+
},
125+
},
126+
wantErr: false,
127+
},
71128
}
72129

73130
for _, tc := range tests {
@@ -141,6 +198,9 @@ func TestIBMPowerVSCluster_update(t *testing.T) {
141198
Network: IBMPowerVSResourceReference{
142199
RegEx: ptr.To("^capi-net-id$"),
143200
},
201+
DHCPServer: &DHCPServer{
202+
Name: ptr.To("capi-net-id"),
203+
},
144204
},
145205
},
146206
newPowervsCluster: &IBMPowerVSCluster{
@@ -149,6 +209,9 @@ func TestIBMPowerVSCluster_update(t *testing.T) {
149209
Network: IBMPowerVSResourceReference{
150210
RegEx: ptr.To("^capi-net-id$"),
151211
},
212+
DHCPServer: &DHCPServer{
213+
Name: ptr.To("capi-net-id"),
214+
},
152215
},
153216
},
154217
wantErr: false,
@@ -175,6 +238,107 @@ func TestIBMPowerVSCluster_update(t *testing.T) {
175238
},
176239
wantErr: true,
177240
},
241+
{
242+
name: "Should error if network regex and dhcp server name is set but network regex does not match dhcp server name",
243+
oldPowervsCluster: &IBMPowerVSCluster{
244+
Spec: IBMPowerVSClusterSpec{
245+
ServiceInstanceID: "capi-si-id",
246+
Network: IBMPowerVSResourceReference{
247+
RegEx: ptr.To("^capi$"),
248+
},
249+
DHCPServer: &DHCPServer{
250+
Name: ptr.To("capi"),
251+
},
252+
},
253+
},
254+
newPowervsCluster: &IBMPowerVSCluster{
255+
Spec: IBMPowerVSClusterSpec{
256+
ServiceInstanceID: "capi-si-id",
257+
Network: IBMPowerVSResourceReference{
258+
RegEx: ptr.To("^capi$"),
259+
},
260+
DHCPServer: &DHCPServer{
261+
Name: ptr.To("test"),
262+
},
263+
},
264+
},
265+
wantErr: true,
266+
},
267+
{
268+
name: "Should allow if network regex, dhcp server name is set and network regex matches dhcp server name",
269+
oldPowervsCluster: &IBMPowerVSCluster{
270+
Spec: IBMPowerVSClusterSpec{
271+
ServiceInstanceID: "capi-si-id",
272+
Network: IBMPowerVSResourceReference{
273+
RegEx: ptr.To("^capi$"),
274+
},
275+
DHCPServer: &DHCPServer{
276+
Name: ptr.To("capi"),
277+
},
278+
},
279+
},
280+
newPowervsCluster: &IBMPowerVSCluster{
281+
Spec: IBMPowerVSClusterSpec{
282+
ServiceInstanceID: "capi-si-id",
283+
Network: IBMPowerVSResourceReference{
284+
RegEx: ptr.To("^capi$"),
285+
},
286+
DHCPServer: &DHCPServer{
287+
Name: ptr.To("capi"),
288+
},
289+
},
290+
},
291+
wantErr: false,
292+
},
293+
{
294+
name: "Should error if network regex is set, dhcp server name is not set and network regex does not match cluster name",
295+
oldPowervsCluster: &IBMPowerVSCluster{
296+
Spec: IBMPowerVSClusterSpec{
297+
ServiceInstanceID: "capi-si-id",
298+
Network: IBMPowerVSResourceReference{
299+
RegEx: ptr.To("^capi$"),
300+
},
301+
DHCPServer: &DHCPServer{
302+
Name: ptr.To("capi"),
303+
},
304+
},
305+
},
306+
newPowervsCluster: &IBMPowerVSCluster{
307+
Spec: IBMPowerVSClusterSpec{
308+
ServiceInstanceID: "capi-si-id",
309+
Network: IBMPowerVSResourceReference{
310+
RegEx: ptr.To("^capi$"),
311+
},
312+
},
313+
ObjectMeta: metav1.ObjectMeta{
314+
Name: "capi",
315+
},
316+
},
317+
wantErr: true,
318+
},
319+
{
320+
name: "Should allow if network regex is set, dhcp server name is not set and network regex matches cluster name",
321+
oldPowervsCluster: &IBMPowerVSCluster{
322+
Spec: IBMPowerVSClusterSpec{
323+
ServiceInstanceID: "capi-si-id",
324+
Network: IBMPowerVSResourceReference{
325+
RegEx: ptr.To("^capi$"),
326+
},
327+
DHCPServer: &DHCPServer{
328+
Name: ptr.To("capi"),
329+
},
330+
},
331+
},
332+
newPowervsCluster: &IBMPowerVSCluster{
333+
Spec: IBMPowerVSClusterSpec{
334+
ServiceInstanceID: "capi-si-id",
335+
Network: IBMPowerVSResourceReference{
336+
RegEx: ptr.To("^capi-cluster-.*"),
337+
},
338+
},
339+
},
340+
wantErr: false,
341+
},
178342
}
179343

180344
for _, tc := range tests {

0 commit comments

Comments
 (0)