diff --git a/.changeset/fresh-icons-vanish.md b/.changeset/fresh-icons-vanish.md new file mode 100644 index 0000000000..ad8fd36ff4 --- /dev/null +++ b/.changeset/fresh-icons-vanish.md @@ -0,0 +1,5 @@ +--- +"@guardian/cdk": minor +--- + +: feat(asg): Allow setting the detailedMonitoring option on launch templates provisioned by our EC2 patterns diff --git a/src/constructs/autoscaling/asg.ts b/src/constructs/autoscaling/asg.ts index 4626e66ac8..6579609772 100644 --- a/src/constructs/autoscaling/asg.ts +++ b/src/constructs/autoscaling/asg.ts @@ -50,6 +50,7 @@ export interface GuAutoScalingGroupProps targetGroup?: ApplicationTargetGroup; withoutImdsv2?: boolean; httpPutResponseHopLimit?: number; + enabledDetailedInstanceMonitoring?: boolean; } /** @@ -95,6 +96,7 @@ export class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) { withoutImdsv2 = false, httpPutResponseHopLimit, updatePolicy, + enabledDetailedInstanceMonitoring, } = 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. @@ -108,6 +110,7 @@ export class GuAutoScalingGroup extends GuAppAwareConstruct(AutoScalingGroup) { const launchTemplateId = `${scope.stack}-${scope.stage}-${app}`; const launchTemplate = new LaunchTemplate(scope, launchTemplateId, { blockDevices, + detailedMonitoring: enabledDetailedInstanceMonitoring, instanceType, machineImage: { getImage: (): MachineImageConfig => { diff --git a/src/patterns/ec2-app/base.test.ts b/src/patterns/ec2-app/base.test.ts index 41b2e0f5d6..6bf343f46e 100644 --- a/src/patterns/ec2-app/base.test.ts +++ b/src/patterns/ec2-app/base.test.ts @@ -1123,4 +1123,32 @@ UserData from accessed construct`); }, }); }); + + it("set detailed monitoring on the ASG launch template when set", 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: UserData.forLinux(), + certificateProps: { + domainName: "domain-name-for-your-application.example", + }, + scaling: { + minimumInstances: 1, + }, + enabledDetailedInstanceMonitoring: true, + }); + Template.fromStack(stack).hasResource("AWS::EC2::LaunchTemplate", { + Properties: { + LaunchTemplateData: { + Monitoring: { + Enabled: true, + }, + }, + }, + }); + }); }); diff --git a/src/patterns/ec2-app/base.ts b/src/patterns/ec2-app/base.ts index dc6ff3f70d..a8952ba3cd 100644 --- a/src/patterns/ec2-app/base.ts +++ b/src/patterns/ec2-app/base.ts @@ -308,6 +308,13 @@ export interface GuEc2AppProps extends AppIdentity { * and must rely on riffraff to do so. */ updatePolicy?: UpdatePolicy; + + /** + * This setting configures the launch template to enable or disable detailed monitoring on instances. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-monitoring.html + */ + enabledDetailedInstanceMonitoring?: boolean; } function restrictedCidrRanges(ranges: IPeer[]) { @@ -363,6 +370,7 @@ export class GuEc2App extends Construct { publicSubnets = GuVpc.subnetsFromParameter(scope, { type: SubnetType.PUBLIC, app }), instanceMetadataHopLimit, updatePolicy, + enabledDetailedInstanceMonitoring, } = props; super(scope, app); // The assumption is `app` is unique @@ -414,6 +422,7 @@ export class GuEc2App extends Construct { imageRecipe, httpPutResponseHopLimit: instanceMetadataHopLimit, updatePolicy, + enabledDetailedInstanceMonitoring, }); // This allows automatic shipping of instance Cloud Init logs when using the