kubeadm --pod-network-cidr supports a comma separated list of pod

CIDRs. This is a necesary change for dual-stack.
This commit is contained in:
Arvinderpal Wander 2019-06-23 17:51:26 -07:00
parent ec77598906
commit 3ac7ae60cc
5 changed files with 77 additions and 33 deletions

View File

@ -21,6 +21,7 @@ go_library(
"//staging/src/k8s.io/cluster-bootstrap/token/util:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/utils/net:go_default_library",
],
)

View File

@ -40,6 +40,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/features"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
utilnet "k8s.io/utils/net"
)
// ValidateInitConfiguration validates an InitConfiguration object and collects all encountered errors
@ -48,6 +49,7 @@ func ValidateInitConfiguration(c *kubeadm.InitConfiguration) field.ErrorList {
allErrs = append(allErrs, ValidateNodeRegistrationOptions(&c.NodeRegistration, field.NewPath("nodeRegistration"))...)
allErrs = append(allErrs, ValidateBootstrapTokens(c.BootstrapTokens, field.NewPath("bootstrapTokens"))...)
allErrs = append(allErrs, ValidateClusterConfiguration(&c.ClusterConfiguration)...)
// TODO(Arvinderpal): update advertiseAddress validation for dual-stack once it's implemented.
allErrs = append(allErrs, ValidateAPIEndpoint(&c.LocalAPIEndpoint, field.NewPath("localAPIEndpoint"))...)
// TODO: Maybe validate that .CertificateKey is a valid hex encoded AES key
return allErrs
@ -56,7 +58,7 @@ func ValidateInitConfiguration(c *kubeadm.InitConfiguration) field.ErrorList {
// ValidateClusterConfiguration validates an ClusterConfiguration object and collects all encountered errors
func ValidateClusterConfiguration(c *kubeadm.ClusterConfiguration) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
allErrs = append(allErrs, ValidateNetworking(c, field.NewPath("networking"))...)
allErrs = append(allErrs, ValidateAPIServer(&c.APIServer, field.NewPath("apiServer"))...)
allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...)
allErrs = append(allErrs, ValidateFeatureGates(c.FeatureGates, field.NewPath("featureGates"))...)
@ -369,30 +371,53 @@ func ValidateHostPort(endpoint string, fldPath *field.Path) field.ErrorList {
}
// ValidateIPNetFromString validates network portion of ip address
func ValidateIPNetFromString(subnet string, minAddrs int64, fldPath *field.Path) field.ErrorList {
func ValidateIPNetFromString(subnetStr string, minAddrs int64, isDualStack bool, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
_, svcSubnet, err := net.ParseCIDR(subnet)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, subnet, "couldn't parse subnet"))
return allErrs
}
numAddresses := ipallocator.RangeSize(svcSubnet)
if numAddresses < minAddrs {
allErrs = append(allErrs, field.Invalid(fldPath, subnet, "subnet is too small"))
if isDualStack {
subnets, err := utilnet.ParseCIDRs(strings.Split(subnetStr, ","))
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, subnetStr, err.Error()))
} else {
areDualStackCIDRs, err := utilnet.IsDualStackCIDRs(subnets)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, subnets, err.Error()))
} else if !areDualStackCIDRs {
allErrs = append(allErrs, field.Invalid(fldPath, subnetStr, "expected at least one IP from each family (v4 or v6) for dual-stack networking"))
}
for _, s := range subnets {
numAddresses := ipallocator.RangeSize(s)
if numAddresses < minAddrs {
allErrs = append(allErrs, field.Invalid(fldPath, s, "subnet is too small"))
}
}
}
} else {
_, svcSubnet, err := net.ParseCIDR(subnetStr)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath, subnetStr, "couldn't parse subnet"))
return allErrs
}
numAddresses := ipallocator.RangeSize(svcSubnet)
if numAddresses < minAddrs {
allErrs = append(allErrs, field.Invalid(fldPath, subnetStr, "subnet is too small"))
}
}
return allErrs
}
// ValidateNetworking validates networking configuration
func ValidateNetworking(c *kubeadm.Networking, fldPath *field.Path) field.ErrorList {
func ValidateNetworking(c *kubeadm.ClusterConfiguration, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
dnsDomainFldPath := field.NewPath("dnsDomain")
for _, err := range validation.IsDNS1123Subdomain(c.DNSDomain) {
allErrs = append(allErrs, field.Invalid(dnsDomainFldPath, c.DNSDomain, err))
for _, err := range validation.IsDNS1123Subdomain(c.Networking.DNSDomain) {
allErrs = append(allErrs, field.Invalid(dnsDomainFldPath, c.Networking.DNSDomain, err))
}
allErrs = append(allErrs, ValidateIPNetFromString(c.ServiceSubnet, constants.MinimumAddressesInServiceSubnet, field.NewPath("serviceSubnet"))...)
if len(c.PodSubnet) != 0 {
allErrs = append(allErrs, ValidateIPNetFromString(c.PodSubnet, constants.MinimumAddressesInServiceSubnet, field.NewPath("podSubnet"))...)
// check if dual-stack feature-gate is enabled
isDualStack := features.Enabled(c.FeatureGates, features.IPv6DualStack)
// TODO(Arvinderpal): use isDualStack flag once list of service CIDRs is supported (PR: #79386)
allErrs = append(allErrs, ValidateIPNetFromString(c.Networking.ServiceSubnet, constants.MinimumAddressesInServiceSubnet, false /*isDualStack*/, field.NewPath("serviceSubnet"))...)
if len(c.Networking.PodSubnet) != 0 {
allErrs = append(allErrs, ValidateIPNetFromString(c.Networking.PodSubnet, constants.MinimumAddressesInServiceSubnet, isDualStack, field.NewPath("podSubnet"))...)
}
return allErrs
}
@ -455,7 +480,6 @@ func ValidateFeatureGates(featureGates map[string]bool, fldPath *field.Path) fie
fmt.Sprintf("%s is not a valid feature name.", k)))
}
}
return allErrs
}

