diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index 283102f367e..ac3bb84bbfc 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -432,7 +432,11 @@ func ValidatePodSubnetNodeMask(subnetStr string, c *kubeadm.ClusterConfiguration mask := podSubnet.Mask maskSize, _ := mask.Size() // obtain node-cidr-mask - nodeMask := getClusterNodeMask(c, utilnet.IsIPv6(podSubnet.IP)) + nodeMask, err := getClusterNodeMask(c, utilnet.IsIPv6(podSubnet.IP)) + if err != nil { + allErrs = append(allErrs, field.Invalid(fldPath, podSubnet.String(), err.Error())) + continue + } // the pod subnet mask needs to allow one or multiple node-masks // i.e. if it has a /24 the node mask must be between 24 and 32 for ipv4 if maskSize > nodeMask { @@ -447,13 +451,14 @@ func ValidatePodSubnetNodeMask(subnetStr string, c *kubeadm.ClusterConfiguration // getClusterNodeMask returns the corresponding node-cidr-mask // based on the Cluster configuration and the IP family // Default is 24 for IPv4 and 64 for IPv6 -func getClusterNodeMask(c *kubeadm.ClusterConfiguration, isIPv6 bool) int { +func getClusterNodeMask(c *kubeadm.ClusterConfiguration, isIPv6 bool) (int, error) { // defaultNodeMaskCIDRIPv4 is default mask size for IPv4 node cidr for use by the controller manager const defaultNodeMaskCIDRIPv4 = 24 // DefaultNodeMaskCIDRIPv6 is default mask size for IPv6 node cidr for use by the controller manager const defaultNodeMaskCIDRIPv6 = 64 var maskSize int var maskArg string + var err error isDualStack := features.Enabled(c.FeatureGates, features.IPv6DualStack) if isDualStack && isIPv6 { @@ -466,13 +471,17 @@ func getClusterNodeMask(c *kubeadm.ClusterConfiguration, isIPv6 bool) int { if v, ok := c.ControllerManager.ExtraArgs[maskArg]; ok && v != "" { // assume it is an integer, if not it will fail later - maskSize, _ = strconv.Atoi(v) + maskSize, err = strconv.Atoi(v) + if err != nil { + errors.Wrapf(err, "could not parse the value of the kube-controller-manager flag %s as an integer: %v", maskArg, err) + return 0, err + } } else if isIPv6 { maskSize = defaultNodeMaskCIDRIPv6 } else { maskSize = defaultNodeMaskCIDRIPv4 } - return maskSize + return maskSize, nil } // ValidateNetworking validates networking configuration diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go index c74c60cfbbf..6b34cc902d2 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go @@ -1130,10 +1130,11 @@ func TestValidateEtcd(t *testing.T) { func TestGetClusterNodeMask(t *testing.T) { tests := []struct { - name string - cfg *kubeadmapi.ClusterConfiguration - isIPv6 bool - expectedMask int + name string + cfg *kubeadmapi.ClusterConfiguration + isIPv6 bool + expectedMask int + expectedError bool }{ { name: "ipv4 default mask", @@ -1151,6 +1152,16 @@ func TestGetClusterNodeMask(t *testing.T) { isIPv6: false, expectedMask: 23, }, + { + name: "ipv4 wrong mask", + cfg: &kubeadmapi.ClusterConfiguration{ + ControllerManager: kubeadmapi.ControlPlaneComponent{ + ExtraArgs: map[string]string{"node-cidr-mask-size": "aa23"}, + }, + }, + isIPv6: false, + expectedError: true, + }, { name: "ipv6 default mask", cfg: &kubeadmapi.ClusterConfiguration{}, @@ -1216,6 +1227,17 @@ func TestGetClusterNodeMask(t *testing.T) { isIPv6: false, expectedMask: 23, }, + { + name: "dual ipv4 wrong mask", + cfg: &kubeadmapi.ClusterConfiguration{ + FeatureGates: map[string]bool{features.IPv6DualStack: true}, + ControllerManager: kubeadmapi.ControlPlaneComponent{ + ExtraArgs: map[string]string{"node-cidr-mask-size-ipv4": "aa"}, + }, + }, + isIPv6: false, + expectedError: true, + }, { name: "dual ipv6 default mask and legacy flag", cfg: &kubeadmapi.ClusterConfiguration{ @@ -1238,10 +1260,25 @@ func TestGetClusterNodeMask(t *testing.T) { isIPv6: true, expectedMask: 83, }, + { + name: "dual ipv6 custom mask and wrong flag", + cfg: &kubeadmapi.ClusterConfiguration{ + FeatureGates: map[string]bool{features.IPv6DualStack: true}, + ControllerManager: kubeadmapi.ControlPlaneComponent{ + ExtraArgs: map[string]string{"node-cidr-mask-size": "23", "node-cidr-mask-size-ipv6": "a83"}, + }, + }, + isIPv6: true, + expectedError: true, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - if mask := getClusterNodeMask(test.cfg, test.isIPv6); mask != test.expectedMask { + mask, err := getClusterNodeMask(test.cfg, test.isIPv6) + if (err == nil) == test.expectedError { + t.Errorf("expected error: %v, got %v", test.expectedError, err) + } + if mask != test.expectedMask { t.Errorf("expected mask: %d, got %d", test.expectedMask, mask) } })