diff --git a/packages/@aws-cdk/aws-autoscaling/README.md b/packages/@aws-cdk/aws-autoscaling/README.md index 44331a3b5b1c3..077f930c3449a 100644 --- a/packages/@aws-cdk/aws-autoscaling/README.md +++ b/packages/@aws-cdk/aws-autoscaling/README.md @@ -233,7 +233,7 @@ about allowing connections between resources backed by instances. To enable the max instance lifetime support, specify `maxInstanceLifetime` property for the `AutoscalingGroup` resource. The value must be between 7 and 365 days(inclusive). -To clear a previously set value, just leave this property undefinied. +To clear a previously set value, leave this property undefined. ### Instance Monitoring @@ -241,6 +241,28 @@ To disable detailed instance monitoring, specify `instanceMonitoring` property for the `AutoscalingGroup` resource as `Monitoring.BASIC`. Otherwise detailed monitoring will be enabled. +### Monitoring Group Metrics + +Group metrics are used to monitor group level properties; they describe the group rather than any of its instances (e.g GroupMaxSize, the group maximum size). To enable group metrics monitoring, use the `groupMetrics` property. +All group metrics are reported in a granularity of 1 minute at no additional charge. + +See [EC2 docs](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-instance-monitoring.html#as-group-metrics) for a list of all available group metrics. + +To enable group metrics monitoring using the `groupMetrics` property: + +```ts +// Enable monitoring of all group metrics +new autoscaling.AutoScalingGroup(stack, 'ASG', { + groupMetrics: [GroupMetrics.all()], + // ... +}); + +// Enable monitoring for a subset of group metrics +new autoscaling.AutoScalingGroup(stack, 'ASG', { + groupMetrics: [new autoscaling.GroupMetrics(GroupMetric.MIN_SIZE, GroupMetric.MAX_SIZE)], + // ... +}); +``` ### Future work diff --git a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts index 04c63308cc2aa..157298b8e10b8 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -215,7 +215,7 @@ export interface CommonAutoScalingGroupProps { * it is terminated and replaced, and cannot be used again. * * You must specify a value of at least 604,800 seconds (7 days). To clear a previously set value, - * simply leave this property undefinied. + * leave this property undefined. * * @see https://docs.aws.amazon.com/autoscaling/ec2/userguide/asg-max-instance-lifetime.html * @@ -236,8 +236,16 @@ export interface CommonAutoScalingGroupProps { readonly instanceMonitoring?: Monitoring; /** - * The name of the Auto Scaling group. This name must be unique per Region per account. + * Enable monitoring for group metrics, these metrics describe the group rather than any of its instances. + * To report all group metrics use `GroupMetrics.all()` + * Group metrics are reported in a granularity of 1 minute at no additional charge. + * @default - no group metrics will be reported * + */ + readonly groupMetrics?: GroupMetrics[]; + + /** + * The name of the Auto Scaling group. This name must be unique per Region per account. * @default - Auto generated by CloudFormation */ readonly autoScalingGroupName?: string; @@ -296,6 +304,88 @@ export interface AutoScalingGroupProps extends CommonAutoScalingGroupProps { readonly role?: iam.IRole; } +/** + * A set of group metrics + */ +export class GroupMetrics { + + /** + * Report all group metrics. + */ + public static all(): GroupMetrics { + return new GroupMetrics(); + } + + /** + * @internal + */ + public _metrics = new Set(); + + constructor(...metrics: GroupMetric[]) { + metrics?.forEach(metric => this._metrics.add(metric)); + } +} + +/** + * Group metrics that an Auto Scaling group sends to Amazon CloudWatch. + */ +export class GroupMetric { + + /** + * The minimum size of the Auto Scaling group + */ + public static readonly MIN_SIZE = new GroupMetric('GroupMinSize'); + + /** + * The maximum size of the Auto Scaling group + */ + public static readonly MAX_SIZE = new GroupMetric('GroupMaxSize'); + + /** + * The number of instances that the Auto Scaling group attempts to maintain + */ + public static readonly DESIRED_CAPACITY = new GroupMetric('GroupDesiredCapacity'); + + /** + * The number of instances that are running as part of the Auto Scaling group + * This metric does not include instances that are pending or terminating + */ + public static readonly IN_SERVICE_INSTANCES = new GroupMetric('GroupInServiceInstances'); + + /** + * The number of instances that are pending + * A pending instance is not yet in service, this metric does not include instances that are in service or terminating + */ + public static readonly PENDING_INSTANCES = new GroupMetric('GroupPendingInstances'); + + /** + * The number of instances that are in a Standby state + * Instances in this state are still running but are not actively in service + */ + public static readonly STANDBY_INSTANCES = new GroupMetric('GroupStandbyInstances'); + + /** + * The number of instances that are in the process of terminating + * This metric does not include instances that are in service or pending + */ + public static readonly TERMINATING_INSTANCES = new GroupMetric('GroupTerminatingInstances'); + + /** + * The total number of instances in the Auto Scaling group + * This metric identifies the number of instances that are in service, pending, and terminating + */ + public static readonly TOTAL_INSTANCES = new GroupMetric('GroupTotalInstances'); + + /** + * The name of the group metric + */ + public readonly name: string; + + constructor(name: string) { + this.name = name; + } +} + abstract class AutoScalingGroupBase extends Resource implements IAutoScalingGroup { public abstract autoScalingGroupName: string; @@ -470,7 +560,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements public readonly userData: ec2.UserData; /** - * The maximum spot price configured for thie autoscaling group. `undefined` + * The maximum spot price configured for the autoscaling group. `undefined` * indicates that this group uses on-demand capacity. */ public readonly spotPrice?: string; @@ -485,6 +575,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements private readonly securityGroups: ec2.ISecurityGroup[] = []; private readonly loadBalancerNames: string[] = []; private readonly targetGroupArns: string[] = []; + private readonly groupMetrics: GroupMetrics[] = []; private readonly notifications: NotificationConfiguration[] = []; constructor(scope: Construct, id: string, props: AutoScalingGroupProps) { @@ -507,6 +598,10 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements this.grantPrincipal = this.role; + if (props.groupMetrics) { + this.groupMetrics.push(...props.groupMetrics); + } + const iamProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', { roles: [ this.role.roleName ], }); @@ -595,6 +690,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements loadBalancerNames: Lazy.listValue({ produce: () => this.loadBalancerNames }, { omitEmpty: true }), targetGroupArns: Lazy.listValue({ produce: () => this.targetGroupArns }, { omitEmpty: true }), notificationConfigurations: this.renderNotificationConfiguration(), + metricsCollection: Lazy.anyValue({ produce: () => this.renderMetricsCollection() }), vpcZoneIdentifier: subnetIds, healthCheckType: props.healthCheck && props.healthCheck.type, healthCheckGracePeriod: props.healthCheck && props.healthCheck.gracePeriod && props.healthCheck.gracePeriod.toSeconds(), @@ -740,6 +836,17 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements notificationTypes: notification.scalingEvents ? notification.scalingEvents._types : ScalingEvents.ALL._types, })); } + + private renderMetricsCollection(): CfnAutoScalingGroup.MetricsCollectionProperty[] | undefined { + if (this.groupMetrics.length === 0) { + return undefined; + } + + return this.groupMetrics.map(group => ({ + granularity: '1Minute', + metrics: group._metrics?.size !== 0 ? [...group._metrics].map(m => m.name) : undefined, + })); + } } /** @@ -786,7 +893,7 @@ export interface NotificationConfiguration { */ export enum ScalingEvent { /** - * Notify when an instance was launced + * Notify when an instance was launched */ INSTANCE_LAUNCH = 'autoscaling:EC2_INSTANCE_LAUNCH', @@ -888,7 +995,7 @@ export interface RollingUpdateConfiguration { /** * A list of ScalingEvents, you can use one of the predefined lists, such as ScalingEvents.ERRORS - * or create a custome group by instantiating a `NotificationTypes` object, e.g: `new NotificationTypes(`NotificationType.INSTANCE_LAUNCH`)`. + * or create a custom group by instantiating a `NotificationTypes` object, e.g: `new NotificationTypes(`NotificationType.INSTANCE_LAUNCH`)`. */ export class ScalingEvents { /** diff --git a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts index 92ef8f62ba2e0..626efdf1c7ce0 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts @@ -186,7 +186,7 @@ nodeunitShim({ test.done(); }, - 'userdata can be overriden by image'(test: Test) { + 'userdata can be overridden by image'(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = mockVpc(stack); @@ -209,7 +209,7 @@ nodeunitShim({ test.done(); }, - 'userdata can be overriden at ASG directly'(test: Test) { + 'userdata can be overridden at ASG directly'(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = mockVpc(stack); @@ -1088,24 +1088,92 @@ nodeunitShim({ test.done(); }, - 'throw if notification and notificationsTopics are both configured'(test: Test) { + 'test GroupMetrics.all(), adds a single MetricsCollection with no Metrics specified'(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = mockVpc(stack); - const topic = new sns.Topic(stack, 'MyTopic'); + // When + new autoscaling.AutoScalingGroup(stack, 'ASG', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), + machineImage: new ec2.AmazonLinuxImage(), + vpc, + groupMetrics: [autoscaling.GroupMetrics.all()], + }); - // THEN - test.throws(() => { - new autoscaling.AutoScalingGroup(stack, 'MyASG', { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), - machineImage: new ec2.AmazonLinuxImage(), - vpc, - notificationsTopic: topic, - notifications: [{ - topic, - }], - }); - }, 'Cannot set \'notificationsTopic\' and \'notifications\', \'notificationsTopic\' is deprecated use \'notifications\' instead'); + // Then + expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { + MetricsCollection: [ + { + Granularity: '1Minute', + Metrics: ABSENT, + }, + ], + })); + test.done(); + }, + + 'test can specify a subset of group metrics'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = mockVpc(stack); + + // WHEN + new autoscaling.AutoScalingGroup(stack, 'ASG', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), + machineImage: new ec2.AmazonLinuxImage(), + groupMetrics: [ + new autoscaling.GroupMetrics(autoscaling.GroupMetric.MIN_SIZE, + autoscaling.GroupMetric.MAX_SIZE, + autoscaling.GroupMetric.DESIRED_CAPACITY, + autoscaling.GroupMetric.IN_SERVICE_INSTANCES), + new autoscaling.GroupMetrics(autoscaling.GroupMetric.PENDING_INSTANCES, + autoscaling.GroupMetric.STANDBY_INSTANCES, + autoscaling.GroupMetric.TOTAL_INSTANCES, + autoscaling.GroupMetric.TERMINATING_INSTANCES, + ), + ], + vpc, + }); + + // Then + expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { + MetricsCollection: [ + { + Granularity: '1Minute', + Metrics: [ 'GroupMinSize', 'GroupMaxSize', 'GroupDesiredCapacity', 'GroupInServiceInstances' ], + }, { + Granularity: '1Minute', + Metrics: [ 'GroupPendingInstances', 'GroupStandbyInstances', 'GroupTotalInstances', 'GroupTerminatingInstances' ], + }, + ], + })); + test.done(); + }, + + 'test deduplication of group metrics '(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = mockVpc(stack); + new autoscaling.AutoScalingGroup(stack, 'ASG', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), + machineImage: new ec2.AmazonLinuxImage(), + vpc, + groupMetrics: [new autoscaling.GroupMetrics(autoscaling.GroupMetric.MIN_SIZE, + autoscaling.GroupMetric.MAX_SIZE, + autoscaling.GroupMetric.MAX_SIZE, + autoscaling.GroupMetric.MIN_SIZE, + )], + }); + + // Then + expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { + MetricsCollection: [ + { + Granularity: '1Minute', + Metrics: [ 'GroupMinSize', 'GroupMaxSize' ], + }, + ], + })); test.done(); }, @@ -1154,6 +1222,27 @@ nodeunitShim({ test.done(); }, + 'throw if notification and notificationsTopics are both configured'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = mockVpc(stack); + const topic = new sns.Topic(stack, 'MyTopic'); + + // THEN + test.throws(() => { + new autoscaling.AutoScalingGroup(stack, 'MyASG', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.MICRO), + machineImage: new ec2.AmazonLinuxImage(), + vpc, + notificationsTopic: topic, + notifications: [{ + topic, + }], + }); + }, 'Cannot set \'notificationsTopic\' and \'notifications\', \'notificationsTopic\' is deprecated use \'notifications\' instead'); + test.done(); + }, + 'notificationTypes default includes all non test NotificationType'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-metrics-collections.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-metrics-collections.expected.json new file mode 100644 index 0000000000000..ba27663a60ccd --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-metrics-collections.expected.json @@ -0,0 +1,661 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet3Subnet631C5E25": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3RouteTable98AE0E14": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3RouteTableAssociation427FE0C6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + } + } + }, + "VPCPublicSubnet3DefaultRouteA0D29D46": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet3EIPAD4BC883": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3NATGatewayD3048F5C": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet3EIPAD4BC883", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCPrivateSubnet3Subnet3EDCD457": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet3" + } + ] + } + }, + "VPCPrivateSubnet3RouteTable192186F8": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet3" + } + ] + } + }, + "VPCPrivateSubnet3RouteTableAssociationC28D144E": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + } + }, + "VPCPrivateSubnet3DefaultRoute27F311AE": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "ASGInstanceSecurityGroup0525485D": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-cdk-asg-integ/ASG/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/ASG" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "ASGInstanceRoleE263A41B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/ASG" + } + ] + } + }, + "ASGInstanceProfile0A2834D7": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "ASGInstanceRoleE263A41B" + } + ] + } + }, + "ASGLaunchConfigC00AF12B": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "Properties": { + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "t2.micro", + "IamInstanceProfile": { + "Ref": "ASGInstanceProfile0A2834D7" + }, + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ASGInstanceSecurityGroup0525485D", + "GroupId" + ] + } + ], + "UserData": { + "Fn::Base64": "#!/bin/bash" + } + }, + "DependsOn": [ + "ASGInstanceRoleE263A41B" + ] + }, + "ASG46ED3070": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "MaxSize": "1", + "MinSize": "1", + "LaunchConfigurationName": { + "Ref": "ASGLaunchConfigC00AF12B" + }, + "MetricsCollection": [ + { + "Granularity": "1Minute" + }, + { + "Granularity": "1Minute", + "Metrics": [ + "GroupPendingInstances", + "GroupStandbyInstances", + "GroupTotalInstances" + ] + } + ], + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-cdk-asg-integ/ASG" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + }, + { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + ] + }, + "UpdatePolicy": { + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + } + } +} \ No newline at end of file