From 3badeacfc101ca84c7d9970f6b8b4518c4b554bd Mon Sep 17 00:00:00 2001 From: Nathan Clonts Date: Wed, 14 Oct 2026 12:10:24 -0700 Subject: [PATCH] Use the EKS default Kubernetes version when --version is not set DescribeClusterVersions already reports which version EKS treats as the default, but create cluster ignored it and always used the hardcoded api.DefaultVersion. eksctl now takes the default version only from DescribeClusterVersions: api.DefaultVersion is removed and NewClusterConfig no longer seeds metadata.version, so both the flag path and config files without metadata.version resolve to the EKS default. If EKS does not flag a default, create cluster without a version, --version auto and create nodegroup --version=default fail and ask for an explicit version. Other commands that go through NewCtl, such as get cluster, utils describe-cluster-versions, utils describe-addon-versions and the delete cluster --force fallback, keep working. utils migrate-to-pod-identity now looks up the pod identity agent addon for the cluster's version instead of the previously seeded default. The integration tests' -eksctl.version flag now defaults to the EKS default version, resolved without panicking when it cannot be looked up. Signed-off-by: Nathan Clonts --- integration/tests/addons/addons_test.go | 12 +-- integration/tests/dry_run/dry_run_test.go | 2 +- integration/tests/gitops/flux_test.go | 2 +- integration/tests/ipv6/ipv6_test.go | 2 +- integration/tests/karpenter/karpenter_test.go | 2 +- integration/tests/params.go | 25 +++++- integration/tests/windows/windows_test.go | 2 +- .../windows_managed/windows_managed_test.go | 2 +- pkg/actions/addon/create_test.go | 2 +- pkg/actions/addon/update_test.go | 4 +- pkg/actions/nodegroup/create_test.go | 2 +- pkg/actions/nodegroup/upgrade_test.go | 2 +- .../v1alpha5/instance_selector_test.go | 2 +- pkg/apis/eksctl.io/v1alpha5/types.go | 9 +- .../eksctl.io/v1alpha5/validation_test.go | 3 + .../managed_nodegroup_ami_type_test.go | 2 +- pkg/ctl/cmdutils/cmd.go | 18 +++- pkg/ctl/cmdutils/cmd_test.go | 66 ++++++++++++++ .../cmdutils/filter/nodegroup_filter_test.go | 3 +- pkg/ctl/create/cluster.go | 6 +- pkg/ctl/create/cluster_test.go | 28 ++++++ pkg/ctl/create/nodegroup.go | 3 + pkg/ctl/create/nodegroup_test.go | 17 ++++ pkg/ctl/update/cluster.go | 2 - pkg/ctl/upgrade/cluster.go | 2 - pkg/ctl/utils/migrate_to_pod_identity.go | 1 + pkg/eks/nodegroup_service_test.go | 12 +-- pkg/eks/versions_manager.go | 7 +- pkg/eks/versions_manager_test.go | 87 +++++++++++++++++++ pkg/vpc/vpc_test.go | 6 +- userdocs/src/getting-started.md | 6 +- 31 files changed, 287 insertions(+), 52 deletions(-) create mode 100644 pkg/ctl/cmdutils/cmd_test.go diff --git a/integration/tests/addons/addons_test.go b/integration/tests/addons/addons_test.go index fcef9a3325..a824cb22d9 100644 --- a/integration/tests/addons/addons_test.go +++ b/integration/tests/addons/addons_test.go @@ -75,7 +75,7 @@ var _ = BeforeSuite(func() { rawClient = getRawClient(context.Background(), params.ClusterName) serverVersion, err := rawClient.ServerVersion() Expect(err).NotTo(HaveOccurred()) - Expect(serverVersion).To(HavePrefix(api.DefaultVersion)) + Expect(serverVersion).To(HavePrefix(params.Version)) }) @@ -555,7 +555,7 @@ var _ = Describe("(Integration) [EKS Addons test]", func() { cmd := params.EksctlUtilsCmd. WithArgs( "describe-addon-versions", - "--kubernetes-version", api.DefaultVersion, + "--kubernetes-version", params.Version, ) Expect(cmd).To(RunSuccessfullyWithOutputStringLines( ContainElement(ContainSubstring("vpc-cni")), @@ -569,7 +569,7 @@ var _ = Describe("(Integration) [EKS Addons test]", func() { By(fmt.Sprintf("listing available addon versions for %s", addonWithSchema)) output, err := eksAPI.DescribeAddonVersions(context.Background(), &awseks.DescribeAddonVersionsInput{ AddonName: aws.String(addonWithSchema), - KubernetesVersion: aws.String(api.DefaultVersion), + KubernetesVersion: aws.String(params.Version), }) Expect(err).NotTo(HaveOccurred(), "error describing addon versions") By(fmt.Sprintf("fetching the configuration schema for %s", addonWithSchema)) @@ -592,7 +592,7 @@ var _ = Describe("(Integration) [EKS Addons test]", func() { cmd := params.EksctlUtilsCmd. WithArgs( "describe-addon-versions", - "--kubernetes-version", api.DefaultVersion, + "--kubernetes-version", params.Version, "--types", "networking", "--owners", "aws", "--publishers", "eks", @@ -625,7 +625,7 @@ var _ = Describe("(Integration) [EKS Addons test]", func() { cmd := params.EksctlUtilsCmd. WithArgs( "describe-addon-versions", - "--kubernetes-version", api.DefaultVersion, + "--kubernetes-version", params.Version, "--types", "networking, storage", ) Expect(cmd).To(RunSuccessfullyWithOutputStringLines( @@ -990,7 +990,7 @@ func getRawClient(ctx context.Context, clusterName string) *kubewrapper.RawClien func getInitialClusterConfig() *api.ClusterConfig { clusterConfig := api.NewClusterConfig() clusterConfig.Metadata.Name = params.ClusterName - clusterConfig.Metadata.Version = api.DefaultVersion + clusterConfig.Metadata.Version = params.Version clusterConfig.Metadata.Region = params.Region clusterConfig.IAM.WithOIDC = api.Enabled() clusterConfig.Addons = []*api.Addon{ diff --git a/integration/tests/dry_run/dry_run_test.go b/integration/tests/dry_run/dry_run_test.go index 0c125ebb86..ae6311f8c2 100644 --- a/integration/tests/dry_run/dry_run_test.go +++ b/integration/tests/dry_run/dry_run_test.go @@ -46,7 +46,7 @@ func TestDryRun(t *testing.T) { testutils.RegisterAndRun(t) } -const eksVersion = api.DefaultVersion +const eksVersion = api.Version1_34 const defaultClusterConfig = ` apiVersion: eksctl.io/v1alpha5 diff --git a/integration/tests/gitops/flux_test.go b/integration/tests/gitops/flux_test.go index 91d254754c..713a788cb0 100644 --- a/integration/tests/gitops/flux_test.go +++ b/integration/tests/gitops/flux_test.go @@ -66,7 +66,7 @@ var _ = Describe("Enable GitOps", func() { clusterConfig = &api.ClusterConfig{ TypeMeta: api.ClusterConfigTypeMeta(), Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: params.Version, Name: params.ClusterName, Region: params.Region, }, diff --git a/integration/tests/ipv6/ipv6_test.go b/integration/tests/ipv6/ipv6_test.go index f33a6c8ba0..81a94bf669 100644 --- a/integration/tests/ipv6/ipv6_test.go +++ b/integration/tests/ipv6/ipv6_test.go @@ -55,7 +55,7 @@ var _ = BeforeSuite(func() { clusterConfig = api.NewClusterConfig() clusterConfig.Metadata.Name = params.ClusterName - clusterConfig.Metadata.Version = api.DefaultVersion + clusterConfig.Metadata.Version = params.Version clusterConfig.Metadata.Region = params.Region clusterConfig.KubernetesNetworkConfig.IPFamily = "iPv6" clusterConfig.VPC.NAT = nil diff --git a/integration/tests/karpenter/karpenter_test.go b/integration/tests/karpenter/karpenter_test.go index 132de854c2..3a205669ef 100644 --- a/integration/tests/karpenter/karpenter_test.go +++ b/integration/tests/karpenter/karpenter_test.go @@ -81,7 +81,7 @@ var _ = Describe("(Integration) Karpenter", func() { Metadata: &api.ClusterMeta{ Name: clusterName, Region: params.Region, - Version: api.DefaultVersion, + Version: params.Version, Tags: map[string]string{ "karpenter.sh/discovery": clusterName, }, diff --git a/integration/tests/params.go b/integration/tests/params.go index 0f149f9aae..91491af4dc 100644 --- a/integration/tests/params.go +++ b/integration/tests/params.go @@ -210,7 +210,7 @@ func NewParamsWithGivenClusterName(clusterNamePrefix string, givenName string) * flag.StringVar(¶ms.EksctlPath, "eksctl.path", "../../../eksctl", "Path to eksctl") flag.StringVar(¶ms.Region, "eksctl.region", api.DefaultRegion, "Region to use for the tests") - flag.StringVar(¶ms.Version, "eksctl.version", api.DefaultVersion, "Version of Kubernetes to test") + flag.StringVar(¶ms.Version, "eksctl.version", "", "Version of Kubernetes to test (default: the EKS default version)") flag.StringVar(¶ms.TestDirectory, "eksctl.test.dir", defaultTestDirectory, "Test directory. Defaulted to: "+defaultTestDirectory) // Flags to help with the development of the integration tests flag.StringVar(¶ms.ClusterName, "eksctl.cluster", "", "Cluster name (default: generate one)") @@ -223,6 +223,9 @@ func NewParamsWithGivenClusterName(clusterNamePrefix string, givenName string) * // go1.13+ testing flags regression fix: https://github.com/golang/go/issues/31859 flag.Parse() + if params.Version == "" { + params.attemptSettingDefaultVersion() + } params.attemptSettingUserID() if params.ClusterName == "" { params.ClusterName = params.newClusterName(clusterNamePrefix, givenName) @@ -257,6 +260,26 @@ func (p *Params) LogStacksEventsOnFailureForCluster(clusterName string) bool { }) } +func (p *Params) attemptSettingDefaultVersion() { + msg := "Warning: failed to resolve the EKS default Kubernetes version, proceeding without it. Error: %v" + clusterProvider, err := eks.New(context.TODO(), &api.ProviderConfig{Region: p.Region}, nil) + if err != nil { + fmt.Fprintf(GinkgoWriter, msg, err) + return + } + cvm, err := eks.NewClusterVersionsManager(clusterProvider.AWSProvider.EKS()) + if err != nil { + fmt.Fprintf(GinkgoWriter, msg, err) + return + } + version, err := cvm.ResolveClusterVersion("") + if err != nil { + fmt.Fprintf(GinkgoWriter, msg, err) + return + } + p.Version = version +} + // attemptSettingUserID will attempt to fetch the first 4 characters of the userID running the // integration tests to be used as a prefix for cluster names. It fails silently if an error occurs func (p *Params) attemptSettingUserID() { diff --git a/integration/tests/windows/windows_test.go b/integration/tests/windows/windows_test.go index 2766e60f9c..aa071f4ee6 100644 --- a/integration/tests/windows/windows_test.go +++ b/integration/tests/windows/windows_test.go @@ -42,7 +42,7 @@ var _ = Describe("(Integration) [Windows Nodegroups]", func() { By("creating a new cluster with Windows nodegroups") clusterConfig := api.NewClusterConfig() clusterConfig.Metadata.Name = clusterName - clusterConfig.Metadata.Version = api.DefaultVersion + clusterConfig.Metadata.Version = params.Version clusterConfig.Metadata.Region = api.DefaultRegion clusterConfig.IAM.WithOIDC = &withOIDC diff --git a/integration/tests/windows_managed/windows_managed_test.go b/integration/tests/windows_managed/windows_managed_test.go index fa6cfc57d8..d1092f0ec8 100644 --- a/integration/tests/windows_managed/windows_managed_test.go +++ b/integration/tests/windows_managed/windows_managed_test.go @@ -43,7 +43,7 @@ func TestWindowsManaged(t *testing.T) { func makeClusterConfig() *api.ClusterConfig { clusterConfig := api.NewClusterConfig() clusterConfig.Metadata.Name = params.ClusterName - clusterConfig.Metadata.Version = api.DefaultVersion + clusterConfig.Metadata.Version = params.Version clusterConfig.Metadata.Region = params.Region return clusterConfig } diff --git a/pkg/actions/addon/create_test.go b/pkg/actions/addon/create_test.go index 078808c395..a154bceae2 100644 --- a/pkg/actions/addon/create_test.go +++ b/pkg/actions/addon/create_test.go @@ -92,7 +92,7 @@ var _ = Describe("Create", func() { RequiresIamPermissions: true, Compatibilities: []ekstypes.Compatibility{ { - ClusterVersion: aws.String(api.DefaultVersion), + ClusterVersion: aws.String(api.Version1_34), DefaultVersion: true, }, }, diff --git a/pkg/actions/addon/update_test.go b/pkg/actions/addon/update_test.go index 52a3d5a9b1..fd658e7716 100644 --- a/pkg/actions/addon/update_test.go +++ b/pkg/actions/addon/update_test.go @@ -667,7 +667,7 @@ var _ = Describe("Update", func() { }, nil).Once() mockProvider.MockEKS().On("DescribeAddonVersions", mock.Anything, &awseks.DescribeAddonVersionsInput{ AddonName: aws.String("vpc-cni"), - KubernetesVersion: aws.String(api.DefaultVersion), + KubernetesVersion: aws.String(api.Version1_34), }).Return(&awseks.DescribeAddonVersionsOutput{ Addons: []ekstypes.AddonInfo{ { @@ -741,7 +741,7 @@ var _ = Describe("Update", func() { addonManager, err := addon.New(&api.ClusterConfig{ Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, Name: clusterName, }, AddonsConfig: e.addonsConfig, diff --git a/pkg/actions/nodegroup/create_test.go b/pkg/actions/nodegroup/create_test.go index 0ad082b59f..0759d5b861 100644 --- a/pkg/actions/nodegroup/create_test.go +++ b/pkg/actions/nodegroup/create_test.go @@ -748,7 +748,7 @@ func newClusterConfig() *api.ClusterConfig { TypeMeta: api.ClusterConfigTypeMeta(), Metadata: &api.ClusterMeta{ Name: "my-cluster", - Version: api.DefaultVersion, + Version: api.Version1_34, }, Status: &api.ClusterStatus{ Endpoint: "https://localhost/", diff --git a/pkg/actions/nodegroup/upgrade_test.go b/pkg/actions/nodegroup/upgrade_test.go index f96051968c..e42172948e 100644 --- a/pkg/actions/nodegroup/upgrade_test.go +++ b/pkg/actions/nodegroup/upgrade_test.go @@ -130,7 +130,7 @@ var _ = Describe("Upgrade", func() { }}, nil) }) It("returns an error if kubernetes version is specified", func() { - options.KubernetesVersion = api.DefaultVersion + options.KubernetesVersion = api.Version1_34 err := m.Upgrade(context.Background(), options) Expect(err).To(MatchError(ContainSubstring("cannot specify kubernetes-version or release-version when using a custom AMI"))) }) diff --git a/pkg/apis/eksctl.io/v1alpha5/instance_selector_test.go b/pkg/apis/eksctl.io/v1alpha5/instance_selector_test.go index 8a21cb17ec..757a82b5e5 100644 --- a/pkg/apis/eksctl.io/v1alpha5/instance_selector_test.go +++ b/pkg/apis/eksctl.io/v1alpha5/instance_selector_test.go @@ -14,7 +14,7 @@ var _ = Describe("Instance Selector Validation", func() { DescribeTable("Supported and unsupported field combinations", func(n *instanceSelectorCase) { cfg := NewClusterConfig() - err := SetNodeGroupDefaults(n.ng, &ClusterMeta{Name: "cluster", Version: DefaultVersion}, cfg.IsControlPlaneOnOutposts()) + err := SetNodeGroupDefaults(n.ng, &ClusterMeta{Name: "cluster", Version: Version1_34}, cfg.IsControlPlaneOnOutposts()) Expect(err).NotTo(HaveOccurred()) err = ValidateNodeGroup(0, n.ng, cfg) diff --git a/pkg/apis/eksctl.io/v1alpha5/types.go b/pkg/apis/eksctl.io/v1alpha5/types.go index 44469091c8..8be00c3ee0 100644 --- a/pkg/apis/eksctl.io/v1alpha5/types.go +++ b/pkg/apis/eksctl.io/v1alpha5/types.go @@ -54,9 +54,6 @@ const ( AmazonLinux2EOLVersion = Version1_33 // EFABuiltInSupportVersion defines the minimum Kubernetes version that supports built-in EFA EFABuiltInSupportVersion = Version1_33 - //TODO: Remove this and replace with output from DescribeClusterVersions endpoint - // DefaultVersion (default) - DefaultVersion = Version1_34 ) const ( @@ -1307,10 +1304,8 @@ func ClusterConfigTypeMeta() metav1.TypeMeta { func NewClusterConfig() *ClusterConfig { cfg := &ClusterConfig{ TypeMeta: ClusterConfigTypeMeta(), - Metadata: &ClusterMeta{ - Version: DefaultVersion, - }, - IAM: NewClusterIAM(), + Metadata: &ClusterMeta{}, + IAM: NewClusterIAM(), KubernetesNetworkConfig: &KubernetesNetworkConfig{ IPFamily: DefaultIPFamily, }, diff --git a/pkg/apis/eksctl.io/v1alpha5/validation_test.go b/pkg/apis/eksctl.io/v1alpha5/validation_test.go index 391cb4c369..c0744ea827 100644 --- a/pkg/apis/eksctl.io/v1alpha5/validation_test.go +++ b/pkg/apis/eksctl.io/v1alpha5/validation_test.go @@ -881,6 +881,7 @@ var _ = Describe("ClusterConfig validation", func() { DescribeTable("AWS Local Zones", func(e localZonesEntry) { clusterConfig := api.NewClusterConfig() + clusterConfig.Metadata.Version = api.Version1_34 e.updateClusterConfig(clusterConfig) clusterConfig.LocalZones = []string{"us-west-2-lax-1a", "us-west-2-lax-1b"} @@ -1013,6 +1014,7 @@ var _ = Describe("ClusterConfig validation", func() { } DescribeTable("RemoteNetworkConfig", func(e remoteNetworkConfigEntry) { cfg := api.NewClusterConfig() + cfg.Metadata.Version = api.Version1_34 api.SetClusterConfigDefaults(cfg) api.SetClusterEndpointAccessDefaults(cfg.VPC) gatewayID := api.VPCGateway("tgw-1234") @@ -1131,6 +1133,7 @@ var _ = Describe("ClusterConfig validation", func() { BeforeEach(func() { cfg = api.NewClusterConfig() + cfg.Metadata.Version = api.Version1_34 vpc = api.NewClusterVPC(false) cfg.VPC = vpc }) diff --git a/pkg/cfn/builder/managed_nodegroup_ami_type_test.go b/pkg/cfn/builder/managed_nodegroup_ami_type_test.go index b54b71bc0e..f6ebbc3fe2 100644 --- a/pkg/cfn/builder/managed_nodegroup_ami_type_test.go +++ b/pkg/cfn/builder/managed_nodegroup_ami_type_test.go @@ -33,7 +33,7 @@ var _ = DescribeTable("Managed Nodegroup AMI type", func(e amiTypeEntry) { if e.clusterVersion != "" { clusterConfig.Metadata.Version = e.clusterVersion } else { - clusterConfig.Metadata.Version = api.DefaultVersion + clusterConfig.Metadata.Version = api.Version1_34 } err := api.SetManagedNodeGroupDefaults(e.nodeGroup, clusterConfig.Metadata, false) Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/ctl/cmdutils/cmd.go b/pkg/ctl/cmdutils/cmd.go index 42e6444f56..a4eba8d318 100644 --- a/pkg/ctl/cmdutils/cmd.go +++ b/pkg/ctl/cmdutils/cmd.go @@ -44,11 +44,9 @@ func (c *Cmd) NewCtl() (*eks.ClusterProvider, error) { return nil, err } - version, err := cvm.ResolveClusterVersion(c.ClusterConfig.Metadata.Version) - if err != nil { - return nil, fmt.Errorf("resolving cluster version: %w", err) + if err := resolveClusterVersion(cvm, c.ClusterConfig.Metadata); err != nil { + return nil, err } - c.ClusterConfig.Metadata.Version = version if err := c.InitializeClusterConfig(); err != nil { return nil, err @@ -61,6 +59,18 @@ func (c *Cmd) NewCtl() (*eks.ClusterProvider, error) { return ctl, nil } +func resolveClusterVersion(cvm eks.ClusterVersionsManagerInterface, meta *api.ClusterMeta) error { + if meta.Version == "" && cvm.DefaultVersion() == "" { + return nil + } + version, err := cvm.ResolveClusterVersion(meta.Version) + if err != nil { + return fmt.Errorf("resolving cluster version: %w", err) + } + meta.Version = version + return nil +} + // InitializeClusterConfig validates and initializes the ClusterConfig. func (c *Cmd) InitializeClusterConfig() error { api.SetClusterConfigDefaults(c.ClusterConfig) diff --git a/pkg/ctl/cmdutils/cmd_test.go b/pkg/ctl/cmdutils/cmd_test.go new file mode 100644 index 0000000000..fbff53295c --- /dev/null +++ b/pkg/ctl/cmdutils/cmd_test.go @@ -0,0 +1,66 @@ +package cmdutils + +import ( + "github.com/aws/aws-sdk-go-v2/aws" + awseks "github.com/aws/aws-sdk-go-v2/service/eks" + ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/stretchr/testify/mock" + + api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + "github.com/weaveworks/eksctl/pkg/eks" + "github.com/weaveworks/eksctl/pkg/testutils/mockprovider" +) + +var _ = Describe("resolveClusterVersion", func() { + type resolveClusterVersionEntry struct { + eksFlagsDefault bool + version string + expectedVersion string + expectedErr string + } + + DescribeTable("resolves the cluster version", func(e resolveClusterVersionEntry) { + mockProvider := mockprovider.NewMockProvider() + mockProvider.MockEKS().On("DescribeClusterVersions", mock.Anything, &awseks.DescribeClusterVersionsInput{}). + Return(&awseks.DescribeClusterVersionsOutput{ + ClusterVersions: []ekstypes.ClusterVersionInformation{ + { + ClusterVersion: aws.String(api.Version1_34), + DefaultVersion: e.eksFlagsDefault, + }, + { + ClusterVersion: aws.String(api.Version1_35), + }, + }, + }, nil) + cvm, err := eks.NewClusterVersionsManager(mockProvider.EKS()) + Expect(err).NotTo(HaveOccurred()) + + meta := &api.ClusterMeta{Version: e.version} + err = resolveClusterVersion(cvm, meta) + if e.expectedErr != "" { + Expect(err).To(MatchError(ContainSubstring(e.expectedErr))) + return + } + Expect(err).NotTo(HaveOccurred()) + Expect(meta.Version).To(Equal(e.expectedVersion)) + }, + Entry("uses the EKS default version when the version is not set", resolveClusterVersionEntry{ + eksFlagsDefault: true, + expectedVersion: api.Version1_34, + }), + Entry("leaves the version unset when EKS does not flag a default", resolveClusterVersionEntry{ + expectedVersion: "", + }), + Entry("uses the specified version when EKS does not flag a default", resolveClusterVersionEntry{ + version: api.Version1_35, + expectedVersion: api.Version1_35, + }), + Entry("fails for auto when EKS does not flag a default", resolveClusterVersionEntry{ + version: "auto", + expectedErr: "EKS did not report a default Kubernetes version", + }), + ) +}) diff --git a/pkg/ctl/cmdutils/filter/nodegroup_filter_test.go b/pkg/ctl/cmdutils/filter/nodegroup_filter_test.go index b7e99a7997..c775a19b62 100644 --- a/pkg/ctl/cmdutils/filter/nodegroup_filter_test.go +++ b/pkg/ctl/cmdutils/filter/nodegroup_filter_test.go @@ -270,6 +270,7 @@ func newClusterConfig() *api.ClusterConfig { cfg.Metadata.Name = "test-3x3-ngs" cfg.Metadata.Region = "eu-central-1" + cfg.Metadata.Version = api.Version1_34 return cfg } @@ -657,7 +658,7 @@ var expected = fmt.Sprintf(` } ] } -`, api.DefaultVersion) +`, api.Version1_34) type mockStackLister struct { nodesResult []manager.NodeGroupStack diff --git a/pkg/ctl/create/cluster.go b/pkg/ctl/create/cluster.go index c79a20b987..965b5ae927 100644 --- a/pkg/ctl/create/cluster.go +++ b/pkg/ctl/create/cluster.go @@ -101,7 +101,7 @@ func createClusterCmdWithRunFunc(cmd *cmdutils.Cmd, runFunc func(cmd *cmdutils.C fs.BoolVar(cfg.IAM.WithOIDC, "with-oidc", false, "Enable the IAM OIDC provider") fs.StringSliceVar(¶ms.AvailabilityZones, "zones", nil, "(auto-select if unspecified)") fs.StringVarP(&cfg.UpgradePolicy.SupportType, "support-type", "", "", "Set cluster's upgradePolicy supportType") - cmdutils.AddVersionFlag(fs, cfg.Metadata, "") + cmdutils.AddVersionFlag(fs, cfg.Metadata, `defaults to the EKS default version; use "latest" for the newest supported version`) cmdutils.AddConfigFileFlag(fs, &cmd.ClusterConfigFile) cmdutils.AddTimeoutFlag(fs, &cmd.ProviderConfig.WaitTimeout) fs.BoolVarP(¶ms.InstallWindowsVPCController, "install-vpc-controllers", "", false, "Install VPC controller that's required for Windows workloads") @@ -153,6 +153,10 @@ func doCreateCluster(cmd *cmdutils.Cmd, ngFilter *filter.NodeGroupFilter, params cfg := cmd.ClusterConfig meta := cmd.ClusterConfig.Metadata + if meta.Version == "" { + return errors.New("EKS did not report a default Kubernetes version; set --version or metadata.version") + } + if meta.Name != "" && api.IsInvalidNameArg(meta.Name) { return api.ErrInvalidName(meta.Name) } diff --git a/pkg/ctl/create/cluster_test.go b/pkg/ctl/create/cluster_test.go index 7c52388537..6a91997b33 100644 --- a/pkg/ctl/create/cluster_test.go +++ b/pkg/ctl/create/cluster_test.go @@ -218,6 +218,26 @@ var _ = Describe("create cluster", func() { ) }) + DescribeTable("version flag", + func(expectedVersion string, args ...string) { + commandArgs := append([]string{"cluster"}, args...) + cmd := newMockEmptyCmd(commandArgs...) + count := 0 + cmdutils.AddResourceCmd(cmdutils.NewGrouping(), cmd.parentCmd, func(cmd *cmdutils.Cmd) { + createClusterCmdWithRunFunc(cmd, func(cmd *cmdutils.Cmd, ngFilter *filter.NodeGroupFilter, params *cmdutils.CreateClusterCmdParams) error { + Expect(cmd.ClusterConfig.Metadata.Version).To(Equal(expectedVersion)) + count++ + return nil + }) + }) + _, err := cmd.execute() + Expect(err).NotTo(HaveOccurred()) + Expect(count).To(Equal(1)) + }, + Entry("without version flag", ""), + Entry("with version flag", "1.33", "--version", "1.33"), + ) + type createClusterEntry struct { updateClusterConfig func(*api.ClusterConfig) updateClusterParams func(*cmdutils.CreateClusterCmdParams) @@ -265,6 +285,7 @@ var _ = Describe("create cluster", func() { clusterConfig := api.NewClusterConfig() clusterConfig.Metadata.Name = clusterName + clusterConfig.Metadata.Version = api.Version1_34 clusterConfig.AddonsConfig.DisableDefaultAddons = true clusterConfig.VPC.ClusterEndpoints = api.ClusterEndpointAccessDefaults() clusterConfig.AccessConfig.AuthenticationMode = ekstypes.AuthenticationModeApiAndConfigMap @@ -311,6 +332,13 @@ var _ = Describe("create cluster", func() { } }, + Entry("fails when the cluster version is not set", createClusterEntry{ + updateClusterConfig: func(c *api.ClusterConfig) { + c.Metadata.Version = "" + }, + expectedErr: "EKS did not report a default Kubernetes version", + }), + Entry("[Cluster with NodeGroups] fails to install device plugins", createClusterEntry{ updateClusterConfig: func(c *api.ClusterConfig) { nodeGroup := getDefaultNodeGroup() diff --git a/pkg/ctl/create/nodegroup.go b/pkg/ctl/create/nodegroup.go index 6d07027d60..9bc87cbdfe 100644 --- a/pkg/ctl/create/nodegroup.go +++ b/pkg/ctl/create/nodegroup.go @@ -149,6 +149,9 @@ func checkNodeGroupVersion(cvm eks.ClusterVersionsManagerInterface, controlPlane meta.Version = "auto" case "default": meta.Version = cvm.DefaultVersion() + if meta.Version == "" { + return fmt.Errorf("EKS did not report a default Kubernetes version; set --version or metadata.version") + } logger.Info("will use default version (%s) for new nodegroup(s)", meta.Version) case "latest": meta.Version = cvm.LatestVersion() diff --git a/pkg/ctl/create/nodegroup_test.go b/pkg/ctl/create/nodegroup_test.go index 947c9c1824..7e808e3e49 100644 --- a/pkg/ctl/create/nodegroup_test.go +++ b/pkg/ctl/create/nodegroup_test.go @@ -177,6 +177,7 @@ var _ = Describe("create nodegroup", func() { type checkNodeGroupVersionInput struct { ctl *eks.ClusterProvider meta *api.ClusterMeta + defaultVersion string expectedVersion string expectedErr string } @@ -198,6 +199,7 @@ var _ = Describe("create nodegroup", func() { return []string{"1.29", "1.30", "1.31"} } cvm.LatestVersionReturns("1.31") + cvm.DefaultVersionReturns(input.defaultVersion) err := checkNodeGroupVersion(cvm, input.ctl.ControlPlaneVersion(), input.meta) if input.expectedErr != "" { Expect(err).To(MatchError(ContainSubstring(input.expectedErr))) @@ -225,6 +227,21 @@ var _ = Describe("create nodegroup", func() { }, expectedVersion: api.Version1_31, }), + Entry("version is set to default", checkNodeGroupVersionInput{ + ctl: providerVersion1_23, + meta: &api.ClusterMeta{ + Version: "default", + }, + defaultVersion: api.Version1_30, + expectedVersion: api.Version1_30, + }), + Entry("version is set to default and EKS does not report a default", checkNodeGroupVersionInput{ + ctl: providerVersion1_23, + meta: &api.ClusterMeta{ + Version: "default", + }, + expectedErr: "EKS did not report a default Kubernetes version", + }), Entry("fails to retrieve control plane version", checkNodeGroupVersionInput{ ctl: &eks.ClusterProvider{ Status: &eks.ProviderStatus{}, diff --git a/pkg/ctl/update/cluster.go b/pkg/ctl/update/cluster.go index 9279c885e2..a5a5da5544 100644 --- a/pkg/ctl/update/cluster.go +++ b/pkg/ctl/update/cluster.go @@ -14,8 +14,6 @@ import ( func updateClusterCmd(cmd *cmdutils.Cmd) { cfg := api.NewClusterConfig() - // Reset version before loading - cfg.Metadata.Version = "" cmd.ClusterConfig = cfg cmd.SetDescription("cluster", "DEPRECATED: use 'upgrade cluster' instead. Upgrade control plane to the next version. ", diff --git a/pkg/ctl/upgrade/cluster.go b/pkg/ctl/upgrade/cluster.go index 25ac4b951a..21da974dba 100644 --- a/pkg/ctl/upgrade/cluster.go +++ b/pkg/ctl/upgrade/cluster.go @@ -24,8 +24,6 @@ func upgradeCluster(cmd *cmdutils.Cmd) { func upgradeClusterWithRunFunc(cmd *cmdutils.Cmd, runFunc func(cmd *cmdutils.Cmd) error) { cfg := api.NewClusterConfig() - // Reset version - cfg.Metadata.Version = "" cmd.ClusterConfig = cfg cmd.SetDescription("cluster", "Upgrade control plane to the next version", diff --git a/pkg/ctl/utils/migrate_to_pod_identity.go b/pkg/ctl/utils/migrate_to_pod_identity.go index 799241101b..9ed93a0379 100644 --- a/pkg/ctl/utils/migrate_to_pod_identity.go +++ b/pkg/ctl/utils/migrate_to_pod_identity.go @@ -74,6 +74,7 @@ func doMigrateToPodIdentity(cmd *cmdutils.Cmd, options podidentityassociation.Po return err } + cfg.Metadata.Version = ctl.ControlPlaneVersion() addonManager, err := addon.New(cfg, ctl.AWSProvider.EKS(), nil, false, nil, nil) if err != nil { return fmt.Errorf("initializing addon creator %w", err) diff --git a/pkg/eks/nodegroup_service_test.go b/pkg/eks/nodegroup_service_test.go index 33d08e72d8..37636e7aff 100644 --- a/pkg/eks/nodegroup_service_test.go +++ b/pkg/eks/nodegroup_service_test.go @@ -78,7 +78,7 @@ var _ = Describe("NodeGroupService", func() { Entry("[Outposts] nodeGroup.instanceType should be set to the smallest available instance type", normalizeEntry{ clusterConfig: &api.ClusterConfig{ Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, Outpost: &api.Outpost{ ControlPlaneOutpostARN: "arn:aws:outposts:us-west-2:1234:outpost/op-1234", @@ -122,7 +122,7 @@ var _ = Describe("NodeGroupService", func() { Entry("[Outposts] unavailable instance type should return an error", normalizeEntry{ clusterConfig: &api.ClusterConfig{ Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, Outpost: &api.Outpost{ ControlPlaneOutpostARN: "arn:aws:outposts:us-west-2:1234:outpost/op-1234", @@ -148,7 +148,7 @@ var _ = Describe("NodeGroupService", func() { Entry("[Outposts] available instance type should not return an error", normalizeEntry{ clusterConfig: &api.ClusterConfig{ Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, Outpost: &api.Outpost{ ControlPlaneOutpostARN: "arn:aws:outposts:us-west-2:1234:outpost/op-1234", @@ -183,7 +183,7 @@ var _ = Describe("NodeGroupService", func() { Entry("instance type should be set to the default instance type", normalizeEntry{ clusterConfig: &api.ClusterConfig{ Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, NodeGroups: []*api.NodeGroup{ { @@ -214,7 +214,7 @@ var _ = Describe("NodeGroupService", func() { Entry(`instance type should be set to "mixed" when using mixed instance types`, normalizeEntry{ clusterConfig: &api.ClusterConfig{ Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, NodeGroups: []*api.NodeGroup{ { @@ -237,7 +237,7 @@ var _ = Describe("NodeGroupService", func() { Entry("instance type should be left unset when instanceSelector or launchTemplate is set", normalizeEntry{ clusterConfig: &api.ClusterConfig{ Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, ManagedNodeGroups: []*api.ManagedNodeGroup{ { diff --git a/pkg/eks/versions_manager.go b/pkg/eks/versions_manager.go index 39e3d69eeb..7d4443a1c3 100644 --- a/pkg/eks/versions_manager.go +++ b/pkg/eks/versions_manager.go @@ -11,7 +11,6 @@ import ( awseks "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/kris-nova/logger" - api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/awsapi" "github.com/weaveworks/eksctl/pkg/utils" ) @@ -100,8 +99,7 @@ func (cvm *ClusterVersionsManager) IsDeprecatedVersion(version string) bool { } func (cvm *ClusterVersionsManager) DefaultVersion() string { - //TODO: replace with output from DescribeClusterVersions endpoint - return api.DefaultVersion + return cvm.defaultVersion } func (cvm *ClusterVersionsManager) LatestVersion() string { @@ -121,6 +119,9 @@ func (cvm *ClusterVersionsManager) ValidateVersion(version string) error { func (cvm *ClusterVersionsManager) ResolveClusterVersion(version string) (string, error) { switch version { case "auto", "": + if cvm.DefaultVersion() == "" { + return "", fmt.Errorf("EKS did not report a default Kubernetes version; set --version or metadata.version") + } return cvm.DefaultVersion(), nil case "latest": return cvm.LatestVersion(), nil diff --git a/pkg/eks/versions_manager_test.go b/pkg/eks/versions_manager_test.go index 8f843865ba..9004747c02 100644 --- a/pkg/eks/versions_manager_test.go +++ b/pkg/eks/versions_manager_test.go @@ -122,3 +122,90 @@ var _ = Describe("upgrade cluster", func() { }), ) }) + +var _ = Describe("resolve cluster version", func() { + type resolveCase struct { + eksDefaultVersion string + givenVersion string + expectedDefaultVersion string + expectedVersion string + expectedErrorText string + } + + DescribeTable("resolves the specified version", + func(c resolveCase) { + var clusterVersions []ekstypes.ClusterVersionInformation + for _, v := range []string{"1.33", "1.34", "1.35", "1.36", "1.37"} { + clusterVersions = append(clusterVersions, ekstypes.ClusterVersionInformation{ + ClusterVersion: utils.StringPtr(v), + DefaultVersion: v == c.eksDefaultVersion, + }) + } + mockProvider := mockprovider.NewMockProvider() + mockProvider.MockEKS().On("DescribeClusterVersions", mock.Anything, &awseks.DescribeClusterVersionsInput{}). + Return(&awseks.DescribeClusterVersionsOutput{ + ClusterVersions: clusterVersions, + }, nil) + + cvm, err := eks.NewClusterVersionsManager(mockProvider.EKS()) + Expect(err).NotTo(HaveOccurred()) + Expect(cvm.DefaultVersion()).To(Equal(c.expectedDefaultVersion)) + + version, err := cvm.ResolveClusterVersion(c.givenVersion) + + if c.expectedErrorText != "" { + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring(c.expectedErrorText)) + } else { + Expect(err).NotTo(HaveOccurred()) + Expect(version).To(Equal(c.expectedVersion)) + } + }, + + Entry("uses the EKS default version when the version is not specified", resolveCase{ + eksDefaultVersion: "1.36", + givenVersion: "", + expectedDefaultVersion: "1.36", + expectedVersion: "1.36", + }), + + Entry("uses the EKS default version when the version is auto", resolveCase{ + eksDefaultVersion: "1.36", + givenVersion: "auto", + expectedDefaultVersion: "1.36", + expectedVersion: "1.36", + }), + + Entry("uses the latest version when the version is latest", resolveCase{ + eksDefaultVersion: "1.36", + givenVersion: "latest", + expectedDefaultVersion: "1.36", + expectedVersion: "1.37", + }), + + Entry("uses the specified version when it is supported", resolveCase{ + eksDefaultVersion: "1.36", + givenVersion: "1.33", + expectedDefaultVersion: "1.36", + expectedVersion: "1.33", + }), + + Entry("fails when the version is not specified and EKS does not flag a default", resolveCase{ + eksDefaultVersion: "", + givenVersion: "", + expectedErrorText: "EKS did not report a default Kubernetes version", + }), + + Entry("fails when the version is auto and EKS does not flag a default", resolveCase{ + eksDefaultVersion: "", + givenVersion: "auto", + expectedErrorText: "EKS did not report a default Kubernetes version", + }), + + Entry("uses the specified version when EKS does not flag a default", resolveCase{ + eksDefaultVersion: "", + givenVersion: "1.35", + expectedVersion: "1.35", + }), + ) +}) diff --git a/pkg/vpc/vpc_test.go b/pkg/vpc/vpc_test.go index 91ef208ae7..35db457729 100644 --- a/pkg/vpc/vpc_test.go +++ b/pkg/vpc/vpc_test.go @@ -827,7 +827,7 @@ var _ = Describe("VPC", func() { cfg: &api.ClusterConfig{ TypeMeta: api.ClusterConfigTypeMeta(), Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, IAM: &api.ClusterIAM{}, VPC: &api.ClusterVPC{ @@ -855,7 +855,7 @@ var _ = Describe("VPC", func() { cfg: &api.ClusterConfig{ TypeMeta: api.ClusterConfigTypeMeta(), Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, IAM: &api.ClusterIAM{}, VPC: &api.ClusterVPC{ @@ -977,7 +977,7 @@ var _ = Describe("VPC", func() { cfg: &api.ClusterConfig{ TypeMeta: api.ClusterConfigTypeMeta(), Metadata: &api.ClusterMeta{ - Version: api.DefaultVersion, + Version: api.Version1_34, }, IAM: &api.ClusterIAM{}, VPC: &api.ClusterVPC{ diff --git a/userdocs/src/getting-started.md b/userdocs/src/getting-started.md index fa46d8a8cc..beb18a8080 100644 --- a/userdocs/src/getting-started.md +++ b/userdocs/src/getting-started.md @@ -124,11 +124,11 @@ eksctl create cluster --name=cluster-1 --nodes=4 ### Supported versions -EKS supports versions `1.23` (extended), `1.24` (extended), `1.25`, `1.26`, `1.27`, `1.28`, `1.29`, **`1.30`** (default) and `1.31`. -With `eksctl` you can deploy any of the supported versions by passing `--version`. +By default, `eksctl` uses the EKS default Kubernetes version (see `eksctl utils describe-cluster-versions --default-only`). +To override it, pass `--version=`, or `--version=latest` for the newest supported version. ```sh -eksctl create cluster --version=1.28 +eksctl create cluster --version=1.35 ``` ### Config-based creation