Skip to content
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

Network regex validation for powervs cluster #2145

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions api/v1beta2/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1beta2

import (
"regexp"
"strconv"

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

return true, nil
}

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

// regexMatches validates if a given regex matches the target string.
func regexMatches(pattern, target string) bool {
matched, err := regexp.MatchString(pattern, target)
return err == nil && matched
}

func validateIBMPowerVSMemoryValues(resValue int32) bool {
if val := float64(resValue); val < 2 {
return false
Expand Down
38 changes: 38 additions & 0 deletions api/v1beta2/ibmpowervscluster_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,48 @@ func (r *IBMPowerVSCluster) validateIBMPowerVSCluster() (admission.Warnings, err
r.Name, allErrs)
}

func (r *IBMPowerVSCluster) validateNetworkRegex() (bool, *field.Error) {
if r.Spec.Network.RegEx == nil {
return true, nil
}
var targetName string
var validationMessage string

// If only spec.Network.RegEx is set and no other network resources are specified,
// the controller will create a DHCP server and the corresponding network in the format:
// DHCPSERVER<dhcp_server_name>_Private.
if r.Spec.DHCPServer != nil && *r.Spec.DHCPServer.Name != "" {
targetName = *r.Spec.DHCPServer.Name
validationMessage = "The RegEx should match the DHCP server name when the DHCP server is set"
} else {
if r.GetObjectMeta().GetName() == "" {
return false, field.Required(
field.NewPath("metadata", "name"),
"Cluster name must be set when Network.RegEx is provided and DHCP server name is not set",
)
}
targetName = r.GetObjectMeta().GetName()
validationMessage = "The RegEx should match the cluster name when the DHCP server is not set"
}

if !regexMatches(*r.Spec.Network.RegEx, targetName) {
return false, field.Invalid(
field.NewPath("spec", "Network", "RegEx"),
r.Spec.Network.RegEx,
validationMessage,
)
}

return true, nil
}

func (r *IBMPowerVSCluster) validateIBMPowerVSClusterNetwork() *field.Error {
if res, err := validateIBMPowerVSNetworkReference(r.Spec.Network); !res {
return err
}
if res, err := r.validateNetworkRegex(); !res {
return err
}
return nil
}

Expand Down
164 changes: 164 additions & 0 deletions api/v1beta2/ibmpowervscluster_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,63 @@ func TestIBMPowerVSCluster_create(t *testing.T) {
},
wantErr: true,
},
{
name: "Should error network regex and dhcp server name is set but does not match dhcp server name",
powervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("test"),
},
},
},
wantErr: true,
},
{
name: "Should allow if network regex, dhcp server name is set and matches dhcp server name",
powervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("capi"),
},
},
},
wantErr: false,
},
{
name: "Should error if only network regex is set, dhcp server name is not set and does not match cluster name",
powervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
},
wantErr: true,
},
{
name: "Should allow if network regex is set, dhcp server name is not set and matches cluster name",
powervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi-cluster-.*"),
},
},
},
wantErr: false,
},
}

for _, tc := range tests {
Expand Down Expand Up @@ -141,6 +198,9 @@ func TestIBMPowerVSCluster_update(t *testing.T) {
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi-net-id$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("capi-net-id"),
},
},
},
newPowervsCluster: &IBMPowerVSCluster{
Expand All @@ -149,6 +209,9 @@ func TestIBMPowerVSCluster_update(t *testing.T) {
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi-net-id$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("capi-net-id"),
},
},
},
wantErr: false,
Expand All @@ -175,6 +238,107 @@ func TestIBMPowerVSCluster_update(t *testing.T) {
},
wantErr: true,
},
{
name: "Should error if network regex and dhcp server name is set but network regex does not match dhcp server name",
oldPowervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("capi"),
},
},
},
newPowervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("test"),
},
},
},
wantErr: true,
},
{
name: "Should allow if network regex, dhcp server name is set and network regex matches dhcp server name",
oldPowervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("capi"),
},
},
},
newPowervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("capi"),
},
},
},
wantErr: false,
},
{
name: "Should error if network regex is set, dhcp server name is not set and network regex does not match cluster name",
oldPowervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("capi"),
},
},
},
newPowervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
},
ObjectMeta: metav1.ObjectMeta{
Name: "capi",
},
},
wantErr: true,
},
{
name: "Should allow if network regex is set, dhcp server name is not set and network regex matches cluster name",
oldPowervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi$"),
},
DHCPServer: &DHCPServer{
Name: ptr.To("capi"),
},
},
},
newPowervsCluster: &IBMPowerVSCluster{
Spec: IBMPowerVSClusterSpec{
ServiceInstanceID: "capi-si-id",
Network: IBMPowerVSResourceReference{
RegEx: ptr.To("^capi-cluster-.*"),
},
},
},
wantErr: false,
},
}

for _, tc := range tests {
Expand Down