From 979f6fd6f9211a4d631e52e9087a9b4ad4bfbb28 Mon Sep 17 00:00:00 2001 From: Thorsten Hoeger Date: Mon, 29 Jul 2019 13:28:29 +0200 Subject: [PATCH] feat(ecs): make cluster and vpc optional for higher level constructs (#2773) * feat(ecs): make cluster and vpc optional for higher level constructs * chore(ecs): review feedback * chore(ecs): improve commenst after review * fix(ecs-patterns): refactor tests after merge * fix(ecs-patterns): whitespace * fix(ecs-patterns): memory in MB * fix(ecs): merge conflicts * feat(ecs-patterns): use default cluster per stack * fix(ecs-patterns): tests * feat(ecs-patterns): add magic id * chore: PR review * chore: add README --- packages/@aws-cdk/aws-ecs-patterns/README.md | 5 + .../lib/base/load-balanced-service-base.ts | 30 +- .../lib/ecs/load-balanced-ecs-service.ts | 2 +- .../fargate/load-balanced-fargate-service.ts | 2 +- .../aws-ecs-patterns/test/ec2/test.l3s.ts | 42 + .../fargate/integ.l3-autocreate.expected.json | 1034 ++++++++++ .../test/fargate/integ.l3-autocreate.ts | 20 + .../fargate/integ.l3-vpconly.expected.json | 1721 +++++++++++++++++ .../test/fargate/integ.l3-vpconly.ts | 32 + .../test.load-balanced-fargate-service.ts | 19 + packages/@aws-cdk/aws-ecs/README.md | 2 + packages/@aws-cdk/aws-ecs/lib/cluster.ts | 13 +- .../@aws-cdk/aws-ecs/test/test.ecs-cluster.ts | 146 +- 13 files changed, 3056 insertions(+), 12 deletions(-) create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.ts create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.ts diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index 001ff47b73da1..6a632f394bdf1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -51,6 +51,11 @@ const loadBalancedFargateService = new ecsPatterns.LoadBalancedFargateService(st }); ``` +Instead of providing a cluster you can specify a VPC and CDK will create a new ECS cluster. +If you deploy multiple services CDK will only create on cluster per VPC. + +You can omit `cluster` and `vpc` to let CDK create a new VPC with two AZs and create a cluster inside this VPC. + ## Queue Processing Services To define a service that creates a queue and reads from that queue, instantiate one of the following: diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/load-balanced-service-base.ts index 9eb7a2b2b7286..1c43b51c3b7f9 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/load-balanced-service-base.ts @@ -1,4 +1,5 @@ import { ICertificate } from '@aws-cdk/aws-certificatemanager'; +import ec2 = require('@aws-cdk/aws-ec2'); import ecs = require('@aws-cdk/aws-ecs'); import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); import { AddressRecordTarget, ARecord, IHostedZone } from '@aws-cdk/aws-route53'; @@ -16,8 +17,19 @@ export enum LoadBalancerType { export interface LoadBalancedServiceBaseProps { /** * The cluster where your service will be deployed + * You can only specify either vpc or cluster. Alternatively, you can leave both blank + * + * @default - create a new cluster; if you do not specify a cluster nor a vpc, a new VPC will be created for you as well + */ + readonly cluster?: ecs.ICluster; + + /** + * VPC that the cluster instances or tasks are running in + * You can only specify either vpc or cluster. Alternatively, you can leave both blank + * + * @default - use vpc of cluster or create a new one */ - readonly cluster: ecs.ICluster; + readonly vpc?: ec2.IVpc; /** * The image to start. @@ -115,11 +127,18 @@ export abstract class LoadBalancedServiceBase extends cdk.Construct { public readonly targetGroup: elbv2.ApplicationTargetGroup | elbv2.NetworkTargetGroup; + public readonly cluster: ecs.ICluster; + public readonly logDriver?: ecs.LogDriver; constructor(scope: cdk.Construct, id: string, props: LoadBalancedServiceBaseProps) { super(scope, id); + if (props.cluster && props.vpc) { + throw new Error(`You can only specify either vpc or cluster. Alternatively, you can leave both blank`); + } + this.cluster = props.cluster || this.getDefaultCluster(this, props.vpc); + // Create log driver if logging is enabled const enableLogging = props.enableLogging !== undefined ? props.enableLogging : true; this.logDriver = enableLogging ? this.createAWSLogDriver(this.node.id) : undefined; @@ -134,7 +153,7 @@ export abstract class LoadBalancedServiceBase extends cdk.Construct { const internetFacing = props.publicLoadBalancer !== undefined ? props.publicLoadBalancer : true; const lbProps = { - vpc: props.cluster.vpc, + vpc: this.cluster.vpc, internetFacing }; @@ -183,6 +202,13 @@ export abstract class LoadBalancedServiceBase extends cdk.Construct { new cdk.CfnOutput(this, 'LoadBalancerDNS', { value: this.loadBalancer.loadBalancerDnsName }); } + protected getDefaultCluster(scope: cdk.Construct, vpc?: ec2.IVpc): ecs.Cluster { + // magic string to avoid collision with user-defined constructs + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; + const stack = cdk.Stack.of(scope); + return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as ecs.Cluster || new ecs.Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + } + protected addServiceAsTarget(service: ecs.BaseService) { if (this.loadBalancerType === LoadBalancerType.APPLICATION) { (this.targetGroup as elbv2.ApplicationTargetGroup).addTarget(service); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/load-balanced-ecs-service.ts index e11b5cf7e3e3e..bc49d6ef7367c 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/load-balanced-ecs-service.ts @@ -63,7 +63,7 @@ export class LoadBalancedEc2Service extends LoadBalancedServiceBase { const assignPublicIp = props.publicTasks !== undefined ? props.publicTasks : false; const service = new ecs.Ec2Service(this, "Service", { - cluster: props.cluster, + cluster: this.cluster, desiredCount: props.desiredCount || 1, taskDefinition, assignPublicIp diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/load-balanced-fargate-service.ts index 018ca77293788..20240e1aa98dc 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/load-balanced-fargate-service.ts @@ -107,7 +107,7 @@ export class LoadBalancedFargateService extends LoadBalancedServiceBase { }); const assignPublicIp = props.publicTasks !== undefined ? props.publicTasks : false; const service = new ecs.FargateService(this, "Service", { - cluster: props.cluster, + cluster: this.cluster, desiredCount: props.desiredCount || 1, taskDefinition, assignPublicIp, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts index fde271f8084e1..e4b4cd3e266a7 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts @@ -56,6 +56,48 @@ export = { test.done(); }, + 'set vpc instead of cluster'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new ecsPatterns.LoadBalancedEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + image: ecs.ContainerImage.fromRegistry('test'), + desiredCount: 2, + environment: { + TEST_ENVIRONMENT_VARIABLE1: "test environment variable 1 value", + TEST_ENVIRONMENT_VARIABLE2: "test environment variable 2 value" + } + }); + + // THEN - stack does not contain a LaunchConfiguration + expect(stack, true).notTo(haveResource("AWS::AutoScaling::LaunchConfiguration")); + + test.throws(() => expect(stack)); + + test.done(); + }, + + 'setting vpc and cluster throws error'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + test.throws(() => new ecsPatterns.LoadBalancedEc2Service(stack, 'Service', { + cluster, + vpc, + loadBalancerType: ecsPatterns.LoadBalancerType.NETWORK, + image: ecs.ContainerImage.fromRegistry("/aws/aws-example-app") + })); + + test.done(); + }, + 'test ECS loadbalanced construct with memoryReservationMiB'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json new file mode 100644 index 0000000000000..a9cd08b3bad06 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json @@ -0,0 +1,1034 @@ +{ + "Resources": { + "L3LB212FC0E0": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3LBSecurityGroupEDE61198", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1Subnet3C273B99" + }, + { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2Subnet95FF715A" + } + ], + "Type": "application" + }, + "DependsOn": [ + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1DefaultRouteFF4E2178", + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2DefaultRouteB1375520" + ] + }, + "L3LBSecurityGroupEDE61198": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awsecsintegL3LB6453BA0A", + "SecurityGroupEgress": [], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + } + } + }, + "L3LBSecurityGrouptoawsecsintegL3ServiceSecurityGroup7B96C87F8094933E0A": { + "Type": "AWS::EC2::SecurityGroupEgress", + "Properties": { + "GroupId": { + "Fn::GetAtt": [ + "L3LBSecurityGroupEDE61198", + "GroupId" + ] + }, + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "DestinationSecurityGroupId": { + "Fn::GetAtt": [ + "L3ServiceSecurityGroup677B0897", + "GroupId" + ] + }, + "FromPort": 80, + "ToPort": 80 + } + }, + "L3LBPublicListener156FFC0F": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "L3LBPublicListenerECSGroup648EEA11" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "L3LB212FC0E0" + }, + "Port": 80, + "Protocol": "HTTP", + "Certificates": [] + } + }, + "L3LBPublicListenerECSGroup648EEA11": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [], + "Targets": [], + "TargetType": "ip", + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + } + } + }, + "L3TaskDefTaskRole21C75D10": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3TaskDef48D8ACB8": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Links": [], + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "L3TaskDefwebLogGroupC6E4A38A" + }, + "awslogs-stream-prefix": "L3", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "MountPoints": [], + "Name": "web", + "PortMappings": [ + { + "ContainerPort": 80, + "Protocol": "tcp" + } + ], + "Ulimits": [], + "VolumesFrom": [] + } + ], + "Cpu": "512", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "L3TaskDefExecutionRole49AF0996", + "Arn" + ] + }, + "Family": "awsecsintegL3TaskDefAA25240E", + "Memory": "1024", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "L3TaskDefTaskRole21C75D10", + "Arn" + ] + }, + "Volumes": [] + } + }, + "L3TaskDefwebLogGroupC6E4A38A": { + "Type": "AWS::Logs::LogGroup", + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain" + }, + "L3TaskDefExecutionRole49AF0996": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3TaskDefExecutionRoleDefaultPolicy4656E642": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "L3TaskDefwebLogGroupC6E4A38A", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "L3TaskDefExecutionRoleDefaultPolicy4656E642", + "Roles": [ + { + "Ref": "L3TaskDefExecutionRole49AF0996" + } + ] + } + }, + "L3Service616D5A93": { + "Type": "AWS::ECS::Service", + "Properties": { + "TaskDefinition": { + "Ref": "L3TaskDef48D8ACB8" + }, + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYN926A5246" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "HealthCheckGracePeriodSeconds": 60, + "LaunchType": "FARGATE", + "LoadBalancers": [ + { + "ContainerName": "web", + "ContainerPort": 80, + "TargetGroupArn": { + "Ref": "L3LBPublicListenerECSGroup648EEA11" + } + } + ], + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3ServiceSecurityGroup677B0897", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1Subnet075EFF4C" + }, + { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2SubnetE4CEDF73" + } + ] + } + }, + "ServiceRegistries": [] + }, + "DependsOn": [ + "L3LBPublicListenerECSGroup648EEA11", + "L3LBPublicListener156FFC0F" + ] + }, + "L3ServiceSecurityGroup677B0897": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ/L3/Service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [], + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + } + } + }, + "L3ServiceSecurityGroupfromawsecsintegL3LBSecurityGroupA70DA46C80DBDFBCD6": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "L3ServiceSecurityGroup677B0897", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "L3LBSecurityGroupEDE61198", + "GroupId" + ] + }, + "ToPort": 80 + } + }, + "EcsDefaultClusterMnL3mNNYN926A5246": { + "Type": "AWS::ECS::Cluster" + }, + "EcsDefaultClusterMnL3mNNYNVpc7788A521": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1Subnet3C273B99": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet1" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1RouteTableA1FD6ACC": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet1" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1RouteTableAssociation8B583A17": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1RouteTableA1FD6ACC" + }, + "SubnetId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1Subnet3C273B99" + } + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1DefaultRouteFF4E2178": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1RouteTableA1FD6ACC" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcIGW9C2C2B8F" + } + }, + "DependsOn": [ + "EcsDefaultClusterMnL3mNNYNVpcVPCGW2447264E" + ] + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1EIP8704DB2F": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1NATGateway5E3732C1": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1EIP8704DB2F", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1Subnet3C273B99" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet1" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2Subnet95FF715A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet2" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2RouteTable263DEAA5": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet2" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2RouteTableAssociation43E5803C": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2RouteTable263DEAA5" + }, + "SubnetId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2Subnet95FF715A" + } + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2DefaultRouteB1375520": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2RouteTable263DEAA5" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcIGW9C2C2B8F" + } + }, + "DependsOn": [ + "EcsDefaultClusterMnL3mNNYNVpcVPCGW2447264E" + ] + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2EIPF0764873": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2NATGateway4C855E00": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2EIPF0764873", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2Subnet95FF715A" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PublicSubnet2" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1Subnet075EFF4C": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PrivateSubnet1" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1RouteTable4F1D2E36": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PrivateSubnet1" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1RouteTableAssociation34B92275": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1RouteTable4F1D2E36" + }, + "SubnetId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1Subnet075EFF4C" + } + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1DefaultRouteA5ADF694": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1RouteTable4F1D2E36" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1NATGateway5E3732C1" + } + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2SubnetE4CEDF73": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PrivateSubnet2" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2RouteTableDCE46591": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc/PrivateSubnet2" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2RouteTableAssociation111C622F": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2RouteTableDCE46591" + }, + "SubnetId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2SubnetE4CEDF73" + } + } + }, + "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2DefaultRoute20CE2D89": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2RouteTableDCE46591" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2NATGateway4C855E00" + } + } + }, + "EcsDefaultClusterMnL3mNNYNVpcIGW9C2C2B8F": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsDefaultClusterMnL3mNNYN/Vpc" + } + ] + } + }, + "EcsDefaultClusterMnL3mNNYNVpcVPCGW2447264E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + }, + "InternetGatewayId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcIGW9C2C2B8F" + } + } + }, + "L3bLBB8FADA4E": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3bLBSecurityGroup7A2B0AA0", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1Subnet3C273B99" + }, + { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2Subnet95FF715A" + } + ], + "Type": "application" + }, + "DependsOn": [ + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1DefaultRouteFF4E2178", + "EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2DefaultRouteB1375520" + ] + }, + "L3bLBSecurityGroup7A2B0AA0": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awsecsintegL3bLB9C1497A7", + "SecurityGroupEgress": [], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + } + } + }, + "L3bLBSecurityGrouptoawsecsintegL3bServiceSecurityGroupC2BD1A598019C4C37D": { + "Type": "AWS::EC2::SecurityGroupEgress", + "Properties": { + "GroupId": { + "Fn::GetAtt": [ + "L3bLBSecurityGroup7A2B0AA0", + "GroupId" + ] + }, + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "DestinationSecurityGroupId": { + "Fn::GetAtt": [ + "L3bServiceSecurityGroupA8DA736E", + "GroupId" + ] + }, + "FromPort": 80, + "ToPort": 80 + } + }, + "L3bLBPublicListenerA825925B": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "L3bLBPublicListenerECSGroup0070C5CA" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "L3bLBB8FADA4E" + }, + "Port": 80, + "Protocol": "HTTP", + "Certificates": [] + } + }, + "L3bLBPublicListenerECSGroup0070C5CA": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [], + "Targets": [], + "TargetType": "ip", + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + } + } + }, + "L3bTaskDefTaskRoleADAB80C8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3bTaskDef5506864D": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Links": [], + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "L3bTaskDefwebLogGroup8E5F1183" + }, + "awslogs-stream-prefix": "L3b", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "MountPoints": [], + "Name": "web", + "PortMappings": [ + { + "ContainerPort": 80, + "Protocol": "tcp" + } + ], + "Ulimits": [], + "VolumesFrom": [] + } + ], + "Cpu": "512", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "L3bTaskDefExecutionRole9A3E2688", + "Arn" + ] + }, + "Family": "awsecsintegL3bTaskDef24D7E4F1", + "Memory": "1024", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "L3bTaskDefTaskRoleADAB80C8", + "Arn" + ] + }, + "Volumes": [] + } + }, + "L3bTaskDefwebLogGroup8E5F1183": { + "Type": "AWS::Logs::LogGroup", + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain" + }, + "L3bTaskDefExecutionRole9A3E2688": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3bTaskDefExecutionRoleDefaultPolicy0CEA0ED2": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "L3bTaskDefwebLogGroup8E5F1183", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "L3bTaskDefExecutionRoleDefaultPolicy0CEA0ED2", + "Roles": [ + { + "Ref": "L3bTaskDefExecutionRole9A3E2688" + } + ] + } + }, + "L3bServiceF9D33D5A": { + "Type": "AWS::ECS::Service", + "Properties": { + "TaskDefinition": { + "Ref": "L3bTaskDef5506864D" + }, + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYN926A5246" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "HealthCheckGracePeriodSeconds": 60, + "LaunchType": "FARGATE", + "LoadBalancers": [ + { + "ContainerName": "web", + "ContainerPort": 80, + "TargetGroupArn": { + "Ref": "L3bLBPublicListenerECSGroup0070C5CA" + } + } + ], + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3bServiceSecurityGroupA8DA736E", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet1Subnet075EFF4C" + }, + { + "Ref": "EcsDefaultClusterMnL3mNNYNVpcPrivateSubnet2SubnetE4CEDF73" + } + ] + } + }, + "ServiceRegistries": [] + }, + "DependsOn": [ + "L3bLBPublicListenerECSGroup0070C5CA", + "L3bLBPublicListenerA825925B" + ] + }, + "L3bServiceSecurityGroupA8DA736E": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ/L3b/Service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [], + "VpcId": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc7788A521" + } + } + }, + "L3bServiceSecurityGroupfromawsecsintegL3bLBSecurityGroupA7B79A628034042CE5": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "L3bServiceSecurityGroupA8DA736E", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "L3bLBSecurityGroup7A2B0AA0", + "GroupId" + ] + }, + "ToPort": 80 + } + } + }, + "Outputs": { + "L3LoadBalancerDNSC6CB4A70": { + "Value": { + "Fn::GetAtt": [ + "L3LB212FC0E0", + "DNSName" + ] + } + }, + "L3bLoadBalancerDNSED096132": { + "Value": { + "Fn::GetAtt": [ + "L3bLBB8FADA4E", + "DNSName" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.ts new file mode 100644 index 0000000000000..6a400f37d0568 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.ts @@ -0,0 +1,20 @@ +import ecs = require('@aws-cdk/aws-ecs'); +import cdk = require('@aws-cdk/core'); +import ecsPatterns = require('../../lib'); + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ'); + +new ecsPatterns.LoadBalancedFargateService(stack, 'L3', { + memoryLimitMiB: 1024, + cpu: 512, + image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), +}); + +new ecsPatterns.LoadBalancedFargateService(stack, 'L3b', { + memoryLimitMiB: 1024, + cpu: 512, + image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json new file mode 100644 index 0000000000000..f1c64c6ee230e --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json @@ -0,0 +1,1721 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "L3LB212FC0E0": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3LBSecurityGroupEDE61198", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + ], + "Type": "application" + }, + "DependsOn": [ + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet2DefaultRoute97F91067" + ] + }, + "L3LBSecurityGroupEDE61198": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awsecsintegL3LB6453BA0A", + "SecurityGroupEgress": [], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "L3LBSecurityGrouptoawsecsintegL3ServiceSecurityGroup7B96C87F8094933E0A": { + "Type": "AWS::EC2::SecurityGroupEgress", + "Properties": { + "GroupId": { + "Fn::GetAtt": [ + "L3LBSecurityGroupEDE61198", + "GroupId" + ] + }, + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "DestinationSecurityGroupId": { + "Fn::GetAtt": [ + "L3ServiceSecurityGroup677B0897", + "GroupId" + ] + }, + "FromPort": 80, + "ToPort": 80 + } + }, + "L3LBPublicListener156FFC0F": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "L3LBPublicListenerECSGroup648EEA11" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "L3LB212FC0E0" + }, + "Port": 80, + "Protocol": "HTTP", + "Certificates": [] + } + }, + "L3LBPublicListenerECSGroup648EEA11": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [], + "Targets": [], + "TargetType": "ip", + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "L3TaskDefTaskRole21C75D10": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3TaskDef48D8ACB8": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Links": [], + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "L3TaskDefwebLogGroupC6E4A38A" + }, + "awslogs-stream-prefix": "L3", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "MountPoints": [], + "Name": "web", + "PortMappings": [ + { + "ContainerPort": 80, + "Protocol": "tcp" + } + ], + "Ulimits": [], + "VolumesFrom": [] + } + ], + "Cpu": "512", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "L3TaskDefExecutionRole49AF0996", + "Arn" + ] + }, + "Family": "awsecsintegL3TaskDefAA25240E", + "Memory": "1024", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "L3TaskDefTaskRole21C75D10", + "Arn" + ] + }, + "Volumes": [] + } + }, + "L3TaskDefwebLogGroupC6E4A38A": { + "Type": "AWS::Logs::LogGroup", + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain" + }, + "L3TaskDefExecutionRole49AF0996": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3TaskDefExecutionRoleDefaultPolicy4656E642": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "L3TaskDefwebLogGroupC6E4A38A", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "L3TaskDefExecutionRoleDefaultPolicy4656E642", + "Roles": [ + { + "Ref": "L3TaskDefExecutionRole49AF0996" + } + ] + } + }, + "L3Service616D5A93": { + "Type": "AWS::ECS::Service", + "Properties": { + "TaskDefinition": { + "Ref": "L3TaskDef48D8ACB8" + }, + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc18E0451A" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "HealthCheckGracePeriodSeconds": 60, + "LaunchType": "FARGATE", + "LoadBalancers": [ + { + "ContainerName": "web", + "ContainerPort": 80, + "TargetGroupArn": { + "Ref": "L3LBPublicListenerECSGroup648EEA11" + } + } + ], + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3ServiceSecurityGroup677B0897", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + } + }, + "ServiceRegistries": [] + }, + "DependsOn": [ + "L3LBPublicListenerECSGroup648EEA11", + "L3LBPublicListener156FFC0F" + ] + }, + "L3ServiceSecurityGroup677B0897": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ/L3/Service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "L3ServiceSecurityGroupfromawsecsintegL3LBSecurityGroupA70DA46C80DBDFBCD6": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "L3ServiceSecurityGroup677B0897", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "L3LBSecurityGroupEDE61198", + "GroupId" + ] + }, + "ToPort": 80 + } + }, + "EcsDefaultClusterMnL3mNNYNVpc18E0451A": { + "Type": "AWS::ECS::Cluster" + }, + "Vpc299FDBC5F": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2" + } + ] + } + }, + "Vpc2PublicSubnet1Subnet758D49A9": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PublicSubnet1" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + } + ] + } + }, + "Vpc2PublicSubnet1RouteTable424A19D4": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PublicSubnet1" + } + ] + } + }, + "Vpc2PublicSubnet1RouteTableAssociationA1651F3A": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "Vpc2PublicSubnet1RouteTable424A19D4" + }, + "SubnetId": { + "Ref": "Vpc2PublicSubnet1Subnet758D49A9" + } + } + }, + "Vpc2PublicSubnet1DefaultRoute64172CA2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "Vpc2PublicSubnet1RouteTable424A19D4" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "Vpc2IGWB10A76EB" + } + }, + "DependsOn": [ + "Vpc2VPCGW62C338EF" + ] + }, + "Vpc2PublicSubnet1EIP42DB8E45": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + }, + "Vpc2PublicSubnet1NATGateway26016506": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "Vpc2PublicSubnet1EIP42DB8E45", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "Vpc2PublicSubnet1Subnet758D49A9" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PublicSubnet1" + } + ] + } + }, + "Vpc2PublicSubnet2Subnet0BF8C291": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PublicSubnet2" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + } + ] + } + }, + "Vpc2PublicSubnet2RouteTableF9AE47B1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PublicSubnet2" + } + ] + } + }, + "Vpc2PublicSubnet2RouteTableAssociation361E1341": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "Vpc2PublicSubnet2RouteTableF9AE47B1" + }, + "SubnetId": { + "Ref": "Vpc2PublicSubnet2Subnet0BF8C291" + } + } + }, + "Vpc2PublicSubnet2DefaultRouteBAB514C1": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "Vpc2PublicSubnet2RouteTableF9AE47B1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "Vpc2IGWB10A76EB" + } + }, + "DependsOn": [ + "Vpc2VPCGW62C338EF" + ] + }, + "Vpc2PublicSubnet2EIP66DD26A4": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + }, + "Vpc2PublicSubnet2NATGateway6CBF7FA6": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "Vpc2PublicSubnet2EIP66DD26A4", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "Vpc2PublicSubnet2Subnet0BF8C291" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PublicSubnet2" + } + ] + } + }, + "Vpc2PrivateSubnet1Subnet34902000": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PrivateSubnet1" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + } + ] + } + }, + "Vpc2PrivateSubnet1RouteTableF8A2430B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PrivateSubnet1" + } + ] + } + }, + "Vpc2PrivateSubnet1RouteTableAssociation74320528": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "Vpc2PrivateSubnet1RouteTableF8A2430B" + }, + "SubnetId": { + "Ref": "Vpc2PrivateSubnet1Subnet34902000" + } + } + }, + "Vpc2PrivateSubnet1DefaultRoute24717F54": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "Vpc2PrivateSubnet1RouteTableF8A2430B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "Vpc2PublicSubnet1NATGateway26016506" + } + } + }, + "Vpc2PrivateSubnet2Subnet3BA0F39B": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PrivateSubnet2" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + } + ] + } + }, + "Vpc2PrivateSubnet2RouteTableB4F37E84": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2/PrivateSubnet2" + } + ] + } + }, + "Vpc2PrivateSubnet2RouteTableAssociation19A1B68F": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "Vpc2PrivateSubnet2RouteTableB4F37E84" + }, + "SubnetId": { + "Ref": "Vpc2PrivateSubnet2Subnet3BA0F39B" + } + } + }, + "Vpc2PrivateSubnet2DefaultRouteA55B1734": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "Vpc2PrivateSubnet2RouteTableB4F37E84" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "Vpc2PublicSubnet2NATGateway6CBF7FA6" + } + } + }, + "Vpc2IGWB10A76EB": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc2" + } + ] + } + }, + "Vpc2VPCGW62C338EF": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc299FDBC5F" + }, + "InternetGatewayId": { + "Ref": "Vpc2IGWB10A76EB" + } + } + }, + "L3bLBB8FADA4E": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3bLBSecurityGroup7A2B0AA0", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "Vpc2PublicSubnet1Subnet758D49A9" + }, + { + "Ref": "Vpc2PublicSubnet2Subnet0BF8C291" + } + ], + "Type": "application" + }, + "DependsOn": [ + "Vpc2PublicSubnet1DefaultRoute64172CA2", + "Vpc2PublicSubnet2DefaultRouteBAB514C1" + ] + }, + "L3bLBSecurityGroup7A2B0AA0": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awsecsintegL3bLB9C1497A7", + "SecurityGroupEgress": [], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "Vpc299FDBC5F" + } + } + }, + "L3bLBSecurityGrouptoawsecsintegL3bServiceSecurityGroupC2BD1A598019C4C37D": { + "Type": "AWS::EC2::SecurityGroupEgress", + "Properties": { + "GroupId": { + "Fn::GetAtt": [ + "L3bLBSecurityGroup7A2B0AA0", + "GroupId" + ] + }, + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "DestinationSecurityGroupId": { + "Fn::GetAtt": [ + "L3bServiceSecurityGroupA8DA736E", + "GroupId" + ] + }, + "FromPort": 80, + "ToPort": 80 + } + }, + "L3bLBPublicListenerA825925B": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "L3bLBPublicListenerECSGroup0070C5CA" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "L3bLBB8FADA4E" + }, + "Port": 80, + "Protocol": "HTTP", + "Certificates": [] + } + }, + "L3bLBPublicListenerECSGroup0070C5CA": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [], + "Targets": [], + "TargetType": "ip", + "VpcId": { + "Ref": "Vpc299FDBC5F" + } + } + }, + "L3bTaskDefTaskRoleADAB80C8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3bTaskDef5506864D": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Links": [], + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "L3bTaskDefwebLogGroup8E5F1183" + }, + "awslogs-stream-prefix": "L3b", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "MountPoints": [], + "Name": "web", + "PortMappings": [ + { + "ContainerPort": 80, + "Protocol": "tcp" + } + ], + "Ulimits": [], + "VolumesFrom": [] + } + ], + "Cpu": "512", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "L3bTaskDefExecutionRole9A3E2688", + "Arn" + ] + }, + "Family": "awsecsintegL3bTaskDef24D7E4F1", + "Memory": "1024", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "L3bTaskDefTaskRoleADAB80C8", + "Arn" + ] + }, + "Volumes": [] + } + }, + "L3bTaskDefwebLogGroup8E5F1183": { + "Type": "AWS::Logs::LogGroup", + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain" + }, + "L3bTaskDefExecutionRole9A3E2688": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3bTaskDefExecutionRoleDefaultPolicy0CEA0ED2": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "L3bTaskDefwebLogGroup8E5F1183", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "L3bTaskDefExecutionRoleDefaultPolicy0CEA0ED2", + "Roles": [ + { + "Ref": "L3bTaskDefExecutionRole9A3E2688" + } + ] + } + }, + "L3bServiceF9D33D5A": { + "Type": "AWS::ECS::Service", + "Properties": { + "TaskDefinition": { + "Ref": "L3bTaskDef5506864D" + }, + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc2B5DB011D" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "HealthCheckGracePeriodSeconds": 60, + "LaunchType": "FARGATE", + "LoadBalancers": [ + { + "ContainerName": "web", + "ContainerPort": 80, + "TargetGroupArn": { + "Ref": "L3bLBPublicListenerECSGroup0070C5CA" + } + } + ], + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3bServiceSecurityGroupA8DA736E", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "Vpc2PrivateSubnet1Subnet34902000" + }, + { + "Ref": "Vpc2PrivateSubnet2Subnet3BA0F39B" + } + ] + } + }, + "ServiceRegistries": [] + }, + "DependsOn": [ + "L3bLBPublicListenerECSGroup0070C5CA", + "L3bLBPublicListenerA825925B" + ] + }, + "L3bServiceSecurityGroupA8DA736E": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ/L3b/Service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [], + "VpcId": { + "Ref": "Vpc299FDBC5F" + } + } + }, + "L3bServiceSecurityGroupfromawsecsintegL3bLBSecurityGroupA7B79A628034042CE5": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "L3bServiceSecurityGroupA8DA736E", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "L3bLBSecurityGroup7A2B0AA0", + "GroupId" + ] + }, + "ToPort": 80 + } + }, + "EcsDefaultClusterMnL3mNNYNVpc2B5DB011D": { + "Type": "AWS::ECS::Cluster" + }, + "L3cLB041B1E8C": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [], + "Scheme": "internet-facing", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3cLBSecurityGroup818CBDE1", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "Vpc2PublicSubnet1Subnet758D49A9" + }, + { + "Ref": "Vpc2PublicSubnet2Subnet0BF8C291" + } + ], + "Type": "application" + }, + "DependsOn": [ + "Vpc2PublicSubnet1DefaultRoute64172CA2", + "Vpc2PublicSubnet2DefaultRouteBAB514C1" + ] + }, + "L3cLBSecurityGroup818CBDE1": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB awsecsintegL3cLB16505710", + "SecurityGroupEgress": [], + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "Vpc299FDBC5F" + } + } + }, + "L3cLBSecurityGrouptoawsecsintegL3cServiceSecurityGroupA4254E838029E3B246": { + "Type": "AWS::EC2::SecurityGroupEgress", + "Properties": { + "GroupId": { + "Fn::GetAtt": [ + "L3cLBSecurityGroup818CBDE1", + "GroupId" + ] + }, + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "DestinationSecurityGroupId": { + "Fn::GetAtt": [ + "L3cServiceSecurityGroup94AFACED", + "GroupId" + ] + }, + "FromPort": 80, + "ToPort": 80 + } + }, + "L3cLBPublicListener1D4B3F11": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "L3cLBPublicListenerECSGroup62D7B705" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "L3cLB041B1E8C" + }, + "Port": 80, + "Protocol": "HTTP", + "Certificates": [] + } + }, + "L3cLBPublicListenerECSGroup62D7B705": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetGroupAttributes": [], + "Targets": [], + "TargetType": "ip", + "VpcId": { + "Ref": "Vpc299FDBC5F" + } + } + }, + "L3cTaskDefTaskRole3C3C6124": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3cTaskDefA575AF8A": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Links": [], + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "L3cTaskDefwebLogGroupE4BDEC1B" + }, + "awslogs-stream-prefix": "L3c", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "MountPoints": [], + "Name": "web", + "PortMappings": [ + { + "ContainerPort": 80, + "Protocol": "tcp" + } + ], + "Ulimits": [], + "VolumesFrom": [] + } + ], + "Cpu": "512", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "L3cTaskDefExecutionRoleF366B4B2", + "Arn" + ] + }, + "Family": "awsecsintegL3cTaskDefF83D4A1D", + "Memory": "1024", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "L3cTaskDefTaskRole3C3C6124", + "Arn" + ] + }, + "Volumes": [] + } + }, + "L3cTaskDefwebLogGroupE4BDEC1B": { + "Type": "AWS::Logs::LogGroup", + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain" + }, + "L3cTaskDefExecutionRoleF366B4B2": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ecs-tasks.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "L3cTaskDefExecutionRoleDefaultPolicy364B8E8C": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "L3cTaskDefwebLogGroupE4BDEC1B", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "L3cTaskDefExecutionRoleDefaultPolicy364B8E8C", + "Roles": [ + { + "Ref": "L3cTaskDefExecutionRoleF366B4B2" + } + ] + } + }, + "L3cServiceADA1E573": { + "Type": "AWS::ECS::Service", + "Properties": { + "TaskDefinition": { + "Ref": "L3cTaskDefA575AF8A" + }, + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc2B5DB011D" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "HealthCheckGracePeriodSeconds": 60, + "LaunchType": "FARGATE", + "LoadBalancers": [ + { + "ContainerName": "web", + "ContainerPort": 80, + "TargetGroupArn": { + "Ref": "L3cLBPublicListenerECSGroup62D7B705" + } + } + ], + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "L3cServiceSecurityGroup94AFACED", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "Vpc2PrivateSubnet1Subnet34902000" + }, + { + "Ref": "Vpc2PrivateSubnet2Subnet3BA0F39B" + } + ] + } + }, + "ServiceRegistries": [] + }, + "DependsOn": [ + "L3cLBPublicListenerECSGroup62D7B705", + "L3cLBPublicListener1D4B3F11" + ] + }, + "L3cServiceSecurityGroup94AFACED": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ/L3c/Service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [], + "VpcId": { + "Ref": "Vpc299FDBC5F" + } + } + }, + "L3cServiceSecurityGroupfromawsecsintegL3cLBSecurityGroup7820B0B28070DB6447": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "L3cServiceSecurityGroup94AFACED", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "L3cLBSecurityGroup818CBDE1", + "GroupId" + ] + }, + "ToPort": 80 + } + } + }, + "Outputs": { + "L3LoadBalancerDNSC6CB4A70": { + "Value": { + "Fn::GetAtt": [ + "L3LB212FC0E0", + "DNSName" + ] + } + }, + "L3bLoadBalancerDNSED096132": { + "Value": { + "Fn::GetAtt": [ + "L3bLBB8FADA4E", + "DNSName" + ] + } + }, + "L3cLoadBalancerDNS9409202E": { + "Value": { + "Fn::GetAtt": [ + "L3cLB041B1E8C", + "DNSName" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.ts new file mode 100644 index 0000000000000..173f428e29b6a --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.ts @@ -0,0 +1,32 @@ +import ec2 = require('@aws-cdk/aws-ec2'); +import ecs = require('@aws-cdk/aws-ecs'); +import cdk = require('@aws-cdk/core'); +import ecsPatterns = require('../../lib'); + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ'); + +const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2 }); +new ecsPatterns.LoadBalancedFargateService(stack, 'L3', { + vpc, + memoryLimitMiB: 1024, + cpu: 512, + image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), +}); + +const vpc2 = new ec2.Vpc(stack, 'Vpc2', { maxAzs: 2 }); +new ecsPatterns.LoadBalancedFargateService(stack, 'L3b', { + vpc: vpc2, + memoryLimitMiB: 1024, + cpu: 512, + image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), +}); + +new ecsPatterns.LoadBalancedFargateService(stack, 'L3c', { + vpc: vpc2, + memoryLimitMiB: 1024, + cpu: 512, + image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts index eacae40b2a487..645ef2b8555ee 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts @@ -51,11 +51,29 @@ export = { test.done(); }, + 'setting vpc and cluster throws error'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + test.throws(() => new ecsPatterns.LoadBalancedFargateService(stack, 'Service', { + cluster, + vpc, + loadBalancerType: ecsPatterns.LoadBalancerType.NETWORK, + image: ecs.ContainerImage.fromRegistry("/aws/aws-example-app") + })); + + test.done(); + }, + 'setting executionRole updated taskDefinition with given execution role'(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const executionRole = new iam.Role(stack, 'ExecutionRole', { path: '/', assumedBy: new iam.CompositePrincipal( @@ -181,4 +199,5 @@ export = { test.equal(serviceTaskDefinition.Properties.ServiceName, undefined); test.done(); } + }; diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index a2e44c6ad5681..0f2a6e2e4178d 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -121,6 +121,8 @@ const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', { cluster.addAutoScalingGroup(autoScalingGroup); ``` +If you omit the property `vpc`, the construct will create a new VPC with two AZs. + ## Task definitions A task Definition describes what a single copy of a **task** should look like. diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index d23fc77f99e76..4b7ba7491119e 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -20,9 +20,11 @@ export interface ClusterProps { readonly clusterName?: string; /** - * The VPC to associate with the cluster. + * The VPC where your ECS instances will be running or your ENIs will be deployed + * + * @default - creates a new VPC with two AZs */ - readonly vpc: ec2.IVpc; + readonly vpc?: ec2.IVpc; } /** @@ -66,10 +68,7 @@ export class Cluster extends Resource implements ICluster { */ private _hasEc2Capacity: boolean = false; - /** - * Constructs a new instance of the Cluster class. - */ - constructor(scope: Construct, id: string, props: ClusterProps) { + constructor(scope: Construct, id: string, props: ClusterProps = {}) { super(scope, id, { physicalName: props.clusterName, }); @@ -85,7 +84,7 @@ export class Cluster extends Resource implements ICluster { }); this.clusterName = this.getResourceNameAttribute(cluster.ref); - this.vpc = props.vpc; + this.vpc = props.vpc || new ec2.Vpc(this, 'Vpc', { maxAzs: 2 }); } /** diff --git a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts b/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts index 8007c40d2d51e..072774c51e033 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts +++ b/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts @@ -8,7 +8,151 @@ import ecs = require('../lib'); export = { "When creating an ECS Cluster": { - "with only required properties set, it correctly sets default properties"(test: Test) { + "with no properties set, it correctly sets default properties"(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const cluster = new ecs.Cluster(stack, 'EcsCluster'); + + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro') + }); + + expect(stack).to(haveResource("AWS::ECS::Cluster")); + + expect(stack).to(haveResource("AWS::EC2::VPC", { + CidrBlock: '10.0.0.0/16', + EnableDnsHostnames: true, + EnableDnsSupport: true, + InstanceTenancy: ec2.DefaultInstanceTenancy.DEFAULT, + Tags: [ + { + Key: "Name", + Value: "EcsCluster/Vpc" + } + ] + })); + + expect(stack).to(haveResource("AWS::AutoScaling::LaunchConfiguration", { + ImageId: { + Ref: "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, + InstanceType: "t2.micro", + IamInstanceProfile: { + Ref: "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" + }, + SecurityGroups: [ + { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupInstanceSecurityGroup912E1231", + "GroupId" + ] + } + ], + UserData: { + "Fn::Base64": { + "Fn::Join": [ + "", + [ + "#!/bin/bash\necho ECS_CLUSTER=", + { + Ref: "EcsCluster97242B84" + }, + // tslint:disable-next-line:max-line-length + " >> /etc/ecs/ecs.config\nsudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP\nsudo service iptables save\necho ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config" + ] + ] + } + } + })); + + expect(stack).to(haveResource("AWS::AutoScaling::AutoScalingGroup", { + MaxSize: "1", + MinSize: "1", + DesiredCapacity: "1", + LaunchConfigurationName: { + Ref: "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1" + }, + Tags: [ + { + Key: "Name", + PropagateAtLaunch: true, + Value: "EcsCluster/DefaultAutoScalingGroup" + } + ], + VPCZoneIdentifier: [ + { + Ref: "EcsClusterVpcPrivateSubnet1SubnetFAB0E487" + }, + { + Ref: "EcsClusterVpcPrivateSubnet2SubnetC2B7B1BA" + } + ] + })); + + expect(stack).to(haveResource("AWS::EC2::SecurityGroup", { + GroupDescription: "EcsCluster/DefaultAutoScalingGroup/InstanceSecurityGroup", + SecurityGroupEgress: [ + { + CidrIp: "0.0.0.0/0", + Description: "Allow all outbound traffic by default", + IpProtocol: "-1" + } + ], + SecurityGroupIngress: [], + Tags: [ + { + Key: "Name", + Value: "EcsCluster/DefaultAutoScalingGroup" + } + ], + VpcId: { + Ref: "EcsClusterVpc779914AB" + } + })); + + expect(stack).to(haveResource("AWS::IAM::Role", { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: "sts:AssumeRole", + Effect: "Allow", + Principal: { + Service: { "Fn::Join": ["", ["ec2.", { Ref: "AWS::URLSuffix" }]] } + } + } + ], + Version: "2012-10-17" + } + })); + + expect(stack).to(haveResource("AWS::IAM::Policy", { + PolicyDocument: { + Statement: [ + { + Action: [ + "ecs:CreateCluster", + "ecs:DeregisterContainerInstance", + "ecs:DiscoverPollEndpoint", + "ecs:Poll", + "ecs:RegisterContainerInstance", + "ecs:StartTelemetrySession", + "ecs:Submit*", + "ecr:GetAuthorizationToken", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + Effect: "Allow", + Resource: "*" + } + ], + Version: "2012-10-17" + } + })); + + test.done(); + }, + + "with only vpc set, it correctly sets default properties"(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'MyVpc', {});