Skip to content

Commit

Permalink
Merge pull request #2369 from guardian/pair/autoscaling-update-policy
Browse files Browse the repository at this point in the history
feat(asg): Allow setting the UpdatePolicy on ASGs provisioned by our EC2 patterns
  • Loading branch information
AshCorr authored Jul 15, 2024
2 parents 75f2737 + 9918987 commit 1cc97c1
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/grumpy-experts-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@guardian/cdk": minor
---

feat(asg): Allow setting the UpdatePolicy on ASGs provisioned by our EC2 patterns
5 changes: 4 additions & 1 deletion src/constructs/autoscaling/asg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) {
vpc,
withoutImdsv2 = false,
httpPutResponseHopLimit,
updatePolicy,
} = props;

// Ensure min and max are defined in the same way. Throwing an `Error` when necessary. For example when min is defined via a Mapping, but max is not.
Expand Down Expand Up @@ -163,7 +164,9 @@ export class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) {
// A CDK AutoScalingGroup comes with this update policy, whereas the CFN autscaling group
// leaves it to the default value, which is actually false.
// { UpdatePolicy: { autoScalingScheduledAction: { IgnoreUnmodifiedGroupSizeProperties: true }}
cfnAsg.addDeletionOverride("UpdatePolicy");
if (!updatePolicy) {
cfnAsg.addDeletionOverride("UpdatePolicy");
}

Tags.of(launchTemplate).add("App", app);
}
Expand Down
30 changes: 29 additions & 1 deletion src/patterns/ec2-app/base.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Match, Template } from "aws-cdk-lib/assertions";
import { BlockDeviceVolume, EbsDeviceVolumeType } from "aws-cdk-lib/aws-autoscaling";
import { BlockDeviceVolume, EbsDeviceVolumeType, UpdatePolicy } from "aws-cdk-lib/aws-autoscaling";
import { InstanceClass, InstanceSize, InstanceType, Peer, Port, Vpc } from "aws-cdk-lib/aws-ec2";
import { type CfnLoadBalancer } from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { AccessScope, MetadataKeys } from "../../constants";
Expand Down Expand Up @@ -1095,4 +1095,32 @@ describe("the GuEC2App pattern", function () {
SslPolicy: "ELBSecurityPolicy-TLS13-1-2-2021-06",
});
});

it("has a defined UpdatePolicy when provided with one", function () {
const stack = simpleGuStackForTesting();
new GuEc2App(stack, {
applicationPort: 3000,
app: "test-gu-ec2-app",
access: { scope: AccessScope.PUBLIC },
instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),
monitoringConfiguration: { noMonitoring: true },
userData: "#!/bin/dev foobarbaz",
certificateProps: {
domainName: "domain-name-for-your-application.example",
},
scaling: {
minimumInstances: 1,
},
instanceMetadataHopLimit: 2,
updatePolicy: UpdatePolicy.replacingUpdate(),
});

Template.fromStack(stack).hasResource("AWS::AutoScaling::AutoScalingGroup", {
UpdatePolicy: {
AutoScalingReplacingUpdate: {
WillReplace: true,
},
},
});
});
});
14 changes: 13 additions & 1 deletion src/patterns/ec2-app/base.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint "@guardian/tsdoc-required/tsdoc-required": 2 -- to begin rolling this out for public APIs. */
import { Duration, SecretValue, Tags } from "aws-cdk-lib";
import type { BlockDevice } from "aws-cdk-lib/aws-autoscaling";
import type { BlockDevice, UpdatePolicy } from "aws-cdk-lib/aws-autoscaling";
import { HealthCheck } from "aws-cdk-lib/aws-autoscaling";
import {
ProviderAttribute,
Expand Down Expand Up @@ -298,6 +298,16 @@ export interface GuEc2AppProps extends AppIdentity {
* for example when sharing the instance profile with a docker container running on the instance.
*/
instanceMetadataHopLimit?: number;

/**
* Specify an update policy for the ASG created by this pattern.
*
* @see https://docs.aws.amazon.com/cdk/api/latest/docs/aws-autoscaling-readme.html#update-policy
*
* @defaultValue UpdatePolicy.none() - Cloudformation does not attempt to rotate instances in the ASG
* and must rely on riffraff to do so.
*/
updatePolicy?: UpdatePolicy;
}

function restrictedCidrRanges(ranges: IPeer[]) {
Expand Down Expand Up @@ -352,6 +362,7 @@ export class GuEc2App extends Construct {
privateSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PRIVATE, app }),
publicSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PUBLIC, app }),
instanceMetadataHopLimit,
updatePolicy,
} = props;

super(scope, app); // The assumption is `app` is unique
Expand Down Expand Up @@ -400,6 +411,7 @@ export class GuEc2App extends Construct {
...(blockDevices && { blockDevices }),
imageRecipe,
httpPutResponseHopLimit: instanceMetadataHopLimit,
updatePolicy,
});

// This allows automatic shipping of instance Cloud Init logs when using the
Expand Down

0 comments on commit 1cc97c1

Please sign in to comment.