From a3c83447be7ffdc7605e4504dc15873239e9ee4f Mon Sep 17 00:00:00 2001 From: Carmine Esposito Date: Thu, 27 Nov 2025 06:46:44 +1100 Subject: [PATCH 1/6] Add support for EKS Provisioned Control Plane This change adds support for the EKS Provisioned Control Plane feature, which allows users to select from a set of scaling tiers (standard, tier-xl, tier-2xl, tier-4xl) for predictable, high performance from the cluster's control plane. Changes: - Add ControlPlaneScalingConfig field to AWSManagedControlPlane API - Add ControlPlaneScalingTier enum type with validation - Implement converters between CAPA and AWS SDK types - Update cluster creation to include scaling configuration - Add reconciliation logic for updating scaling configuration - Update v1beta1 conversion functions for backward compatibility - Upgrade AWS SDK for EKS to v1.75.1 to support the new API --- ...ster.x-k8s.io_awsmanagedcontrolplanes.yaml | 17 +++++++++++ ...8s.io_awsmanagedcontrolplanetemplates.yaml | 17 +++++++++++ controlplane/eks/api/v1beta1/conversion.go | 1 + .../api/v1beta1/zz_generated.conversion.go | 1 + .../v1beta2/awsmanagedcontrolplane_types.go | 6 ++++ controlplane/eks/api/v1beta2/types.go | 26 +++++++++++++++++ .../eks/api/v1beta2/zz_generated.deepcopy.go | 25 +++++++++++++++++ go.mod | 10 +++---- go.sum | 20 ++++++------- pkg/cloud/converters/eks.go | 23 +++++++++++++++ pkg/cloud/endpoints/partitions.go | 7 +++++ pkg/cloud/services/eks/cluster.go | 28 +++++++++++++++++++ 12 files changed, 166 insertions(+), 15 deletions(-) diff --git a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml index 662022c257..6a21423c74 100644 --- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml @@ -2411,6 +2411,23 @@ spec: - host - port type: object + controlPlaneScalingConfig: + description: |- + ControlPlaneScalingConfig specifies the scaling configuration for the EKS control plane. + This allows you to select from a set of scaling tiers for predictable, high performance from the cluster's control plane. + (Official AWS docs: https://docs.aws.amazon.com/eks/latest/userguide/eks-provisioned-control-plane.html) + properties: + tier: + description: |- + Tier specifies the tier for the EKS control plane. + Valid values are: standard, tier-xl, tier-2xl, tier-4xl + enum: + - standard + - tier-xl + - tier-2xl + - tier-4xl + type: string + type: object eksClusterName: description: |- EKSClusterName allows you to specify the name of the EKS cluster in diff --git a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml index e0a9b811ce..4caed3c98e 100644 --- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml @@ -187,6 +187,23 @@ spec: - host - port type: object + controlPlaneScalingConfig: + description: |- + ControlPlaneScalingConfig specifies the scaling configuration for the EKS control plane. + This allows you to select from a set of scaling tiers for predictable, high performance from the cluster's control plane. + (Official AWS docs: https://docs.aws.amazon.com/eks/latest/userguide/eks-provisioned-control-plane.html) + properties: + tier: + description: |- + Tier specifies the tier for the EKS control plane. + Valid values are: standard, tier-xl, tier-2xl, tier-4xl + enum: + - standard + - tier-xl + - tier-2xl + - tier-4xl + type: string + type: object eksClusterName: description: |- EKSClusterName allows you to specify the name of the EKS cluster in diff --git a/controlplane/eks/api/v1beta1/conversion.go b/controlplane/eks/api/v1beta1/conversion.go index c8663e27ec..7244d5a9dd 100644 --- a/controlplane/eks/api/v1beta1/conversion.go +++ b/controlplane/eks/api/v1beta1/conversion.go @@ -121,6 +121,7 @@ func (r *AWSManagedControlPlane) ConvertTo(dstRaw conversion.Hub) error { dst.Status.Version = restored.Status.Version dst.Spec.BootstrapSelfManagedAddons = restored.Spec.BootstrapSelfManagedAddons dst.Spec.UpgradePolicy = restored.Spec.UpgradePolicy + dst.Spec.ControlPlaneScalingConfig = restored.Spec.ControlPlaneScalingConfig return nil } diff --git a/controlplane/eks/api/v1beta1/zz_generated.conversion.go b/controlplane/eks/api/v1beta1/zz_generated.conversion.go index 6e71a2c7ee..493ca54c19 100644 --- a/controlplane/eks/api/v1beta1/zz_generated.conversion.go +++ b/controlplane/eks/api/v1beta1/zz_generated.conversion.go @@ -381,6 +381,7 @@ func autoConvert_v1beta2_AWSManagedControlPlaneSpec_To_v1beta1_AWSManagedControl return err } // WARNING: in.UpgradePolicy requires manual conversion: does not exist in peer-type + // WARNING: in.ControlPlaneScalingConfig requires manual conversion: does not exist in peer-type return nil } diff --git a/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go b/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go index a904069de9..0aae4bc80d 100644 --- a/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go +++ b/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go @@ -221,6 +221,12 @@ type AWSManagedControlPlaneSpec struct { //nolint: maligned // +kubebuilder:validation:Enum=extended;standard // +optional UpgradePolicy UpgradePolicy `json:"upgradePolicy,omitempty"` + + // ControlPlaneScalingConfig specifies the scaling configuration for the EKS control plane. + // This allows you to select from a set of scaling tiers for predictable, high performance from the cluster's control plane. + // (Official AWS docs: https://docs.aws.amazon.com/eks/latest/userguide/eks-provisioned-control-plane.html) + // +optional + ControlPlaneScalingConfig *ControlPlaneScalingConfig `json:"controlPlaneScalingConfig,omitempty"` } // KubeProxy specifies how the kube-proxy daemonset is managed. diff --git a/controlplane/eks/api/v1beta2/types.go b/controlplane/eks/api/v1beta2/types.go index 60cd4b454d..e0e42c5637 100644 --- a/controlplane/eks/api/v1beta2/types.go +++ b/controlplane/eks/api/v1beta2/types.go @@ -259,6 +259,32 @@ func (e UpgradePolicy) String() string { return string(e) } +// ControlPlaneScalingConfig represents the configuration for EKS Control Plane scaling. +type ControlPlaneScalingConfig struct { + // Tier specifies the tier for the EKS control plane. + // Valid values are: standard, tier-xl, tier-2xl, tier-4xl + // +optional + // +kubebuilder:validation:Enum=standard;tier-xl;tier-2xl;tier-4xl + Tier *ControlPlaneScalingTier `json:"tier,omitempty"` +} + +// ControlPlaneScalingTier defines the scaling tier for the EKS control plane. +type ControlPlaneScalingTier string + +var ( + // ControlPlaneScalingTierStandard indicates standard scaling tier (default). + ControlPlaneScalingTierStandard = ControlPlaneScalingTier("standard") + + // ControlPlaneScalingTierXL indicates XL tier. + ControlPlaneScalingTierXL = ControlPlaneScalingTier("tier-xl") + + // ControlPlaneScalingTier2XL indicates 2XL tier. + ControlPlaneScalingTier2XL = ControlPlaneScalingTier("tier-2xl") + + // ControlPlaneScalingTier4XL indicates 4XL tier. + ControlPlaneScalingTier4XL = ControlPlaneScalingTier("tier-4xl") +) + const ( // SecurityGroupCluster is the security group for communication between EKS // control plane and managed node groups. diff --git a/controlplane/eks/api/v1beta2/zz_generated.deepcopy.go b/controlplane/eks/api/v1beta2/zz_generated.deepcopy.go index 0e1b766d8b..d7ba4c6637 100644 --- a/controlplane/eks/api/v1beta2/zz_generated.deepcopy.go +++ b/controlplane/eks/api/v1beta2/zz_generated.deepcopy.go @@ -177,6 +177,11 @@ func (in *AWSManagedControlPlaneSpec) DeepCopyInto(out *AWSManagedControlPlaneSp } in.VpcCni.DeepCopyInto(&out.VpcCni) out.KubeProxy = in.KubeProxy + if in.ControlPlaneScalingConfig != nil { + in, out := &in.ControlPlaneScalingConfig, &out.ControlPlaneScalingConfig + *out = new(ControlPlaneScalingConfig) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSManagedControlPlaneSpec. @@ -462,6 +467,26 @@ func (in *ControlPlaneLoggingSpec) DeepCopy() *ControlPlaneLoggingSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneScalingConfig) DeepCopyInto(out *ControlPlaneScalingConfig) { + *out = *in + if in.Tier != nil { + in, out := &in.Tier, &out.Tier + *out = new(ControlPlaneScalingTier) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneScalingConfig. +func (in *ControlPlaneScalingConfig) DeepCopy() *ControlPlaneScalingConfig { + if in == nil { + return nil + } + out := new(ControlPlaneScalingConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EncryptionConfig) DeepCopyInto(out *EncryptionConfig) { *out = *in diff --git a/go.mod b/go.mod index ad5ab78087..90ae29c6c8 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/apparentlymart/go-cidr v1.1.0 github.com/aws/amazon-vpc-cni-k8s v1.15.5 github.com/aws/aws-lambda-go v1.41.0 - github.com/aws/aws-sdk-go-v2 v1.39.2 + github.com/aws/aws-sdk-go-v2 v1.40.0 github.com/aws/aws-sdk-go-v2/config v1.31.12 github.com/aws/aws-sdk-go-v2/credentials v1.18.16 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.12 @@ -20,7 +20,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ec2 v1.233.0 github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.36.0 github.com/aws/aws-sdk-go-v2/service/efs v1.39.0 - github.com/aws/aws-sdk-go-v2/service/eks v1.64.0 + github.com/aws/aws-sdk-go-v2/service/eks v1.75.1 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.29.6 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.45.2 github.com/aws/aws-sdk-go-v2/service/iam v1.32.0 @@ -29,7 +29,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6 github.com/aws/aws-sdk-go-v2/service/ssm v1.59.1 github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 - github.com/aws/smithy-go v1.23.0 + github.com/aws/smithy-go v1.23.2 github.com/awslabs/goformation/v4 v4.19.5 github.com/blang/semver v3.5.1+incompatible github.com/coreos/ignition v0.35.0 @@ -115,8 +115,8 @@ require ( github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9 // indirect github.com/aws/aws-sdk-go-v2/service/cloudformation v1.50.0 diff --git a/go.sum b/go.sum index 65adb705a5..df30291775 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,8 @@ github.com/aws/amazon-vpc-cni-k8s v1.15.5 h1:/mqTXB4HoGYg4CiU4Gco9iEvZ+V/309Na4H github.com/aws/amazon-vpc-cni-k8s v1.15.5/go.mod h1:jV4wNtmgT2Ra1/oZU99DPOFsCUKnf0mYfIyzDyAUVAY= github.com/aws/aws-lambda-go v1.41.0 h1:l/5fyVb6Ud9uYd411xdHZzSf2n86TakxzpvIoz7l+3Y= github.com/aws/aws-lambda-go v1.41.0/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM= -github.com/aws/aws-sdk-go-v2 v1.39.2 h1:EJLg8IdbzgeD7xgvZ+I8M1e0fL0ptn/M47lianzth0I= -github.com/aws/aws-sdk-go-v2 v1.39.2/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= +github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc= +github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 h1:i8p8P4diljCr60PpJp6qZXNlgX4m2yQFpYk+9ZT+J4E= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1/go.mod h1:ddqbooRZYNoJ2dsTwOty16rM+/Aqmk/GOXrK8cg7V00= github.com/aws/aws-sdk-go-v2/config v1.31.12 h1:pYM1Qgy0dKZLHX2cXslNacbcEFMkDMl+Bcj5ROuS6p8= @@ -60,10 +60,10 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 h1:Mv4Bc0mWmv6oDuSWTKnk+wg github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9/go.mod h1:IKlKfRppK2a1y0gy1yH6zD+yX5uplJ6UuPlgd48dJiQ= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.12 h1:ofHawDLJTI6ytDIji+g4dXQ6u2idzTb04tDlN9AS614= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.19.12/go.mod h1:f5pL4iLDfbcxj1SZcdRdIokBB5eHbuYPS/Fs9DwUPRQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 h1:se2vOWGD3dWQUtfn4wEjRQJb1HK1XsNIt825gskZ970= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9/go.mod h1:hijCGH2VfbZQxqCDN7bwz/4dzxV+hkyhjawAtdPWKZA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 h1:6RBnKZLkJM4hQ+kN6E7yWFveOTg8NLPHAkqrs4ZPlTU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9/go.mod h1:V9rQKRmK7AWuEsOMnHzKj8WyrIir1yUJbZxDuZLFvXI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9 h1:w9LnHqTq8MEdlnyhV4Bwfizd65lfNCNgdlNC6mM5paE= @@ -82,8 +82,8 @@ github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.36.0 h1:8GcatvIKYx5WkwjwY4H+K7 github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.36.0/go.mod h1:yz4NeCWotlbHoT41Vc9NofCbKEyiNlKYZFT4SiqVQCY= github.com/aws/aws-sdk-go-v2/service/efs v1.39.0 h1:nxn7P1nAd7ThB1B0WASAKvjddJQcvLzaOo9iN4tp3ZU= github.com/aws/aws-sdk-go-v2/service/efs v1.39.0/go.mod h1:8Ij4/TIExqfWWjcyQy82/V/aec2kQruuyndljE+Vuo0= -github.com/aws/aws-sdk-go-v2/service/eks v1.64.0 h1:EYeOThTRysemFtC6J6h6b7dNg3jN03QuO5cg92ojIQE= -github.com/aws/aws-sdk-go-v2/service/eks v1.64.0/go.mod h1:v1xXy6ea0PHtWkjFUvAUh6B/5wv7UF909Nru0dOIJDk= +github.com/aws/aws-sdk-go-v2/service/eks v1.75.1 h1:WFcSYWHNNdnRnN8H2jyokrn3Yz5T1DMg+D3CWog4luk= +github.com/aws/aws-sdk-go-v2/service/eks v1.75.1/go.mod h1:lrJRZkSj6nIXH/SN3gbGQp4i4AtNyha0wT7VgYZ3KDw= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.29.6 h1:9grU/+HRwLXJV8XUjEPThJj/H+0oHkeNBFpSSfZekeg= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.29.6/go.mod h1:N4fs285CsnBHlAkzBpQapefR/noggTyF09fWs72EzB4= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.45.2 h1:vX70Z4lNSr7XsioU0uJq5yvxgI50sB66MvD+V/3buS4= @@ -120,8 +120,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1 h1:5fm5RTONng73/QA73LhCNR7U github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1/go.mod h1:xBEjWD13h+6nq+z4AkqSfSvqRKFgDIQeaMguAJndOWo= github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 h1:p3jIvqYwUZgu/XYeI48bJxOhvm47hZb5HUQ0tn6Q9kA= github.com/aws/aws-sdk-go-v2/service/sts v1.38.6/go.mod h1:WtKK+ppze5yKPkZ0XwqIVWD4beCwv056ZbPQNoeHqM8= -github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE= -github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= +github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/awslabs/goformation/v4 v4.19.5 h1:Y+Tzh01tWg8gf//AgGKUamaja7Wx9NPiJf1FpZu4/iU= github.com/awslabs/goformation/v4 v4.19.5/go.mod h1:JoNpnVCBOUtEz9bFxc9sjy8uBUCLF5c4D1L7RhRTVM8= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= diff --git a/pkg/cloud/converters/eks.go b/pkg/cloud/converters/eks.go index 243b6d9cbd..7ccce7af8b 100644 --- a/pkg/cloud/converters/eks.go +++ b/pkg/cloud/converters/eks.go @@ -300,3 +300,26 @@ func SupportTypeToSDK(input ekscontrolplanev1.UpgradePolicy) ekstypes.SupportTyp } return ekstypes.SupportTypeExtended } + +// ControlPlaneScalingConfigToSDK converts CAPA ControlPlaneScalingConfig to AWS SDK ControlPlaneScalingConfig. +func ControlPlaneScalingConfigToSDK(config *ekscontrolplanev1.ControlPlaneScalingConfig) *ekstypes.ControlPlaneScalingConfig { + if config == nil || config.Tier == nil { + return nil + } + + return &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier(*config.Tier), + } +} + +// ControlPlaneScalingConfigFromSDK converts AWS SDK ControlPlaneScalingConfig to CAPA ControlPlaneScalingConfig. +func ControlPlaneScalingConfigFromSDK(config *ekstypes.ControlPlaneScalingConfig) *ekscontrolplanev1.ControlPlaneScalingConfig { + if config == nil { + return nil + } + + tier := ekscontrolplanev1.ControlPlaneScalingTier(config.Tier) + return &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: &tier, + } +} diff --git a/pkg/cloud/endpoints/partitions.go b/pkg/cloud/endpoints/partitions.go index 66c42917c3..346efcd1b5 100644 --- a/pkg/cloud/endpoints/partitions.go +++ b/pkg/cloud/endpoints/partitions.go @@ -402,6 +402,13 @@ var partitions = []Partition { SupportsFIPS: nil, SupportsDualStack: nil, }, + "us-isob-west-1": RegionOverrides{ + Name: nil, + DnsSuffix: nil, + DualStackDnsSuffix: nil, + SupportsFIPS: nil, + SupportsDualStack: nil, + }, }, }, Partition { diff --git a/pkg/cloud/services/eks/cluster.go b/pkg/cloud/services/eks/cluster.go index 403051510d..22c2dc42b4 100644 --- a/pkg/cloud/services/eks/cluster.go +++ b/pkg/cloud/services/eks/cluster.go @@ -504,6 +504,8 @@ func (s *Service) createCluster(ctx context.Context, eksClusterName string) (*ek } } + controlPlaneScalingConfig := converters.ControlPlaneScalingConfigToSDK(s.scope.ControlPlane.Spec.ControlPlaneScalingConfig) + bootstrapAddon := s.scope.BootstrapSelfManagedAddons() input := &eks.CreateClusterInput{ Name: aws.String(eksClusterName), @@ -517,6 +519,7 @@ func (s *Service) createCluster(ctx context.Context, eksClusterName string) (*ek KubernetesNetworkConfig: netConfig, BootstrapSelfManagedAddons: bootstrapAddon, UpgradePolicy: upgradePolicy, + ControlPlaneScalingConfig: controlPlaneScalingConfig, } var out *eks.CreateClusterOutput @@ -577,6 +580,11 @@ func (s *Service) reconcileClusterConfig(ctx context.Context, cluster *ekstypes. input.UpgradePolicy = updateUpgradePolicy } + if updateScalingConfig := s.reconcileScalingConfig(cluster.ControlPlaneScalingConfig); updateScalingConfig != nil { + needsUpdate = true + input.ControlPlaneScalingConfig = updateScalingConfig + } + if needsUpdate { if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) { if _, err := s.EKSClient.UpdateClusterConfig(ctx, input); err != nil { @@ -834,6 +842,26 @@ func (s *Service) reconcileUpgradePolicy(upgradePolicy *ekstypes.UpgradePolicyRe } } +func (s *Service) reconcileScalingConfig(scalingConfig *ekstypes.ControlPlaneScalingConfig) *ekstypes.ControlPlaneScalingConfig { + // If no scaling config is specified in the spec, don't update + if s.scope.ControlPlane.Spec.ControlPlaneScalingConfig == nil { + return nil + } + + // If the cluster doesn't have a scaling config yet, or if it differs from the spec, update it + desiredConfig := converters.ControlPlaneScalingConfigToSDK(s.scope.ControlPlane.Spec.ControlPlaneScalingConfig) + if desiredConfig == nil { + return nil + } + + // If current config is nil or tier differs, update is needed + if scalingConfig == nil || scalingConfig.Tier != desiredConfig.Tier { + return desiredConfig + } + + return nil +} + func (s *Service) describeEKSCluster(ctx context.Context, eksClusterName string) (*ekstypes.Cluster, error) { input := &eks.DescribeClusterInput{ Name: aws.String(eksClusterName), From 8af3d115b7d91a23d373919c6a86eb1fe0a2a409 Mon Sep 17 00:00:00 2001 From: Carmine Esposito Date: Thu, 27 Nov 2025 09:50:30 +1100 Subject: [PATCH 2/6] Add unit tests for EKS Provisioned Control Plane Add comprehensive unit tests for: - ControlPlaneScalingConfigToSDK converter function - ControlPlaneScalingConfigFromSDK converter function - reconcileScalingConfig reconciliation logic Tests cover: - Nil input handling - All tier values (standard, tier-xl, tier-2xl, tier-4xl) - Update detection logic when tier changes - No update when tier is the same --- pkg/cloud/converters/eks_test.go | 127 +++++++++++++++++++++++++ pkg/cloud/services/eks/cluster_test.go | 115 ++++++++++++++++++++++ 2 files changed, 242 insertions(+) diff --git a/pkg/cloud/converters/eks_test.go b/pkg/cloud/converters/eks_test.go index 5e87ba0f0e..38e4368e70 100644 --- a/pkg/cloud/converters/eks_test.go +++ b/pkg/cloud/converters/eks_test.go @@ -23,7 +23,9 @@ import ( ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "k8s.io/utils/ptr" + ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2" ) @@ -63,3 +65,128 @@ func TestNodeRepairConfigToSDK(t *testing.T) { }) } } + +func TestControlPlaneScalingConfigToSDK(t *testing.T) { + tests := []struct { + name string + input *ekscontrolplanev1.ControlPlaneScalingConfig + expected *ekstypes.ControlPlaneScalingConfig + }{ + { + name: "nil input returns nil", + input: nil, + expected: nil, + }, + { + name: "nil tier returns nil", + input: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: nil, + }, + expected: nil, + }, + { + name: "standard tier", + input: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTierStandard), + }, + expected: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTierStandard, + }, + }, + { + name: "tier-xl", + input: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTierXL), + }, + expected: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-xl"), + }, + }, + { + name: "tier-2xl", + input: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTier2XL), + }, + expected: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-2xl"), + }, + }, + { + name: "tier-4xl", + input: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTier4XL), + }, + expected: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-4xl"), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ControlPlaneScalingConfigToSDK(tt.input) + if !cmp.Equal(result, tt.expected, cmpopts.IgnoreUnexported(ekstypes.ControlPlaneScalingConfig{})) { + t.Errorf("ControlPlaneScalingConfigToSDK() diff (-want +got):\n%s", cmp.Diff(tt.expected, result, cmpopts.IgnoreUnexported(ekstypes.ControlPlaneScalingConfig{}))) + } + }) + } +} + +func TestControlPlaneScalingConfigFromSDK(t *testing.T) { + tests := []struct { + name string + input *ekstypes.ControlPlaneScalingConfig + expected *ekscontrolplanev1.ControlPlaneScalingConfig + }{ + { + name: "nil input returns nil", + input: nil, + expected: nil, + }, + { + name: "standard tier", + input: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTierStandard, + }, + expected: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTierStandard), + }, + }, + { + name: "tier-xl", + input: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-xl"), + }, + expected: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTierXL), + }, + }, + { + name: "tier-2xl", + input: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-2xl"), + }, + expected: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTier2XL), + }, + }, + { + name: "tier-4xl", + input: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-4xl"), + }, + expected: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTier4XL), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ControlPlaneScalingConfigFromSDK(tt.input) + if !cmp.Equal(result, tt.expected) { + t.Errorf("ControlPlaneScalingConfigFromSDK() diff (-want +got):\n%s", cmp.Diff(tt.expected, result)) + } + }) + } +} diff --git a/pkg/cloud/services/eks/cluster_test.go b/pkg/cloud/services/eks/cluster_test.go index f51ee4c340..8119267a42 100644 --- a/pkg/cloud/services/eks/cluster_test.go +++ b/pkg/cloud/services/eks/cluster_test.go @@ -1064,3 +1064,118 @@ func TestCreateClusterWithBootstrapClusterCreatorAdminPermissions(t *testing.T) _, err = s.createCluster(context.TODO(), clusterName) g.Expect(err).To(BeNil()) } + +func TestReconcileScalingConfig(t *testing.T) { + testCases := []struct { + name string + specConfig *ekscontrolplanev1.ControlPlaneScalingConfig + clusterConfig *ekstypes.ControlPlaneScalingConfig + expectUpdate bool + expectedConfig *ekstypes.ControlPlaneScalingConfig + }{ + { + name: "spec has no scaling config - no update", + specConfig: nil, + clusterConfig: nil, + expectUpdate: false, + expectedConfig: nil, + }, + { + name: "spec has nil tier - no update", + specConfig: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: nil, + }, + clusterConfig: nil, + expectUpdate: false, + expectedConfig: nil, + }, + { + name: "cluster has no scaling config but spec does - update needed", + specConfig: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTier2XL), + }, + clusterConfig: nil, + expectUpdate: true, + expectedConfig: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-2xl"), + }, + }, + { + name: "tier differs - update needed", + specConfig: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTier4XL), + }, + clusterConfig: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-2xl"), + }, + expectUpdate: true, + expectedConfig: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-4xl"), + }, + }, + { + name: "tier is same - no update", + specConfig: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTier2XL), + }, + clusterConfig: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-2xl"), + }, + expectUpdate: false, + expectedConfig: nil, + }, + { + name: "changing from standard to xl - update needed", + specConfig: &ekscontrolplanev1.ControlPlaneScalingConfig{ + Tier: ptr.To(ekscontrolplanev1.ControlPlaneScalingTierXL), + }, + clusterConfig: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTierStandard, + }, + expectUpdate: true, + expectedConfig: &ekstypes.ControlPlaneScalingConfig{ + Tier: ekstypes.ProvisionedControlPlaneTier("tier-xl"), + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + mockControl := gomock.NewController(t) + defer mockControl.Finish() + + scheme := runtime.NewScheme() + _ = infrav1.AddToScheme(scheme) + _ = ekscontrolplanev1.AddToScheme(scheme) + client := fake.NewClientBuilder().WithScheme(scheme).Build() + + scope, err := scope.NewManagedControlPlaneScope(scope.ManagedControlPlaneScopeParams{ + Client: client, + Cluster: &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "ns", + Name: "capi-name", + }, + }, + ControlPlane: &ekscontrolplanev1.AWSManagedControlPlane{ + Spec: ekscontrolplanev1.AWSManagedControlPlaneSpec{ + EKSClusterName: "test-cluster", + ControlPlaneScalingConfig: tc.specConfig, + }, + }, + }) + g.Expect(err).To(BeNil()) + + s := NewService(scope) + result := s.reconcileScalingConfig(tc.clusterConfig) + + if tc.expectUpdate { + g.Expect(result).ToNot(BeNil(), "expected update config to be returned") + g.Expect(result.Tier).To(Equal(tc.expectedConfig.Tier)) + } else { + g.Expect(result).To(BeNil(), "expected no update") + } + }) + } +} From ad78220056b5be261c3dcfd49fd50ebb9b3e1444 Mon Sep 17 00:00:00 2001 From: Carmine Date: Wed, 3 Dec 2025 08:38:51 +1100 Subject: [PATCH 3/6] Update controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go Co-authored-by: Mohamed Ali ElSerngawy --- controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go b/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go index 0aae4bc80d..78ae08b8a6 100644 --- a/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go +++ b/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go @@ -223,7 +223,7 @@ type AWSManagedControlPlaneSpec struct { //nolint: maligned UpgradePolicy UpgradePolicy `json:"upgradePolicy,omitempty"` // ControlPlaneScalingConfig specifies the scaling configuration for the EKS control plane. - // This allows you to select from a set of scaling tiers for predictable, high performance from the cluster's control plane. + // Enables selection of predefined scaling tiers to ensure consistent, high-performance operation of the cluster’s control plane. // (Official AWS docs: https://docs.aws.amazon.com/eks/latest/userguide/eks-provisioned-control-plane.html) // +optional ControlPlaneScalingConfig *ControlPlaneScalingConfig `json:"controlPlaneScalingConfig,omitempty"` From a478cdfbab6baf76e516ac0b3785be9f15d949a2 Mon Sep 17 00:00:00 2001 From: Carmine Esposito Date: Wed, 3 Dec 2025 09:37:41 +1100 Subject: [PATCH 4/6] Regenerate CRD manifests --- .../controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml | 2 +- ...lplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml index 6a21423c74..91e6e4dbbe 100644 --- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml @@ -2414,7 +2414,7 @@ spec: controlPlaneScalingConfig: description: |- ControlPlaneScalingConfig specifies the scaling configuration for the EKS control plane. - This allows you to select from a set of scaling tiers for predictable, high performance from the cluster's control plane. + Enables selection of predefined scaling tiers to ensure consistent, high-performance operation of the cluster’s control plane. (Official AWS docs: https://docs.aws.amazon.com/eks/latest/userguide/eks-provisioned-control-plane.html) properties: tier: diff --git a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml index 4caed3c98e..9a972fde02 100644 --- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml @@ -190,7 +190,7 @@ spec: controlPlaneScalingConfig: description: |- ControlPlaneScalingConfig specifies the scaling configuration for the EKS control plane. - This allows you to select from a set of scaling tiers for predictable, high performance from the cluster's control plane. + Enables selection of predefined scaling tiers to ensure consistent, high-performance operation of the cluster’s control plane. (Official AWS docs: https://docs.aws.amazon.com/eks/latest/userguide/eks-provisioned-control-plane.html) properties: tier: From 3941730203e3e9001b2126b355bf0c0e360b9211 Mon Sep 17 00:00:00 2001 From: Carmine Esposito Date: Thu, 4 Dec 2025 09:44:41 +1100 Subject: [PATCH 5/6] Add e2e test for EKS Provisioned Control Plane scaling config --- .../cluster-template-eks-scaling-config.yaml | 37 +++++ test/e2e/shared/defaults.go | 1 + .../suites/managed/eks_scaling_config_test.go | 147 ++++++++++++++++++ test/e2e/suites/managed/helpers.go | 1 + 4 files changed, 186 insertions(+) create mode 100644 test/e2e/data/eks/cluster-template-eks-scaling-config.yaml create mode 100644 test/e2e/suites/managed/eks_scaling_config_test.go diff --git a/test/e2e/data/eks/cluster-template-eks-scaling-config.yaml b/test/e2e/data/eks/cluster-template-eks-scaling-config.yaml new file mode 100644 index 0000000000..779b975893 --- /dev/null +++ b/test/e2e/data/eks/cluster-template-eks-scaling-config.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: "${CLUSTER_NAME}" +spec: + clusterNetwork: + pods: + cidrBlocks: ["192.168.0.0/16"] + infrastructureRef: + kind: AWSManagedCluster + apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 + name: "${CLUSTER_NAME}" + controlPlaneRef: + kind: AWSManagedControlPlane + apiVersion: controlplane.cluster.x-k8s.io/v1beta2 + name: "${CLUSTER_NAME}-control-plane" +--- +kind: AWSManagedCluster +apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 +metadata: + name: "${CLUSTER_NAME}" +spec: {} +--- +kind: AWSManagedControlPlane +apiVersion: controlplane.cluster.x-k8s.io/v1beta2 +metadata: + name: "${CLUSTER_NAME}-control-plane" +spec: + region: "${AWS_REGION}" + version: "${KUBERNETES_VERSION}" + controlPlaneScalingConfig: + tier: "${SCALING_TIER}" + identityRef: + kind: AWSClusterStaticIdentity + name: e2e-account + diff --git a/test/e2e/shared/defaults.go b/test/e2e/shared/defaults.go index 3a9b00d2a5..3e72c7bcbe 100644 --- a/test/e2e/shared/defaults.go +++ b/test/e2e/shared/defaults.go @@ -73,6 +73,7 @@ const ( EksUpgradeFromVersion = "UPGRADE_FROM_VERSION" EksUpgradeToVersion = "UPGRADE_TO_VERSION" UpgradePolicy = "UPGRADE_POLICY" + ScalingTier = "SCALING_TIER" ClassicElbTestKubernetesFrom = "CLASSICELB_TEST_KUBERNETES_VERSION_FROM" ClassicElbTestKubernetesTo = "CLASSICELB_TEST_KUBERNETES_VERSION_TO" diff --git a/test/e2e/suites/managed/eks_scaling_config_test.go b/test/e2e/suites/managed/eks_scaling_config_test.go new file mode 100644 index 0000000000..87fe8e2624 --- /dev/null +++ b/test/e2e/suites/managed/eks_scaling_config_test.go @@ -0,0 +1,147 @@ +//go:build e2e +// +build e2e + +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package managed + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" + "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + + ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" + "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/awserrors" + "sigs.k8s.io/cluster-api-provider-aws/v2/test/e2e/shared" + "sigs.k8s.io/cluster-api/test/framework" + "sigs.k8s.io/cluster-api/util" +) + +// EKS scaling config test. +var _ = ginkgo.Describe("EKS scaling config test", func() { + var ( + namespace *corev1.Namespace + ctx context.Context + specName = "cluster" + clusterName string + ) + + ginkgo.It("[managed] [scaling-config] Able to create cluster with scaling tier and update from standard to tier-xl", func() { + ginkgo.By("should have a valid test configuration") + Expect(e2eCtx.Environment.BootstrapClusterProxy).ToNot(BeNil(), "Invalid argument. BootstrapClusterProxy can't be nil") + Expect(e2eCtx.E2EConfig).ToNot(BeNil(), "Invalid argument. e2eConfig can't be nil when calling %s spec", specName) + + scalingTier := ekscontrolplanev1.ControlPlaneScalingTierStandard + shared.SetEnvVar(shared.ScalingTier, string(scalingTier), false) + + ctx = context.TODO() + namespace = shared.SetupSpecNamespace(ctx, specName, e2eCtx) + clusterName = fmt.Sprintf("%s-%s", specName, util.RandomString(6)) + eksClusterName := getEKSClusterName(namespace.Name, clusterName) + + ginkgo.By("default iam role should exist") + VerifyRoleExistsAndOwned(ctx, ekscontrolplanev1.DefaultEKSControlPlaneRole, eksClusterName, false, e2eCtx.AWSSession) + + getManagedClusterSpec := func() ManagedClusterSpecInput { + return ManagedClusterSpecInput{ + E2EConfig: e2eCtx.E2EConfig, + ConfigClusterFn: defaultConfigCluster, + BootstrapClusterProxy: e2eCtx.Environment.BootstrapClusterProxy, + AWSSession: e2eCtx.BootstrapUserAWSSession, + Namespace: namespace, + ClusterName: clusterName, + Flavour: EKSScalingConfigFlavor, + ControlPlaneMachineCount: 1, // NOTE: this cannot be zero as clusterctl returns an error + WorkerMachineCount: 0, + } + } + + ginkgo.By("should create an EKS control plane with standard scaling tier") + ManagedClusterSpec(ctx, getManagedClusterSpec) + + ginkgo.By(fmt.Sprintf("getting cluster with name %s", clusterName)) + cluster := framework.GetClusterByName(ctx, framework.GetClusterByNameInput{ + Getter: e2eCtx.Environment.BootstrapClusterProxy.GetClient(), + Namespace: namespace.Name, + Name: clusterName, + }) + Expect(cluster).NotTo(BeNil(), "couldn't find cluster") + + WaitForEKSClusterScalingTier(ctx, e2eCtx.BootstrapUserAWSSession, eksClusterName, scalingTier) + + changedScalingTier := ekscontrolplanev1.ControlPlaneScalingTierXL + ginkgo.By(fmt.Sprintf("Changing the scaling tier from %s to %s", scalingTier, changedScalingTier)) + shared.SetEnvVar(shared.ScalingTier, string(changedScalingTier), false) + ManagedClusterSpec(ctx, getManagedClusterSpec) + WaitForEKSClusterScalingTier(ctx, e2eCtx.BootstrapUserAWSSession, eksClusterName, changedScalingTier) + + framework.DeleteCluster(ctx, framework.DeleteClusterInput{ + Deleter: e2eCtx.Environment.BootstrapClusterProxy.GetClient(), + Cluster: cluster, + }) + framework.WaitForClusterDeleted(ctx, framework.WaitForClusterDeletedInput{ + ClusterProxy: e2eCtx.Environment.BootstrapClusterProxy, + Cluster: cluster, + ClusterctlConfigPath: e2eCtx.Environment.ClusterctlConfigPath, + ArtifactFolder: e2eCtx.Settings.ArtifactFolder, + }, e2eCtx.E2EConfig.GetIntervals("", "wait-delete-cluster")...) + }) +}) + +// WaitForEKSClusterScalingTier waits for the EKS cluster to have the expected scaling tier. +func WaitForEKSClusterScalingTier(ctx context.Context, sess *aws.Config, eksClusterName string, scalingTier ekscontrolplanev1.ControlPlaneScalingTier) { + ginkgo.By(fmt.Sprintf("Checking EKS control plane scaling tier matches %s", scalingTier)) + Eventually(func() error { + cluster, err := getEKSCluster(ctx, eksClusterName, sess) + if err != nil { + smithyErr := awserrors.ParseSmithyError(err) + notFoundErr := &ekstypes.ResourceNotFoundException{} + if smithyErr.ErrorCode() == notFoundErr.ErrorCode() { + // Unrecoverable error stop trying and fail early. + return StopTrying(fmt.Sprintf("unrecoverable error: cluster %q not found: %s", eksClusterName, smithyErr.ErrorMessage())) + } + return err // For transient errors, retry + } + + // Check if scaling config exists + if cluster.ControlPlaneScalingConfig == nil { + // If no scaling config, the cluster is in standard mode + if scalingTier == ekscontrolplanev1.ControlPlaneScalingTierStandard { + return nil + } + return fmt.Errorf("scaling config is nil, but expected tier %s", scalingTier) + } + + expectedTier := ekstypes.ProvisionedControlPlaneTier(scalingTier) + actualTier := cluster.ControlPlaneScalingConfig.Tier + + if actualTier != expectedTier { + // The scaling tier change hasn't been reflected in EKS yet, error and try again. + return fmt.Errorf("scaling tier mismatch: expected %s, but found %s", expectedTier, actualTier) + } + + // Success in finding the change has been reflected in EKS. + return nil + }, 5*time.Minute, 10*time.Second).Should(Succeed(), fmt.Sprintf("eventually failed checking EKS Cluster %q scaling tier is %s", eksClusterName, scalingTier)) +} + diff --git a/test/e2e/suites/managed/helpers.go b/test/e2e/suites/managed/helpers.go index dce878d89a..ce24581fb7 100644 --- a/test/e2e/suites/managed/helpers.go +++ b/test/e2e/suites/managed/helpers.go @@ -49,6 +49,7 @@ const ( EKSMachinePoolOnlyFlavor = "eks-machinepool-only" EKSIPv6ClusterFlavor = "eks-ipv6-cluster" EKSUpgradePolicyFlavor = "eks-upgrade-policy" + EKSScalingConfigFlavor = "eks-scaling-config" EKSControlPlaneOnlyLegacyFlavor = "eks-control-plane-only-legacy" EKSClusterClassFlavor = "eks-clusterclass" EKSAuthAPIAndConfigMapFlavor = "eks-auth-api-and-config-map" From d151bb52e89aa614705610a31dc577636ea9dc1b Mon Sep 17 00:00:00 2001 From: Carmine Esposito Date: Thu, 4 Dec 2025 10:09:15 +1100 Subject: [PATCH 6/6] Fix gci formatting in e2e test --- test/e2e/suites/managed/eks_scaling_config_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/test/e2e/suites/managed/eks_scaling_config_test.go b/test/e2e/suites/managed/eks_scaling_config_test.go index 87fe8e2624..866cffd720 100644 --- a/test/e2e/suites/managed/eks_scaling_config_test.go +++ b/test/e2e/suites/managed/eks_scaling_config_test.go @@ -144,4 +144,3 @@ func WaitForEKSClusterScalingTier(ctx context.Context, sess *aws.Config, eksClus return nil }, 5*time.Minute, 10*time.Second).Should(Succeed(), fmt.Sprintf("eventually failed checking EKS Cluster %q scaling tier is %s", eksClusterName, scalingTier)) } -