Skip to content

Commit 94f9d27

Browse files
authored
feat(aws-ec2): Enable/disable EC2 "Detailed Monitoring" (#19437)
Closes #19346 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 8f9d274 commit 94f9d27

File tree

7 files changed

+123
-21
lines changed

7 files changed

+123
-21
lines changed

packages/@aws-cdk/aws-ec2/README.md

+16
Original file line numberDiff line numberDiff line change
@@ -1475,3 +1475,19 @@ const template = new ec2.LaunchTemplate(this, 'LaunchTemplate', {
14751475
}),
14761476
});
14771477
```
1478+
1479+
## Detailed Monitoring
1480+
1481+
The following demonstrates how to enable [Detailed Monitoring](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-cloudwatch-new.html) for an EC2 instance. Keep in mind that Detailed Monitoring results in [additional charges](http://aws.amazon.com/cloudwatch/pricing/).
1482+
1483+
```ts
1484+
declare const vpc: ec2.Vpc;
1485+
declare const instanceType: ec2.InstanceType;
1486+
1487+
new ec2.Instance(this, 'Instance1', {
1488+
vpc,
1489+
instanceType,
1490+
machineImage: new ec2.AmazonLinuxImage(),
1491+
detailedMonitoring: true,
1492+
});
1493+
```

packages/@aws-cdk/aws-ec2/lib/instance.ts

+10
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,15 @@ export interface InstanceProps {
245245
* @default - false
246246
*/
247247
readonly requireImdsv2?: boolean;
248+
249+
/**
250+
* Whether "Detailed Monitoring" is enabled for this instance
251+
* Keep in mind that Detailed Monitoring results in extra charges
252+
*
253+
* @see http://aws.amazon.com/cloudwatch/pricing/
254+
* @default - false
255+
*/
256+
readonly detailedMonitoring?: boolean;
248257
}
249258

250259
/**
@@ -381,6 +390,7 @@ export class Instance extends Resource implements IInstance {
381390
blockDeviceMappings: props.blockDevices !== undefined ? instanceBlockDeviceMappings(this, props.blockDevices) : undefined,
382391
privateIpAddress: props.privateIpAddress,
383392
propagateTagsToVolumeOnCreation: props.propagateTagsToVolumeOnCreation,
393+
monitoring: props.detailedMonitoring,
384394
});
385395
this.instance.node.addDependency(this.role);
386396

packages/@aws-cdk/aws-ec2/test/instance.test.ts

+78-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,19 @@ import { Asset } from '@aws-cdk/aws-s3-assets';
55
import { StringParameter } from '@aws-cdk/aws-ssm';
66
import { Stack } from '@aws-cdk/core';
77
import {
8-
AmazonLinuxImage, BlockDeviceVolume, CloudFormationInit,
9-
EbsDeviceVolumeType, InitCommand, Instance, InstanceArchitecture, InstanceClass, InstanceSize, InstanceType, LaunchTemplate, UserData, Vpc,
8+
AmazonLinuxImage,
9+
BlockDeviceVolume,
10+
CloudFormationInit,
11+
EbsDeviceVolumeType,
12+
InitCommand,
13+
Instance,
14+
InstanceArchitecture,
15+
InstanceClass,
16+
InstanceSize,
17+
InstanceType,
18+
LaunchTemplate,
19+
UserData,
20+
Vpc,
1021
} from '../lib';
1122

1223
let stack: Stack;
@@ -144,7 +155,7 @@ describe('instance', () => {
144155

145156
for (const instanceClass of sampleInstanceClassKeys) {
146157
// WHEN
147-
const key = instanceClass.key as keyof(typeof InstanceClass);
158+
const key = instanceClass.key as keyof (typeof InstanceClass);
148159
const instanceType = InstanceClass[key];
149160

150161
// THEN
@@ -432,6 +443,62 @@ describe('instance', () => {
432443
},
433444
});
434445
});
446+
447+
describe('Detailed Monitoring', () => {
448+
test('instance with Detailed Monitoring enabled', () => {
449+
// WHEN
450+
new Instance(stack, 'Instance', {
451+
vpc,
452+
machineImage: new AmazonLinuxImage(),
453+
instanceType: new InstanceType('t2.micro'),
454+
detailedMonitoring: true,
455+
});
456+
457+
// Force stack synth so the Instance is applied
458+
Template.fromStack(stack);
459+
460+
// THEN
461+
Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', {
462+
Monitoring: true,
463+
});
464+
});
465+
466+
test('instance with Detailed Monitoring disabled', () => {
467+
// WHEN
468+
new Instance(stack, 'Instance', {
469+
vpc,
470+
machineImage: new AmazonLinuxImage(),
471+
instanceType: new InstanceType('t2.micro'),
472+
detailedMonitoring: false,
473+
});
474+
475+
// Force stack synth so the Instance is applied
476+
Template.fromStack(stack);
477+
478+
// THEN
479+
Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', {
480+
Monitoring: false,
481+
});
482+
});
483+
484+
test('instance with Detailed Monitoring unset falls back to disabled', () => {
485+
// WHEN
486+
new Instance(stack, 'Instance', {
487+
vpc,
488+
machineImage: new AmazonLinuxImage(),
489+
instanceType: new InstanceType('t2.micro'),
490+
});
491+
492+
// Force stack synth so the Instance is applied
493+
Template.fromStack(stack);
494+
495+
// THEN
496+
Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', {
497+
Monitoring: Match.absent(),
498+
});
499+
});
500+
});
501+
435502
});
436503

437504
test('add CloudFormation Init to instance', () => {
@@ -519,8 +586,14 @@ test('cause replacement from s3 asset in userdata', () => {
519586
const hash = 'f88eace39faf39d7';
520587
Template.fromStack(stack).templateMatches(Match.objectLike({
521588
Resources: Match.objectLike({
522-
[`InstanceOne5B821005${hash}`]: Match.objectLike({ Type: 'AWS::EC2::Instance', Properties: Match.anyValue() }),
523-
[`InstanceTwoDC29A7A7${hash}`]: Match.objectLike({ Type: 'AWS::EC2::Instance', Properties: Match.anyValue() }),
589+
[`InstanceOne5B821005${hash}`]: Match.objectLike({
590+
Type: 'AWS::EC2::Instance',
591+
Properties: Match.anyValue(),
592+
}),
593+
[`InstanceTwoDC29A7A7${hash}`]: Match.objectLike({
594+
Type: 'AWS::EC2::Instance',
595+
Properties: Match.anyValue(),
596+
}),
524597
}),
525598
}));
526599
});

packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json

+16-15
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
"VPCPublicSubnet1SubnetB4246D30": {
1919
"Type": "AWS::EC2::Subnet",
2020
"Properties": {
21-
"CidrBlock": "10.0.0.0/19",
2221
"VpcId": {
2322
"Ref": "VPCB9E5F0B4"
2423
},
2524
"AvailabilityZone": "test-region-1a",
25+
"CidrBlock": "10.0.0.0/19",
2626
"MapPublicIpOnLaunch": true,
2727
"Tags": [
2828
{
@@ -95,15 +95,15 @@
9595
"VPCPublicSubnet1NATGatewayE0556630": {
9696
"Type": "AWS::EC2::NatGateway",
9797
"Properties": {
98+
"SubnetId": {
99+
"Ref": "VPCPublicSubnet1SubnetB4246D30"
100+
},
98101
"AllocationId": {
99102
"Fn::GetAtt": [
100103
"VPCPublicSubnet1EIP6AD938E8",
101104
"AllocationId"
102105
]
103106
},
104-
"SubnetId": {
105-
"Ref": "VPCPublicSubnet1SubnetB4246D30"
106-
},
107107
"Tags": [
108108
{
109109
"Key": "Name",
@@ -115,11 +115,11 @@
115115
"VPCPublicSubnet2Subnet74179F39": {
116116
"Type": "AWS::EC2::Subnet",
117117
"Properties": {
118-
"CidrBlock": "10.0.32.0/19",
119118
"VpcId": {
120119
"Ref": "VPCB9E5F0B4"
121120
},
122121
"AvailabilityZone": "test-region-1b",
122+
"CidrBlock": "10.0.32.0/19",
123123
"MapPublicIpOnLaunch": true,
124124
"Tags": [
125125
{
@@ -192,15 +192,15 @@
192192
"VPCPublicSubnet2NATGateway3C070193": {
193193
"Type": "AWS::EC2::NatGateway",
194194
"Properties": {
195+
"SubnetId": {
196+
"Ref": "VPCPublicSubnet2Subnet74179F39"
197+
},
195198
"AllocationId": {
196199
"Fn::GetAtt": [
197200
"VPCPublicSubnet2EIP4947BC00",
198201
"AllocationId"
199202
]
200203
},
201-
"SubnetId": {
202-
"Ref": "VPCPublicSubnet2Subnet74179F39"
203-
},
204204
"Tags": [
205205
{
206206
"Key": "Name",
@@ -212,11 +212,11 @@
212212
"VPCPublicSubnet3Subnet631C5E25": {
213213
"Type": "AWS::EC2::Subnet",
214214
"Properties": {
215-
"CidrBlock": "10.0.64.0/19",
216215
"VpcId": {
217216
"Ref": "VPCB9E5F0B4"
218217
},
219218
"AvailabilityZone": "test-region-1c",
219+
"CidrBlock": "10.0.64.0/19",
220220
"MapPublicIpOnLaunch": true,
221221
"Tags": [
222222
{
@@ -289,15 +289,15 @@
289289
"VPCPublicSubnet3NATGatewayD3048F5C": {
290290
"Type": "AWS::EC2::NatGateway",
291291
"Properties": {
292+
"SubnetId": {
293+
"Ref": "VPCPublicSubnet3Subnet631C5E25"
294+
},
292295
"AllocationId": {
293296
"Fn::GetAtt": [
294297
"VPCPublicSubnet3EIPAD4BC883",
295298
"AllocationId"
296299
]
297300
},
298-
"SubnetId": {
299-
"Ref": "VPCPublicSubnet3Subnet631C5E25"
300-
},
301301
"Tags": [
302302
{
303303
"Key": "Name",
@@ -309,11 +309,11 @@
309309
"VPCPrivateSubnet1Subnet8BCA10E0": {
310310
"Type": "AWS::EC2::Subnet",
311311
"Properties": {
312-
"CidrBlock": "10.0.96.0/19",
313312
"VpcId": {
314313
"Ref": "VPCB9E5F0B4"
315314
},
316315
"AvailabilityZone": "test-region-1a",
316+
"CidrBlock": "10.0.96.0/19",
317317
"MapPublicIpOnLaunch": false,
318318
"Tags": [
319319
{
@@ -371,11 +371,11 @@
371371
"VPCPrivateSubnet2SubnetCFCDAA7A": {
372372
"Type": "AWS::EC2::Subnet",
373373
"Properties": {
374-
"CidrBlock": "10.0.128.0/19",
375374
"VpcId": {
376375
"Ref": "VPCB9E5F0B4"
377376
},
378377
"AvailabilityZone": "test-region-1b",
378+
"CidrBlock": "10.0.128.0/19",
379379
"MapPublicIpOnLaunch": false,
380380
"Tags": [
381381
{
@@ -433,11 +433,11 @@
433433
"VPCPrivateSubnet3Subnet3EDCD457": {
434434
"Type": "AWS::EC2::Subnet",
435435
"Properties": {
436-
"CidrBlock": "10.0.160.0/19",
437436
"VpcId": {
438437
"Ref": "VPCB9E5F0B4"
439438
},
440439
"AvailabilityZone": "test-region-1c",
440+
"CidrBlock": "10.0.160.0/19",
441441
"MapPublicIpOnLaunch": false,
442442
"Tags": [
443443
{
@@ -620,6 +620,7 @@
620620
"Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter"
621621
},
622622
"InstanceType": "t3.nano",
623+
"Monitoring": true,
623624
"SecurityGroupIds": [
624625
{
625626
"Fn::GetAtt": [

packages/@aws-cdk/aws-ec2/test/integ.instance.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class TestStack extends cdk.Stack {
1515
vpc,
1616
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.NANO),
1717
machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 }),
18+
detailedMonitoring: true,
1819
});
1920

2021
instance.addToRolePolicy(new PolicyStatement({

packages/@aws-cdk/aws-ec2/test/userdata.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Bucket } from '@aws-cdk/aws-s3';
21
import { Template, Match } from '@aws-cdk/assertions';
2+
import { Bucket } from '@aws-cdk/aws-s3';
33
import { Aws, Stack, CfnResource } from '@aws-cdk/core';
44
import * as ec2 from '../lib';
55

packages/aws-cdk-lib/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@
414414
"./aws-autoscalingplans": "./aws-autoscalingplans/index.js",
415415
"./aws-backup": "./aws-backup/index.js",
416416
"./aws-batch": "./aws-batch/index.js",
417+
"./aws-billingconductor": "./aws-billingconductor/index.js",
417418
"./aws-budgets": "./aws-budgets/index.js",
418419
"./aws-cassandra": "./aws-cassandra/index.js",
419420
"./aws-ce": "./aws-ce/index.js",

0 commit comments

Comments
 (0)