Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ubuntu 24.04 support #8094

Merged
merged 1 commit into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions integration/tests/custom_ami/custom_ami_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var (
customAMIAL2023 string
customAMIBottlerocket string
customAMIUbuntuPro2204 string
customAMIUbuntuPro2404 string
)

var _ = BeforeSuite(func() {
Expand Down Expand Up @@ -79,6 +80,14 @@ var _ = BeforeSuite(func() {
Expect(err).NotTo(HaveOccurred())
customAMIUbuntuPro2204 = *output.Parameter.Value

// retrieve Ubuntu Pro 24.04 AMI
input = &awsssm.GetParameterInput{
Name: aws.String(fmt.Sprintf("/aws/service/canonical/ubuntu/eks-pro/24.04/%s/stable/current/amd64/hvm/ebs-gp3/ami-id", params.Version)),
}
output, err = ssm.GetParameter(context.Background(), input)
Expect(err).NotTo(HaveOccurred())
customAMIUbuntuPro2404 = *output.Parameter.Value

cmd := params.EksctlCreateCmd.WithArgs(
"cluster",
"--verbose", "4",
Expand Down Expand Up @@ -178,6 +187,28 @@ var _ = Describe("(Integration) [Test Custom AMI]", func() {
})

})

Context("ubuntu-pro-2404 un-managed nodegroups", func() {

It("can create a working nodegroup which can join the cluster", func() {
By(fmt.Sprintf("using the following EKS optimised AMI: %s", customAMIUbuntuPro2404))
content, err := os.ReadFile(filepath.Join("testdata/ubuntu-pro-2404.yaml"))
Expect(err).NotTo(HaveOccurred())
content = bytes.ReplaceAll(content, []byte("<generated>"), []byte(params.ClusterName))
content = bytes.ReplaceAll(content, []byte("<generated-region>"), []byte(params.Region))
content = bytes.ReplaceAll(content, []byte("<generated-ami>"), []byte(customAMIUbuntuPro2404))
cmd := params.EksctlCreateCmd.
WithArgs(
"nodegroup",
"--config-file", "-",
"--verbose", "4",
).
WithoutArg("--region", params.Region).
WithStdin(bytes.NewReader(content))
Expect(cmd).To(RunSuccessfully())
})

})
})

var _ = AfterSuite(func() {
Expand Down
17 changes: 17 additions & 0 deletions integration/tests/custom_ami/testdata/ubuntu-pro-2404.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

# name is generated
metadata:
name: <generated>
region: <generated-region>

nodeGroups:
- name: unm-ubuntu-pro-2404
ami: <generated-ami>
amiFamily: UbuntuPro2404
desiredCapacity: 1
overrideBootstrapCommand: |
#!/bin/bash
source /var/lib/cloud/scripts/eksctl/bootstrap.helper.sh
/etc/eks/bootstrap.sh <generated> --kubelet-extra-args "--node-labels=${NODE_LABELS}"
10 changes: 9 additions & 1 deletion pkg/ami/auto_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,18 @@ func MakeImageSearchPatterns(version string) map[string]map[int]string {
ImageClassNeuron: fmt.Sprintf("amazon-eks-gpu-node-%s-*", version),
ImageClassARM: fmt.Sprintf("amazon-eks-arm64-node-%s-*", version),
},
api.NodeImageFamilyUbuntuPro2404: {
ImageClassGeneral: fmt.Sprintf("ubuntu-eks-pro/k8s_%s/images/*24.04-amd64*", version),
ImageClassARM: fmt.Sprintf("ubuntu-eks-pro/k8s_%s/images/*24.04-arm64*", version),
},
api.NodeImageFamilyUbuntuPro2204: {
ImageClassGeneral: fmt.Sprintf("ubuntu-eks-pro/k8s_%s/images/*22.04-amd64*", version),
ImageClassARM: fmt.Sprintf("ubuntu-eks-pro/k8s_%s/images/*22.04-arm64*", version),
},
api.NodeImageFamilyUbuntu2404: {
ImageClassGeneral: fmt.Sprintf("ubuntu-eks/k8s_%s/images/*24.04-amd64*", version),
ImageClassARM: fmt.Sprintf("ubuntu-eks/k8s_%s/images/*24.04-arm64*", version),
},
api.NodeImageFamilyUbuntu2204: {
ImageClassGeneral: fmt.Sprintf("ubuntu-eks/k8s_%s/images/*22.04-amd64*", version),
ImageClassARM: fmt.Sprintf("ubuntu-eks/k8s_%s/images/*22.04-arm64*", version),
Expand Down Expand Up @@ -68,7 +76,7 @@ func MakeImageSearchPatterns(version string) map[string]map[int]string {
// OwnerAccountID returns the AWS account ID that owns worker AMI.
func OwnerAccountID(imageFamily, region string) (string, error) {
switch imageFamily {
case api.NodeImageFamilyUbuntuPro2204, api.NodeImageFamilyUbuntu2204, api.NodeImageFamilyUbuntu2004, api.NodeImageFamilyUbuntu1804:
case api.NodeImageFamilyUbuntuPro2404, api.NodeImageFamilyUbuntu2404, api.NodeImageFamilyUbuntuPro2204, api.NodeImageFamilyUbuntu2204, api.NodeImageFamilyUbuntu2004, api.NodeImageFamilyUbuntu1804:
return ownerIDUbuntuFamily, nil
case api.NodeImageFamilyAmazonLinux2023, api.NodeImageFamilyAmazonLinux2:
return api.EKSResourceAccountID(region), nil
Expand Down
10 changes: 10 additions & 0 deletions pkg/ami/auto_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ var _ = Describe("AMI Auto Resolution", func() {
Expect(ownerAccount).To(BeEquivalentTo("099720109477"))
Expect(err).NotTo(HaveOccurred())
})
It("should return the Ubuntu Account ID for Ubuntu images", func() {
ownerAccount, err := OwnerAccountID(api.NodeImageFamilyUbuntu2404, region)
Expect(ownerAccount).To(BeEquivalentTo("099720109477"))
Expect(err).NotTo(HaveOccurred())
})
It("should return the Ubuntu Account ID for Ubuntu images", func() {
ownerAccount, err := OwnerAccountID(api.NodeImageFamilyUbuntuPro2404, region)
Expect(ownerAccount).To(BeEquivalentTo("099720109477"))
Expect(err).NotTo(HaveOccurred())
})

It("should return the Windows Account ID for Windows Server images", func() {
ownerAccount, err := OwnerAccountID(api.NodeImageFamilyWindowsServer2022CoreContainer, region)
Expand Down
23 changes: 23 additions & 0 deletions pkg/ami/ssm_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ func MakeSSMParameterName(version, instanceType, imageFamily string) (string, er
return fmt.Sprint("/aws/service/canonical/ubuntu/", eksProduct, "/", ubuntuReleaseName(imageFamily), "/", version, "/stable/current/", ubuntuArchName(instanceType), "/hvm/ebs-gp2/ami-id"), nil
default:
return "", fmt.Errorf("unknown image family %s", imageFamily)
case api.NodeImageFamilyUbuntu2404,
api.NodeImageFamilyUbuntuPro2404:
if err := validateVersionForUbuntu(version, imageFamily); err != nil {
return "", err
}
eksProduct := "eks"
if imageFamily == api.NodeImageFamilyUbuntuPro2404 {
eksProduct = "eks-pro"
}
return fmt.Sprint("/aws/service/canonical/ubuntu/", eksProduct, "/", ubuntuReleaseName(imageFamily), "/", version, "/stable/current/", ubuntuArchName(instanceType), "/hvm/ebs-gp3/ami-id"), nil
}
}

Expand Down Expand Up @@ -177,6 +187,8 @@ func ubuntuReleaseName(imageFamily string) string {
return "20.04"
case api.NodeImageFamilyUbuntu2204, api.NodeImageFamilyUbuntuPro2204:
return "22.04"
case api.NodeImageFamilyUbuntu2404, api.NodeImageFamilyUbuntuPro2404:
return "24.04"
default:
return "18.04"
}
Expand Down Expand Up @@ -214,6 +226,17 @@ func validateVersionForUbuntu(version, imageFamily string) error {
if !supportsUbuntu {
return &UnsupportedQueryError{msg: fmt.Sprintf("%s requires EKS version greater or equal than %s", imageFamily, minVersion)}
}
case api.NodeImageFamilyUbuntu2404, api.NodeImageFamilyUbuntuPro2404:
var err error
supportsUbuntu := false
const minVersion = api.Version1_31
supportsUbuntu, err = utils.IsMinVersion(minVersion, version)
if err != nil {
return err
}
if !supportsUbuntu {
return &UnsupportedQueryError{msg: fmt.Sprintf("%s requires EKS version greater or equal than %s", imageFamily, minVersion)}
}
default:
return &UnsupportedQueryError{msg: fmt.Sprintf("SSM Parameter lookups for %s AMIs is not supported", imageFamily)}
}
Expand Down
112 changes: 112 additions & 0 deletions pkg/ami/ssm_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,118 @@ var _ = Describe("AMI Auto Resolution", func() {
})
})

Context("and Ubuntu2404 family", func() {
BeforeEach(func() {
p = mockprovider.NewMockProvider()
instanceType = "t2.medium"
imageFamily = "Ubuntu2404"
})

DescribeTable("should return an error",
func(version string) {
resolver := NewSSMResolver(p.MockSSM())
resolvedAmi, err = resolver.Resolve(context.Background(), region, version, instanceType, imageFamily)

Expect(err).To(HaveOccurred())
Expect(err).To(MatchError("Ubuntu2404 requires EKS version greater or equal than 1.31"))
},
EntryDescription("When EKS version is %s"),
Entry(nil, "1.21"),
Entry(nil, "1.30"),
)

DescribeTable("should return a valid AMI",
func(version string) {
addMockGetParameter(p, fmt.Sprintf("/aws/service/canonical/ubuntu/eks/24.04/%s/stable/current/amd64/hvm/ebs-gp3/ami-id", version), expectedAmi)

resolver := NewSSMResolver(p.MockSSM())
resolvedAmi, err = resolver.Resolve(context.Background(), region, version, instanceType, imageFamily)

Expect(err).NotTo(HaveOccurred())
Expect(p.MockSSM().AssertNumberOfCalls(GinkgoT(), "GetParameter", 1)).To(BeTrue())
Expect(resolvedAmi).To(BeEquivalentTo(expectedAmi))
},
EntryDescription("When EKS version is %s"),
Entry(nil, "1.31"),
)

Context("for arm instance type", func() {
BeforeEach(func() {
instanceType = "a1.large"
})
DescribeTable("should return a valid AMI for arm64",
func(version string) {
addMockGetParameter(p, fmt.Sprintf("/aws/service/canonical/ubuntu/eks/24.04/%s/stable/current/arm64/hvm/ebs-gp3/ami-id", version), expectedAmi)

resolver := NewSSMResolver(p.MockSSM())
resolvedAmi, err = resolver.Resolve(context.Background(), region, version, instanceType, imageFamily)

Expect(err).NotTo(HaveOccurred())
Expect(p.MockSSM().AssertNumberOfCalls(GinkgoT(), "GetParameter", 1)).To(BeTrue())
Expect(resolvedAmi).To(BeEquivalentTo(expectedAmi))
},
EntryDescription("When EKS version is %s"),
Entry(nil, "1.31"),
)
})
})

Context("and UbuntuPro2404 family", func() {
BeforeEach(func() {
p = mockprovider.NewMockProvider()
instanceType = "t2.medium"
imageFamily = "UbuntuPro2404"
})

DescribeTable("should return an error",
func(version string) {
resolver := NewSSMResolver(p.MockSSM())
resolvedAmi, err = resolver.Resolve(context.Background(), region, version, instanceType, imageFamily)

Expect(err).To(HaveOccurred())
Expect(err).To(MatchError("UbuntuPro2404 requires EKS version greater or equal than 1.31"))
},
EntryDescription("When EKS version is %s"),
Entry(nil, "1.21"),
Entry(nil, "1.30"),
)

DescribeTable("should return a valid AMI",
func(version string) {
addMockGetParameter(p, fmt.Sprintf("/aws/service/canonical/ubuntu/eks-pro/24.04/%s/stable/current/amd64/hvm/ebs-gp3/ami-id", version), expectedAmi)

resolver := NewSSMResolver(p.MockSSM())
resolvedAmi, err = resolver.Resolve(context.Background(), region, version, instanceType, imageFamily)

Expect(err).NotTo(HaveOccurred())
Expect(p.MockSSM().AssertNumberOfCalls(GinkgoT(), "GetParameter", 1)).To(BeTrue())
Expect(resolvedAmi).To(BeEquivalentTo(expectedAmi))
},
EntryDescription("When EKS version is %s"),
Entry(nil, "1.31"),
)

Context("for arm instance type", func() {
BeforeEach(func() {
instanceType = "a1.large"
})
DescribeTable("should return a valid AMI for arm64",
func(version string) {
addMockGetParameter(p, fmt.Sprintf("/aws/service/canonical/ubuntu/eks-pro/24.04/%s/stable/current/arm64/hvm/ebs-gp3/ami-id", version), expectedAmi)

resolver := NewSSMResolver(p.MockSSM())
resolvedAmi, err = resolver.Resolve(context.Background(), region, version, instanceType, imageFamily)

Expect(err).NotTo(HaveOccurred())
Expect(p.MockSSM().AssertNumberOfCalls(GinkgoT(), "GetParameter", 1)).To(BeTrue())
Expect(resolvedAmi).To(BeEquivalentTo(expectedAmi))
},
EntryDescription("When EKS version is %s"),
Entry(nil, "1.31"),
)
})
})

Context("and Bottlerocket image family", func() {
BeforeEach(func() {
instanceType = "t2.medium"
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/outposts_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ var _ = Describe("Outposts validation", func() {
Entry("Ubuntu2004", api.NodeImageFamilyUbuntu2004, true),
Entry("Ubuntu2204", api.NodeImageFamilyUbuntu2204, true),
Entry("UbuntuPro2204", api.NodeImageFamilyUbuntuPro2204, true),
Entry("Ubuntu2404", api.NodeImageFamilyUbuntuPro2204, true),
Entry("UbuntuPro2404", api.NodeImageFamilyUbuntuPro2204, true),
Entry("Windows2019Core", api.NodeImageFamilyWindowsServer2019CoreContainer, true),
Entry("Windows2019Full", api.NodeImageFamilyWindowsServer2019FullContainer, true),
Entry("Windows2022Core", api.NodeImageFamilyWindowsServer2022CoreContainer, true),
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ const (
DefaultNodeImageFamily = NodeImageFamilyAmazonLinux2
NodeImageFamilyAmazonLinux2023 = "AmazonLinux2023"
NodeImageFamilyAmazonLinux2 = "AmazonLinux2"
NodeImageFamilyUbuntuPro2404 = "UbuntuPro2404"
NodeImageFamilyUbuntu2404 = "Ubuntu2404"
NodeImageFamilyUbuntuPro2204 = "UbuntuPro2204"
NodeImageFamilyUbuntu2204 = "Ubuntu2204"
NodeImageFamilyUbuntu2004 = "Ubuntu2004"
Expand Down Expand Up @@ -615,6 +617,8 @@ func SupportedAMIFamilies() []string {
return []string{
NodeImageFamilyAmazonLinux2023,
NodeImageFamilyAmazonLinux2,
NodeImageFamilyUbuntuPro2404,
NodeImageFamilyUbuntu2404,
NodeImageFamilyUbuntuPro2204,
NodeImageFamilyUbuntu2204,
NodeImageFamilyUbuntu2004,
Expand Down
4 changes: 3 additions & 1 deletion pkg/apis/eksctl.io/v1alpha5/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -1568,7 +1568,9 @@ func IsAmazonLinuxImage(imageFamily string) bool {

func IsUbuntuImage(imageFamily string) bool {
switch imageFamily {
case NodeImageFamilyUbuntuPro2204,
case NodeImageFamilyUbuntuPro2404,
NodeImageFamilyUbuntu2404,
NodeImageFamilyUbuntuPro2204,
NodeImageFamilyUbuntu2204,
NodeImageFamilyUbuntu2004,
NodeImageFamilyUbuntu1804:
Expand Down
8 changes: 8 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2183,6 +2183,14 @@ var _ = Describe("ClusterConfig validation", func() {
err = api.ValidateManagedNodeGroup(0, mng)
Expect(err).NotTo(HaveOccurred())

mng.AMIFamily = api.NodeImageFamilyUbuntu2404
err = api.ValidateManagedNodeGroup(0, mng)
Expect(err).NotTo(HaveOccurred())

mng.AMIFamily = api.NodeImageFamilyUbuntuPro2404
err = api.ValidateManagedNodeGroup(0, mng)
Expect(err).NotTo(HaveOccurred())

mng.AMIFamily = api.NodeImageFamilyBottlerocket
mng.OverrideBootstrapCommand = nil
err = api.ValidateManagedNodeGroup(0, mng)
Expand Down
29 changes: 29 additions & 0 deletions pkg/eks/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,35 @@ var _ = Describe("eksctl API", func() {
testEnsureAMI(Equal("ami-ubuntu"), "1.14")
})

It("should resolve AMI using SSM Parameter Store for Ubuntu2404 on 1.31", func() {
provider.MockSSM().On("GetParameter", mock.Anything, &ssm.GetParameterInput{
Name: aws.String("/aws/service/canonical/ubuntu/eks/24.04/1.31/stable/current/amd64/hvm/ebs-gp3/ami-id"),
}).Return(&ssm.GetParameterOutput{
Parameter: &ssmtypes.Parameter{
Value: aws.String("ami-ubuntu"),
},
}, nil)
ng.AMIFamily = api.NodeImageFamilyUbuntu2404

testEnsureAMI(Equal("ami-ubuntu"), "1.31")
})

It("should fall back to auto resolution for Ubuntu2404", func() {
ng.AMIFamily = api.NodeImageFamilyUbuntu2404
mockDescribeImages(provider, "ami-ubuntu", func(input *ec2.DescribeImagesInput) bool {
return input.Owners[0] == "099720109477"
})
testEnsureAMI(Equal("ami-ubuntu"), "1.14")
})

It("should fall back to auto resolution for UbuntuPro2404", func() {
ng.AMIFamily = api.NodeImageFamilyUbuntuPro2404
mockDescribeImages(provider, "ami-ubuntu", func(input *ec2.DescribeImagesInput) bool {
return input.Owners[0] == "099720109477"
})
testEnsureAMI(Equal("ami-ubuntu"), "1.14")
})

It("should retrieve the AMI from EC2 when AMI is auto", func() {
ng.AMI = "auto"
ng.InstanceType = "p2.xlarge"
Expand Down
4 changes: 2 additions & 2 deletions pkg/nodebootstrap/userdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func NewBootstrapper(clusterConfig *api.ClusterConfig, ng *api.NodeGroup) (Boots
return NewWindowsBootstrapper(clusterConfig, ng, clusterDNS), nil
}
switch ng.AMIFamily {
case api.NodeImageFamilyUbuntuPro2204, api.NodeImageFamilyUbuntu2204, api.NodeImageFamilyUbuntu2004, api.NodeImageFamilyUbuntu1804:
case api.NodeImageFamilyUbuntuPro2404, api.NodeImageFamilyUbuntu2404, api.NodeImageFamilyUbuntuPro2204, api.NodeImageFamilyUbuntu2204, api.NodeImageFamilyUbuntu2004, api.NodeImageFamilyUbuntu1804:
return NewUbuntuBootstrapper(clusterConfig, ng, clusterDNS), nil
case api.NodeImageFamilyBottlerocket:
return NewBottlerocketBootstrapper(clusterConfig, ng), nil
Expand Down Expand Up @@ -80,7 +80,7 @@ func NewManagedBootstrapper(clusterConfig *api.ClusterConfig, ng *api.ManagedNod
return NewManagedAL2Bootstrapper(ng), nil
case api.NodeImageFamilyBottlerocket:
return NewManagedBottlerocketBootstrapper(clusterConfig, ng), nil
case api.NodeImageFamilyUbuntu1804, api.NodeImageFamilyUbuntu2004, api.NodeImageFamilyUbuntu2204, api.NodeImageFamilyUbuntuPro2204:
case api.NodeImageFamilyUbuntu1804, api.NodeImageFamilyUbuntu2004, api.NodeImageFamilyUbuntu2204, api.NodeImageFamilyUbuntuPro2204, api.NodeImageFamilyUbuntu2404, api.NodeImageFamilyUbuntuPro2404:
return NewUbuntuBootstrapper(clusterConfig, ng, clusterDNS), nil
}
return nil, nil
Expand Down
Loading
Loading