From 041868c6ef9b7776877dcbf0240b52b8a3335d81 Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Fri, 12 Jan 2024 17:49:35 +0900 Subject: [PATCH 01/10] feat(ecs): attach EBS to ECS change to volumeName doc renderVolumeConfigurations propagateTags task definition --- .../aws-ecs/lib/base/base-service.ts | 273 ++++++++++++++++++ .../aws-ecs/lib/base/task-definition.ts | 17 +- 2 files changed, 289 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts index 9726ef21526ce..6dfd80a3b0e31 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts @@ -6,6 +6,7 @@ import * as ec2 from '../../../aws-ec2'; import * as elb from '../../../aws-elasticloadbalancing'; import * as elbv2 from '../../../aws-elasticloadbalancingv2'; import * as iam from '../../../aws-iam'; +import * as kms from '../../../aws-kms'; import * as cloudmap from '../../../aws-servicediscovery'; import { Annotations, @@ -221,6 +222,227 @@ export interface ServiceConnectService { readonly ingressPortOverride?: number; } +/** + * Filesystem Type for EBS Volume Configuration. + */ +export enum FilesystemType { + /** + * ext3 type + */ + EXT3 = 'ext3', + /** + * ext4 type + */ + EXT4 = 'ext4', + /** + * xfs type + */ + XFS = 'xfs', +} + +/** + * Volume Type for EBS Volume Configuration. + */ +export enum VolumeType { + /** + * General Purpose SSD: gp2 + */ + GP2 = 'gp2', + /** + * General Purpose SSD: gp3 + */ + GP3 = 'gp3', + /** + * Provisioned IOPS SSD: io1 + */ + IO1 = 'io1', + /** + * Provisioned IOPS SSD: io2 + */ + IO2 = 'io2', + /** + * Throughput Optimized HDD: st1 + */ + ST1 = 'st1', + /** + * Cold HDD: sc1 + */ + SC1 = 'sc1', + /** + * Magnetic: standard + * + * This volume type is not supported on Fargate. + */ + STANDARD = 'standard', +} + +/** + * Propagate tags for EBS Volume Configuration from either service or task definition. + */ +export enum EbsPropagatedTagSource { + /** + * SERVICE + */ + SERVICE = 'SERVICE', + /** + * TASK_DEFINITION + */ + TASK_DEFINITION = 'TASK_DEFINITION', +} + +/** + * Metadata that you apply to a resource to help categorize and organize the resource. + * + * Each tag consists of a key and an optional value, both of which you define. + */ +export interface Tag { + + /** + * Key is the name of the tag + */ + readonly key: string; + /** + * Value is the metadata contents of the tag + */ + readonly value: string; +} + +/** + * Interface for Tag specifications for EBS Volume Configuration. + */ +export interface EbsTagSpecifications { + /** + * Determines whether to propagate the tags from the task definition to the Amazon EBS volume. + * + * @default - No value. The tags aren't propagated. + */ + readonly propagateTags?: EbsPropagatedTagSource; + + /** + * The tags applied to this Amazon EBS volume. + * + * `AmazonECSCreated` and `AmazonECSManaged` are reserved tags that can't be used. + * + * @default - No tags. + */ + readonly tags?: Tag[]; +} + +/** + * Interface for EBS Volume Configuration. + */ +export interface EbsVolumeConfiguration { + /** + * The name of the volume. + * This value must match the volume name from the Volume object in the task definition. + */ + readonly volumeName: string; + + /** + * Indicates whether the volume should be encrypted. + * + * @default - encryption is turned on by default. + */ + readonly encrypted?: boolean; + + /** + * The Linux filesystem type for the volume. + * + * For volumes created from a snapshot, you must specify the same filesystem type that + * the volume was using when the snapshot was created. + * + * @default - FilesystemType.XFS + */ + readonly filesystemType?: FilesystemType; + + /** + * The number of I/O operations per second (IOPS). + * + * For gp3, io1, and io2 volumes, this represents the number of IOPS that are provisioned + * for the volume. For gp2 volumes, this represents the baseline performance of the volume + * and the rate at which the volume accumulates I/O credits for bursting. + * + * The following are the supported values for each volume type. + * - gp3: 3,000 - 16,000 IOPS + * - io1: 100 - 64,000 IOPS + * - io2: 100 - 256,000 IOPS + * + * This parameter is required for io1 and io2 volume types. The default for gp3 volumes is + * 3,000 IOPS. This parameter is not supported for st1, sc1, or standard volume types. + * + * @default - FilesystemType.XFS + */ + readonly iops?: number; + + /** + * AWS Key Management Service key to use for Amazon EBS encryption. + * + * @default - When `encryption` is turned on and no `kmsKey` is specified, + * the default AWS managed key for Amazon EBS volumes is used. + */ + readonly kmsKey?: kms.IKey; + + /** + * IAM role to associate with this volume. + * + * This is the Amazon ECS infrastructure IAM role that is used to manage your AWS infrastructure. + * We recommend using the Amazon ECS-managed `AmazonECSInfrastructureRolePolicyForVolumes` IAM policy + * with this role. + * + * @default - automatically generated role. + */ + readonly role?: iam.IRole; + + /** + * The size of the volume in GiB. + * + * You must specify either `sizeInGiB` or `snapshotId`. + * You can optionally specify a volume size greater than or equal to the snapshot size. + * + * The following are the supported volume size values for each volume type. + * - gp2 and gp3: 1-16,384 + * - io1 and io2: 4-16,384 + * - st1 and sc1: 125-16,384 + * - standard: 1-1,024 + * + * @default - The snapshot size is used for the volume size if you specify `snapshotId`, + * otherwise this parameter is required. + */ + readonly sizeInGiB?: number; + + /** + * The snapshot that Amazon ECS uses to create the volume. + * + * You must specify either `sizeInGiB` or `snapshotId`. + * + * @default - No snapshot. + */ + readonly snapshotId?: string; + + /** + * The tags to apply to the volume. + * + * @default - service-managed tags will be applied. + */ + readonly tagSpecifications?: EbsTagSpecifications[]; + + /** + * The throughput to provision for a volume, in MiB/s, with a maximum of 1,000 MiB/s. + * + * This parameter is only supported for the gp3 volume type. + * + * @default - No throughput. + */ + readonly throughput?: number; + + /** + * The volume type. + * + * @default - No volume type. + */ + readonly volumeType?: VolumeType; +} + /** * The properties for the base Ec2Service or FargateService service. */ @@ -357,6 +579,14 @@ export interface BaseServiceOptions { * @default - Uses the revision of the passed task definition deployed by CloudFormation */ readonly taskDefinitionRevision?: TaskDefinitionRevision; + + /** + * The configuration for EBS volume specified in the task definition as a volume that is configured + * at launch time. + * + * @default - No EBS volume configuration. + */ + readonly ebsVolumeConfiguration?: EbsVolumeConfiguration; } /** @@ -622,6 +852,7 @@ export abstract class BaseService extends Resource enableExecuteCommand: props.enableExecuteCommand, capacityProviderStrategy: props.capacityProviderStrategies, healthCheckGracePeriodSeconds: this.evaluateHealthGracePeriod(props.healthCheckGracePeriod), + volumeConfigurations: this.renderVolumeConfigurations(props.ebsVolumeConfiguration), /* role: never specified, supplanted by Service Linked Role */ networkConfiguration: Lazy.any({ produce: () => this.networkConfiguration }, { omitEmptyArray: true }), serviceRegistries: Lazy.any({ produce: () => this.serviceRegistries }, { omitEmptyArray: true }), @@ -1400,6 +1631,48 @@ export abstract class BaseService extends Resource } return true; } + + private renderVolumeConfigurations(ebsVolumeConfiguration?: EbsVolumeConfiguration): CfnService.ServiceVolumeConfigurationProperty[] | undefined { + if (!ebsVolumeConfiguration) { + return; + } + + const ebsVolumeRole = ebsVolumeConfiguration.role ?? new iam.Role(this, 'EbsVolumeRole', { + assumedBy: new iam.ServicePrincipal('ecs.amazonaws.com'), + managedPolicies: [ + iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSInfrastructureRolePolicyForVolumes'), + ], + }); + + const tagSpecifications: CfnService.EBSTagSpecificationProperty[] | undefined = ebsVolumeConfiguration.tagSpecifications?.map(tagSpec => { + return { + propagateTags: tagSpec.propagateTags, + resourceType: 'volume', + tags: tagSpec.tags?.map(tag => { + return { + key: tag.key, + value: tag.value, + }; + }), + }; + }); + + return [{ + name: ebsVolumeConfiguration?.volumeName, + managedEbsVolume: { + encrypted: ebsVolumeConfiguration.encrypted, + filesystemType: ebsVolumeConfiguration.filesystemType, + iops: ebsVolumeConfiguration.iops, + kmsKeyId: ebsVolumeConfiguration.kmsKey?.keyId, + roleArn: ebsVolumeRole.roleArn, + sizeInGiB: ebsVolumeConfiguration.sizeInGiB, + snapshotId: ebsVolumeConfiguration.snapshotId, + tagSpecifications: tagSpecifications, + throughput: ebsVolumeConfiguration.throughput, + volumeType: ebsVolumeConfiguration.volumeType, + }, + }]; + } } /** diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts index 34793208d28d5..3abe85d86063b 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts @@ -538,8 +538,8 @@ export class TaskDefinition extends TaskDefinitionBase { rootDirectory: spec.efsVolumeConfiguration.rootDirectory, transitEncryption: spec.efsVolumeConfiguration.transitEncryption, transitEncryptionPort: spec.efsVolumeConfiguration.transitEncryptionPort, - }, + // configuredAtLaunch: spec.configuredAtLaunch, }; } } @@ -999,6 +999,21 @@ export interface Volume { * @default No Elastic FileSystem is setup */ readonly efsVolumeConfiguration?: EfsVolumeConfiguration; + + /** + * This property is specified when you are using Amazon EBS. + * + * Indicates whether the volume should be configured at launch time. This is used to create + * Amazon EBS volumes for standalone tasks or tasks created as part of a service. + * Each task definition revision may only have one volume configured at launch in the volume + * configuration. + * + * To configure a volume at launch time, use this task definition revision and specify a + * `ebsVolumeConfiguration` in `BaseServiceProps` for ECS Service. + * + * @default false + */ + readonly configuredAtLaunch?: boolean; } /** From 7ad0431c9d875661ffea2cf7e8b07567e6965c7a Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Fri, 12 Jan 2024 20:03:59 +0900 Subject: [PATCH 02/10] validations and VolumeType default change validations change validation validations --- .../aws-ecs/lib/base/base-service.ts | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts index 6dfd80a3b0e31..b80823ae82b9f 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts @@ -438,7 +438,7 @@ export interface EbsVolumeConfiguration { /** * The volume type. * - * @default - No volume type. + * @default - VolumeType.GP2. */ readonly volumeType?: VolumeType; } @@ -1632,19 +1632,37 @@ export abstract class BaseService extends Resource return true; } - private renderVolumeConfigurations(ebsVolumeConfiguration?: EbsVolumeConfiguration): CfnService.ServiceVolumeConfigurationProperty[] | undefined { - if (!ebsVolumeConfiguration) { + private renderVolumeConfigurations(config?: EbsVolumeConfiguration): CfnService.ServiceVolumeConfigurationProperty[] | undefined { + if (!config) { return; } - const ebsVolumeRole = ebsVolumeConfiguration.role ?? new iam.Role(this, 'EbsVolumeRole', { + if (config.throughput) { // No need to check tokens as it is good to know if they are specified or not. + if (config.volumeType !== VolumeType.GP3) { + throw new Error(`throughput can only be configured with gp3 volume type, got ${config.volumeType}`); + } + if (!Token.isUnresolved(config.throughput) && config.throughput > 1000) { + throw new Error(`throughput must be less than or equal to 1000 MiB/s, got ${config.throughput} MiB/s`); + } + } + if (config.iops) { // No need to check tokens as it is good to know if they are specified or not. + if ([VolumeType.SC1, VolumeType.ST1, VolumeType.STANDARD].some(type => config.volumeType === type)) { + throw new Error(`iops cannot be specified with sc1, st1, and standard volume types, got ${config.volumeType}`); + } + } else { + if ([VolumeType.IO1, VolumeType.IO2].some(type => config.volumeType === type)) { + throw new Error(`iops must be specified with io1 and io2 volume types, got ${config.volumeType}`); + } + } + + const ebsVolumeRole = config.role ?? new iam.Role(this, 'EbsVolumeRole', { assumedBy: new iam.ServicePrincipal('ecs.amazonaws.com'), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSInfrastructureRolePolicyForVolumes'), ], }); - const tagSpecifications: CfnService.EBSTagSpecificationProperty[] | undefined = ebsVolumeConfiguration.tagSpecifications?.map(tagSpec => { + const tagSpecifications: CfnService.EBSTagSpecificationProperty[] | undefined = config.tagSpecifications?.map(tagSpec => { return { propagateTags: tagSpec.propagateTags, resourceType: 'volume', @@ -1658,18 +1676,18 @@ export abstract class BaseService extends Resource }); return [{ - name: ebsVolumeConfiguration?.volumeName, + name: config?.volumeName, managedEbsVolume: { - encrypted: ebsVolumeConfiguration.encrypted, - filesystemType: ebsVolumeConfiguration.filesystemType, - iops: ebsVolumeConfiguration.iops, - kmsKeyId: ebsVolumeConfiguration.kmsKey?.keyId, + encrypted: config.encrypted, + filesystemType: config.filesystemType, + iops: config.iops, + kmsKeyId: config.kmsKey?.keyId, roleArn: ebsVolumeRole.roleArn, - sizeInGiB: ebsVolumeConfiguration.sizeInGiB, - snapshotId: ebsVolumeConfiguration.snapshotId, + sizeInGiB: config.sizeInGiB, + snapshotId: config.snapshotId, tagSpecifications: tagSpecifications, - throughput: ebsVolumeConfiguration.throughput, - volumeType: ebsVolumeConfiguration.volumeType, + throughput: config.throughput, + volumeType: config.volumeType, }, }]; } From 00d93c7eadefcd5ee0a76363297d6f41d78c499a Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Fri, 12 Jan 2024 20:39:59 +0900 Subject: [PATCH 03/10] add configuredAtLaunch --- packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts index 3abe85d86063b..e74933bde4c23 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts @@ -539,7 +539,7 @@ export class TaskDefinition extends TaskDefinitionBase { transitEncryption: spec.efsVolumeConfiguration.transitEncryption, transitEncryptionPort: spec.efsVolumeConfiguration.transitEncryptionPort, }, - // configuredAtLaunch: spec.configuredAtLaunch, + configuredAtLaunch: spec.configuredAtLaunch, }; } } From dedb643fb534ee24d6a4ecf64998b1ec1e29c25d Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Fri, 12 Jan 2024 23:35:33 +0900 Subject: [PATCH 04/10] validations --- .../aws-cdk-lib/aws-ecs/lib/base/base-service.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts index b80823ae82b9f..abec011931550 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts @@ -1637,7 +1637,10 @@ export abstract class BaseService extends Resource return; } - if (config.throughput) { // No need to check tokens as it is good to know if they are specified or not. + if (config.sizeInGiB === undefined && config.snapshotId === undefined) { + throw new Error('sizeInGiB or snapshotId must be specified'); + } + if (config.throughput) { if (config.volumeType !== VolumeType.GP3) { throw new Error(`throughput can only be configured with gp3 volume type, got ${config.volumeType}`); } @@ -1645,13 +1648,13 @@ export abstract class BaseService extends Resource throw new Error(`throughput must be less than or equal to 1000 MiB/s, got ${config.throughput} MiB/s`); } } - if (config.iops) { // No need to check tokens as it is good to know if they are specified or not. + if (config.iops) { if ([VolumeType.SC1, VolumeType.ST1, VolumeType.STANDARD].some(type => config.volumeType === type)) { throw new Error(`iops cannot be specified with sc1, st1, and standard volume types, got ${config.volumeType}`); } } else { if ([VolumeType.IO1, VolumeType.IO2].some(type => config.volumeType === type)) { - throw new Error(`iops must be specified with io1 and io2 volume types, got ${config.volumeType}`); + throw new Error(`iops must be specified with io1 or io2 volume types, got ${config.volumeType}`); } } @@ -1675,8 +1678,9 @@ export abstract class BaseService extends Resource }; }); + // only one EBS can be specified but return type is an array. return [{ - name: config?.volumeName, + name: config.volumeName, managedEbsVolume: { encrypted: config.encrypted, filesystemType: config.filesystemType, From 154404d5d0aad9728ee22b123d0a9e1447f4df04 Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Sat, 13 Jan 2024 00:24:53 +0900 Subject: [PATCH 05/10] add integ test --- .../aws-ecs-fargate-ebs.assets.json | 19 + .../aws-ecs-fargate-ebs.template.json | 617 ++++++++++ ...efaultTestDeployAssert4AE0252E.assets.json | 19 + ...aultTestDeployAssert4AE0252E.template.json | 36 + .../cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 281 +++++ .../tree.json | 1056 +++++++++++++++++ .../test/fargate/integ.fargate-with-ebs.ts | 63 + 9 files changed, 2104 insertions(+) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/awsecsfargateebstestDefaultTestDeployAssert4AE0252E.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/awsecsfargateebstestDefaultTestDeployAssert4AE0252E.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.assets.json new file mode 100644 index 0000000000000..86cfba9ca5e50 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "9edb7bcd0f080e2694e52107adfe8a2f97076b0a464bbc88973fc17cbc462ac0": { + "source": { + "path": "aws-ecs-fargate-ebs.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "9edb7bcd0f080e2694e52107adfe8a2f97076b0a464bbc88973fc17cbc462ac0.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.template.json new file mode 100644 index 0000000000000..6d0ddc98df14f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.template.json @@ -0,0 +1,617 @@ +{ + "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-fargate-ebs/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet1RouteTableAssociation97140677" + ] + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.64.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "VpcPublicSubnet2DefaultRoute97F91067", + "VpcPublicSubnet2RouteTableAssociationDD5762D8" + ] + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.192.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-fargate-ebs/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ClusterEB0386A7": { + "Type": "AWS::ECS::Cluster" + }, + "TaskDefTaskRole1EDB4A67": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TaskDef54694570": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "MountPoints": [ + { + "ContainerPath": "/mnt/ebs", + "ReadOnly": false, + "SourceVolume": "ebs-volume" + } + ], + "Name": "Container" + } + ], + "Cpu": "256", + "Family": "awsecsfargateebsTaskDefFA358D08", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + }, + "Volumes": [ + { + "ConfiguredAtLaunch": true, + "Name": "ebs-volume" + } + ] + } + }, + "ServiceEbsVolumeRoleE8DBBCBA": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" + ] + ] + } + ] + }, + "DependsOn": [ + "TaskDefTaskRole1EDB4A67" + ] + }, + "ServiceD69D759B": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "ClusterEB0386A7" + }, + "DeploymentConfiguration": { + "Alarms": { + "AlarmNames": [], + "Enable": false, + "Rollback": false + }, + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ServiceSecurityGroupC96ED6A7", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + } + }, + "TaskDefinition": { + "Ref": "TaskDef54694570" + }, + "VolumeConfigurations": [ + { + "ManagedEBSVolume": { + "Encrypted": true, + "FilesystemType": "xfs", + "Iops": 3000, + "RoleArn": { + "Fn::GetAtt": [ + "ServiceEbsVolumeRoleE8DBBCBA", + "Arn" + ] + }, + "SizeInGiB": 1, + "TagSpecifications": [ + { + "PropagateTags": "SERVICE", + "ResourceType": "volume", + "Tags": [ + { + "Key": "ebs", + "Value": "volume" + } + ] + } + ], + "Throughput": 100, + "VolumeType": "gp3" + }, + "Name": "ebs-volume" + } + ] + }, + "DependsOn": [ + "TaskDefTaskRole1EDB4A67" + ] + }, + "ServiceSecurityGroupC96ED6A7": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-fargate-ebs/Service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "DependsOn": [ + "TaskDefTaskRole1EDB4A67" + ] + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/awsecsfargateebstestDefaultTestDeployAssert4AE0252E.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/awsecsfargateebstestDefaultTestDeployAssert4AE0252E.assets.json new file mode 100644 index 0000000000000..e2ebbbbc5cd85 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/awsecsfargateebstestDefaultTestDeployAssert4AE0252E.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "awsecsfargateebstestDefaultTestDeployAssert4AE0252E.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/awsecsfargateebstestDefaultTestDeployAssert4AE0252E.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/awsecsfargateebstestDefaultTestDeployAssert4AE0252E.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/awsecsfargateebstestDefaultTestDeployAssert4AE0252E.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/integ.json new file mode 100644 index 0000000000000..8f0fa3668fbf9 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "36.0.0", + "testCases": { + "aws-ecs-fargate-ebs-test/DefaultTest": { + "stacks": [ + "aws-ecs-fargate-ebs" + ], + "assertionStack": "aws-ecs-fargate-ebs-test/DefaultTest/DeployAssert", + "assertionStackName": "awsecsfargateebstestDefaultTestDeployAssert4AE0252E" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/manifest.json new file mode 100644 index 0000000000000..5fd8cc08911e5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/manifest.json @@ -0,0 +1,281 @@ +{ + "version": "36.0.0", + "artifacts": { + "aws-ecs-fargate-ebs.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-ecs-fargate-ebs.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-ecs-fargate-ebs": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-ecs-fargate-ebs.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/9edb7bcd0f080e2694e52107adfe8a2f97076b0a464bbc88973fc17cbc462ac0.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-ecs-fargate-ebs.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-ecs-fargate-ebs.assets" + ], + "metadata": { + "/aws-ecs-fargate-ebs/Vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Vpc8378EB38" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1Subnet5C2D37C4" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1RouteTable6C95E38E" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1RouteTableAssociation97140677" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1DefaultRoute3DA9E72A" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet1/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1EIPD7E02669" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet1/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1NATGateway4D7517AA" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2Subnet691E08A3" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2RouteTable94F7E489" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2RouteTableAssociationDD5762D8" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2DefaultRoute97F91067" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet2/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2EIP3C605A87" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PublicSubnet2/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2NATGateway9182C01D" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet1Subnet536B997A" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet1RouteTableB2C5B500" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet1RouteTableAssociation70C59FA6" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet1DefaultRouteBE02A9ED" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet2Subnet3788AAA1" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet2RouteTableA678073B" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet2RouteTableAssociationA89CAD56" + } + ], + "/aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet2DefaultRoute060D2087" + } + ], + "/aws-ecs-fargate-ebs/Vpc/IGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcIGWD7BA715C" + } + ], + "/aws-ecs-fargate-ebs/Vpc/VPCGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcVPCGWBF912B6E" + } + ], + "/aws-ecs-fargate-ebs/Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterEB0386A7" + } + ], + "/aws-ecs-fargate-ebs/TaskDef/TaskRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TaskDefTaskRole1EDB4A67" + } + ], + "/aws-ecs-fargate-ebs/TaskDef/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TaskDef54694570" + } + ], + "/aws-ecs-fargate-ebs/Service/EbsVolumeRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ServiceEbsVolumeRoleE8DBBCBA" + } + ], + "/aws-ecs-fargate-ebs/Service/Service": [ + { + "type": "aws:cdk:logicalId", + "data": "ServiceD69D759B" + } + ], + "/aws-ecs-fargate-ebs/Service/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ServiceSecurityGroupC96ED6A7" + } + ], + "/aws-ecs-fargate-ebs/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-ecs-fargate-ebs/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-ecs-fargate-ebs" + }, + "awsecsfargateebstestDefaultTestDeployAssert4AE0252E.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "awsecsfargateebstestDefaultTestDeployAssert4AE0252E.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "awsecsfargateebstestDefaultTestDeployAssert4AE0252E": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "awsecsfargateebstestDefaultTestDeployAssert4AE0252E.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "awsecsfargateebstestDefaultTestDeployAssert4AE0252E.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "awsecsfargateebstestDefaultTestDeployAssert4AE0252E.assets" + ], + "metadata": { + "/aws-ecs-fargate-ebs-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-ecs-fargate-ebs-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-ecs-fargate-ebs-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/tree.json new file mode 100644 index 0000000000000..4fc289ba60ec8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/tree.json @@ -0,0 +1,1056 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-ecs-fargate-ebs": { + "id": "aws-ecs-fargate-ebs", + "path": "aws-ecs-fargate-ebs", + "children": { + "Vpc": { + "id": "Vpc", + "path": "aws-ecs-fargate-ebs/Vpc", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-fargate-ebs/Vpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "PublicSubnet1": { + "id": "PublicSubnet1", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1/Acl", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "EIP": { + "id": "EIP", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "PublicSubnet2": { + "id": "PublicSubnet2", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.64.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2/Acl", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "EIP": { + "id": "EIP", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "PrivateSubnet1": { + "id": "PrivateSubnet1", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/Acl", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "subnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "PrivateSubnet2": { + "id": "PrivateSubnet2", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.192.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/Acl", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "subnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-ecs-fargate-ebs/Vpc/PrivateSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "IGW": { + "id": "IGW", + "path": "aws-ecs-fargate-ebs/Vpc/IGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-ecs-fargate-ebs/Vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "VPCGW": { + "id": "VPCGW", + "path": "aws-ecs-fargate-ebs/Vpc/VPCGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", + "aws:cdk:cloudformation:props": { + "internetGatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Cluster": { + "id": "Cluster", + "path": "aws-ecs-fargate-ebs/Cluster", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-fargate-ebs/Cluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ECS::Cluster", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "TaskDef": { + "id": "TaskDef", + "path": "aws-ecs-fargate-ebs/TaskDef", + "children": { + "TaskRole": { + "id": "TaskRole", + "path": "aws-ecs-fargate-ebs/TaskDef/TaskRole", + "children": { + "ImportTaskRole": { + "id": "ImportTaskRole", + "path": "aws-ecs-fargate-ebs/TaskDef/TaskRole/ImportTaskRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-fargate-ebs/TaskDef/TaskRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-fargate-ebs/TaskDef/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ECS::TaskDefinition", + "aws:cdk:cloudformation:props": { + "containerDefinitions": [ + { + "essential": true, + "image": "amazon/amazon-ecs-sample", + "mountPoints": [ + { + "containerPath": "/mnt/ebs", + "readOnly": false, + "sourceVolume": "ebs-volume" + } + ], + "name": "Container" + } + ], + "cpu": "256", + "family": "awsecsfargateebsTaskDefFA358D08", + "memory": "512", + "networkMode": "awsvpc", + "requiresCompatibilities": [ + "FARGATE" + ], + "taskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + }, + "volumes": [ + { + "name": "ebs-volume", + "configuredAtLaunch": true + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Container": { + "id": "Container", + "path": "aws-ecs-fargate-ebs/Container", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Service": { + "id": "Service", + "path": "aws-ecs-fargate-ebs/Service", + "children": { + "EbsVolumeRole": { + "id": "EbsVolumeRole", + "path": "aws-ecs-fargate-ebs/Service/EbsVolumeRole", + "children": { + "ImportEbsVolumeRole": { + "id": "ImportEbsVolumeRole", + "path": "aws-ecs-fargate-ebs/Service/EbsVolumeRole/ImportEbsVolumeRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-fargate-ebs/Service/EbsVolumeRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Service": { + "id": "Service", + "path": "aws-ecs-fargate-ebs/Service/Service", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ECS::Service", + "aws:cdk:cloudformation:props": { + "cluster": { + "Ref": "ClusterEB0386A7" + }, + "deploymentConfiguration": { + "maximumPercent": 200, + "minimumHealthyPercent": 50, + "alarms": { + "alarmNames": [], + "enable": false, + "rollback": false + } + }, + "enableEcsManagedTags": false, + "launchType": "FARGATE", + "networkConfiguration": { + "awsvpcConfiguration": { + "assignPublicIp": "DISABLED", + "subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ], + "securityGroups": [ + { + "Fn::GetAtt": [ + "ServiceSecurityGroupC96ED6A7", + "GroupId" + ] + } + ] + } + }, + "taskDefinition": { + "Ref": "TaskDef54694570" + }, + "volumeConfigurations": [ + { + "name": "ebs-volume", + "managedEbsVolume": { + "encrypted": true, + "filesystemType": "xfs", + "iops": 3000, + "roleArn": { + "Fn::GetAtt": [ + "ServiceEbsVolumeRoleE8DBBCBA", + "Arn" + ] + }, + "sizeInGiB": 1, + "tagSpecifications": [ + { + "propagateTags": "SERVICE", + "resourceType": "volume", + "tags": [ + { + "key": "ebs", + "value": "volume" + } + ] + } + ], + "throughput": 100, + "volumeType": "gp3" + } + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-ecs-fargate-ebs/Service/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-ecs-fargate-ebs/Service/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "aws-ecs-fargate-ebs/Service/SecurityGroup", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-ecs-fargate-ebs/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-ecs-fargate-ebs/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "aws-ecs-fargate-ebs-test": { + "id": "aws-ecs-fargate-ebs-test", + "path": "aws-ecs-fargate-ebs-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "aws-ecs-fargate-ebs-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "aws-ecs-fargate-ebs-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "aws-ecs-fargate-ebs-test/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-ecs-fargate-ebs-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-ecs-fargate-ebs-test/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts new file mode 100644 index 0000000000000..d8fb7e435d87f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts @@ -0,0 +1,63 @@ +import * as cdk from 'aws-cdk-lib'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import { Construct } from 'constructs'; +// eslint-disable-next-line import/no-extraneous-dependencies +import * as integ from '@aws-cdk/integ-tests-alpha'; + +class FargateWithEbsStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2, restrictDefaultSecurityGroup: false }); + + const cluster = new ecs.Cluster(this, 'Cluster', { + vpc, + }); + + const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef'); + taskDefinition.addVolume({ + name: 'ebs-volume', + configuredAtLaunch: true, + }); + + const containerDefinition = new ecs.ContainerDefinition(this, 'Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + taskDefinition, + }); + containerDefinition.addMountPoints({ + containerPath: '/mnt/ebs', + sourceVolume: 'ebs-volume', + readOnly: false, + }); + + new ecs.FargateService(this, 'Service', { + cluster, + taskDefinition, + ebsVolumeConfiguration: { + volumeName: 'ebs-volume', + encrypted: true, + filesystemType: ecs.FilesystemType.XFS, + iops: 3000, + sizeInGiB: 1, + tagSpecifications: [{ + propagateTags: ecs.EbsPropagatedTagSource.SERVICE, + tags: [{ + key: 'ebs', + value: 'volume', + }], + }], + throughput: 100, + volumeType: ecs.VolumeType.GP3, + }, + }); + } +} + +const app = new cdk.App(); +const stack = new FargateWithEbsStack(app, 'aws-ecs-fargate-ebs'); + +new integ.IntegTest(app, 'aws-ecs-fargate-ebs-test', { + testCases: [stack], +}); +app.synth(); \ No newline at end of file From 798defc53a7de8bf9fe2042974e2ddd69182986b Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Sat, 13 Jan 2024 01:09:16 +0900 Subject: [PATCH 06/10] change --- .../test/fargate/integ.fargate-with-ebs.ts | 38 ++-- .../aws-ecs/lib/base/base-service.ts | 172 +++++++++++------- 2 files changed, 124 insertions(+), 86 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts index d8fb7e435d87f..c8c80f5bda2d6 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts @@ -15,9 +15,26 @@ class FargateWithEbsStack extends cdk.Stack { vpc, }); + const ebs = new ecs.EbsVolume(this, 'EbsVolume', { + volumeName: 'ebs-volume', + encrypted: true, + filesystemType: ecs.FilesystemType.XFS, + iops: 3000, + sizeInGiB: 1, + tagSpecifications: [{ + propagateTags: ecs.EbsPropagatedTagSource.SERVICE, + tags: [{ + key: 'ebs', + value: 'volume', + }], + }], + throughput: 100, + volumeType: ecs.VolumeType.GP3, + }); + const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef'); taskDefinition.addVolume({ - name: 'ebs-volume', + name: ebs.volumeName, configuredAtLaunch: true, }); @@ -27,29 +44,14 @@ class FargateWithEbsStack extends cdk.Stack { }); containerDefinition.addMountPoints({ containerPath: '/mnt/ebs', - sourceVolume: 'ebs-volume', + sourceVolume: ebs.volumeName, readOnly: false, }); new ecs.FargateService(this, 'Service', { cluster, taskDefinition, - ebsVolumeConfiguration: { - volumeName: 'ebs-volume', - encrypted: true, - filesystemType: ecs.FilesystemType.XFS, - iops: 3000, - sizeInGiB: 1, - tagSpecifications: [{ - propagateTags: ecs.EbsPropagatedTagSource.SERVICE, - tags: [{ - key: 'ebs', - value: 'volume', - }], - }], - throughput: 100, - volumeType: ecs.VolumeType.GP3, - }, + ebsVolumeConfiguration: ebs, }); } } diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts index abec011931550..61deb3edb854d 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts @@ -329,9 +329,9 @@ export interface EbsTagSpecifications { } /** - * Interface for EBS Volume Configuration. + * EbsVolume props. */ -export interface EbsVolumeConfiguration { +export interface EbsVolumeProps { /** * The name of the volume. * This value must match the volume name from the Volume object in the task definition. @@ -443,6 +443,106 @@ export interface EbsVolumeConfiguration { readonly volumeType?: VolumeType; } +/** + * EBS Volume. + */ +export class EbsVolume extends Construct { + /** + * EBS volume name. + */ + public readonly volumeName: string; + private readonly encrypted?: boolean; + private readonly filesystemType?: FilesystemType; + private readonly iops?: number; + private readonly kmsKey?: kms.IKey; + private readonly role: iam.IRole; + private readonly sizeInGiB?: number; + private readonly snapshotId?: string; + private readonly tagSpecifications?: EbsTagSpecifications[]; + private readonly throughput?: number; + private readonly volumeType?: VolumeType; + + constructor(scope: Construct, id: string, props: EbsVolumeProps) { + super(scope, id); + + this.volumeName = props.volumeName; + this.encrypted = props.encrypted; + this.filesystemType = props.filesystemType; + this.iops = props.iops; + this.kmsKey = props.kmsKey; + this.role = props.role ?? new iam.Role(this, 'EbsVolumeRole', { + assumedBy: new iam.ServicePrincipal('ecs.amazonaws.com'), + managedPolicies: [ + iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSInfrastructureRolePolicyForVolumes'), + ], + }); + this.sizeInGiB = props.sizeInGiB; + this.snapshotId = props.snapshotId; + this.tagSpecifications = props.tagSpecifications; + this.throughput = props.throughput; + this.volumeType = props.volumeType; + + this.validate(); + } + + private validate() { + if (this.sizeInGiB === undefined && this.snapshotId === undefined) { + throw new Error('sizeInGiB or snapshotId must be specified'); + } + if (this.throughput) { + if (this.volumeType !== VolumeType.GP3) { + throw new Error(`throughput can only be thisured with gp3 volume type, got ${this.volumeType}`); + } + if (!Token.isUnresolved(this.throughput) && this.throughput > 1000) { + throw new Error(`throughput must be less than or equal to 1000 MiB/s, got ${this.throughput} MiB/s`); + } + } + if (this.iops) { + if ([VolumeType.SC1, VolumeType.ST1, VolumeType.STANDARD].some(type => this.volumeType === type)) { + throw new Error(`iops cannot be specified with sc1, st1, and standard volume types, got ${this.volumeType}`); + } + } else { + if ([VolumeType.IO1, VolumeType.IO2].some(type => this.volumeType === type)) { + throw new Error(`iops must be specified with io1 or io2 volume types, got ${this.volumeType}`); + } + } + } + + public render(): CfnService.ServiceVolumeConfigurationProperty[] | undefined { + if (!this) { + return; + } + + // only one EBS can be specified but return type is an array. + return [{ + name: this.volumeName, + managedEbsVolume: { + encrypted: this.encrypted, + filesystemType: this.filesystemType, + iops: this.iops, + kmsKeyId: this.kmsKey?.keyId, + roleArn: this.role.roleArn, + sizeInGiB: this.sizeInGiB, + snapshotId: this.snapshotId, + tagSpecifications: this.tagSpecifications?.map(tagSpec => { + return { + propagateTags: tagSpec.propagateTags, + resourceType: 'volume', + tags: tagSpec.tags?.map(tag => { + return { + key: tag.key, + value: tag.value, + }; + }), + }; + }), + throughput: this.throughput, + volumeType: this.volumeType, + }, + }]; + } +} + /** * The properties for the base Ec2Service or FargateService service. */ @@ -586,7 +686,7 @@ export interface BaseServiceOptions { * * @default - No EBS volume configuration. */ - readonly ebsVolumeConfiguration?: EbsVolumeConfiguration; + readonly ebsVolumeConfiguration?: EbsVolume; } /** @@ -852,7 +952,7 @@ export abstract class BaseService extends Resource enableExecuteCommand: props.enableExecuteCommand, capacityProviderStrategy: props.capacityProviderStrategies, healthCheckGracePeriodSeconds: this.evaluateHealthGracePeriod(props.healthCheckGracePeriod), - volumeConfigurations: this.renderVolumeConfigurations(props.ebsVolumeConfiguration), + volumeConfigurations: props.ebsVolumeConfiguration?.render(), /* role: never specified, supplanted by Service Linked Role */ networkConfiguration: Lazy.any({ produce: () => this.networkConfiguration }, { omitEmptyArray: true }), serviceRegistries: Lazy.any({ produce: () => this.serviceRegistries }, { omitEmptyArray: true }), @@ -1631,70 +1731,6 @@ export abstract class BaseService extends Resource } return true; } - - private renderVolumeConfigurations(config?: EbsVolumeConfiguration): CfnService.ServiceVolumeConfigurationProperty[] | undefined { - if (!config) { - return; - } - - if (config.sizeInGiB === undefined && config.snapshotId === undefined) { - throw new Error('sizeInGiB or snapshotId must be specified'); - } - if (config.throughput) { - if (config.volumeType !== VolumeType.GP3) { - throw new Error(`throughput can only be configured with gp3 volume type, got ${config.volumeType}`); - } - if (!Token.isUnresolved(config.throughput) && config.throughput > 1000) { - throw new Error(`throughput must be less than or equal to 1000 MiB/s, got ${config.throughput} MiB/s`); - } - } - if (config.iops) { - if ([VolumeType.SC1, VolumeType.ST1, VolumeType.STANDARD].some(type => config.volumeType === type)) { - throw new Error(`iops cannot be specified with sc1, st1, and standard volume types, got ${config.volumeType}`); - } - } else { - if ([VolumeType.IO1, VolumeType.IO2].some(type => config.volumeType === type)) { - throw new Error(`iops must be specified with io1 or io2 volume types, got ${config.volumeType}`); - } - } - - const ebsVolumeRole = config.role ?? new iam.Role(this, 'EbsVolumeRole', { - assumedBy: new iam.ServicePrincipal('ecs.amazonaws.com'), - managedPolicies: [ - iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSInfrastructureRolePolicyForVolumes'), - ], - }); - - const tagSpecifications: CfnService.EBSTagSpecificationProperty[] | undefined = config.tagSpecifications?.map(tagSpec => { - return { - propagateTags: tagSpec.propagateTags, - resourceType: 'volume', - tags: tagSpec.tags?.map(tag => { - return { - key: tag.key, - value: tag.value, - }; - }), - }; - }); - - // only one EBS can be specified but return type is an array. - return [{ - name: config.volumeName, - managedEbsVolume: { - encrypted: config.encrypted, - filesystemType: config.filesystemType, - iops: config.iops, - kmsKeyId: config.kmsKey?.keyId, - roleArn: ebsVolumeRole.roleArn, - sizeInGiB: config.sizeInGiB, - snapshotId: config.snapshotId, - tagSpecifications: tagSpecifications, - throughput: config.throughput, - volumeType: config.volumeType, - }, - }]; - } } /** From e98cb8110e0c48a0bc0e52ecc35ff7ee3e989dc6 Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Sat, 13 Jan 2024 01:10:10 +0900 Subject: [PATCH 07/10] constructor --- packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts index 61deb3edb854d..eaf5172d17536 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts @@ -482,10 +482,6 @@ export class EbsVolume extends Construct { this.throughput = props.throughput; this.volumeType = props.volumeType; - this.validate(); - } - - private validate() { if (this.sizeInGiB === undefined && this.snapshotId === undefined) { throw new Error('sizeInGiB or snapshotId must be specified'); } From ef75e471ba764140465e9bce36b395882add6aea Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Sat, 13 Jan 2024 01:18:38 +0900 Subject: [PATCH 08/10] integ --- .../aws-ecs-fargate-ebs.assets.json | 4 +- .../aws-ecs-fargate-ebs.template.json | 67 +++++----- .../manifest.json | 23 +++- .../tree.json | 126 ++++++++++-------- .../test/fargate/integ.fargate-with-ebs.ts | 8 +- 5 files changed, 122 insertions(+), 106 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.assets.json index 86cfba9ca5e50..b148a5d52bced 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.assets.json @@ -1,7 +1,7 @@ { "version": "36.0.0", "files": { - "9edb7bcd0f080e2694e52107adfe8a2f97076b0a464bbc88973fc17cbc462ac0": { + "42cbbf517ac1922f883b813b88cc92c1567639430a0833c12fad973b39678941": { "source": { "path": "aws-ecs-fargate-ebs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "9edb7bcd0f080e2694e52107adfe8a2f97076b0a464bbc88973fc17cbc462ac0.json", + "objectKey": "42cbbf517ac1922f883b813b88cc92c1567639430a0833c12fad973b39678941.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.template.json index 6d0ddc98df14f..80317b14e0a2a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/aws-ecs-fargate-ebs.template.json @@ -394,6 +394,37 @@ "ClusterEB0386A7": { "Type": "AWS::ECS::Cluster" }, + "EbsVolumeEbsVolumeRole0E167CE3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" + ] + ] + } + ] + } + }, "TaskDefTaskRole1EDB4A67": { "Type": "AWS::IAM::Role", "Properties": { @@ -449,40 +480,6 @@ ] } }, - "ServiceEbsVolumeRoleE8DBBCBA": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "ecs.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "ManagedPolicyArns": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" - ] - ] - } - ] - }, - "DependsOn": [ - "TaskDefTaskRole1EDB4A67" - ] - }, "ServiceD69D759B": { "Type": "AWS::ECS::Service", "Properties": { @@ -532,7 +529,7 @@ "Iops": 3000, "RoleArn": { "Fn::GetAtt": [ - "ServiceEbsVolumeRoleE8DBBCBA", + "EbsVolumeEbsVolumeRole0E167CE3", "Arn" ] }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/manifest.json index 5fd8cc08911e5..fcb64589580aa 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/manifest.json @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/9edb7bcd0f080e2694e52107adfe8a2f97076b0a464bbc88973fc17cbc462ac0.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/42cbbf517ac1922f883b813b88cc92c1567639430a0833c12fad973b39678941.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -178,22 +178,22 @@ "data": "ClusterEB0386A7" } ], - "/aws-ecs-fargate-ebs/TaskDef/TaskRole/Resource": [ + "/aws-ecs-fargate-ebs/EbsVolume/EbsVolumeRole/Resource": [ { "type": "aws:cdk:logicalId", - "data": "TaskDefTaskRole1EDB4A67" + "data": "EbsVolumeEbsVolumeRole0E167CE3" } ], - "/aws-ecs-fargate-ebs/TaskDef/Resource": [ + "/aws-ecs-fargate-ebs/TaskDef/TaskRole/Resource": [ { "type": "aws:cdk:logicalId", - "data": "TaskDef54694570" + "data": "TaskDefTaskRole1EDB4A67" } ], - "/aws-ecs-fargate-ebs/Service/EbsVolumeRole/Resource": [ + "/aws-ecs-fargate-ebs/TaskDef/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ServiceEbsVolumeRoleE8DBBCBA" + "data": "TaskDef54694570" } ], "/aws-ecs-fargate-ebs/Service/Service": [ @@ -219,6 +219,15 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "ServiceEbsVolumeRoleE8DBBCBA": [ + { + "type": "aws:cdk:logicalId", + "data": "ServiceEbsVolumeRoleE8DBBCBA", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "aws-ecs-fargate-ebs" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/tree.json index 4fc289ba60ec8..88a7b7cd0dbeb 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.js.snapshot/tree.json @@ -673,6 +673,73 @@ "version": "10.3.0" } }, + "EbsVolume": { + "id": "EbsVolume", + "path": "aws-ecs-fargate-ebs/EbsVolume", + "children": { + "EbsVolumeRole": { + "id": "EbsVolumeRole", + "path": "aws-ecs-fargate-ebs/EbsVolume/EbsVolumeRole", + "children": { + "ImportEbsVolumeRole": { + "id": "ImportEbsVolumeRole", + "path": "aws-ecs-fargate-ebs/EbsVolume/EbsVolumeRole/ImportEbsVolumeRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-fargate-ebs/EbsVolume/EbsVolumeRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, "TaskDef": { "id": "TaskDef", "path": "aws-ecs-fargate-ebs/TaskDef", @@ -784,63 +851,6 @@ "id": "Service", "path": "aws-ecs-fargate-ebs/Service", "children": { - "EbsVolumeRole": { - "id": "EbsVolumeRole", - "path": "aws-ecs-fargate-ebs/Service/EbsVolumeRole", - "children": { - "ImportEbsVolumeRole": { - "id": "ImportEbsVolumeRole", - "path": "aws-ecs-fargate-ebs/Service/EbsVolumeRole/ImportEbsVolumeRole", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" - } - }, - "Resource": { - "id": "Resource", - "path": "aws-ecs-fargate-ebs/Service/EbsVolumeRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "assumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "ecs.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "managedPolicyArns": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" - ] - ] - } - ] - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" - } - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" - } - }, "Service": { "id": "Service", "path": "aws-ecs-fargate-ebs/Service/Service", @@ -894,7 +904,7 @@ "iops": 3000, "roleArn": { "Fn::GetAtt": [ - "ServiceEbsVolumeRoleE8DBBCBA", + "EbsVolumeEbsVolumeRole0E167CE3", "Arn" ] }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts index c8c80f5bda2d6..f991d1de1a952 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.fargate-with-ebs.ts @@ -11,10 +11,6 @@ class FargateWithEbsStack extends cdk.Stack { const vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2, restrictDefaultSecurityGroup: false }); - const cluster = new ecs.Cluster(this, 'Cluster', { - vpc, - }); - const ebs = new ecs.EbsVolume(this, 'EbsVolume', { volumeName: 'ebs-volume', encrypted: true, @@ -32,6 +28,10 @@ class FargateWithEbsStack extends cdk.Stack { volumeType: ecs.VolumeType.GP3, }); + const cluster = new ecs.Cluster(this, 'Cluster', { + vpc, + }); + const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef'); taskDefinition.addVolume({ name: ebs.volumeName, From 1a93d1afce259b6f5d2e1264118068afe0802dea Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Sat, 13 Jan 2024 01:22:55 +0900 Subject: [PATCH 09/10] README --- packages/aws-cdk-lib/aws-ecs/README.md | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/packages/aws-cdk-lib/aws-ecs/README.md b/packages/aws-cdk-lib/aws-ecs/README.md index b120df0bf0049..5f32465275bba 100644 --- a/packages/aws-cdk-lib/aws-ecs/README.md +++ b/packages/aws-cdk-lib/aws-ecs/README.md @@ -984,6 +984,55 @@ const service = ecs.FargateService.fromFargateServiceAttributes(this, 'EcsServic const service = ecs.FargateService.fromFargateServiceArn(this, 'EcsService', 'arn:aws:ecs:us-west-2:123456789012:service/my-http-service'); ``` +### EBS attachments + +To attach EBS volume to ECS tasks, use `EbsVolume` for a task definition and a service. + +```ts +declare const cluster: ecs.Cluster; +declare const taskDefinition: ecs.TaskDefinition; +declare const vpc: ec2.Vpc; + +const ebs = new ecs.EbsVolume(this, 'EbsVolume', { + volumeName: 'ebs-volume', + encrypted: true, + filesystemType: ecs.FilesystemType.XFS, + iops: 3000, + sizeInGiB: 1, + tagSpecifications: [{ + propagateTags: ecs.EbsPropagatedTagSource.SERVICE, + tags: [{ + key: 'ebs', + value: 'volume', + }], + }], + throughput: 100, + volumeType: ecs.VolumeType.GP3, +}); + +const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef'); +taskDefinition.addVolume({ + name: ebs.volumeName, + configuredAtLaunch: true, +}); + +const containerDefinition = new ecs.ContainerDefinition(this, 'Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + taskDefinition, +}); +containerDefinition.addMountPoints({ + containerPath: '/mnt/ebs', + sourceVolume: ebs.volumeName, + readOnly: false, +}); + +new ecs.FargateService(this, 'Service', { + cluster, + taskDefinition, + ebsVolumeConfiguration: ebs, +}); +``` + ## Task Auto-Scaling You can configure the task count of a service to match demand. Task auto-scaling is From e6155d26361794f570be003a23666f3900d34cec Mon Sep 17 00:00:00 2001 From: go-to-k <24818752+go-to-k@users.noreply.github.com> Date: Sat, 13 Jan 2024 01:31:09 +0900 Subject: [PATCH 10/10] docs and tests --- .../aws-ecs/lib/base/base-service.ts | 3 +++ .../aws-ecs/test/task-definition.test.ts | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts index eaf5172d17536..984a234c0abdc 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts @@ -504,6 +504,9 @@ export class EbsVolume extends Construct { } } + /** + * Render for CloudFormation property. + */ public render(): CfnService.ServiceVolumeConfigurationProperty[] | undefined { if (!this) { return; diff --git a/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts b/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts index 2b4bad0b5d5a1..922346451fa60 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts @@ -315,6 +315,30 @@ describe('task definition', () => { Template.fromStack(stack); }).toThrow("ECS Container Container must have at least one of 'memoryLimitMiB' or 'memoryReservationMiB' specified"); }); + + test('A task definition with EC2 and configuredAtLaunch', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const def = new ecs.TaskDefinition(stack, 'TD', { + cpu: '512', + memoryMiB: '512', + compatibility: ecs.Compatibility.EC2_AND_FARGATE, + }); + def.addVolume({ + name: 'volume', + configuredAtLaunch: true, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { + Volumes: [{ + Name: 'volume', + ConfiguredAtLaunch: true, + }], + }); + }); }); describe('When importing from an existing Task definition', () => {