Skip to content

Commit

Permalink
Merge pull request #2378 from guardian/ash/explicit-user-data
Browse files Browse the repository at this point in the history
feat(ec2): Require explicit `UserData` type instead of `string` in Pattern props.
  • Loading branch information
AshCorr authored Jul 22, 2024
2 parents d424632 + cf58c7b commit 234bca7
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 60 deletions.
32 changes: 32 additions & 0 deletions .changeset/thick-owls-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
"@guardian/cdk": major
---

GuCDK EC2 patterns now require an explicit `UserData` or `GuUserDataProps` input, instead of a string.

The UserData class comes with helpers that allow us to mutate the user data in our patterns which will be helpful with some of our upcoming work.
Unfortunately whenever a `string` is passed to our patterns we have to wrap it in a special `CustomUserData` class which disables most of these helpers.

For applications that were already using `GuUserDataProps` no change is required, however applications that used strings will have to make a small change.

```js
new GuEc2App({
userData: `#!/usr/bin/bash echo "hello world"`,
...
})
```

becomes

```js
const userData = UserData.forLinux();
userData.addCommands(`echo "hello world"`);

new GuEc2App({
userData,
...
})
```

Note that you no longer need to specify a shebang, by default `UserData` adds one for you. If you need to customize this behaviour you can look at the props accepted by `forLinux`.
You may also want to look at some of the other methods that UserData has to understand if it may be able to help you in other ways, for example `addS3DownloadCommand` the method helps you write commands to download from S3.
8 changes: 4 additions & 4 deletions src/constructs/autoscaling/asg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ describe("The GuAutoScalingGroup", () => {

new GuAutoScalingGroup(stack, "AutoscalingGroup", {
app: "TestApp",
userData: "SomeUserData",
userData: UserData.forLinux(),
instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),
vpc,
minimumInstances: 1,
Expand All @@ -194,7 +194,7 @@ describe("The GuAutoScalingGroup", () => {

new GuAutoScalingGroup(stack, "AutoscalingGroup", {
app: "TestApp",
userData: "UserData",
userData: UserData.forLinux(),
instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),
vpc,
role: new GuInstanceRole(stack, {
Expand Down Expand Up @@ -243,7 +243,7 @@ describe("The GuAutoScalingGroup", () => {

new GuAutoScalingGroup(stack, "AutoscalingGroup", {
app: "TestApp",
userData: "SomeUserData",
userData: UserData.forLinux(),
instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),
vpc,
minimumInstances: 3,
Expand All @@ -260,7 +260,7 @@ describe("The GuAutoScalingGroup", () => {

new GuAutoScalingGroup(stack, "AutoscalingGroup", {
app: "TestApp",
userData: "SomeUserData",
userData: UserData.forLinux(),
instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),
vpc,
minimumInstances: 2,
Expand Down
10 changes: 4 additions & 6 deletions src/constructs/autoscaling/asg.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Tags, Token } from "aws-cdk-lib";
import { AutoScalingGroup, GroupMetric, GroupMetrics } from "aws-cdk-lib/aws-autoscaling";
import type { AutoScalingGroupProps, CfnAutoScalingGroup } from "aws-cdk-lib/aws-autoscaling";
import { LaunchTemplate, OperatingSystemType, UserData } from "aws-cdk-lib/aws-ec2";
import type { InstanceType, ISecurityGroup, MachineImageConfig } from "aws-cdk-lib/aws-ec2";
import { LaunchTemplate, OperatingSystemType } from "aws-cdk-lib/aws-ec2";
import type { InstanceType, ISecurityGroup, MachineImageConfig, UserData } from "aws-cdk-lib/aws-ec2";
import type { ApplicationTargetGroup } from "aws-cdk-lib/aws-elasticloadbalancingv2";
import type { GuAsgCapacity } from "../../types";
import type { AmigoProps } from "../../types/amigo";
Expand Down Expand Up @@ -45,7 +45,7 @@ export interface GuAutoScalingGroupProps
*/
imageRecipe?: string | AmigoProps;
instanceType: InstanceType;
userData: UserData | string;
userData: UserData;
additionalSecurityGroups?: ISecurityGroup[];
targetGroup?: ApplicationTargetGroup;
withoutImdsv2?: boolean;
Expand Down Expand Up @@ -90,7 +90,7 @@ export class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) {
maximumInstances,
role = new GuInstanceRole(scope, { app }),
targetGroup,
userData: userDataLike,
userData,
vpc,
withoutImdsv2 = false,
httpPutResponseHopLimit,
Expand All @@ -104,8 +104,6 @@ export class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) {
);
}

const userData = userDataLike instanceof UserData ? userDataLike : UserData.custom(userDataLike);

// Generate an ID unique to this app
const launchTemplateId = `${scope.stack}-${scope.stage}-${app}`;
const launchTemplate = new LaunchTemplate(scope, launchTemplateId, {
Expand Down
2 changes: 2 additions & 0 deletions src/constructs/autoscaling/user-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface GuUserDataProps {
*/
export class GuUserData {
private readonly _userData: UserData;
readonly configuration?: GuPrivateS3ConfigurationProps;

get userData(): UserData {
return this._userData;
Expand Down Expand Up @@ -64,6 +65,7 @@ export class GuUserData {

constructor(scope: GuStack, props: GuUserDataPropsWithApp) {
this._userData = UserData.forLinux();
this.configuration = props.configuration;

if (props.configuration) {
this.downloadConfiguration(scope, props.app, props.configuration);
Expand Down
4 changes: 2 additions & 2 deletions src/patterns/ec2-app/__snapshots__/base.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ exports[`the GuEC2App pattern can produce a restricted EC2 app locked to specifi
},
],
"UserData": {
"Fn::Base64": "#!/bin/dev foobarbaz",
"Fn::Base64": "#!/bin/bash",
},
},
"TagSpecifications": [
Expand Down Expand Up @@ -1861,7 +1861,7 @@ exports[`the GuEC2App pattern should produce a functional EC2 app with minimal a
},
],
"UserData": {
"Fn::Base64": "#!/bin/dev foobarbaz",
"Fn::Base64": "#!/bin/bash",
},
},
"TagSpecifications": [
Expand Down
Loading

0 comments on commit 234bca7

Please sign in to comment.