Skip to content

Commit 752728d

Browse files
author
Wei Weng
committed
validate cluster vnet
1 parent 8fa937a commit 752728d

5 files changed

Lines changed: 866 additions & 3 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha3
18+
19+
import (
20+
"fmt"
21+
"regexp"
22+
23+
apierrors "k8s.io/apimachinery/pkg/api/errors"
24+
"k8s.io/apimachinery/pkg/runtime/schema"
25+
"k8s.io/apimachinery/pkg/util/validation/field"
26+
)
27+
28+
const (
29+
// obtained from https://docs.microsoft.com/en-us/rest/api/resources/resourcegroups/createorupdate#uri-parameters
30+
resourceGroupRegex = `^[-\w\._\(\)]+$`
31+
// described in https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules
32+
subnetRegex = `^[-\w\._]+$`
33+
ipv4Regex = `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`
34+
)
35+
36+
// validateCluster validates a cluster
37+
func (c *AzureCluster) validateCluster() error {
38+
var allErrs field.ErrorList
39+
allErrs = append(allErrs, c.validateClusterSpec()...)
40+
if len(allErrs) == 0 {
41+
return nil
42+
}
43+
44+
return apierrors.NewInvalid(
45+
schema.GroupKind{Group: "infrastructure.cluster.x-k8s.io", Kind: "AzureCluster"},
46+
c.Name, allErrs)
47+
}
48+
49+
// validateClusterSpec validates a ClusterSpec
50+
func (c *AzureCluster) validateClusterSpec() field.ErrorList {
51+
return validateNetworkSpec(
52+
c.Spec.NetworkSpec,
53+
field.NewPath("spec").Child("networkSpec"))
54+
}
55+
56+
// validateNetworkSpec validates a NetworkSpec
57+
func validateNetworkSpec(networkSpec NetworkSpec, fldPath *field.Path) field.ErrorList {
58+
var allErrs field.ErrorList
59+
// If the user specifies a resourceGroup for vnet, it means
60+
// that she intends to use a pre-existing vnet. In this case,
61+
// we need to verify the information she provides
62+
if networkSpec.Vnet.ResourceGroup != "" {
63+
if err := validateResourceGroup(networkSpec.Vnet.ResourceGroup,
64+
fldPath.Child("vnet").Child("resourceGroup")); err != nil {
65+
allErrs = append(allErrs, err)
66+
}
67+
allErrs = append(allErrs, validateSubnets(networkSpec.Subnets, fldPath.Child("subnets"))...)
68+
}
69+
if len(allErrs) == 0 {
70+
return nil
71+
}
72+
return allErrs
73+
}
74+
75+
// validateResourceGroup validates a ResourceGroup
76+
func validateResourceGroup(resourceGroup string, fldPath *field.Path) *field.Error {
77+
if success, _ := regexp.Match(resourceGroupRegex, []byte(resourceGroup)); !success {
78+
return field.Invalid(fldPath, resourceGroup,
79+
fmt.Sprintf("resourceGroup doesn't match regex %s", resourceGroupRegex))
80+
}
81+
return nil
82+
}
83+
84+
// validateSubnets validates a list of Subnets
85+
func validateSubnets(subnets Subnets, fldPath *field.Path) field.ErrorList {
86+
var allErrs field.ErrorList
87+
requiredSubnetRoles := map[string]bool{
88+
"control-plane": false,
89+
"node": false,
90+
}
91+
for i, subnet := range subnets {
92+
if err := validateSubnetName(subnet.Name, fldPath.Index(i).Child("name")); err != nil {
93+
allErrs = append(allErrs, err)
94+
}
95+
if subnet.InternalLBIPAddress != "" {
96+
if err := validateInternalLBIPAddress(subnet.InternalLBIPAddress,
97+
fldPath.Index(i).Child("internalLBIPAddress")); err != nil {
98+
allErrs = append(allErrs, err)
99+
}
100+
}
101+
for role := range requiredSubnetRoles {
102+
if role == string(subnet.Role) {
103+
requiredSubnetRoles[role] = true
104+
}
105+
}
106+
}
107+
for k, v := range requiredSubnetRoles {
108+
if v == false {
109+
allErrs = append(allErrs, field.Required(fldPath,
110+
fmt.Sprintf("required role %s not included in provided subnets", k)))
111+
}
112+
}
113+
if len(allErrs) == 0 {
114+
return nil
115+
}
116+
return allErrs
117+
}
118+
119+
// validateSubnetName validates the Name of a Subnet
120+
func validateSubnetName(name string, fldPath *field.Path) *field.Error {
121+
if success, _ := regexp.Match(subnetRegex, []byte(name)); !success {
122+
return field.Invalid(fldPath, name,
123+
fmt.Sprintf("name of subnet doesn't match regex %s", subnetRegex))
124+
}
125+
return nil
126+
}
127+
128+
// validateInternalLBIPAddress validates a InternalLBIPAddress
129+
func validateInternalLBIPAddress(address string, fldPath *field.Path) *field.Error {
130+
if success, _ := regexp.Match(ipv4Regex, []byte(address)); !success {
131+
return field.Invalid(fldPath, address,
132+
fmt.Sprintf("internalLBIPAddress doesn't match regex %s", ipv4Regex))
133+
}
134+
return nil
135+
}

0 commit comments

Comments
 (0)