From 94f9d27e626bced5fc68a6ebbd653fea21c6e21e Mon Sep 17 00:00:00 2001 From: Dzhuneyt <1754428+Dzhuneyt@users.noreply.github.com> Date: Tue, 29 Mar 2022 15:33:47 +0300 Subject: [PATCH] feat(aws-ec2): Enable/disable EC2 "Detailed Monitoring" (#19437) Closes https://github.com/aws/aws-cdk/issues/19346 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/README.md | 16 ++++ packages/@aws-cdk/aws-ec2/lib/instance.ts | 10 +++ .../@aws-cdk/aws-ec2/test/instance.test.ts | 83 +++++++++++++++++-- .../aws-ec2/test/integ.instance.expected.json | 31 +++---- .../@aws-cdk/aws-ec2/test/integ.instance.ts | 1 + .../@aws-cdk/aws-ec2/test/userdata.test.ts | 2 +- packages/aws-cdk-lib/package.json | 1 + 7 files changed, 123 insertions(+), 21 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index af8c5ff64594e..20b9dab23c434 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -1475,3 +1475,19 @@ const template = new ec2.LaunchTemplate(this, 'LaunchTemplate', { }), }); ``` + +## Detailed Monitoring + +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/). + +```ts +declare const vpc: ec2.Vpc; +declare const instanceType: ec2.InstanceType; + +new ec2.Instance(this, 'Instance1', { + vpc, + instanceType, + machineImage: new ec2.AmazonLinuxImage(), + detailedMonitoring: true, +}); +``` diff --git a/packages/@aws-cdk/aws-ec2/lib/instance.ts b/packages/@aws-cdk/aws-ec2/lib/instance.ts index a12c3a45d6108..213b1ef0e4629 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance.ts @@ -245,6 +245,15 @@ export interface InstanceProps { * @default - false */ readonly requireImdsv2?: boolean; + + /** + * Whether "Detailed Monitoring" is enabled for this instance + * Keep in mind that Detailed Monitoring results in extra charges + * + * @see http://aws.amazon.com/cloudwatch/pricing/ + * @default - false + */ + readonly detailedMonitoring?: boolean; } /** @@ -381,6 +390,7 @@ export class Instance extends Resource implements IInstance { blockDeviceMappings: props.blockDevices !== undefined ? instanceBlockDeviceMappings(this, props.blockDevices) : undefined, privateIpAddress: props.privateIpAddress, propagateTagsToVolumeOnCreation: props.propagateTagsToVolumeOnCreation, + monitoring: props.detailedMonitoring, }); this.instance.node.addDependency(this.role); diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index 5f4011aa12f3e..6fd215af31bff 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -5,8 +5,19 @@ import { Asset } from '@aws-cdk/aws-s3-assets'; import { StringParameter } from '@aws-cdk/aws-ssm'; import { Stack } from '@aws-cdk/core'; import { - AmazonLinuxImage, BlockDeviceVolume, CloudFormationInit, - EbsDeviceVolumeType, InitCommand, Instance, InstanceArchitecture, InstanceClass, InstanceSize, InstanceType, LaunchTemplate, UserData, Vpc, + AmazonLinuxImage, + BlockDeviceVolume, + CloudFormationInit, + EbsDeviceVolumeType, + InitCommand, + Instance, + InstanceArchitecture, + InstanceClass, + InstanceSize, + InstanceType, + LaunchTemplate, + UserData, + Vpc, } from '../lib'; let stack: Stack; @@ -144,7 +155,7 @@ describe('instance', () => { for (const instanceClass of sampleInstanceClassKeys) { // WHEN - const key = instanceClass.key as keyof(typeof InstanceClass); + const key = instanceClass.key as keyof (typeof InstanceClass); const instanceType = InstanceClass[key]; // THEN @@ -432,6 +443,62 @@ describe('instance', () => { }, }); }); + + describe('Detailed Monitoring', () => { + test('instance with Detailed Monitoring enabled', () => { + // WHEN + new Instance(stack, 'Instance', { + vpc, + machineImage: new AmazonLinuxImage(), + instanceType: new InstanceType('t2.micro'), + detailedMonitoring: true, + }); + + // Force stack synth so the Instance is applied + Template.fromStack(stack); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Monitoring: true, + }); + }); + + test('instance with Detailed Monitoring disabled', () => { + // WHEN + new Instance(stack, 'Instance', { + vpc, + machineImage: new AmazonLinuxImage(), + instanceType: new InstanceType('t2.micro'), + detailedMonitoring: false, + }); + + // Force stack synth so the Instance is applied + Template.fromStack(stack); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Monitoring: false, + }); + }); + + test('instance with Detailed Monitoring unset falls back to disabled', () => { + // WHEN + new Instance(stack, 'Instance', { + vpc, + machineImage: new AmazonLinuxImage(), + instanceType: new InstanceType('t2.micro'), + }); + + // Force stack synth so the Instance is applied + Template.fromStack(stack); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Instance', { + Monitoring: Match.absent(), + }); + }); + }); + }); test('add CloudFormation Init to instance', () => { @@ -519,8 +586,14 @@ test('cause replacement from s3 asset in userdata', () => { const hash = 'f88eace39faf39d7'; Template.fromStack(stack).templateMatches(Match.objectLike({ Resources: Match.objectLike({ - [`InstanceOne5B821005${hash}`]: Match.objectLike({ Type: 'AWS::EC2::Instance', Properties: Match.anyValue() }), - [`InstanceTwoDC29A7A7${hash}`]: Match.objectLike({ Type: 'AWS::EC2::Instance', Properties: Match.anyValue() }), + [`InstanceOne5B821005${hash}`]: Match.objectLike({ + Type: 'AWS::EC2::Instance', + Properties: Match.anyValue(), + }), + [`InstanceTwoDC29A7A7${hash}`]: Match.objectLike({ + Type: 'AWS::EC2::Instance', + Properties: Match.anyValue(), + }), }), })); }); diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json index 957af9c0f453e..d30b3a47c711e 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json @@ -18,11 +18,11 @@ "VPCPublicSubnet1SubnetB4246D30": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.0.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.0.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -115,11 +115,11 @@ "VPCPublicSubnet2Subnet74179F39": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.32.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.32.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -212,11 +212,11 @@ "VPCPublicSubnet3Subnet631C5E25": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.64.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.64.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -309,11 +309,11 @@ "VPCPrivateSubnet1Subnet8BCA10E0": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.96.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.96.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -371,11 +371,11 @@ "VPCPrivateSubnet2SubnetCFCDAA7A": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.128.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.128.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -433,11 +433,11 @@ "VPCPrivateSubnet3Subnet3EDCD457": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.160.0/19", "VpcId": { "Ref": "VPCB9E5F0B4" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.160.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -620,6 +620,7 @@ "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t3.nano", + "Monitoring": true, "SecurityGroupIds": [ { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance.ts b/packages/@aws-cdk/aws-ec2/test/integ.instance.ts index bae57818521cc..1b120c511eaaa 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance.ts @@ -15,6 +15,7 @@ class TestStack extends cdk.Stack { vpc, instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.NANO), machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 }), + detailedMonitoring: true, }); instance.addToRolePolicy(new PolicyStatement({ diff --git a/packages/@aws-cdk/aws-ec2/test/userdata.test.ts b/packages/@aws-cdk/aws-ec2/test/userdata.test.ts index c385ce83a7254..fc877cbb2c7c9 100644 --- a/packages/@aws-cdk/aws-ec2/test/userdata.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/userdata.test.ts @@ -1,5 +1,5 @@ -import { Bucket } from '@aws-cdk/aws-s3'; import { Template, Match } from '@aws-cdk/assertions'; +import { Bucket } from '@aws-cdk/aws-s3'; import { Aws, Stack, CfnResource } from '@aws-cdk/core'; import * as ec2 from '../lib'; diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 82233d7412b63..632d8357b9976 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -414,6 +414,7 @@ "./aws-autoscalingplans": "./aws-autoscalingplans/index.js", "./aws-backup": "./aws-backup/index.js", "./aws-batch": "./aws-batch/index.js", + "./aws-billingconductor": "./aws-billingconductor/index.js", "./aws-budgets": "./aws-budgets/index.js", "./aws-cassandra": "./aws-cassandra/index.js", "./aws-ce": "./aws-ce/index.js",