View File

@ -194,29 +194,43 @@ func TestValidateIPFromString(t *testing.T) {
func TestValidateIPNetFromString(t *testing.T) {
var tests = []struct {
name string
subnet string
minaddrs int64
expected bool
name string
subnet string
minaddrs int64
checkDualStack bool
expected bool
}{
{"invalid missing CIDR", "", 0, false},
{"invalid CIDR missing decimal points in IPv4 address and / mask", "1234", 0, false},
{"invalid CIDR use of letters instead of numbers and / mask", "abc", 0, false},
{"invalid IPv4 address provided instead of CIDR representation", "1.2.3.4", 0, false},
{"invalid IPv6 address provided instead of CIDR representation", "2001:db8::1", 0, false},
{"valid, but IPv4 CIDR too small. At least 10 addresses needed", "10.0.0.16/29", 10, false},
{"valid, but IPv6 CIDR too small. At least 10 addresses needed", "2001:db8::/125", 10, false},
{"valid IPv4 CIDR", "10.0.0.16/12", 10, true},
{"valid IPv6 CIDR", "2001:db8::/98", 10, true},
{"invalid missing CIDR", "", 0, false, false},
{"invalid CIDR missing decimal points in IPv4 address and / mask", "1234", 0, false, false},
{"invalid CIDR use of letters instead of numbers and / mask", "abc", 0, false, false},
{"invalid IPv4 address provided instead of CIDR representation", "1.2.3.4", 0, false, false},
{"invalid IPv6 address provided instead of CIDR representation", "2001:db8::1", 0, false, false},
{"valid, but IPv4 CIDR too small. At least 10 addresses needed", "10.0.0.16/29", 10, false, false},
{"valid, but IPv6 CIDR too small. At least 10 addresses needed", "2001:db8::/125", 10, false, false},
{"valid IPv4 CIDR", "10.0.0.16/12", 10, false, true},
{"valid IPv6 CIDR", "2001:db8::/98", 10, false, true},
// dual-stack:
{"invalid missing CIDR", "", 0, true, false},
{"invalid only an IPv4 CIDR specified", "10.0.0.16/12", 10, true, false},
{"invalid only an IPv6 CIDR specified", "2001:db8::/98", 10, true, false},
{"invalid IPv4 address provided instead of CIDR representation", "1.2.3.4,2001:db8::/98", 0, true, false},
{"invalid IPv6 address provided instead of CIDR representation", "2001:db8::1,10.0.0.16/12", 0, true, false},
{"valid, but IPv4 CIDR too small. At least 10 addresses needed", "10.0.0.16/29,2001:db8::/98", 10, true, false},
{"valid, but IPv6 CIDR too small. At least 10 addresses needed", "10.0.0.16/12,2001:db8::/125", 10, true, false},
{"valid, but only IPv4 family addresses specified. IPv6 CIDR is necessary.", "10.0.0.16/12,192.168.0.0/16", 10, true, false},
{"valid, but only IPv6 family addresses specified. IPv4 CIDR is necessary.", "2001:db8::/98,2005:db8::/98", 10, true, false},
{"valid IPv4 and IPv6 CIDR", "10.0.0.16/12,2001:db8::/98", 10, true, true},
{"valid IPv6 and IPv4 CIDR", "10.0.0.16/12,2001:db8::/98", 10, true, true},
}
for _, rt := range tests {
actual := ValidateIPNetFromString(rt.subnet, rt.minaddrs, nil)
actual := ValidateIPNetFromString(rt.subnet, rt.minaddrs, rt.checkDualStack, nil)
if (len(actual) == 0) != rt.expected {
t.Errorf(
"%s test case failed :\n\texpected: %t\n\t actual: %t",
"%s test case failed :\n\texpected: %t\n\t actual: %t\n\t err(s): %v\n\t",
rt.name,
rt.expected,
(len(actual) == 0),
actual,
)
}
}

View File

@ -292,6 +292,7 @@ func getControllerManagerCommand(cfg *kubeadmapi.ClusterConfiguration) []string
// Let the controller-manager allocate Node CIDRs for the Pod network.
// Each node will get a subspace of the address CIDR provided with --pod-network-cidr.
if cfg.Networking.PodSubnet != "" {
// TODO(Arvinderpal): Needs to be fixed once PR #73977 lands. Should be a list of maskSizes.
maskSize := calcNodeCidrSize(cfg.Networking.PodSubnet)
defaultArguments["allocate-node-cidrs"] = "true"
defaultArguments["cluster-cidr"] = cfg.Networking.PodSubnet

View File

@ -908,7 +908,11 @@ func RunInitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfigura
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.Etcd, manifestsDir)},
HTTPProxyCheck{Proto: "https", Host: cfg.LocalAPIEndpoint.AdvertiseAddress},
HTTPProxyCIDRCheck{Proto: "https", CIDR: cfg.Networking.ServiceSubnet},
HTTPProxyCIDRCheck{Proto: "https", CIDR: cfg.Networking.PodSubnet},
}
cidrs := strings.Split(cfg.Networking.PodSubnet, ",")
for _, cidr := range cidrs {
checks = append(checks, HTTPProxyCIDRCheck{Proto: "https", CIDR: cidr})
}
if !isSecondaryControlPlane {