|
1 | 1 |
|
| 2 | +# Previously, we found AMIs by using the aws_ami data source with a name_regex filter |
| 3 | +# and `most_recent = true`. Unfortunately, `most_recent` means most recently created, |
| 4 | +# and may not be the most recent Kubernetes version if, for example, a previous version |
| 5 | +# had a new `eksbuild`. So instead, we now use the AMI IDs published in SSM. |
| 6 | +# See https://docs.aws.amazon.com/eks/latest/userguide/retrieve-ami-id.html |
| 7 | +# https://docs.aws.amazon.com/eks/latest/userguide/retrieve-ami-id-bottlerocket.html |
| 8 | + |
| 9 | +# Amazon Linux: https://docs.aws.amazon.com/eks/latest/userguide/retrieve-ami-id.html |
| 10 | +# aws ssm get-parameter --name /aws/service/eks/optimized-ami/1.30/amazon-linux-2/recommended/image_id \ |
| 11 | +# --query "Parameter.Value" --output text |
| 12 | +# Bottlerocket https://github.com/bottlerocket-os/bottlerocket/blob/develop/QUICKSTART-EKS.md#finding-an-ami |
| 13 | +# aws ssm get-parameter --name /aws/service/bottlerocket/aws-k8s-1.30/x86_64/latest/image_id \ |
| 14 | +# --query "Parameter.Value" --output text |
| 15 | +# Windows: https://docs.aws.amazon.com/eks/latest/userguide/retrieve-windows-ami-id.html |
| 16 | +# aws ssm get-parameter --name /aws/service/ami-windows-latest/Windows_Server-2019-English-Core-EKS_Optimized-1.30/image_id \ |
| 17 | +# --region region-code --query "Parameter.Value" --output text |
| 18 | + |
| 19 | + |
2 | 20 | locals { |
3 | | - # "amazon-eks-gpu-node-", |
4 | | - arch_label_map = { |
5 | | - AL2_x86_64 = "", |
6 | | - AL2_x86_64_GPU = "-gpu", |
7 | | - AL2_ARM_64 = "-arm64", |
8 | | - BOTTLEROCKET_x86_64 = "x86_64", |
9 | | - BOTTLEROCKET_ARM_64 = "aarch64" |
10 | | - BOTTLEROCKET_ARM_64_NVIDIA = "-gpu" |
11 | | - BOTTLEROCKET_x86_64_NVIDIA = "-gpu" |
12 | | - WINDOWS_CORE_2019_x86_64 = "" |
13 | | - WINDOWS_FULL_2019_x86_64 = "" |
14 | | - WINDOWS_CORE_2022_x86_64 = "" |
15 | | - WINDOWS_FULL_2022_x86_64 = "" |
| 21 | + given_ami_id = length(var.ami_image_id) > 0 |
| 22 | + |
| 23 | + # Public SSM parameters all start with /aws/service/ |
| 24 | + |
| 25 | + ami_os = split("_", var.ami_type)[0] |
| 26 | + |
| 27 | + # format string that makes |
| 28 | + # format(fmt, specifier, k8s_version) the SSM parameter name to retrieve |
| 29 | + |
| 30 | + ami_ssm_format = { |
| 31 | + AL2_x86_64 = "/aws/service/eks/optimized-ami/%[2]v/amazon-linux-2/%[1]v/image_id" |
| 32 | + AL2_x86_64_GPU = "/aws/service/eks/optimized-ami/%[2]v/amazon-linux-2-gpu/%[1]v/image_id" |
| 33 | + AL2_ARM_64 = "/aws/service/eks/optimized-ami/%[2]v/amazon-linux-2-arm64/%[1]v/image_id" |
| 34 | + AL2023_x86_64_STANDARD = "/aws/service/eks/optimized-ami/%[2]v/amazon-linux-2023/x86_64/standard/%[1]v/image_id" |
| 35 | + AL2023_ARM_64_STANDARD = "/aws/service/eks/optimized-ami/%[2]v/amazon-linux-2023/arm64/standard/%[1]v/image_id" |
| 36 | + BOTTLEROCKET_x86_64 = "/aws/service/bottlerocket/aws-k8s-%[2]v/x86_64/%[1]v/image_id" |
| 37 | + BOTTLEROCKET_ARM_64 = "/aws/service/bottlerocket/aws-k8s-%[2]v/arm64/%[1]v/image_id" |
| 38 | + BOTTLEROCKET_x86_64_NVIDIA = "/aws/service/bottlerocket/aws-k8s-%[2]v-nvidia/x86_64/%[1]v/image_id" |
| 39 | + BOTTLEROCKET_ARM_64_NVIDIA = "/aws/service/bottlerocket/aws-k8s-%[2]v-nvidia/arm64/%[1]v/image_id" |
| 40 | + WINDOWS_CORE_2019_x86_64 = "/aws/service/ami-windows-latest/Windows_Server-2019-English-Core-EKS_Optimized-%[2]v/image_id" |
| 41 | + WINDOWS_FULL_2019_x86_64 = "/aws/service/ami-windows-latest/Windows_Server-2019-English-Full-EKS_Optimized-%[2]v/image_id" |
| 42 | + WINDOWS_CORE_2022_x86_64 = "/aws/service/ami-windows-latest/Windows_Server-2022-English-Core-EKS_Optimized-%[2]v/image_id" |
| 43 | + WINDOWS_FULL_2022_x86_64 = "/aws/service/ami-windows-latest/Windows_Server-2022-English-Full-EKS_Optimized-%[2]v/image_id" |
| 44 | + } |
| 45 | + |
| 46 | + release_version_parts = concat(split("-", try(var.ami_release_version[0], "")), ["", ""]) |
| 47 | + amazon_linux_ami_name_release_part = try(join(".", slice(split(".", local.release_version_parts[0]), 0, 2)), "") |
| 48 | + # AMI Public SSM Parameter specifiers? |
| 49 | + # Release versions for AL2 and AL2023 are from https://github.com/awslabs/amazon-eks-ami/releases |
| 50 | + # Amazon Linux Release Version: 1.29.0-20240213 |
| 51 | + # AL2 |
| 52 | + # AMI name: amazon-eks-node-1.29-v20240117 |
| 53 | + # AMI SSM param: /aws/service/eks/optimized-ami/1.29/amazon-linux-2/amazon-eks-node-1.29-v20240117/image_id |
| 54 | + # AL2023 |
| 55 | + # AMI name: amazon-eks-node-al2023-x86_64-standard-1.29-v20240213 |
| 56 | + # AMI SSM param: /aws/service/eks/optimized-ami/1.29/amazon-linux-2023/x86_64/standard/amazon-eks-node-al2023-x86_64-standard-1.29-v20240213/image_id |
| 57 | + # Specifiers for Bottlerocket are the bare release version (e.g. `1.18.0`) or |
| 58 | + # the release version and the first 8 characters of the commit hash (e.g. `1.18.0-7452c37e`). NOTE: GitHub commit hash abbreviations are only 7 characters. |
| 59 | + # From: |
| 60 | + # Bottlerocket: |
| 61 | + # AMI name: bottlerocket-aws-k8s-1.29-nvidia-x86_64-v1.18.0-7452c37e |
| 62 | + # AMI SSM param: /aws/service/bottlerocket/aws-k8s-1.26-nvidia/x86_64/1.18.0/image_id # No "v" |
| 63 | + # /aws/service/bottlerocket/aws-k8s-1.26-nvidia/x86_64/1.18.0-7452c37e/image_id |
| 64 | + # Windows does not allow a specifier for SSM parameters, they only have the latest AMI ID |
| 65 | + ami_specifier_amazon_linux = { |
| 66 | + AL2_x86_64 = format("amazon-eks-node-%v-v%v", local.amazon_linux_ami_name_release_part, local.release_version_parts[1]) |
| 67 | + AL2_x86_64_GPU = format("amazon-eks-gpu-node-%v-v%v", local.amazon_linux_ami_name_release_part, local.release_version_parts[1]) |
| 68 | + AL2_ARM_64 = format("amazon-eks-arm64-node-%v-v%v", local.amazon_linux_ami_name_release_part, local.release_version_parts[1]) |
| 69 | + AL2023_x86_64_STANDARD = format("amazon-eks-node-al2023-x86_64-standard-%v-v%v", local.amazon_linux_ami_name_release_part, local.release_version_parts[1]) |
| 70 | + AL2023_ARM_64_STANDARD = format("amazon-eks-node-al2023-arm64-standard-%v-v%v", local.amazon_linux_ami_name_release_part, local.release_version_parts[1]) |
16 | 71 | } |
17 | 72 |
|
18 | | - ami_kind = split("_", var.ami_type)[0] != "WINDOWS" ? split("_", var.ami_type)[0] : format("WINDOWS_%s_%s", split("_", var.ami_type)[1], split("_", var.ami_type)[2]) |
19 | | - |
20 | | - ami_format = { |
21 | | - # amazon-eks{arch_label}-node-{ami_kubernetes_version}-v{ami_version} |
22 | | - # e.g. amazon-eks-arm64-node-1.21-v20211013 |
23 | | - AL2 = "amazon-eks%s-node-%s" |
24 | | - # bottlerocket-aws-k8s-{ami_kubernetes_version}-{arch_label}-v{ami_version} |
25 | | - # e.g. bottlerocket-aws-k8s-1.21-x86_64-v1[2].0-ccf1b754 |
26 | | - BOTTLEROCKET = "bottlerocket-aws-k8s-%s-%s-%s" |
27 | | - # Windows_Server-2019-English-Core-EKS_Optimized-{ami_kubernetes_version}-{ami_version} |
28 | | - # e.g. Windows_Server-2019-English-Core-EKS_Optimized-1.23-2022.11.08 |
29 | | - WINDOWS_CORE_2019 = "Windows_Server-2019-English-Core-EKS_Optimized-%s-%s" |
30 | | - WINDOWS_FULL_2019 = "Windows_Server-2019-English-Full-EKS_Optimized-%s-%s" |
31 | | - WINDOWS_CORE_2022 = "Windows_Server-2022-English-Core-EKS_Optimized-%s-%s" |
32 | | - WINDOWS_FULL_2022 = "Windows_Server-2022-English-Full-EKS_Optimized-%s-%s" |
| 73 | + ami_specifier = length(var.ami_release_version) == 0 ? (local.ami_os == "BOTTLEROCKET" ? "latest" : "recommended") : ( |
| 74 | + lookup(local.ami_specifier_amazon_linux, var.ami_type, var.ami_release_version[0]) |
| 75 | + ) |
| 76 | + |
| 77 | + # As usual, Windows is difficult. |
| 78 | + is_window_version = local.ami_os == "WINDOWS" && local.ami_specifier != "recommended" |
| 79 | + |
| 80 | + windows_name_base = { |
| 81 | + WINDOWS_CORE_2019_x86_64 = "Windows_Server-2019-English-Core-EKS_Optimized" |
| 82 | + WINDOWS_FULL_2019_x86_64 = "Windows_Server-2019-English-Full-EKS_Optimized" |
| 83 | + WINDOWS_CORE_2022_x86_64 = "Windows_Server-2022-English-Core-EKS_Optimized" |
| 84 | + WINDOWS_FULL_2022_x86_64 = "Windows_Server-2022-English-Full-EKS_Optimized" |
33 | 85 | } |
34 | 86 |
|
35 | | - # Kubernetes version priority (first one to be set wins) |
36 | | - # 1. prefix of var.ami_release_version |
37 | | - # 2. var.kubernetes_version |
38 | | - # 3. data.eks_cluster.this.kubernetes_version |
39 | | - need_cluster_kubernetes_version = local.enabled ? local.need_ami_id && length(var.kubernetes_version) == 0 : false |
40 | | - |
41 | | - use_cluster_kubernetes_version = local.need_cluster_kubernetes_version && (local.ami_kind == "BOTTLEROCKET" || length(var.ami_release_version) == 0) |
42 | | - |
43 | | - ami_kubernetes_version = local.need_ami_id ? (local.use_cluster_kubernetes_version ? data.aws_eks_cluster.this[0].version : |
44 | | - regex("^(\\d+\\.\\d+)", coalesce(local.ami_kind == "AL2" ? try(var.ami_release_version[0], null) : null, try(var.kubernetes_version[0], null)))[0] |
45 | | - ) : "" |
46 | | - |
47 | | - # if ami_release_version is provided |
48 | | - ami_version_regex = local.need_ami_id ? { |
49 | | - # if ami_release_version = "1.21-20211013" |
50 | | - # insert the letter v prior to the ami_version so it becomes 1.21-v20211013 |
51 | | - # if not, use the kubernetes version |
52 | | - AL2 = (length(var.ami_release_version) == 1 ? replace(var.ami_release_version[0], "/^(\\d+\\.\\d+)\\.\\d+-(\\d+)$/", "$1-v$2") : "${local.ami_kubernetes_version}-*"), |
53 | | - # if ami_release_version = "1.2.0-ccf1b754" |
54 | | - # prefix the ami release version with the letter v |
55 | | - # if not, use an asterisk |
56 | | - BOTTLEROCKET = (length(var.ami_release_version) == 1 ? format("v%s", var.ami_release_version[0]) : "*"), |
57 | | - WINDOWS_CORE_2019 = (length(var.ami_release_version) == 1 ? format("%s", var.ami_release_version[0]) : "*"), |
58 | | - WINDOWS_FULL_2019 = (length(var.ami_release_version) == 1 ? format("%s", var.ami_release_version[0]) : "*"), |
59 | | - WINDOWS_CORE_2022 = (length(var.ami_release_version) == 1 ? format("%s", var.ami_release_version[0]) : "*"), |
60 | | - WINDOWS_FULL_2022 = (length(var.ami_release_version) == 1 ? format("%s", var.ami_release_version[0]) : "*"), |
61 | | - } : {} |
62 | | - |
63 | | - ami_regex = local.need_ami_id ? { |
64 | | - AL2 = format(local.ami_format["AL2"], local.arch_label_map[var.ami_type], local.ami_version_regex[local.ami_kind]), |
65 | | - BOTTLEROCKET = format(local.ami_format["BOTTLEROCKET"], local.ami_kubernetes_version, local.arch_label_map[var.ami_type], local.ami_version_regex[local.ami_kind]), |
66 | | - WINDOWS_CORE_2019 = format(local.ami_format["WINDOWS_CORE_2019"], local.ami_kubernetes_version, local.ami_version_regex[local.ami_kind]), |
67 | | - WINDOWS_FULL_2019 = format(local.ami_format["WINDOWS_FULL_2019"], local.ami_kubernetes_version, local.ami_version_regex[local.ami_kind]), |
68 | | - WINDOWS_CORE_2022 = format(local.ami_format["WINDOWS_CORE_2022"], local.ami_kubernetes_version, local.ami_version_regex[local.ami_kind]), |
69 | | - WINDOWS_FULL_2022 = format(local.ami_format["WINDOWS_FULL_2022"], local.ami_kubernetes_version, local.ami_version_regex[local.ami_kind]), |
70 | | - } : {} |
| 87 | + # We do not really need to compute all the names, but it makes debugging easier if we do. |
| 88 | + ami_name_windows = { for k, v in local.windows_name_base : k => format("%s-%s", v, try(var.ami_release_version[0], "")) } |
| 89 | + |
| 90 | + fetched_ami_id = try(local.is_window_version ? data.aws_ami.windows_ami[0].image_id : data.aws_ssm_parameter.ami_id[0].insecure_value, "") |
| 91 | + ami_id = local.given_ami_id ? var.ami_image_id[0] : local.fetched_ami_id |
71 | 92 | } |
72 | 93 |
|
73 | | -data "aws_ami" "selected" { |
74 | | - count = local.enabled && local.need_ami_id ? 1 : 0 |
| 94 | +data "aws_ssm_parameter" "ami_id" { |
| 95 | + count = local.need_to_get_ami_id && !local.is_window_version ? 1 : 0 |
75 | 96 |
|
76 | | - most_recent = true |
77 | | - name_regex = local.ami_regex[local.ami_kind] |
| 97 | + name = format(local.ami_ssm_format[var.ami_type], local.ami_specifier, local.resolved_kubernetes_version) |
| 98 | + |
| 99 | + lifecycle { |
| 100 | + precondition { |
| 101 | + condition = var.ami_type != "CUSTOM" |
| 102 | + error_message = "The AMI ID must be supplied when AMI type is \"CUSTOM\"." |
| 103 | + } |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +data "aws_ami" "windows_ami" { |
| 108 | + count = local.need_to_get_ami_id && local.is_window_version ? 1 : 0 |
78 | 109 |
|
79 | 110 | owners = ["amazon"] |
| 111 | + filter { |
| 112 | + name = "name" |
| 113 | + values = [local.ami_name_windows[var.ami_type]] |
| 114 | + } |
80 | 115 | } |
| 116 | + |
0 commit comments