diff --git a/.changeset/sixty-eggs-cheat.md b/.changeset/sixty-eggs-cheat.md new file mode 100644 index 0000000000..f1d68eef8a --- /dev/null +++ b/.changeset/sixty-eggs-cheat.md @@ -0,0 +1,5 @@ +--- +"@guardian/cdk": patch +--- + +feat(experimental-ec2-pattern): Tag launch template to improve observability diff --git a/src/constants/metadata-keys.ts b/src/constants/metadata-keys.ts index 55f88de8d0..520937024c 100644 --- a/src/constants/metadata-keys.ts +++ b/src/constants/metadata-keys.ts @@ -4,4 +4,5 @@ export const MetadataKeys = { REPOSITORY_NAME: "gu:repo", LOG_KINESIS_STREAM_NAME: "LogKinesisStreamName", SYSTEMD_UNIT: "SystemdUnit", + BUILD_IDENTIFIER: "gu:build-identifier", }; diff --git a/src/constructs/autoscaling/asg.ts b/src/constructs/autoscaling/asg.ts index bd7aaaedcc..2bbfab1281 100644 --- a/src/constructs/autoscaling/asg.ts +++ b/src/constructs/autoscaling/asg.ts @@ -80,6 +80,9 @@ export class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) { public readonly amiParameter: GuAmiParameter; public readonly imageRecipe?: string | AmigoProps; + // Sadly this cannot be named `launchTemplate` as it would clash with a private property on the `AutoScalingGroup` class + public readonly instanceLaunchTemplate: LaunchTemplate; + constructor(scope: GuStack, id: string, props: GuAutoScalingGroupProps) { const { app, @@ -162,6 +165,7 @@ export class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) { this.app = app; this.amiParameter = imageId; this.imageRecipe = imageRecipe; + this.instanceLaunchTemplate = launchTemplate; targetGroup && this.attachToApplicationTargetGroup(targetGroup); diff --git a/src/experimental/patterns/__snapshots__/ec2-app.test.ts.snap b/src/experimental/patterns/__snapshots__/ec2-app.test.ts.snap index 5626d49f49..cd9e9ce9f7 100644 --- a/src/experimental/patterns/__snapshots__/ec2-app.test.ts.snap +++ b/src/experimental/patterns/__snapshots__/ec2-app.test.ts.snap @@ -841,6 +841,10 @@ exports[`The GuEc2AppExperimental pattern matches the snapshot 1`] = ` "Key": "App", "Value": "test-gu-ec2-app", }, + { + "Key": "gu:build-identifier", + "Value": "TEST", + }, { "Key": "gu:cdk:version", "Value": "TEST", @@ -870,6 +874,10 @@ exports[`The GuEc2AppExperimental pattern matches the snapshot 1`] = ` "Key": "App", "Value": "test-gu-ec2-app", }, + { + "Key": "gu:build-identifier", + "Value": "TEST", + }, { "Key": "gu:cdk:version", "Value": "TEST", @@ -937,7 +945,7 @@ dpkg -i /test-gu-ec2-app/test-gu-ec2-app-123.deb " --targets Id=$INSTANCE_ID,Port=9000 --query "TargetHealthDescriptions[0].TargetHealth.State") until [ "$STATE" == "\\"healthy\\"" ]; do - echo "Instance not yet healthy within target group. Current state $STATE. Sleeping..." + echo "Instance running build TEST not yet healthy within target group. Current state $STATE. Sleeping..." sleep 5 STATE=$(aws elbv2 describe-target-health --target-group-arn ", { @@ -950,7 +958,7 @@ dpkg -i /test-gu-ec2-app/test-gu-ec2-app-123.deb " --targets Id=$INSTANCE_ID,Port=9000 --query "TargetHealthDescriptions[0].TargetHealth.State") done - echo "Instance is healthy in target group." + echo "Instance running build TEST is healthy in target group." # GuEc2AppExperimental UserData End", ], @@ -966,6 +974,10 @@ dpkg -i /test-gu-ec2-app/test-gu-ec2-app-123.deb "Key": "App", "Value": "test-gu-ec2-app", }, + { + "Key": "gu:build-identifier", + "Value": "TEST", + }, { "Key": "gu:cdk:version", "Value": "TEST", diff --git a/src/experimental/patterns/ec2-app.test.ts b/src/experimental/patterns/ec2-app.test.ts index 676f3695ee..b687443ddb 100644 --- a/src/experimental/patterns/ec2-app.test.ts +++ b/src/experimental/patterns/ec2-app.test.ts @@ -62,6 +62,7 @@ describe("The GuEc2AppExperimental pattern", () => { scaling: { minimumInstances: 1, }, + buildIdentifier: "TEST", }; } diff --git a/src/experimental/patterns/ec2-app.ts b/src/experimental/patterns/ec2-app.ts index a028264c2c..ea41fe1f4b 100644 --- a/src/experimental/patterns/ec2-app.ts +++ b/src/experimental/patterns/ec2-app.ts @@ -1,9 +1,10 @@ import type { IAspect } from "aws-cdk-lib"; -import { Aspects, CfnParameter, Duration } from "aws-cdk-lib"; +import { Aspects, CfnParameter, Duration, Tags } from "aws-cdk-lib"; import { CfnAutoScalingGroup, CfnScalingPolicy, ScalingProcess, UpdatePolicy } from "aws-cdk-lib/aws-autoscaling"; import type { CfnPolicy } from "aws-cdk-lib/aws-iam"; import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam"; import type { IConstruct } from "constructs"; +import { MetadataKeys } from "../../constants"; import { GuAutoScalingGroup } from "../../constructs/autoscaling"; import type { GuStack } from "../../constructs/core"; import type { GuEc2AppProps } from "../../patterns"; @@ -234,7 +235,16 @@ class AsgRollingUpdatePolicy extends Policy { } } -export interface GuEc2AppExperimentalProps extends Omit {} +export interface GuEc2AppExperimentalProps extends Omit { + /** + * Which application build to run. + * This will typically match the build number provided by CI. + * + * @example + * process.env.GITHUB_RUN_NUMBER + */ + buildIdentifier: string; +} /** * An experimental pattern to instantiate an EC2 application that is updated entirely via CloudFormation. @@ -273,7 +283,7 @@ export interface GuEc2AppExperimentalProps extends Omit { }, applicationPort: 9000, imageRecipe: "arm64-bionic-java11-deploy-infrastructure", + buildIdentifier: "TEST", }); } }