From 5038b8e4cbeabcfe0eeca8604c472aec312f6a82 Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Larsen Date: Fri, 4 Oct 2024 10:09:38 +0200 Subject: [PATCH] Support dynamic IPv4 EKS service CIDR Signed-off-by: Mikkel Oscar Lyderik Larsen --- provisioner/aws.go | 15 +++++++++++---- provisioner/clusterpy.go | 4 ++-- provisioner/provisioner.go | 6 +++--- provisioner/template.go | 27 +++++++++++++++++++-------- provisioner/template_test.go | 18 +++++++++++++++--- provisioner/zalando_eks.go | 2 +- 6 files changed, 51 insertions(+), 21 deletions(-) diff --git a/provisioner/aws.go b/provisioner/aws.go index b130c1cd..2487a083 100644 --- a/provisioner/aws.go +++ b/provisioner/aws.go @@ -761,7 +761,7 @@ type EKSClusterDetails struct { Endpoint string CertificateAuthority string OIDCIssuerURL string - ServiceIPv6CIDR string + ServiceCIDR string } func (a *awsAdapter) GetEKSClusterDetails(cluster *api.Cluster) (*EKSClusterDetails, error) { @@ -772,10 +772,17 @@ func (a *awsAdapter) GetEKSClusterDetails(cluster *api.Cluster) (*EKSClusterDeta return nil, err } - return &EKSClusterDetails{ + clusterDetails := &EKSClusterDetails{ Endpoint: aws.StringValue(resp.Cluster.Endpoint), CertificateAuthority: aws.StringValue(resp.Cluster.CertificateAuthority.Data), OIDCIssuerURL: aws.StringValue(resp.Cluster.Identity.Oidc.Issuer), - ServiceIPv6CIDR: aws.StringValue(resp.Cluster.KubernetesNetworkConfig.ServiceIpv6Cidr), - }, nil + } + + if aws.StringValue(resp.Cluster.KubernetesNetworkConfig.IpFamily) == "ipv4" { + clusterDetails.ServiceCIDR = aws.StringValue(resp.Cluster.KubernetesNetworkConfig.ServiceIpv4Cidr) + } else { + clusterDetails.ServiceCIDR = aws.StringValue(resp.Cluster.KubernetesNetworkConfig.ServiceIpv6Cidr) + } + + return clusterDetails, nil } diff --git a/provisioner/clusterpy.go b/provisioner/clusterpy.go index 2c056857..74422a92 100644 --- a/provisioner/clusterpy.go +++ b/provisioner/clusterpy.go @@ -316,8 +316,8 @@ func (p *clusterpyProvisioner) provision( if postOptions.APIServerURL != "" { cluster.APIServerURL = postOptions.APIServerURL } - if postOptions.ServiceIPv6CIDR != "" { - cluster.ConfigItems["service_ipv6_cidr"] = postOptions.ServiceIPv6CIDR + if postOptions.ServiceCIDR != "" { + cluster.ConfigItems["service_cidr"] = postOptions.ServiceCIDR } } diff --git a/provisioner/provisioner.go b/provisioner/provisioner.go index 692bd01b..3a4cb45b 100644 --- a/provisioner/provisioner.go +++ b/provisioner/provisioner.go @@ -55,9 +55,9 @@ type ( // HookResponse contain configuration parameters that a provisioner can use // at a later stage. HookResponse struct { - APIServerURL string - CAData []byte - ServiceIPv6CIDR string + APIServerURL string + CAData []byte + ServiceCIDR string } // Options is the options that can be passed to a provisioner when initialized. diff --git a/provisioner/template.go b/provisioner/template.go index b499e10e..b737dc6e 100644 --- a/provisioner/template.go +++ b/provisioner/template.go @@ -116,7 +116,7 @@ func renderTemplate(context *templateContext, file string) (string, error) { }, "nodeCIDRMaxNodesPodCIDR": nodeCIDRMaxNodes, "nodeCIDRMaxPods": nodeCIDRMaxPods, - "addressNFromIPv6CIDR": addressNFromIPv6CIDR, + "nthAddressFromCIDR": nthAddressFromCIDR, "parseInt64": parseInt64, "generateJWKSDocument": generateJWKSDocument, "generateOIDCDiscoveryDocument": generateOIDCDiscoveryDocument, @@ -582,22 +582,33 @@ func nodeCIDRMaxPods(maskSize int64, extraCapacity int64) (int64, error) { return maxPods, nil } -// addressNFromIPv6CIDR takes an IPv6 CIDR and returns the Nth address in the -// subnet. -func addressNFromIPv6CIDR(cidr string, n int) (string, error) { +// nthAddressFromCIDR takes an IPv4 or IPv6 CIDR and returns the Nth address in +// the subnet. +func nthAddressFromCIDR(cidr string, n int) (string, error) { _, ipNet, err := net.ParseCIDR(cidr) if err != nil { return "", err } ip := ipNet.IP - ip = ip.To16() - if ip == nil { - return "", fmt.Errorf("invalid IP address: %s", ipNet.IP) + + nthByte := 0 + if ip.To4() != nil { + // ipv4 address + nthByte = 3 + ip = ip.To4() + } else { + // ipv6 address + ip = ip.To16() + if ip == nil { + return "", fmt.Errorf("invalid IP address: %s", ipNet.IP) + } + nthByte = 15 } + ip = ip.Mask(ipNet.Mask) for i := 0; i < n; i++ { - ip[15]++ + ip[nthByte]++ } return ip.String(), nil } diff --git a/provisioner/template_test.go b/provisioner/template_test.go index 4c4fe350..6cc1d007 100644 --- a/provisioner/template_test.go +++ b/provisioner/template_test.go @@ -1486,7 +1486,7 @@ func TestScalingTemplate(t *testing.T) { } } -func TestAddressNFromIPv6CIDR(t *testing.T) { +func TestNthAddressFromCIDR(t *testing.T) { for _, tc := range []struct { name string cidr string @@ -1494,16 +1494,28 @@ func TestAddressNFromIPv6CIDR(t *testing.T) { expected string err bool }{ + { + name: "50th address of IPv4 CIDR", + cidr: "172.20.0.0/16", + input: `{{ nthAddressFromCIDR .Values.data.cidr 50 }}`, + expected: "172.20.0.50", + }, + { + name: "invalid CIDR causes error", + cidr: "172.20.0.0/100", // invalid CIDR + input: `{{ nthAddressFromCIDR .Values.data.cidr 50 }}`, + err: true, + }, { name: "50th address of IPv6 CIDR", cidr: "2a05:d014:9c0:bf05::/64", - input: `{{ addressNFromIPv6CIDR .Values.data.cidr 50 }}`, + input: `{{ nthAddressFromCIDR .Values.data.cidr 50 }}`, expected: "2a05:d014:9c0:bf05::32", }, { name: "invalid CIDR causes error", cidr: "2a05:d014:9c0:bf05::/2000", // invalid CIDR - input: `{{ addressNFromIPv6CIDR .Values.data.cidr 50 }}`, + input: `{{ nthAddressFromCIDR .Values.data.cidr 50 }}`, err: true, }, } { diff --git a/provisioner/zalando_eks.go b/provisioner/zalando_eks.go index 3245f472..4c00ca39 100644 --- a/provisioner/zalando_eks.go +++ b/provisioner/zalando_eks.go @@ -200,7 +200,7 @@ func (z *ZalandoEKSCreationHook) Execute( res.APIServerURL = clusterDetails.Endpoint res.CAData = decodedCA - res.ServiceIPv6CIDR = clusterDetails.ServiceIPv6CIDR + res.ServiceCIDR = clusterDetails.ServiceCIDR return res, nil }