Skip to content

Commit

Permalink
Allow using user provided version for retrieving node group AMIs (#1286)
Browse files Browse the repository at this point in the history
Previously the user provided kubernetes version wasn't used when
looking up the AMI for a node group. Instead the cluster version
was used implicitely.
This fixes that and allows users to specify the kubernetes version.
This also allows users now to upgrade their cluster control plane
and node groups in multiple steps.

Fixes #1283
  • Loading branch information
flostadler authored Jul 30, 2024
1 parent c5fd959 commit db81ca1
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 1 deletion.
18 changes: 18 additions & 0 deletions examples/examples_nodejs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -811,3 +811,21 @@ func TestAccManagedNodeGroupCustom(t *testing.T) {

integration.ProgramTest(t, &test)
}

func TestAccManagedNodeGroupWithVersion(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: path.Join(getCwd(t), "tests", "managed-ng-with-version"),
ExtraRuntimeValidation: func(t *testing.T, info integration.RuntimeValidationStackInfo) {
utils.RunEKSSmokeTest(t,
info.Deployment.Resources,
info.Outputs["kubeconfig"],
)
},
})

integration.ProgramTest(t, &test)
}
3 changes: 3 additions & 0 deletions examples/tests/managed-ng-with-version/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: managed-ng-with-version
description: Tests that the versions of managed node groups can be configured
runtime: nodejs
3 changes: 3 additions & 0 deletions examples/tests/managed-ng-with-version/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# tests/managed-ng-with-version

Tests that the versions of managed node groups can be configured
40 changes: 40 additions & 0 deletions examples/tests/managed-ng-with-version/iam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
import * as iam from "./iam";

const managedPolicyArns: string[] = [
"arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy",
"arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy",
"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",
"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
];

// Creates a role and attaches the EKS worker node IAM managed policies
export function createRole(name: string): aws.iam.Role {
const role = new aws.iam.Role(name, {
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
Service: "ec2.amazonaws.com",
}),
});

let counter = 0;
for (const policy of managedPolicyArns) {
// Create RolePolicyAttachment without returning it.
const rpa = new aws.iam.RolePolicyAttachment(`${name}-policy-${counter++}`,
{ policyArn: policy, role: role },
);
}

return role;
}

// Creates a collection of IAM roles.
export function createRoles(name: string, quantity: number): aws.iam.Role[] {
const roles: aws.iam.Role[] = [];

for (let i = 0; i < quantity; i++) {
roles.push(iam.createRole(`${name}-role-${i}`));
}

return roles;
}
45 changes: 45 additions & 0 deletions examples/tests/managed-ng-with-version/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as awsx from "@pulumi/awsx";
import * as eks from "@pulumi/eks";
import * as iam from "./iam";

// IAM roles for the node groups.
const role0 = iam.createRole("example-role0");
const role1 = iam.createRole("example-role1");

// Create a new VPC
const eksVpc = new awsx.ec2.Vpc("eks-vpc", {
enableDnsHostnames: true,
cidrBlock: "10.0.0.0/16",
});

// Create an EKS cluster.
const cluster = new eks.Cluster("example-managed-nodegroups", {
skipDefaultNodeGroup: true,
deployDashboard: false,
vpcId: eksVpc.vpcId,
// Public subnets will be used for load balancers
publicSubnetIds: eksVpc.publicSubnetIds,
// Private subnets will be used for cluster nodes
privateSubnetIds: eksVpc.privateSubnetIds,
instanceRoles: [role0, role1],
});

// Export the cluster's kubeconfig.
export const kubeconfig = cluster.kubeconfig;

// Managed node group with parameters that cause a custom launch template to be created
const managedNodeGroup0 = eks.createManagedNodeGroup("example-managed-ng0", {
cluster: cluster,
nodeRole: role0,
kubeletExtraArgs: "--max-pods=500",
enableIMDSv2: true,
version: cluster.eksCluster.version,
}, cluster);

// Simple managed node group
const managedNodeGroup1 = eks.createManagedNodeGroup("example-managed-ng1", {
cluster: cluster,
nodeGroupName: "aws-managed-ng1",
nodeRoleArn: role1.arn,
version: cluster.eksCluster.version,
}, cluster);
13 changes: 13 additions & 0 deletions examples/tests/managed-ng-with-version/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "managed-ng-with-version",
"devDependencies": {
"typescript": "^4.0.0",
"@types/node": "latest"
},
"dependencies": {
"@pulumi/pulumi": "^3.0.0",
"@pulumi/aws": "^6.0.0",
"@pulumi/awsx": "^2.0.2",
"@pulumi/eks": "latest"
}
}
24 changes: 24 additions & 0 deletions examples/tests/managed-ng-with-version/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"outDir": "bin",
"target": "es6",
"lib": [
"es6"
],
"module": "commonjs",
"moduleResolution": "node",
"declaration": true,
"sourceMap": true,
"stripInternal": true,
"experimentalDecorators": true,
"pretty": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true,
"strictNullChecks": true
},
"files": [
"index.ts"
]
}
7 changes: 6 additions & 1 deletion nodejs/eks/nodegroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,8 @@ function createManagedNodeGroupInternal(
let launchTemplate: aws.ec2.LaunchTemplate | undefined;
if (args.kubeletExtraArgs || args.bootstrapExtraArgs || args.enableIMDSv2) {
launchTemplate = createMNGCustomLaunchTemplate(name, args, core, parent, provider);
// EKS doesn't allow setting the kubernetes version in the node group if a custom launch template is used.
delete nodeGroupArgs.version;
}

// Make the aws-auth configmap a dependency of the node group.
Expand Down Expand Up @@ -1867,7 +1869,10 @@ function getRecommendedAMI(
const instanceType = "instanceType" in args ? args.instanceType : undefined;

const amiType = getAMIType(args.amiType, gpu, instanceType);
const amiID = pulumi.output([k8sVersion, amiType]).apply(([version, type]) => {
// if specified use the version from the args, otherwise use the version from the cluster.
const version = args.version ? args.version : k8sVersion;

const amiID = pulumi.output([version, amiType]).apply(([version, type]) => {
const parameterName = `/aws/service/eks/optimized-ami/${version}/${type}/recommended/image_id`;
return pulumi.output(aws.ssm.getParameter({ name: parameterName }, { parent, async: true }))
.value;
Expand Down

0 comments on commit db81ca1

Please sign in to comment.