aws-cdk
aws-cdk copied to clipboard
@aws-cdk/aws-ec2: Wrong enum declare enum AmazonLinuxKernel
Describe the bug
the enum declare enum AmazonLinuxKernel return 5.10 as latest kernel where it should be 5.15 for AMAZON_LINUX_2022
This leads to an error in CDK when trying to deploy:
failed: Error [ValidationError]: Unable to fetch parameters [/aws/service/ami-amazon-linux-latest/al2022-ami-kernel-5.10-x86_64] from parameter store for this account.
at Request.extractError (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/protocol/query.js:50:29)
at Request.callListeners (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at Request.emit (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/request.js:686:14)
at Request.transition (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/request.js:688:12)
at Request.callListeners (/home/adonis/work/FOLDER/FOLDER-cicd/CORE/node_modules/node_modules/aws-sdk/lib/sequential_executor.js:116:18) {
code: 'ValidationError',
time: 2022-07-06T10:59:21.163Z,
requestId: '4b933ef2-11b7-4525-8ac2-59252ad34825',
statusCode: 400,
retryable: false,
retryDelay: 311.0208741007581
}
Unable to fetch parameters [/aws/service/ami-amazon-linux-latest/al2022-ami-kernel-5.10-x86_64] from parameter store for this account.
Expected Behavior
to return 5.15
Current Behavior
it returns 5.10
Reproduction Steps
new ec2.Instance(that, "id", {
instanceName: "name",
vpc: options.vpc,
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T3A,
ec2.InstanceSize.MICRO
),
machineImage: new ec2.AmazonLinuxImage({
generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2022,
}),
vpcSubnets: {
subnetType: ec2.SubnetType.PUBLIC,
},
securityGroup: securityGroup,
keyName: "key",
userData: ec2.UserData.custom(
fs.readFileSync("./lib/scripts/ssh-tunnel.sh", "utf8")
),
});
Possible Solution
No response
Additional Information/Context
No response
CDK CLI Version
1.162.0 (build 0bad87b)
Framework Version
No response
Node.js Version
v16.13.1
OS
Linux (X86_64)
Language
Typescript
Language Version
4.6.3
Other information
No response
This should be correct according to AL2022 docs https://docs.aws.amazon.com/linux/al2022/ug/get-started.html#launch-from-cloudformation
However, you can see here that as you say, it's been updated to 5.15
We can fix this pretty easily, all we have to do is update the enum in the code here https://github.com/aws/aws-cdk/blob/v1.162.0/packages/@aws-cdk/aws-ec2/lib/machine-image.ts#L480-L485
@robertd @corymhall I think that having the 5_X is confusing if we were to add a 5_15. Should we update the 5_X enum to be equal to 5.15, or should we deprecate 5_X and create two new values for 5_10 and 5_15?
I think what we may want to do here is to use the default kernel version instead of specifying a
specific version. For example /aws/service/ami-amazon-linux-latest/al2022-ami-kernel-default-x86_64 will default to
the latest version.
AMIs are the same.
aws ssm get-parameters --names /aws/service/ami-amazon-linux-latest/al2022-ami-kernel-default-x86_64 /aws/service/ami-amazon-linux-latest/al2022-ami-kernel-5.15-x86_64 --profile sandbox --query 'Parameters[].Value'
Another, larger effort option is to change the kernel version enum into an abstract class the provides all of the options + an override.
e.g.
AmazonLinuxKernel.DEFAULT;
AmazonLinuxKernel.5_10;
AmazonLinuxKernel.of('kernel-5.10');
It seems like this issue impacts a significant number of customers, and I've tagged it as P1, which means it should be on our near-term roadmap.
We welcome community contributions! If you are able, we encourage you to contribute (https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) a bug fix or new feature to the CDK. If you decide to contribute, please start an engineering discussion in this issue to ensure there is a commonly understood design before submitting code. This will minimize the number of review cycles and get your code merged faster.
Ugh... I remember this being such a pain in the rear to add more options to it w/o introducing a breaking change. #18117
I gave it a shot – would love to be able to run cdk deploy again with my stack ❤️
Thanks for the contribution @tomfa! We should be able to take a look soon
Encountered the same issue with 2.37.0 (build aba5ef6) when tried to use AMAZON_LINUX_2022.
So just for the record, a workaround is to look up a valid image here and directly reference the SSM parameter like so?
machineImage: ec2.MachineImage.fromSsmParameter('/aws/service/ami-amazon-linux-latest/al2022-ami-kernel-5.15-x86_64')
@486 yes that is the workaround for now. Long term we will be refactoring the AmazonLinuxImage to better handle the differences between the generations.
@corymhall Any update on this blocker? Even if just the AmazonLInuxKernel enum allowed for KERNEL_DEFAULT, this would make this much better than current state, where the AmazonLinuxImage class is unusable for AL2022.
@jsamuel1 I've thought a little bit about the design of a new implementation, but haven't had the time to start working on it. I'm just putting it here if someone wants to pick it up since I probably won't have time in the near term.
This is an interesting use case and one of the only places that we are using “latest” today. This works by pulling the AMI to use from an AWS managed SSM parameter. To view the currently available options run the following command:
As an aside, Currently this uses a value that is resolved at deploy time, i.e. AWS::SSM::Parameter::ValueAWS::EC2::Image::Id
This can cause errors on deploy if the parameter doesn't exist (it could have been removed on deprecation). Another option could be to use a
fromLookupinstead and resolve the AMI at synth time. This would provide another interpretation of "latest" since we would cache the value in cdk.context.json. "latest" would mean latest version at the time of initial lookup, but after that the user would have to "pull" updates by clearing and updating the context.
aws ssm get-parameters-by-path --path /aws/service/ami-amazon-linux-latest
latestAmazonLinux constructs the correct path based on a bunch of different criteria.
- The generation (Amazon Linux(2)(2022))
- Edition
- Kernel version
- virtualization
- CPU type (x86 or arm)
- storage
You end up with something like this /aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2.
I propose we depricate latestAmazonLinux and create three+ new methods, latestAmznLinux, latestAmznLinux2, & latestAmznLinux2022. Each generation should be treated as a separate option because they are different distributions. They also have different supported criteria (listed above).
Here is a rough high level implementation to illustrate. I’ve also separated out AmznLinux2 into latestAmznLinux2 & defaultAmznLinux2. This is similar to how we would implement a LATEST and an LTS. The default kernel version installed in Amazon Linux 2 is 4.14 and will be supported until Amazon Linux 2 goes EOL, but there is a newer version that is available. Users can select defaultAmznLinux2 and still get updated AMIs, but know that the kernel version will stay the default. An important caveat is that it may be possible for the default to change (just like how LTS versions change), but it will change less frequently.
/**
* Common options across all generations. These options
* do not affect the "version" of the AMI so the user
* can specify. Note that the user cannot specify
* the kernelVersion because that should always be the "latest"
*/
export interface LatestAmznLinuxOptions {
readonly edition?: AmazonLinuxEdition;
readonly cpuType?: AmazonLinuxCpuType;
}
/**
* Storage doesn't apply to al2022 for example
*/
export interface LatestAmznLinuxProps extends LatestAmznLinuxOptions {
readonly storage?: AmazonLinuxStorage;
readonly virtualization?: AmazonLinuxVirt;
}
export interface LatestAmznLinux2022Props extends LatestAmznLinuxOptions {}
export class MachineImage {
public latestAmznLinux(props: LatestAmznLinuxProps): MachineImage {
return new AmznLinuxImage(props);
};
public latestAmznLinxu2(props: LatestAmznLinux2Props): MachineImage {
return new AmznLinux2Image({
...props,
kernelVersion: AmznLinux2Kernel.LATEST,
});
};
public defaultAmznLinux2(props: LatestAmznLinux2Props): MachineImage {
return new AmznLinux2Image({
...props,
kernelVersion: AmznLinux2Kernel.DEFAULT,
});
};
}
export class AmznLinux2Kernel extends AmazonLinuxKernelVersion {
/**
* The latest kernel version available as an SSM parameter is 5.10.
* Version 5.15 is technically the "latest" kernel version
* but it is not yet available in an AMI
* (users have to manually upgrade the kernel).
*
* When an AMI for 5.15 is released this will be updated to 5.15
*/
public static readonly LATEST = new AmznLinux2Kernel('5.10');
/**
* The default kernel version for Amazon Linux 2 is 4.14 and
* the SSM parameter does not include it in the name
* (i.e.
* /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2)
*/
public static readonly DEFAULT = new AmznLinux2Kernel('default');
public static readonly KERNEL_5_10 = new AmznLinux2Kernel('5.10');
/**
*
* @deprecated - this specific version can no longer be specified.
* 4.14 is now available as the DEFAULT version.
*/
public static readonly KERNEL_4_14 = new AmznLinux2Kernel('4.14');
constructor(private readonly version: string) {}
public toString(): {
return this.version === 'default'
? undefined
: `kernel-${this.version}`;
}
}
Now if a user wants to consume this.
new ec2.Instance(this, 'Instance', {
machineImage: MachineImage.latestAmznLinux2(),
});
// or you can still be very specific
new ec2.Instance(this, 'Instance', {
machineImage: new AmznLinux2Image({
kernelVersion: AmznLinux2Kernel.KERNEL_5_10,
edition: AmazonLinuxEdition.MINIMAL,
});
});
Benefits of this approach
- Users must opt-in to using a “latest” version. It is explicitly clear that when they do so this will always be the latest version in that category.
- Users can otherwise specify a specific version to deploy, which they can manually update when they are ready.
Limitations of this approach
- We need to keep up with “latest”.
I like the approach proposed by @corymhall above. It also allows us to inject a warning message similar to when certain properties are deprecated to advise customers to stop using Amazon Linux 1 and (eventually) Amazon Linux 2 when they go into EoS.
The downside, about needing to keep up with "latest", can be mitigated by having an internal discussion with the Amazon Linux AMI publishing team. Insist that they provide more "generic" parameters that we can take advantage of, for example, Amazon Linux 2 should have either a "5.x" kernel version, or a "default".
It also allows us to expand the scope into different families using this as a template. For example, we could look into doing the same for Ubuntu AMIs.
We will, until Version 3, need to maintain a deprecated "meta" class that points to the variant classes, but that doesn't seem too bad. At least we can provide warnings like if someone uses Amazon Linux 2022 in the meta class we can say "please instead use this class as you will run into issues when attempting to deploy this template" with an error.
Aside: I do thing there is scope to discuss things like "schema" vs "functionality" updates. At the moment they're coupled, but it may be worth separating them out, and the "schema" can be auto-generated based upon upstream inputs. It would complicate the troubleshooting a little bit, but would allow people who experience a breaking change in a functionality still to use the latest "schema", but that's probably out of scope for this thread.
⚠️COMMENT VISIBILITY WARNING⚠️
Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.