mirror of https://github.com/kubernetes/kops.git
Move validation of ClusterSubnetSpec into pkg/apis/kops/validation
This commit is contained in:
parent
c6eca9db81
commit
2c0f9809eb
|
|
@ -17,6 +17,8 @@ limitations under the License.
|
||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -35,6 +37,7 @@ func awsValidateCluster(c *kops.Cluster) field.ErrorList {
|
||||||
if c.Spec.API.LoadBalancer != nil {
|
if c.Spec.API.LoadBalancer != nil {
|
||||||
allErrs = append(allErrs, awsValidateAdditionalSecurityGroups(field.NewPath("spec", "api", "loadBalancer", "additionalSecurityGroups"), c.Spec.API.LoadBalancer.AdditionalSecurityGroups)...)
|
allErrs = append(allErrs, awsValidateAdditionalSecurityGroups(field.NewPath("spec", "api", "loadBalancer", "additionalSecurityGroups"), c.Spec.API.LoadBalancer.AdditionalSecurityGroups)...)
|
||||||
allErrs = append(allErrs, awsValidateSSLPolicy(field.NewPath("spec", "api", "loadBalancer", "sslPolicy"), c.Spec.API.LoadBalancer)...)
|
allErrs = append(allErrs, awsValidateSSLPolicy(field.NewPath("spec", "api", "loadBalancer", "sslPolicy"), c.Spec.API.LoadBalancer)...)
|
||||||
|
allErrs = append(allErrs, awsValidateLoadBalancerSubnets(field.NewPath("spec", "api", "loadBalancer", "subnets"), c.Spec)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,3 +199,49 @@ func awsValidateSSLPolicy(fieldPath *field.Path, spec *kops.LoadBalancerAccessSp
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func awsValidateLoadBalancerSubnets(fieldPath *field.Path, spec kops.ClusterSpec) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
lbSpec := spec.API.LoadBalancer
|
||||||
|
|
||||||
|
for i, subnet := range lbSpec.Subnets {
|
||||||
|
var clusterSubnet *kops.ClusterSubnetSpec
|
||||||
|
if subnet.Name == "" {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Index(i).Child("name"), subnet, "subnet name can't be empty"))
|
||||||
|
} else {
|
||||||
|
for _, cs := range spec.Subnets {
|
||||||
|
if subnet.Name == cs.Name {
|
||||||
|
clusterSubnet = &cs
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if clusterSubnet == nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Index(i).Child("name"), subnet, fmt.Sprintf("subnet %q not found in cluster subnets", subnet.Name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if subnet.PrivateIPv4Address != nil {
|
||||||
|
if *subnet.PrivateIPv4Address == "" {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Index(i).Child("privateIPv4Address"), subnet, "privateIPv4Address can't be empty"))
|
||||||
|
}
|
||||||
|
ip := net.ParseIP(*subnet.PrivateIPv4Address)
|
||||||
|
if ip == nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Index(i).Child("privateIPv4Address"), subnet, "privateIPv4Address is not a valid IPv4 address"))
|
||||||
|
} else if clusterSubnet != nil {
|
||||||
|
_, ipNet, err := net.ParseCIDR(clusterSubnet.CIDR)
|
||||||
|
if err == nil { // we assume that the cidr is actually valid
|
||||||
|
if !ipNet.Contains(ip) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Index(i).Child("privateIPv4Address"), subnet, "privateIPv4Address is not part of the subnet CIDR"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if lbSpec.Class != kops.LoadBalancerClassNetwork || lbSpec.Type != kops.LoadBalancerTypeInternal {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Index(i).Child("privateIPv4Address"), subnet, "privateIPv4Address only allowed for internal NLBs"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,3 +239,143 @@ func TestInstanceMetadataOptions(t *testing.T) {
|
||||||
testErrors(t, test.ig.ObjectMeta.Name, errs, test.expected)
|
testErrors(t, test.ig.ObjectMeta.Name, errs, test.expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadBalancerSubnets(t *testing.T) {
|
||||||
|
cidr := "10.0.0.0/24"
|
||||||
|
tests := []struct {
|
||||||
|
lbType *string
|
||||||
|
class *string
|
||||||
|
clusterSubnets []string
|
||||||
|
lbSubnets []kops.LoadBalancerSubnetSpec
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{ // valid (no privateIPv4Address)
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
PrivateIPv4Address: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "b",
|
||||||
|
PrivateIPv4Address: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // valid (with privateIPv4Address)
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
PrivateIPv4Address: fi.String("10.0.0.10"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "b",
|
||||||
|
PrivateIPv4Address: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // empty subnet name
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "",
|
||||||
|
PrivateIPv4Address: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []string{"Invalid value::spec.api.loadBalancer.subnets[0].name"},
|
||||||
|
},
|
||||||
|
{ // subnet not found
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "d",
|
||||||
|
PrivateIPv4Address: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []string{"Invalid value::spec.api.loadBalancer.subnets[0].name"},
|
||||||
|
},
|
||||||
|
{ // empty privateIPv4Address
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
PrivateIPv4Address: fi.String(""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []string{"Invalid value::spec.api.loadBalancer.subnets[0].privateIPv4Address"},
|
||||||
|
},
|
||||||
|
{ // invalid privateIPv4Address
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
PrivateIPv4Address: fi.String("invalidip"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []string{"Invalid value::spec.api.loadBalancer.subnets[0].privateIPv4Address"},
|
||||||
|
},
|
||||||
|
{ // privateIPv4Address not matching subnet cidr
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
PrivateIPv4Address: fi.String("11.0.0.10"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []string{"Invalid value::spec.api.loadBalancer.subnets[0].privateIPv4Address"},
|
||||||
|
},
|
||||||
|
{ // invalid class
|
||||||
|
class: fi.String(string(kops.LoadBalancerClassClassic)),
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
PrivateIPv4Address: fi.String("10.0.0.10"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []string{"Invalid value::spec.api.loadBalancer.subnets[0].privateIPv4Address"},
|
||||||
|
},
|
||||||
|
{ // invalid type
|
||||||
|
lbType: fi.String(string(kops.LoadBalancerTypePublic)),
|
||||||
|
clusterSubnets: []string{"a", "b", "c"},
|
||||||
|
lbSubnets: []kops.LoadBalancerSubnetSpec{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
PrivateIPv4Address: fi.String("10.0.0.10"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []string{"Invalid value::spec.api.loadBalancer.subnets[0].privateIPv4Address"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
cluster := kops.Cluster{
|
||||||
|
Spec: kops.ClusterSpec{
|
||||||
|
API: &kops.AccessSpec{
|
||||||
|
LoadBalancer: &kops.LoadBalancerAccessSpec{
|
||||||
|
Class: kops.LoadBalancerClassNetwork,
|
||||||
|
Type: kops.LoadBalancerTypeInternal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if test.class != nil {
|
||||||
|
cluster.Spec.API.LoadBalancer.Class = kops.LoadBalancerClass(*test.class)
|
||||||
|
}
|
||||||
|
if test.lbType != nil {
|
||||||
|
cluster.Spec.API.LoadBalancer.Type = kops.LoadBalancerType(*test.lbType)
|
||||||
|
}
|
||||||
|
for _, s := range test.clusterSubnets {
|
||||||
|
cluster.Spec.Subnets = append(cluster.Spec.Subnets, kops.ClusterSubnetSpec{
|
||||||
|
Name: s,
|
||||||
|
CIDR: cidr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, s := range test.lbSubnets {
|
||||||
|
cluster.Spec.API.LoadBalancer.Subnets = append(cluster.Spec.API.LoadBalancer.Subnets, s)
|
||||||
|
}
|
||||||
|
errs := awsValidateCluster(&cluster)
|
||||||
|
testErrors(t, test, errs, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,31 +68,19 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||||
if len(lbSpec.Subnets) != 0 {
|
if len(lbSpec.Subnets) != 0 {
|
||||||
// Subnets have been explicitly set
|
// Subnets have been explicitly set
|
||||||
for _, subnet := range lbSpec.Subnets {
|
for _, subnet := range lbSpec.Subnets {
|
||||||
found := false
|
|
||||||
for _, clusterSubnet := range b.Cluster.Spec.Subnets {
|
for _, clusterSubnet := range b.Cluster.Spec.Subnets {
|
||||||
if subnet.Name == clusterSubnet.Name {
|
if subnet.Name == clusterSubnet.Name {
|
||||||
found = true
|
|
||||||
elbSubnet := b.LinkToSubnet(&clusterSubnet)
|
elbSubnet := b.LinkToSubnet(&clusterSubnet)
|
||||||
elbSubnets = append(elbSubnets, elbSubnet)
|
elbSubnets = append(elbSubnets, elbSubnet)
|
||||||
nlbSubnetMappings = append(nlbSubnetMappings, &awstasks.SubnetMapping{
|
nlbSubnetMappings = append(nlbSubnetMappings, &awstasks.SubnetMapping{
|
||||||
Subnet: elbSubnet,
|
Subnet: elbSubnet,
|
||||||
})
|
})
|
||||||
if subnet.PrivateIPv4Address != nil {
|
if subnet.PrivateIPv4Address != nil {
|
||||||
if *subnet.PrivateIPv4Address == "" {
|
|
||||||
return fmt.Errorf("privateIPv4Address can't be empty")
|
|
||||||
}
|
|
||||||
if lbSpec.Class != kops.LoadBalancerClassNetwork || lbSpec.Type != kops.LoadBalancerTypeInternal {
|
|
||||||
return fmt.Errorf("privateIPv4Address only allowed for internal NLBs")
|
|
||||||
}
|
|
||||||
|
|
||||||
nlbSubnetMappings[len(nlbSubnetMappings)-1].PrivateIPv4Address = subnet.PrivateIPv4Address
|
nlbSubnetMappings[len(nlbSubnetMappings)-1].PrivateIPv4Address = subnet.PrivateIPv4Address
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("subnet %q not found in cluster subnets", subnet.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Compute the subnets - only one per zone, and then break ties based on chooseBestSubnetForELB
|
// Compute the subnets - only one per zone, and then break ties based on chooseBestSubnetForELB
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue