Skip to content

Commit

Permalink
feat: add CUSTOM amiType
Browse files Browse the repository at this point in the history
  • Loading branch information
Artemigos committed Jun 25, 2024
1 parent 8ebfade commit b8792a2
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 8 deletions.
11 changes: 10 additions & 1 deletion packages/aws-cdk-lib/aws-eks/lib/managed-nodegroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export enum NodegroupAmiType {
* Amazon Linux 2023 (ARM-64)
*/
AL2023_ARM_64_STANDARD = 'AL2023_ARM_64_STANDARD',
/**
* Custom AMI defined in the launch template
*/
CUSTOM = 'CUSTOM',
}

/**
Expand Down Expand Up @@ -426,7 +430,7 @@ export class Nodegroup extends Resource implements INodegroup {
* 1. instance types of different CPU architectures are not mixed(e.g. X86 with ARM).
* 2. user-specified amiType should be included in `possibleAmiTypes`.
*/
possibleAmiTypes = getPossibleAmiTypes(instanceTypes);
possibleAmiTypes = getPossibleAmiTypes(instanceTypes).concat(NodegroupAmiType.CUSTOM);

// if the user explicitly configured an ami type, make sure it's included in the possibleAmiTypes
if (props.amiType && !possibleAmiTypes.includes(props.amiType)) {
Expand All @@ -442,6 +446,11 @@ export class Nodegroup extends Resource implements INodegroup {
}
}

// custom AMI type can be used only when there's a launch template that picks an AMI
if (props.amiType === NodegroupAmiType.CUSTOM && !props.launchTemplateSpec) {
throw new Error('When amiType is CUSTOM, launchTemplateSpec must be defined');
}

if (!props.nodeRole) {
const ngRole = new Role(this, 'NodeGroupRole', {
assumedBy: new ServicePrincipal('ec2.amazonaws.com'),
Expand Down
54 changes: 47 additions & 7 deletions packages/aws-cdk-lib/aws-eks/test/nodegroup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ describe('node group', () => {
new ec2.InstanceType('p3.large'),
new ec2.InstanceType('g3.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64_GPU, BOTTLEROCKET_X86_64_NVIDIA, BOTTLEROCKET_ARM_64_NVIDIA or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64_GPU, BOTTLEROCKET_X86_64_NVIDIA, BOTTLEROCKET_ARM_64_NVIDIA, CUSTOM or don't specify any/);
});

/**
Expand All @@ -669,7 +669,7 @@ describe('node group', () => {
new ec2.InstanceType('c6g.large'),
new ec2.InstanceType('t4g.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_ARM_64, AL2023_ARM_64_STANDARD, BOTTLEROCKET_ARM_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_ARM_64, AL2023_ARM_64_STANDARD, BOTTLEROCKET_ARM_64, CUSTOM or don't specify any/);
});

/**
Expand All @@ -691,7 +691,7 @@ describe('node group', () => {
new ec2.InstanceType('m5.large'),
new ec2.InstanceType('c5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64, CUSTOM or don't specify any/);
});

/**
Expand All @@ -713,7 +713,7 @@ describe('node group', () => {
new ec2.InstanceType('c5.large'),
new ec2.InstanceType('m5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64, CUSTOM or don't specify any/);
});

test('throws when AmiType is Windows and forbidden instanceType is selected', () => {
Expand Down Expand Up @@ -752,7 +752,7 @@ describe('node group', () => {
new ec2.InstanceType('c5.large'),
new ec2.InstanceType('m5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64, CUSTOM or don't specify any/);
});

test('throws when LaunchTemplate is undefined, amiType is BOTTLEROCKET_ARM_64_NVIDIA and instanceTypes are not GPU', () => {
Expand All @@ -770,7 +770,7 @@ describe('node group', () => {
new ec2.InstanceType('c5.large'),
new ec2.InstanceType('m5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64, CUSTOM or don't specify any/);
});

test('throws when LaunchTemplate is undefined, amiType is BOTTLEROCKET_X86_64_NVIDIA and instanceTypes are not GPU', () => {
Expand All @@ -788,7 +788,21 @@ describe('node group', () => {
new ec2.InstanceType('c5.large'),
new ec2.InstanceType('m5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64, CUSTOM or don't specify any/);
});

test('throws when LaunchTemplate is undefined and amiType is CUSTOM', () => {
// GIVEN
const { stack, vpc } = testFixture();
const cluster = new eks.Cluster(stack, 'Cluster', {
vpc,
defaultCapacity: 0,
version: CLUSTER_VERSION,
});
// THEN
expect(() => cluster.addNodegroupCapacity('ng', {
amiType: NodegroupAmiType.CUSTOM,
})).toThrow(/When amiType is CUSTOM, launchTemplateSpec must be defined/);
});

/**
Expand Down Expand Up @@ -878,6 +892,32 @@ describe('node group', () => {
expect(ng).not.toHaveProperty('AmiType');
});

/**
* When LaunchTemplate is defined and amiType is CUSTOM, we should deploy correctly.
*/
test('deploy correctly with defined LaunchTemplate and instanceTypes(x86_64) and amiType undefined.', () => {
// GIVEN
const { stack, vpc } = testFixture();

// WHEN
const cluster = new eks.Cluster(stack, 'Cluster', {
vpc,
defaultCapacity: 0,
version: CLUSTER_VERSION,
});
cluster.addNodegroupCapacity('ng', {
amiType: NodegroupAmiType.CUSTOM,
launchTemplateSpec: {
id: 'mock',
},
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::EKS::Nodegroup', {
AmiType: 'CUSTOM',
});
});

/**
* BOTTLEROCKET_X86_64 with defined instance types w/o launchTemplateSpec should deploy correctly.
*/
Expand Down

0 comments on commit b8792a2

Please sign in to comment.