Skip to content

Commit

Permalink
Merge pull request #2465 from guardian/aa/build-identifier
Browse files Browse the repository at this point in the history
feat(experimental-ec2-pattern): Add `buildIdentifier` prop
  • Loading branch information
akash1810 authored Sep 20, 2024
2 parents 311607c + 5add16c commit e9f9862
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-eggs-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@guardian/cdk": patch
---

feat(experimental-ec2-pattern): Tag launch template to improve observability
1 change: 1 addition & 0 deletions src/constants/metadata-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export const MetadataKeys = {
REPOSITORY_NAME: "gu:repo",
LOG_KINESIS_STREAM_NAME: "LogKinesisStreamName",
SYSTEMD_UNIT: "SystemdUnit",
BUILD_IDENTIFIER: "gu:build-identifier",
};
4 changes: 4 additions & 0 deletions src/constructs/autoscaling/asg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);

Expand Down
16 changes: 14 additions & 2 deletions src/experimental/patterns/__snapshots__/ec2-app.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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 ",
{
Expand All @@ -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",
],
Expand All @@ -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",
Expand Down
1 change: 1 addition & 0 deletions src/experimental/patterns/ec2-app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ describe("The GuEc2AppExperimental pattern", () => {
scaling: {
minimumInstances: 1,
},
buildIdentifier: "TEST",
};
}

Expand Down
25 changes: 20 additions & 5 deletions src/experimental/patterns/ec2-app.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -234,7 +235,16 @@ class AsgRollingUpdatePolicy extends Policy {
}
}

export interface GuEc2AppExperimentalProps extends Omit<GuEc2AppProps, "updatePolicy"> {}
export interface GuEc2AppExperimentalProps extends Omit<GuEc2AppProps, "updatePolicy"> {
/**
* 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.
Expand Down Expand Up @@ -273,7 +283,7 @@ export interface GuEc2AppExperimentalProps extends Omit<GuEc2AppProps, "updatePo
export class GuEc2AppExperimental extends GuEc2App {
constructor(scope: GuStack, props: GuEc2AppExperimentalProps) {
const { minimumInstances, maximumInstances = minimumInstances * 2 } = props.scaling;
const { applicationPort } = props;
const { applicationPort, buildIdentifier } = props;
const { region, stackId } = scope;

super(scope, {
Expand Down Expand Up @@ -334,7 +344,7 @@ export class GuEc2AppExperimental extends GuEc2App {
--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 ${buildIdentifier} not yet healthy within target group. Current state $STATE. Sleeping..."
sleep ${RollingUpdateDurations.sleep.toSeconds()}
STATE=$(aws elbv2 describe-target-health \
--target-group-arn ${targetGroup.targetGroupArn} \
Expand All @@ -343,7 +353,7 @@ export class GuEc2AppExperimental extends GuEc2App {
--query "TargetHealthDescriptions[0].TargetHealth.State")
done
echo "Instance is healthy in target group."
echo "Instance running build ${buildIdentifier} is healthy in target group."
`,
`# ${GuEc2AppExperimental.name} UserData End`,
);
Expand All @@ -357,6 +367,11 @@ export class GuEc2AppExperimental extends GuEc2App {
`,
);

// If https://github.com/guardian/devx-logs is used, this tag will be added as a marker to logs in Central ELK.
Tags.of(autoScalingGroup.instanceLaunchTemplate).add(MetadataKeys.BUILD_IDENTIFIER, buildIdentifier, {
applyToLaunchedInstances: true,
});

// TODO Once out of experimental, instantiate these `Aspect`s directly in `GuStack`.
Aspects.of(scope).add(AutoScalingRollingUpdateTimeout.getInstance(scope));
Aspects.of(scope).add(HorizontallyScalingDeploymentProperties.getInstance(scope));
Expand Down
1 change: 1 addition & 0 deletions src/riff-raff-yaml-file/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,7 @@ describe("The RiffRaffYamlFile class", () => {
},
applicationPort: 9000,
imageRecipe: "arm64-bionic-java11-deploy-infrastructure",
buildIdentifier: "TEST",
});
}
}
Expand Down

0 comments on commit e9f9862

Please sign in to comment.