Skip to content

Commit e8ee862

Browse files
committed
Add support for new dual-stack flags for kubernetes-controller-
manager in kubeadm: - node-cidr-mask-size-ipv4 - node-cidr-mask-size-ipv6
1 parent 459b1d7 commit e8ee862

File tree

3 files changed

+109
-8
lines changed

3 files changed

+109
-8
lines changed

cmd/kubeadm/app/phases/controlplane/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ go_test(
1919
"//cmd/kubeadm/app/phases/certs:go_default_library",
2020
"//cmd/kubeadm/app/util/staticpod:go_default_library",
2121
"//cmd/kubeadm/test:go_default_library",
22+
"//pkg/features:go_default_library",
2223
"//staging/src/k8s.io/api/core/v1:go_default_library",
2324
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
2425
"//vendor/github.com/lithammer/dedent:go_default_library",

cmd/kubeadm/app/phases/controlplane/manifests.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,13 @@ func isValidAuthzMode(authzMode string) bool {
260260
// the available bits to maximize the number used for nodes, but still have the node
261261
// CIDR be a multiple of eight.
262262
//
263-
func calcNodeCidrSize(podSubnet string) string {
263+
func calcNodeCidrSize(podSubnet string) (string, bool) {
264264
maskSize := "24"
265+
isIPv6 := false
265266
if ip, podCidr, err := net.ParseCIDR(podSubnet); err == nil {
266267
if utilsnet.IsIPv6(ip) {
267268
var nodeCidrSize int
269+
isIPv6 = true
268270
podNetSize, totalBits := podCidr.Mask.Size()
269271
switch {
270272
case podNetSize == 112:
@@ -280,7 +282,7 @@ func calcNodeCidrSize(podSubnet string) string {
280282
maskSize = strconv.Itoa(nodeCidrSize)
281283
}
282284
}
283-
return maskSize
285+
return maskSize, isIPv6
284286
}
285287

286288
// getControllerManagerCommand builds the right controller manager command from the given config object and version
@@ -324,12 +326,25 @@ func getControllerManagerCommand(cfg *kubeadmapi.ClusterConfiguration) []string
324326

325327
// TODO: The following code should be remvoved after dual-stack is GA.
326328
// Note: The user still retains the ability to explicitly set feature-gates and that value will overwrite this base value.
327-
if enabled, present := cfg.FeatureGates[features.IPv6DualStack]; present {
329+
enabled, present := cfg.FeatureGates[features.IPv6DualStack]
330+
if present {
328331
defaultArguments["feature-gates"] = fmt.Sprintf("%s=%t", features.IPv6DualStack, enabled)
329-
} else if cfg.Networking.PodSubnet != "" {
330-
// TODO(Arvinderpal): Needs to be fixed once PR #73977 lands. Should be a list of maskSizes.
331-
maskSize := calcNodeCidrSize(cfg.Networking.PodSubnet)
332-
defaultArguments["node-cidr-mask-size"] = maskSize
332+
}
333+
if cfg.Networking.PodSubnet != "" {
334+
if enabled {
335+
// any errors will be caught during validation
336+
subnets := strings.Split(cfg.Networking.PodSubnet, ",")
337+
for _, podSubnet := range subnets {
338+
if maskSize, isIPv6 := calcNodeCidrSize(podSubnet); isIPv6 {
339+
defaultArguments["node-cidr-mask-size-ipv6"] = maskSize
340+
} else {
341+
defaultArguments["node-cidr-mask-size-ipv4"] = maskSize
342+
}
343+
}
344+
} else {
345+
maskSize, _ := calcNodeCidrSize(cfg.Networking.PodSubnet)
346+
defaultArguments["node-cidr-mask-size"] = maskSize
347+
}
333348
}
334349

335350
command := []string{"kube-controller-manager"}

cmd/kubeadm/app/phases/controlplane/manifests_test.go

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
3535
staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod"
3636
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
37+
"k8s.io/kubernetes/pkg/features"
3738
)
3839

3940
const (
@@ -719,6 +720,73 @@ func TestGetControllerManagerCommand(t *testing.T) {
719720
"--service-cluster-ip-range=fd03::/112",
720721
},
721722
},
723+
{
724+
name: "dual-stack networking for " + cpVersion,
725+
cfg: &kubeadmapi.ClusterConfiguration{
726+
Networking: kubeadmapi.Networking{
727+
PodSubnet: "2001:db8::/64,10.1.0.0/16",
728+
ServiceSubnet: "fd03::/112,192.168.0.0/16",
729+
},
730+
CertificatesDir: testCertsDir,
731+
KubernetesVersion: cpVersion,
732+
FeatureGates: map[string]bool{string(features.IPv6DualStack): true},
733+
},
734+
expected: []string{
735+
"kube-controller-manager",
736+
"--bind-address=127.0.0.1",
737+
"--leader-elect=true",
738+
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
739+
"--root-ca-file=" + testCertsDir + "/ca.crt",
740+
"--service-account-private-key-file=" + testCertsDir + "/sa.key",
741+
"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
742+
"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
743+
"--use-service-account-credentials=true",
744+
"--controllers=*,bootstrapsigner,tokencleaner",
745+
"--authentication-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
746+
"--authorization-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
747+
"--client-ca-file=" + testCertsDir + "/ca.crt",
748+
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
749+
"--feature-gates=IPv6DualStack=true",
750+
"--allocate-node-cidrs=true",
751+
"--cluster-cidr=2001:db8::/64,10.1.0.0/16",
752+
"--node-cidr-mask-size-ipv4=24",
753+
"--node-cidr-mask-size-ipv6=80",
754+
"--service-cluster-ip-range=fd03::/112,192.168.0.0/16",
755+
},
756+
},
757+
{
758+
name: "dual-stack networking custom extra-args for " + cpVersion,
759+
cfg: &kubeadmapi.ClusterConfiguration{
760+
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16,2001:db8::/64"},
761+
ControllerManager: kubeadmapi.ControlPlaneComponent{
762+
ExtraArgs: map[string]string{"node-cidr-mask-size-ipv4": "20", "node-cidr-mask-size-ipv6": "96"},
763+
},
764+
CertificatesDir: testCertsDir,
765+
KubernetesVersion: cpVersion,
766+
FeatureGates: map[string]bool{string(features.IPv6DualStack): true},
767+
},
768+
expected: []string{
769+
"kube-controller-manager",
770+
"--bind-address=127.0.0.1",
771+
"--leader-elect=true",
772+
"--kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
773+
"--root-ca-file=" + testCertsDir + "/ca.crt",
774+
"--service-account-private-key-file=" + testCertsDir + "/sa.key",
775+
"--cluster-signing-cert-file=" + testCertsDir + "/ca.crt",
776+
"--cluster-signing-key-file=" + testCertsDir + "/ca.key",
777+
"--use-service-account-credentials=true",
778+
"--controllers=*,bootstrapsigner,tokencleaner",
779+
"--authentication-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
780+
"--authorization-kubeconfig=" + kubeadmconstants.KubernetesDir + "/controller-manager.conf",
781+
"--client-ca-file=" + testCertsDir + "/ca.crt",
782+
"--requestheader-client-ca-file=" + testCertsDir + "/front-proxy-ca.crt",
783+
"--feature-gates=IPv6DualStack=true",
784+
"--allocate-node-cidrs=true",
785+
"--cluster-cidr=10.0.1.15/16,2001:db8::/64",
786+
"--node-cidr-mask-size-ipv4=20",
787+
"--node-cidr-mask-size-ipv6=96",
788+
},
789+
},
722790
}
723791

724792
for _, rt := range tests {
@@ -738,75 +806,92 @@ func TestCalcNodeCidrSize(t *testing.T) {
738806
name string
739807
podSubnet string
740808
expectedPrefix string
809+
expectedIPv6 bool
741810
}{
742811
{
743812
name: "Malformed pod subnet",
744813
podSubnet: "10.10.10/160",
745814
expectedPrefix: "24",
815+
expectedIPv6: false,
746816
},
747817
{
748818
name: "V4: Always uses 24",
749819
podSubnet: "10.10.10.10/16",
750820
expectedPrefix: "24",
821+
expectedIPv6: false,
751822
},
752823
{
753824
name: "V6: Use pod subnet size, when not enough space",
754825
podSubnet: "2001:db8::/128",
755826
expectedPrefix: "128",
827+
expectedIPv6: true,
756828
},
757829
{
758830
name: "V6: Use pod subnet size, when not enough space",
759831
podSubnet: "2001:db8::/113",
760832
expectedPrefix: "113",
833+
expectedIPv6: true,
761834
},
762835
{
763836
name: "V6: Special case with 256 nodes",
764837
podSubnet: "2001:db8::/112",
765838
expectedPrefix: "120",
839+
expectedIPv6: true,
766840
},
767841
{
768842
name: "V6: Using /120 for node CIDR",
769843
podSubnet: "2001:db8::/104",
770844
expectedPrefix: "120",
845+
expectedIPv6: true,
771846
},
772847
{
773848
name: "V6: Using /112 for node CIDR",
774849
podSubnet: "2001:db8::/103",
775850
expectedPrefix: "112",
851+
expectedIPv6: true,
776852
},
777853
{
778854
name: "V6: Using /112 for node CIDR",
779855
podSubnet: "2001:db8::/96",
780856
expectedPrefix: "112",
857+
expectedIPv6: true,
781858
},
782859
{
783860
name: "V6: Using /104 for node CIDR",
784861
podSubnet: "2001:db8::/95",
785862
expectedPrefix: "104",
863+
expectedIPv6: true,
786864
},
787865
{
788866
name: "V6: For /64 pod net, use /80",
789867
podSubnet: "2001:db8::/64",
790868
expectedPrefix: "80",
869+
expectedIPv6: true,
791870
},
792871
{
793872
name: "V6: For /48 pod net, use /64",
794873
podSubnet: "2001:db8::/48",
795874
expectedPrefix: "64",
875+
expectedIPv6: true,
796876
},
797877
{
798878
name: "V6: For /32 pod net, use /48",
799879
podSubnet: "2001:db8::/32",
800880
expectedPrefix: "48",
881+
expectedIPv6: true,
801882
},
802883
}
803884
for _, test := range tests {
804885
t.Run(test.name, func(t *testing.T) {
805-
actualPrefix := calcNodeCidrSize(test.podSubnet)
886+
actualPrefix, actualIPv6 := calcNodeCidrSize(test.podSubnet)
806887
if actualPrefix != test.expectedPrefix {
807888
t.Errorf("Case [%s]\nCalc of node CIDR size for pod subnet %q failed: Expected %q, saw %q",
808889
test.name, test.podSubnet, test.expectedPrefix, actualPrefix)
809890
}
891+
if actualIPv6 != test.expectedIPv6 {
892+
t.Errorf("Case [%s]\nCalc of node CIDR size for pod subnet %q failed: Expected isIPv6=%v, saw isIPv6=%v",
893+
test.name, test.podSubnet, test.expectedIPv6, actualIPv6)
894+
}
810895
})
811896
}
812897

0 commit comments

Comments
 (0)