From c6256992902fc4237ceb9f965e970e2c2ef00777 Mon Sep 17 00:00:00 2001 From: Scott Walker Date: Tue, 16 Feb 2021 10:13:43 +1100 Subject: [PATCH 01/20] feat(aws-ecs-patterns): allow ScheduledTaskBase be created in a DISABLED state (#12837) fixes #12836 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ecs-patterns/README.md | 1 + .../aws-ecs-patterns/lib/base/scheduled-task-base.ts | 8 ++++++++ .../aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts | 3 +++ .../test/fargate/test.scheduled-fargate-task.ts | 3 +++ 4 files changed, 15 insertions(+) diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index 38915031f4346..8289145b4fb04 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -305,6 +305,7 @@ const ecsScheduledTask = new ScheduledEc2Task(stack, 'ScheduledTask', { environment: { name: 'TRIGGER', value: 'CloudWatch Events' }, }, schedule: events.Schedule.expression('rate(1 minute)'), + enabled: true, ruleName: 'sample-scheduled-task-rule' }); ``` diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts index 38ac4e30a79af..7dc6492f42919 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts @@ -38,6 +38,13 @@ export interface ScheduledTaskBaseProps { */ readonly schedule: Schedule; + /** + * Indicates whether the rule is enabled. + * + * @default true + */ + readonly enabled?: boolean; + /** * A name for the rule. * @@ -148,6 +155,7 @@ export abstract class ScheduledTaskBase extends CoreConstruct { this.eventRule = new Rule(this, 'ScheduledEventRule', { schedule: props.schedule, ruleName: props.ruleName, + enabled: props.enabled, }); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts index d96c8cd2edc7d..af262cd5de5ef 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts @@ -27,6 +27,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::Events::Rule', { + State: 'ENABLED', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -78,6 +79,7 @@ export = { new ScheduledEc2Task(stack, 'ScheduledEc2Task', { cluster, + enabled: false, scheduledEc2TaskImageOptions: { image: ecs.ContainerImage.fromRegistry('henk'), memoryLimitMiB: 512, @@ -92,6 +94,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::Events::Rule', { Name: 'sample-scheduled-task-rule', + State: 'DISABLED', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts index fa62f079862f1..9496288f3b235 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts @@ -24,6 +24,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::Events::Rule', { + State: 'ENABLED', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, @@ -90,6 +91,7 @@ export = { new ScheduledFargateTask(stack, 'ScheduledFargateTask', { cluster, + enabled: false, scheduledFargateTaskImageOptions: { image: ecs.ContainerImage.fromRegistry('henk'), memoryLimitMiB: 512, @@ -104,6 +106,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::Events::Rule', { Name: 'sample-scheduled-task-rule', + State: 'DISABLED', Targets: [ { Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, From 49419c876bff89d89aa749bdf6dd9920767f6572 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 16 Feb 2021 05:52:31 +0000 Subject: [PATCH 02/20] chore(deps): bump eslint-import-resolver-typescript from 2.3.0 to 2.4.0 (#13072) Bumps [eslint-import-resolver-typescript](https://github.com/alexgorbatchev/eslint-import-resolver-typescript) from 2.3.0 to 2.4.0. - [Release notes](https://github.com/alexgorbatchev/eslint-import-resolver-typescript/releases) - [Changelog](https://github.com/alexgorbatchev/eslint-import-resolver-typescript/blob/master/CHANGELOG.md) - [Commits](https://github.com/alexgorbatchev/eslint-import-resolver-typescript/compare/v2.3.0...v2.4.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- tools/cdk-build-tools/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 0d291a934b125..18a98dd004198 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -45,7 +45,7 @@ "colors": "^1.4.0", "eslint": "^7.20.0", "eslint-import-resolver-node": "^0.3.4", - "eslint-import-resolver-typescript": "^2.3.0", + "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-jest": "^24.1.3", diff --git a/yarn.lock b/yarn.lock index 03f62016c81b9..2d94f17a93642 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3898,10 +3898,10 @@ eslint-import-resolver-node@^0.3.4: debug "^2.6.9" resolve "^1.13.1" -eslint-import-resolver-typescript@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.3.0.tgz#0870988098bc6c6419c87705e6b42bee89425445" - integrity sha512-MHSXvmj5e0SGOOBhBbt7C+fWj1bJbtSYFAD85Xeg8nvUtuooTod2HQb8bfhE9f5QyyNxEfgzqOYFCvmdDIcCuw== +eslint-import-resolver-typescript@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.4.0.tgz#ec1e7063ebe807f0362a7320543aaed6fe1100e1" + integrity sha512-useJKURidCcldRLCNKWemr1fFQL1SzB3G4a0li6lFGvlc5xGe1hY343bvG07cbpCzPuM/lK19FIJB3XGFSkplA== dependencies: debug "^4.1.1" glob "^7.1.6" From 69ef3d691b95fe4488b41af6709486a82b662f2a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 16 Feb 2021 06:35:28 +0000 Subject: [PATCH 03/20] chore(deps): bump aws-sdk from 2.843.0 to 2.844.0 (#13061) Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.843.0 to 2.844.0. - [Release notes](https://github.com/aws/aws-sdk-js/releases) - [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js/compare/v2.843.0...v2.844.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-cloudfront-origins/package.json | 2 +- packages/@aws-cdk/aws-cloudfront/package.json | 2 +- packages/@aws-cdk/aws-cloudtrail/package.json | 2 +- packages/@aws-cdk/aws-codebuild/package.json | 2 +- packages/@aws-cdk/aws-codecommit/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-eks/package.json | 2 +- packages/@aws-cdk/aws-events-targets/package.json | 2 +- packages/@aws-cdk/aws-logs/package.json | 2 +- packages/@aws-cdk/aws-route53/package.json | 2 +- packages/@aws-cdk/aws-sqs/package.json | 2 +- packages/@aws-cdk/custom-resources/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- yarn.lock | 8 ++++---- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index aa361d322caa1..01046b4b76db3 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -71,7 +71,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "pkglint": "0.0.0" diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index a519240ea2f31..b062987931755 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -72,7 +72,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 7dda406e626be..3846c59bcb320 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -72,7 +72,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 314210113d2b7..c2586a4ba8651 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -78,7 +78,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 051cb15db124e..69d4fbdccb3bc 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -78,7 +78,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index e45cd7a017e4d..4018b684050db 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -73,7 +73,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/jest": "^26.0.20", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index d602ef1e30c10..46f695fbca027 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -73,7 +73,7 @@ "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "@types/yaml": "1.9.6", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 73998519c62a5..55e9a40fcb596 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -74,7 +74,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index 98712b8960e29..fbb9fbf369e37 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -72,7 +72,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 4fe0450261da2..df2977cc84608 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -73,7 +73,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 587ebea3f0158..860f3aca46971 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -73,7 +73,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index ce09a84f6f0e1..863c0dbc8af47 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -78,7 +78,7 @@ "@types/aws-lambda": "^8.10.72", "@types/fs-extra": "^8.1.1", "@types/sinon": "^9.0.10", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 507cb2c0ec3ca..d7932d97aac66 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -73,7 +73,7 @@ "@aws-cdk/region-info": "0.0.0", "@aws-cdk/yaml-cfn": "0.0.0", "archiver": "^5.2.0", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "camelcase": "^6.2.0", "cdk-assets": "0.0.0", "colors": "^1.4.0", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index a33c6f5369b95..550424d5ebdb4 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -47,7 +47,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "archiver": "^5.2.0", - "aws-sdk": "^2.842.0", + "aws-sdk": "^2.844.0", "glob": "^7.1.6", "yargs": "^16.2.0" }, diff --git a/yarn.lock b/yarn.lock index 2d94f17a93642..dcd1837827e30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2259,10 +2259,10 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.842.0: - version "2.843.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.843.0.tgz#3e274214565597de6ccfbfaf6727a47f42b3774d" - integrity sha512-wTHKHDzblaNjWsdCuKTnfAr2zSLgN+Nc2yGpqPxnr7emEQG4V3B0gYEfV9rvv9dVq5Jw8Y1q6VNWS6k8oclnSw== +aws-sdk@^2.637.0, aws-sdk@^2.844.0: + version "2.844.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.844.0.tgz#0d90279f9d224fd5c218a8b5cef4cb4c3949fd8a" + integrity sha512-8RMVGRhJ+s5xITDgR2bAVwuq/U2dhFhk83x4O7G4Sav/UxeXgmMfa6YU5P6CSDCq80ikBZVLb1bBVuW75h2nKQ== dependencies: buffer "4.9.2" events "1.1.1" From 8d51ac958eb9275322964b3d557cc31c7fbd1313 Mon Sep 17 00:00:00 2001 From: Neta Nir Date: Tue, 16 Feb 2021 00:29:07 -0800 Subject: [PATCH 04/20] chore(core): add monocdk to reporting (#13071) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/core/lib/private/runtime-info.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/core/lib/private/runtime-info.ts b/packages/@aws-cdk/core/lib/private/runtime-info.ts index 34a4129abe491..b0cf266e8e11d 100644 --- a/packages/@aws-cdk/core/lib/private/runtime-info.ts +++ b/packages/@aws-cdk/core/lib/private/runtime-info.ts @@ -3,9 +3,9 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { major as nodeMajorVersion } from './node-version'; // list of NPM scopes included in version reporting e.g. @aws-cdk and @aws-solutions-konstruk -const WHITELIST_SCOPES = ['@aws-cdk', '@aws-cdk-containers', '@aws-solutions-konstruk', '@aws-solutions-constructs', '@amzn']; +const ALLOWED_SCOPES = ['@aws-cdk', '@aws-cdk-containers', '@aws-solutions-konstruk', '@aws-solutions-constructs', '@amzn']; // list of NPM packages included in version reporting -const WHITELIST_PACKAGES = ['aws-rfdk', 'aws-cdk-lib']; +const ALLOWED_PACKAGES = ['aws-rfdk', 'aws-cdk-lib', 'monocdk']; /** * Returns a list of loaded modules and their versions. @@ -20,15 +20,15 @@ export function collectRuntimeInformation(): cxschema.RuntimeInfo { } } - // include only libraries that are in the whitelistLibraries list + // include only libraries that are in the allowlistLibraries list for (const name of Object.keys(libraries)) { let foundMatch = false; - for (const scope of WHITELIST_SCOPES) { + for (const scope of ALLOWED_SCOPES) { if (name.startsWith(`${scope}/`)) { foundMatch = true; } } - foundMatch = foundMatch || WHITELIST_PACKAGES.includes(name); + foundMatch = foundMatch || ALLOWED_PACKAGES.includes(name); if (!foundMatch) { delete libraries[name]; From 5f0ee88ff1e618a3f3c50dec7308c4da279e42ac Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Tue, 16 Feb 2021 01:19:04 -0800 Subject: [PATCH 05/20] fix(codecommit): take the region and account of an imported Repository from its ARN (#13066) To align it with how other resources work, for example [S3 Buckets](https://github.com/aws/aws-cdk/blob/c6256992902fc4237ceb9f965e970e2c2ef00777/packages/%40aws-cdk/aws-s3/lib/bucket.ts#L1285-L1286). Fixes #13025 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-codecommit/lib/repository.ts | 5 ++++- packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-codecommit/lib/repository.ts b/packages/@aws-cdk/aws-codecommit/lib/repository.ts index c1bd88ff6d4f6..495be2f981d86 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/repository.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/repository.ts @@ -310,7 +310,10 @@ export class Repository extends RepositoryBase { public readonly repositoryCloneUrlGrc = makeCloneUrl(stack, repositoryName, 'grc', region); } - return new Import(scope, id); + return new Import(scope, id, { + account: arn.account, + region, + }); } public static fromRepositoryName(scope: Construct, id: string, repositoryName: string): IRepository { diff --git a/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts b/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts index 954c48561758a..1f49f852b1e57 100644 --- a/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts +++ b/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts @@ -104,6 +104,9 @@ export = { test.deepEqual(stack.resolve(repo.repositoryCloneUrlGrc), 'codecommit::us-west-2://my-repo'); + test.deepEqual(repo.env.account, '585695036304'); + test.deepEqual(repo.env.region, 'us-west-2'); + test.done(); }, From 355fed870cf427afe1dbfadb05a854f040ef2680 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 16 Feb 2021 11:58:17 +0100 Subject: [PATCH 06/20] chore(rds): use nodeunit-shim (#13077) Use `jest` for RDS tests, as I plan to add data-driven tests. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-rds/.gitignore | 3 ++- packages/@aws-cdk/aws-rds/.npmignore | 3 ++- packages/@aws-cdk/aws-rds/jest.config.js | 2 ++ packages/@aws-cdk/aws-rds/package.json | 6 +++--- .../test/{test.cluster-engine.ts => cluster-engine.test.ts} | 6 +++--- .../aws-rds/test/{test.cluster.ts => cluster.test.ts} | 6 +++--- .../{test.database-secret.ts => database-secret.test.ts} | 6 +++--- ...base-secretmanager.ts => database-secretmanager.test.ts} | 6 +++--- .../{test.instance-engine.ts => instance-engine.test.ts} | 6 +++--- .../aws-rds/test/{test.instance.ts => instance.test.ts} | 6 +++--- .../test/{test.option-group.ts => option-group.test.ts} | 6 +++--- .../{test.parameter-group.ts => parameter-group.test.ts} | 6 +++--- .../@aws-cdk/aws-rds/test/{test.proxy.ts => proxy.test.ts} | 6 +++--- ...est.serverless-cluster.ts => serverless-cluster.test.ts} | 6 +++--- ...nstance-engine.ts => sql-server.instance-engine.test.ts} | 6 +++--- .../test/{test.subnet-group.ts => subnet-group.test.ts} | 6 +++--- 16 files changed, 45 insertions(+), 41 deletions(-) create mode 100644 packages/@aws-cdk/aws-rds/jest.config.js rename packages/@aws-cdk/aws-rds/test/{test.cluster-engine.ts => cluster-engine.test.ts} (98%) rename packages/@aws-cdk/aws-rds/test/{test.cluster.ts => cluster.test.ts} (99%) rename packages/@aws-cdk/aws-rds/test/{test.database-secret.ts => database-secret.test.ts} (97%) rename packages/@aws-cdk/aws-rds/test/{test.database-secretmanager.ts => database-secretmanager.test.ts} (96%) rename packages/@aws-cdk/aws-rds/test/{test.instance-engine.ts => instance-engine.test.ts} (99%) rename packages/@aws-cdk/aws-rds/test/{test.instance.ts => instance.test.ts} (99%) rename packages/@aws-cdk/aws-rds/test/{test.option-group.ts => option-group.test.ts} (98%) rename packages/@aws-cdk/aws-rds/test/{test.parameter-group.ts => parameter-group.test.ts} (97%) rename packages/@aws-cdk/aws-rds/test/{test.proxy.ts => proxy.test.ts} (99%) rename packages/@aws-cdk/aws-rds/test/{test.serverless-cluster.ts => serverless-cluster.test.ts} (99%) rename packages/@aws-cdk/aws-rds/test/sql-server/{test.sql-server.instance-engine.ts => sql-server.instance-engine.test.ts} (94%) rename packages/@aws-cdk/aws-rds/test/{test.subnet-group.ts => subnet-group.test.ts} (97%) diff --git a/packages/@aws-cdk/aws-rds/.gitignore b/packages/@aws-cdk/aws-rds/.gitignore index dcc1dc41e477f..17a41566f0002 100644 --- a/packages/@aws-cdk/aws-rds/.gitignore +++ b/packages/@aws-cdk/aws-rds/.gitignore @@ -15,4 +15,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/.npmignore b/packages/@aws-cdk/aws-rds/.npmignore index a94c531529866..9e88226921c33 100644 --- a/packages/@aws-cdk/aws-rds/.npmignore +++ b/packages/@aws-cdk/aws-rds/.npmignore @@ -23,4 +23,5 @@ tsconfig.json # exclude cdk artifacts **/cdk.out junit.xml -test/ \ No newline at end of file +test/ +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/jest.config.js b/packages/@aws-cdk/aws-rds/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-rds/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index bf1ce83d40d00..86c229a41f293 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -53,6 +53,7 @@ }, "cdk-build": { "cloudformation": "AWS::RDS", + "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +74,11 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "nodeunit-shim": "0.0.0" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster-engine.ts b/packages/@aws-cdk/aws-rds/test/cluster-engine.test.ts similarity index 98% rename from packages/@aws-cdk/aws-rds/test/test.cluster-engine.ts rename to packages/@aws-cdk/aws-rds/test/cluster-engine.test.ts index d5af56f1d10da..54a02441fb9c7 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster-engine.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster-engine.test.ts @@ -1,7 +1,7 @@ -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, DatabaseClusterEngine } from '../lib'; -export = { +nodeunitShim({ "default parameterGroupFamily for versionless Aurora cluster engine is 'aurora5.6'"(test: Test) { // GIVEN const engine = DatabaseClusterEngine.AURORA; @@ -115,4 +115,4 @@ export = { test.deepEqual(DatabaseClusterEngine.auroraPostgres({ version: AuroraPostgresEngineVersion.VER_9_6_9 }).supportedLogTypes, ['postgresql']); test.done(); }, -} +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster.ts b/packages/@aws-cdk/aws-rds/test/cluster.test.ts similarity index 99% rename from packages/@aws-cdk/aws-rds/test/test.cluster.ts rename to packages/@aws-cdk/aws-rds/test/cluster.test.ts index fc877641dcc42..ec7c36129b30d 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster.test.ts @@ -5,13 +5,13 @@ import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, Credentials, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, } from '../lib'; -export = { +nodeunitShim({ 'creating a Cluster also creates 2 DB Instances'(test: Test) { // GIVEN const stack = testStack(); @@ -1838,7 +1838,7 @@ export = { test.done(); }, -}; +}); function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); diff --git a/packages/@aws-cdk/aws-rds/test/test.database-secret.ts b/packages/@aws-cdk/aws-rds/test/database-secret.test.ts similarity index 97% rename from packages/@aws-cdk/aws-rds/test/test.database-secret.ts rename to packages/@aws-cdk/aws-rds/test/database-secret.test.ts index 6e4edb551d764..97de0085806e0 100644 --- a/packages/@aws-cdk/aws-rds/test/test.database-secret.ts +++ b/packages/@aws-cdk/aws-rds/test/database-secret.test.ts @@ -1,10 +1,10 @@ import { expect, haveResource } from '@aws-cdk/assert'; import { CfnResource, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { DatabaseSecret } from '../lib'; import { DEFAULT_PASSWORD_EXCLUDE_CHARS } from '../lib/private/util'; -export = { +nodeunitShim({ 'create a database secret'(test: Test) { // GIVEN const stack = new Stack(); @@ -110,7 +110,7 @@ export = { test.done(); }, -}; +}); function getSecretLogicalId(dbSecret: DatabaseSecret, stack: Stack): string { const cfnSecret = dbSecret.node.defaultChild as CfnResource; diff --git a/packages/@aws-cdk/aws-rds/test/test.database-secretmanager.ts b/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts similarity index 96% rename from packages/@aws-cdk/aws-rds/test/test.database-secretmanager.ts rename to packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts index 8d6310d21ce42..760a16e228cd7 100644 --- a/packages/@aws-cdk/aws-rds/test/test.database-secretmanager.ts +++ b/packages/@aws-cdk/aws-rds/test/database-secretmanager.test.ts @@ -2,10 +2,10 @@ import { ABSENT, expect, haveResource, ResourcePart } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { ServerlessCluster, DatabaseClusterEngine, ParameterGroup, Credentials } from '../lib'; -export = { +nodeunitShim({ 'can create a Serverless Cluster using an existing secret from secretmanager'(test: Test) { // GIVEN const stack = testStack(); @@ -47,7 +47,7 @@ export = { test.done(); }, -}; +}); function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); diff --git a/packages/@aws-cdk/aws-rds/test/test.instance-engine.ts b/packages/@aws-cdk/aws-rds/test/instance-engine.test.ts similarity index 99% rename from packages/@aws-cdk/aws-rds/test/test.instance-engine.ts rename to packages/@aws-cdk/aws-rds/test/instance-engine.test.ts index 90d5a7a204eae..2c9f1fddf8076 100644 --- a/packages/@aws-cdk/aws-rds/test/test.instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/test/instance-engine.test.ts @@ -1,10 +1,10 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../lib'; -export = { +nodeunitShim({ 'default parameterGroupFamily for versionless MariaDB instance engine is not defined'(test: Test) { const engine = rds.DatabaseInstanceEngine.MARIADB; @@ -284,4 +284,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.instance.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts similarity index 99% rename from packages/@aws-cdk/aws-rds/test/test.instance.ts rename to packages/@aws-cdk/aws-rds/test/instance.test.ts index 608e3baf5c926..8c4e4460f65f1 100644 --- a/packages/@aws-cdk/aws-rds/test/test.instance.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -7,13 +7,13 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../lib'; let stack: cdk.Stack; let vpc: ec2.Vpc; -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); vpc = new ec2.Vpc(stack, 'VPC'); @@ -1242,4 +1242,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.option-group.ts b/packages/@aws-cdk/aws-rds/test/option-group.test.ts similarity index 98% rename from packages/@aws-cdk/aws-rds/test/test.option-group.ts rename to packages/@aws-cdk/aws-rds/test/option-group.test.ts index d4129b6aebd5a..b7c6cc851874c 100644 --- a/packages/@aws-cdk/aws-rds/test/test.option-group.ts +++ b/packages/@aws-cdk/aws-rds/test/option-group.test.ts @@ -1,10 +1,10 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { DatabaseInstanceEngine, OptionGroup, OracleEngineVersion, OracleLegacyEngineVersion } from '../lib'; -export = { +nodeunitShim({ 'create an option group'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -160,4 +160,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.parameter-group.ts b/packages/@aws-cdk/aws-rds/test/parameter-group.test.ts similarity index 97% rename from packages/@aws-cdk/aws-rds/test/test.parameter-group.ts rename to packages/@aws-cdk/aws-rds/test/parameter-group.test.ts index f4a21db1fdec0..0f9fd73f44e8c 100644 --- a/packages/@aws-cdk/aws-rds/test/test.parameter-group.ts +++ b/packages/@aws-cdk/aws-rds/test/parameter-group.test.ts @@ -1,9 +1,9 @@ import { countResources, expect, haveResource } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { DatabaseClusterEngine, ParameterGroup } from '../lib'; -export = { +nodeunitShim({ "does not create a parameter group if it wasn't bound to a cluster or instance"(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -126,4 +126,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.proxy.ts b/packages/@aws-cdk/aws-rds/test/proxy.test.ts similarity index 99% rename from packages/@aws-cdk/aws-rds/test/test.proxy.ts rename to packages/@aws-cdk/aws-rds/test/proxy.test.ts index eceec3011e584..c4014d321d6e7 100644 --- a/packages/@aws-cdk/aws-rds/test/test.proxy.ts +++ b/packages/@aws-cdk/aws-rds/test/proxy.test.ts @@ -3,13 +3,13 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import { AccountPrincipal, Role } from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../lib'; let stack: cdk.Stack; let vpc: ec2.IVpc; -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); vpc = new ec2.Vpc(stack, 'VPC'); @@ -321,4 +321,4 @@ export = { test.done(); }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.serverless-cluster.ts b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts similarity index 99% rename from packages/@aws-cdk/aws-rds/test/test.serverless-cluster.ts rename to packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts index de3c8a0018beb..257d23d9ffec2 100644 --- a/packages/@aws-cdk/aws-rds/test/test.serverless-cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts @@ -3,10 +3,10 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import { AuroraPostgresEngineVersion, ServerlessCluster, DatabaseClusterEngine, ParameterGroup, AuroraCapacityUnit, DatabaseSecret } from '../lib'; -export = { +nodeunitShim({ 'can create a Serverless Cluster with Aurora Postgres database engine'(test: Test) { // GIVEN const stack = testStack(); @@ -818,7 +818,7 @@ export = { test.done(); }, -}; +}); function testStack() { diff --git a/packages/@aws-cdk/aws-rds/test/sql-server/test.sql-server.instance-engine.ts b/packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts similarity index 94% rename from packages/@aws-cdk/aws-rds/test/sql-server/test.sql-server.instance-engine.ts rename to packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts index 7f9ecf0311faa..4255298f87d10 100644 --- a/packages/@aws-cdk/aws-rds/test/sql-server/test.sql-server.instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/test/sql-server/sql-server.instance-engine.test.ts @@ -1,9 +1,9 @@ import { expect, haveResourceLike } from '@aws-cdk/assert'; import * as core from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../../lib'; -export = { +nodeunitShim({ 'SQL Server instance engine': { "has ParameterGroup family ending in '11.0' for major version 11"(test: Test) { const stack = new core.Stack(); @@ -43,4 +43,4 @@ export = { test.done(); }, }, -}; +}); diff --git a/packages/@aws-cdk/aws-rds/test/test.subnet-group.ts b/packages/@aws-cdk/aws-rds/test/subnet-group.test.ts similarity index 97% rename from packages/@aws-cdk/aws-rds/test/test.subnet-group.ts rename to packages/@aws-cdk/aws-rds/test/subnet-group.test.ts index 6d2a71e84bad7..c6c16add591ce 100644 --- a/packages/@aws-cdk/aws-rds/test/test.subnet-group.ts +++ b/packages/@aws-cdk/aws-rds/test/subnet-group.test.ts @@ -1,13 +1,13 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; +import { nodeunitShim, Test } from 'nodeunit-shim'; import * as rds from '../lib'; let stack: cdk.Stack; let vpc: ec2.IVpc; -export = { +nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); vpc = new ec2.Vpc(stack, 'VPC'); @@ -95,4 +95,4 @@ export = { test.done(); }, -}; +}); From d04308481b6c83a0d412dcdefb5332363b8772a3 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Tue, 16 Feb 2021 12:15:21 +0000 Subject: [PATCH 07/20] chore: backport CHANGELOG generation fix (#13082) See #13019 for the original fix, which was committed to the v2-main branch. This backports the change to the master/v1 branch. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- scripts/bump.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/bump.js b/scripts/bump.js index a1d678c57ce18..5d8b4d63a62d0 100755 --- a/scripts/bump.js +++ b/scripts/bump.js @@ -1,8 +1,9 @@ #!/usr/bin/env node -const standardVersion = require('standard-version'); const fs = require('fs'); const path = require('path'); +const semver = require('semver'); const ver = require('./resolve-version'); +const { exec } = require('child_process'); const repoRoot = path.join(__dirname, '..'); const releaseAs = process.argv[2] || 'minor'; @@ -40,7 +41,19 @@ async function main() { console.error(`BUMP_CANDIDATE is set, so bumping version for testing (with the "${opts.prerelease}" prerelease tag)`); } - return standardVersion(opts); + // `standard-release` will -- among other things -- create the changelog. + // However, on the v2 branch, `conventional-changelog` (which `standard-release` uses) gets confused + // and creates really muddled changelogs with both v1 and v2 releases intermingled, and lots of missing data. + // A super HACK here is to locally remove all version tags that don't match this major version prior + // to doing the bump, and then later fetching to restore those tags. + const majorVersion = semver.major(ver.version); + await exec(`git tag -d $(git tag -l | grep -v '^v${majorVersion}.')`); + + // Delay loading standard-version until the git tags have been pruned. + const standardVersion = require('standard-version'); + await standardVersion(opts); + + await exec('git fetch -t'); } main().catch(err => { From 46043e04a1603796c766dd1e280384f46c27e2de Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 16 Feb 2021 16:39:43 +0100 Subject: [PATCH 08/20] fix(core): `exportValue()` does not work with resource names (#13052) Most L2 resources employ the "PhysicalName" protocol, which checks usage of resource names across environment borders, and can automatically turn auto-named resources into physically-named resources if the situation calls for it. Unfortunately, this wrapped token is a generic IResolvable, not a Reference, and so did not work with the `exportValue()` automatic reference detection. Make the token returned by `getResourceNameAttribute()` etc. a `Reference` that mimics the underlying `Reference` to make this work out. Fixes #13002, fixes #12918. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-s3/test/bucket.test.ts | 2 - packages/@aws-cdk/core/README.md | 4 +- packages/@aws-cdk/core/lib/resource.ts | 36 ++++++++-- packages/@aws-cdk/core/lib/token.ts | 25 ++++++- .../core/test/cross-environment-token.test.ts | 70 ++++++++++++++++++- 5 files changed, 123 insertions(+), 14 deletions(-) diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index 51b2874311af8..b54957f32d500 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -2405,7 +2405,5 @@ describe('bucket', () => { expect(() => new s3.Bucket(stack, 'MyBucket', { autoDeleteObjects: true, })).toThrow(/Cannot use \'autoDeleteObjects\' property on a bucket without setting removal policy to \'DESTROY\'/); - - }); }); diff --git a/packages/@aws-cdk/core/README.md b/packages/@aws-cdk/core/README.md index 880aea79a55fc..0e0b38943a803 100644 --- a/packages/@aws-cdk/core/README.md +++ b/packages/@aws-cdk/core/README.md @@ -141,7 +141,7 @@ DEPLOYMENT 1: break the relationship - Make sure `stack2` no longer references `bucket.bucketName` (maybe the consumer stack now uses its own bucket, or it writes to an AWS DynamoDB table, or maybe you just remove the Lambda Function altogether). -- In the `stack1` class, call `this.exportAttribute(this.bucket.bucketName)`. This +- In the `stack1` class, call `this.exportValue(this.bucket.bucketName)`. This will make sure the CloudFormation Export continues to exist while the relationship between the two stacks is being broken. - Deploy (this will effectively only change the `stack2`, but it's safe to deploy both). @@ -149,7 +149,7 @@ DEPLOYMENT 1: break the relationship DEPLOYMENT 2: remove the resource - You are now free to remove the `bucket` resource from `stack1`. -- Don't forget to remove the `exportAttribute()` call as well. +- Don't forget to remove the `exportValue()` call as well. - Deploy again (this time only the `stack1` will be changed -- the bucket will be deleted). ## Durations diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index 917a2c442dcf1..6445fe718c547 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -4,11 +4,12 @@ import { IConstruct, Construct as CoreConstruct } from './construct-compat'; import { Construct } from 'constructs'; import { ArnComponents } from './arn'; -import { Lazy } from './lazy'; +import { IStringProducer, Lazy } from './lazy'; import { generatePhysicalName, isGeneratedWhenNeededMarker } from './private/physical-name-generator'; import { IResolveContext } from './resolvable'; import { Stack } from './stack'; -import { Token } from './token'; +import { Token, Tokenization } from './token'; +import { Reference } from './reference'; /** * Represents the environment a given resource lives in. @@ -181,7 +182,7 @@ export abstract class Resource extends CoreConstruct implements IResource { * @experimental */ protected getResourceNameAttribute(nameAttr: string) { - return Lazy.uncachedString({ + return mimicReference(nameAttr, { produce: (context: IResolveContext) => { const consumingStack = Stack.of(context.scope); @@ -214,8 +215,8 @@ export abstract class Resource extends CoreConstruct implements IResource { * @experimental */ protected getResourceArnAttribute(arnAttr: string, arnComponents: ArnComponents) { - return Token.asString({ - resolve: (context: IResolveContext) => { + return mimicReference(arnAttr, { + produce: (context: IResolveContext) => { const consumingStack = Stack.of(context.scope); if (this.stack.environment !== consumingStack.environment) { this._enableCrossEnvironment(); @@ -227,3 +228,28 @@ export abstract class Resource extends CoreConstruct implements IResource { }); } } + +/** + * Produce a Lazy that is also a Reference (if the base value is a Reference). + * + * If the given value is a Reference (or resolves to a Reference), return a new + * Reference that mimics the same target and display name, but resolves using + * the logic of the passed lazy. + * + * If the given value is NOT a Reference, just return a simple Lazy. + */ +function mimicReference(refSource: any, producer: IStringProducer): string { + const reference = Tokenization.reverse(refSource, { + // If this is an ARN concatenation, just fail to extract a reference. + failConcat: false, + }); + if (!Reference.isReference(reference)) { + return Lazy.uncachedString(producer); + } + + return Token.asString(new class extends Reference { + resolve(context: IResolveContext) { + return producer.produce(context); + } + }(reference, reference.target, reference.displayName)); +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/token.ts b/packages/@aws-cdk/core/lib/token.ts index f92a2560cac7c..e17227d0f8ef5 100644 --- a/packages/@aws-cdk/core/lib/token.ts +++ b/packages/@aws-cdk/core/lib/token.ts @@ -164,9 +164,16 @@ export class Tokenization { * * In case of a string, the string must not be a concatenation. */ - public static reverse(x: any): IResolvable | undefined { + public static reverse(x: any, options: ReverseOptions = {}): IResolvable | undefined { if (Tokenization.isResolvable(x)) { return x; } - if (typeof x === 'string') { return Tokenization.reverseCompleteString(x); } + if (typeof x === 'string') { + if (options.failConcat === false) { + // Handle this specially because reverseCompleteString might fail + const fragments = Tokenization.reverseString(x); + return fragments.length === 1 ? fragments.firstToken : undefined; + } + return Tokenization.reverseCompleteString(x); + } if (Array.isArray(x)) { return Tokenization.reverseList(x); } if (typeof x === 'number') { return Tokenization.reverseNumber(x); } return undefined; @@ -220,6 +227,20 @@ export class Tokenization { } } +/** + * Options for the 'reverse()' operation + */ +export interface ReverseOptions { + /** + * Fail if the given string is a concatenation + * + * If `false`, just return `undefined`. + * + * @default true + */ + readonly failConcat?: boolean; +} + /** * Options to the resolve() operation * diff --git a/packages/@aws-cdk/core/test/cross-environment-token.test.ts b/packages/@aws-cdk/core/test/cross-environment-token.test.ts index 4ab55922369e4..a0d833996121c 100644 --- a/packages/@aws-cdk/core/test/cross-environment-token.test.ts +++ b/packages/@aws-cdk/core/test/cross-environment-token.test.ts @@ -244,6 +244,36 @@ nodeunitShim({ }, }); +test.each([undefined, 'SomeName'])('stack.exportValue() on name attributes with PhysicalName=%s', physicalName => { + // Check that automatic exports and manual exports look the same + // GIVEN - auto + const appA = new App(); + const producerA = new Stack(appA, 'Producer'); + const resourceA = new MyResource(producerA, 'Resource', physicalName); + + const consumerA = new Stack(appA, 'Consumer'); + new CfnOutput(consumerA, 'ConsumeName', { value: resourceA.name }); + new CfnOutput(consumerA, 'ConsumeArn', { value: resourceA.arn }); + + // WHEN - manual + const appM = new App(); + const producerM = new Stack(appM, 'Producer'); + const resourceM = new MyResource(producerM, 'Resource', physicalName); + producerM.exportValue(resourceM.name); + producerM.exportValue(resourceM.arn); + + // THEN - producers are the same + const templateA = appA.synth().getStackByName(producerA.stackName).template; + const templateM = appM.synth().getStackByName(producerM.stackName).template; + + expect(templateA).toEqual(templateM); +}); + +test('can instantiate resource with constructed physicalname ARN', () => { + const stack = new Stack(); + new MyResourceWithConstructedArnAttribute(stack, 'Resource'); +}); + class MyResource extends Resource { public readonly arn: string; public readonly name: string; @@ -251,20 +281,54 @@ class MyResource extends Resource { constructor(scope: Construct, id: string, physicalName?: string) { super(scope, id, { physicalName }); - this.arn = this.getResourceArnAttribute('simple-arn', { + const res = new CfnResource(this, 'Resource', { + type: 'My::Resource', + properties: { + resourceName: this.physicalName, + }, + }); + + this.name = this.getResourceNameAttribute(res.ref.toString()); + this.arn = this.getResourceArnAttribute(res.getAtt('Arn').toString(), { region: '', account: '', resource: 'my-resource', resourceName: this.physicalName, service: 'myservice', }); - this.name = this.getResourceNameAttribute('simple-name'); + } +} - new CfnResource(this, 'Resource', { +/** + * Some resources build their own Arn attribute by constructing strings + * + * This will be because the L1 doesn't expose a `{ Fn::GetAtt: ['Arn'] }`. + * + * They won't be able to `exportValue()` it, but it shouldn't crash. + */ +class MyResourceWithConstructedArnAttribute extends Resource { + public readonly arn: string; + public readonly name: string; + + constructor(scope: Construct, id: string, physicalName?: string) { + super(scope, id, { physicalName }); + + const res = new CfnResource(this, 'Resource', { type: 'My::Resource', properties: { resourceName: this.physicalName, }, }); + + this.name = this.getResourceNameAttribute(res.ref.toString()); + this.arn = this.getResourceArnAttribute(Stack.of(this).formatArn({ + resource: 'my-resource', + resourceName: res.ref.toString(), + service: 'myservice', + }), { + resource: 'my-resource', + resourceName: this.physicalName, + service: 'myservice', + }); } } From b984b19015624f3b47641e91a47b241e417af6c6 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Tue, 16 Feb 2021 17:08:09 +0000 Subject: [PATCH 09/20] chore(cdk-build-tools): backport feature flag based conditional from v2-main (#13056) This was originally commented out - d7e028a1 - since this was not yet compatible with the v2-main branch. Since then, the v2-main branch has been updated - 7554246ab - with the necessary fixes and the conditional has been enabled there[1]. No effective change to master branch because of this. It reduces divergence of the two active branches. [1]: https://github.com/aws/aws-cdk/commit/7554246ab6d0819bc57d5e67cd9e4e10a3b7e742#diff-d325e066c7cdf5d2a8423e65b0190045defe711b4dc25adc0a94a11eef163ed9 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- tools/cdk-build-tools/lib/feature-flag.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/cdk-build-tools/lib/feature-flag.ts b/tools/cdk-build-tools/lib/feature-flag.ts index eec1d28d6e9e4..36b22588288aa 100644 --- a/tools/cdk-build-tools/lib/feature-flag.ts +++ b/tools/cdk-build-tools/lib/feature-flag.ts @@ -30,9 +30,8 @@ export function testFutureBehavior( const major = cdkMajorVersion(repoRoot); if (major === 2) { - // Temporaily disable CDKv2 behaviour - // const app = new cdkApp(); - // return test(name, async () => fn(app)); + const app = new cdkApp(); + return test(name, async () => fn(app)); } const app = new cdkApp({ context: flags }); return test(name, () => fn(app)); @@ -59,8 +58,7 @@ export function testLegacyBehavior( const major = cdkMajorVersion(repoRoot); if (major === 2) { - // Temporarily disable CDKv2 behaviour - // return; + return; } const app = new cdkApp(); return test(name, () => fn(app)); @@ -78,4 +76,4 @@ function cdkMajorVersion(repoRoot: string) { throw new Error(`version ${ver} is not a semver`); } return sem.major; -} \ No newline at end of file +} From ca08245c52e1d6765450ff12f6871a6f5beac2cf Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Tue, 16 Feb 2021 17:50:00 +0000 Subject: [PATCH 10/20] chore: update contribution guide with feature flag support for v2 (#13084) Update how feature flags that are destined to be dropped in v2 should be developed. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- CONTRIBUTING.md | 16 ++++++++++++++++ packages/@aws-cdk/cx-api/test/features.test.ts | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d113183c9a67..8f26e8198abc2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -849,6 +849,22 @@ CDK](https://github.com/aws/aws-cdk/issues/3398) we will either remove the legacy behavior or flip the logic for all these features and then reset the `FEATURE_FLAGS` map for the next cycle. +#### CDKv2 + +We have started working on the next version of the CDK, specifically CDKv2. This is currently being maintained +on a separate branch `v2-main` whereas `master` continues to track versions `1.x`. + +Feature flags introduced in the CDK 1.x and removed in 2.x, must be added to the `FUTURE_FLAGS_EXPIRED` list in +[cx-api/lib/features.ts](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/cx-api/lib/features.ts) +on the `v2-main` branch. +This will make the default behaviour in CDKv2 as if the flag is enabled and also prevents users from disabling +the feature flag. + +A couple of [jest helper methods] are available for use with unit tests. These help run unit tests that test +behaviour when flags are enabled or disabled in the two major versions. + +[jest helper methods]: https://github.com/aws/aws-cdk/blob/master/tools/cdk-build-tools/lib/feature-flag.ts + ### Versioning and Release The `release.json` file at the root of the repo determines which release line diff --git a/packages/@aws-cdk/cx-api/test/features.test.ts b/packages/@aws-cdk/cx-api/test/features.test.ts index fbff6c236b984..81b42773fd292 100644 --- a/packages/@aws-cdk/cx-api/test/features.test.ts +++ b/packages/@aws-cdk/cx-api/test/features.test.ts @@ -1,7 +1,12 @@ +import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; import * as feats from '../lib/features'; test('all future flags have defaults configured', () => { Object.keys(feats.FUTURE_FLAGS).forEach(flag => { expect(typeof(feats.futureFlagDefault(flag))).toEqual('boolean'); }); +}); + +testLegacyBehavior('FUTURE_FLAGS_EXPIRED must be empty in CDKv1', Object, () => { + expect(feats.FUTURE_FLAGS_EXPIRED.length).toEqual(0); }); \ No newline at end of file From b3197db1c87067231b0642b7f9e1e37a48b12b6d Mon Sep 17 00:00:00 2001 From: Jeff Dvornek Date: Tue, 16 Feb 2021 13:53:27 -0500 Subject: [PATCH 11/20] fix(aws-rds): correct Policy resource for Proxy::grantConnect() (#12416) fixes #12415 To generate the correct policy, the DatabaseProxy ARN is parsed and the resulting components are used along with a new parameter to grantConnect. The unit test was updated and passes. Caveat lector, I was not able to get a full docker build or a full local build to work on my box. I'm not sure if this should be considered a breaking change. While it technically alters the functionality of a published function, the current behavior provides no utility. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-rds/README.md | 4 +- packages/@aws-cdk/aws-rds/lib/proxy.ts | 37 +++++- packages/@aws-cdk/aws-rds/test/proxy.test.ts | 120 ++++++++++++++++++- 3 files changed, 151 insertions(+), 10 deletions(-) diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index 67bb8328696bc..b00e3c64187f0 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -283,7 +283,7 @@ instance.grantConnect(role); // Grant the role connection access to the DB. The following example shows granting connection access for RDS Proxy to an IAM role. ```ts -const cluster = new rds.DatabaseCluster(stack, 'Database'{ +const cluster = new rds.DatabaseCluster(stack, 'Database', { engine: rds.DatabaseClusterEngine.AURORA, instanceProps: { vpc }, }); @@ -295,7 +295,7 @@ const proxy = new rds.DatabaseProxy(stack, 'Proxy', { }); const role = new Role(stack, 'DBProxyRole', { assumedBy: new AccountPrincipal(stack.account) }); -proxy.grantConnect(role); // Grant the role connection access to the DB Proxy. +proxy.grantConnect(role, 'admin'); // Grant the role connection access to the DB Proxy for database user 'admin'. ``` **Note**: In addition to the setup above, a database user will need to be created to support IAM auth. diff --git a/packages/@aws-cdk/aws-rds/lib/proxy.ts b/packages/@aws-cdk/aws-rds/lib/proxy.ts index 8e95c343b39be..fa50b891fca80 100644 --- a/packages/@aws-cdk/aws-rds/lib/proxy.ts +++ b/packages/@aws-cdk/aws-rds/lib/proxy.ts @@ -322,8 +322,14 @@ export interface IDatabaseProxy extends cdk.IResource { /** * Grant the given identity connection access to the proxy. + * + * @param grantee the Principal to grant the permissions to + * @param dbUser the name of the database user to allow connecting as to the proxy + * + * @default - if the Proxy had been provided a single Secret value, + * the user will be taken from that Secret */ - grantConnect(grantee: iam.IGrantable): iam.Grant; + grantConnect(grantee: iam.IGrantable, dbUser?: string): iam.Grant; } /** @@ -335,11 +341,22 @@ abstract class DatabaseProxyBase extends cdk.Resource implements IDatabaseProxy public abstract readonly dbProxyArn: string; public abstract readonly endpoint: string; - public grantConnect(grantee: iam.IGrantable): iam.Grant { + public grantConnect(grantee: iam.IGrantable, dbUser?: string): iam.Grant { + if (!dbUser) { + throw new Error('For imported Database Proxies, the dbUser is required in grantConnect()'); + } + const scopeStack = cdk.Stack.of(this); + const proxyGeneratedId = scopeStack.parseArn(this.dbProxyArn, ':').resourceName; + const userArn = scopeStack.formatArn({ + service: 'rds-db', + resource: 'dbuser', + resourceName: `${proxyGeneratedId}/${dbUser}`, + sep: ':', + }); return iam.Grant.addToPrincipal({ grantee, actions: ['rds-db:connect'], - resourceArns: [this.dbProxyArn], + resourceArns: [userArn], }); } } @@ -393,6 +410,7 @@ export class DatabaseProxy extends DatabaseProxyBase */ public readonly connections: ec2.Connections; + private readonly secrets: secretsmanager.ISecret[]; private readonly resource: CfnDBProxy; constructor(scope: Construct, id: string, props: DatabaseProxyProps) { @@ -419,6 +437,7 @@ export class DatabaseProxy extends DatabaseProxyBase if (props.secrets.length < 1) { throw new Error('One or more secrets are required.'); } + this.secrets = props.secrets; this.resource = new CfnDBProxy(this, 'Resource', { auth: props.secrets.map(_ => { @@ -477,6 +496,18 @@ export class DatabaseProxy extends DatabaseProxyBase targetType: secretsmanager.AttachmentTargetType.RDS_DB_PROXY, }; } + + public grantConnect(grantee: iam.IGrantable, dbUser?: string): iam.Grant { + if (!dbUser) { + if (this.secrets.length > 1) { + throw new Error('When the Proxy contains multiple Secrets, you must pass a dbUser explicitly to grantConnect()'); + } + // 'username' is the field RDS uses here, + // see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/rds-proxy.html#rds-proxy-secrets-arns + dbUser = this.secrets[0].secretValueFromJson('username').toString(); + } + return super.grantConnect(grantee, dbUser); + } } /** diff --git a/packages/@aws-cdk/aws-rds/test/proxy.test.ts b/packages/@aws-cdk/aws-rds/test/proxy.test.ts index c4014d321d6e7..a0835879b5d79 100644 --- a/packages/@aws-cdk/aws-rds/test/proxy.test.ts +++ b/packages/@aws-cdk/aws-rds/test/proxy.test.ts @@ -9,6 +9,8 @@ import * as rds from '../lib'; let stack: cdk.Stack; let vpc: ec2.IVpc; +let importedDbProxy: rds.IDatabaseProxy; + nodeunitShim({ 'setUp'(cb: () => void) { stack = new cdk.Stack(); @@ -244,7 +246,67 @@ nodeunitShim({ test.done(); }, - 'grantConnect should add IAM Policy with action rds-db:connect'(test: Test) { + 'imported Proxies': { + 'setUp'(cb: () => void) { + importedDbProxy = rds.DatabaseProxy.fromDatabaseProxyAttributes(stack, 'Proxy', { + dbProxyName: 'my-proxy', + dbProxyArn: 'arn:aws:rds:us-east-1:123456789012:db-proxy:prx-1234abcd', + endpoint: 'my-endpoint', + securityGroups: [], + }); + + cb(); + }, + + 'grant rds-db:connect in grantConnect() with a dbUser explicitly passed'(test: Test) { + // WHEN + const role = new Role(stack, 'DBProxyRole', { + assumedBy: new AccountPrincipal(stack.account), + }); + const databaseUser = 'test'; + importedDbProxy.grantConnect(role, databaseUser); + + // THEN + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Effect: 'Allow', + Action: 'rds-db:connect', + Resource: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':rds-db:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':dbuser:prx-1234abcd/test', + ]], + }, + }], + Version: '2012-10-17', + }, + })); + + test.done(); + }, + + 'throws when grantConnect() is used without a dbUser'(test: Test) { + // WHEN + const role = new Role(stack, 'DBProxyRole', { + assumedBy: new AccountPrincipal(stack.account), + }); + + // THEN + test.throws(() => { + importedDbProxy.grantConnect(role); + }, /For imported Database Proxies, the dbUser is required in grantConnect/); + + test.done(); + }, + }, + + 'new Proxy with a single Secret can use grantConnect() without a dbUser passed'(test: Test) { // GIVEN const cluster = new rds.DatabaseCluster(stack, 'Database', { engine: rds.DatabaseClusterEngine.AURORA, @@ -270,10 +332,29 @@ nodeunitShim({ Effect: 'Allow', Action: 'rds-db:connect', Resource: { - 'Fn::GetAtt': [ - 'ProxyCB0DFB71', - 'DBProxyArn', - ], + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':rds-db:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':dbuser:', + { + 'Fn::Select': [ + 6, + { + 'Fn::Split': [ + ':', + { 'Fn::GetAtt': ['ProxyCB0DFB71', 'DBProxyArn'] }, + ], + }, + ], + }, + '/{{resolve:secretsmanager:', + { Ref: 'DatabaseSecretAttachmentE5D1B020' }, + ':SecretString:username::}}', + ]], }, }], Version: '2012-10-17', @@ -283,6 +364,35 @@ nodeunitShim({ test.done(); }, + 'new Proxy with multiple Secrets cannot use grantConnect() without a dbUser passed'(test: Test) { + // GIVEN + const cluster = new rds.DatabaseCluster(stack, 'Database', { + engine: rds.DatabaseClusterEngine.AURORA, + instanceProps: { vpc }, + }); + + const proxy = new rds.DatabaseProxy(stack, 'Proxy', { + proxyTarget: rds.ProxyTarget.fromCluster(cluster), + secrets: [ + cluster.secret!, + new secretsmanager.Secret(stack, 'ProxySecret'), + ], + vpc, + }); + + // WHEN + const role = new Role(stack, 'DBProxyRole', { + assumedBy: new AccountPrincipal(stack.account), + }); + + // THEN + test.throws(() => { + proxy.grantConnect(role); + }, /When the Proxy contains multiple Secrets, you must pass a dbUser explicitly to grantConnect/); + + test.done(); + }, + 'DBProxyTargetGroup should have dependency on the proxy targets'(test: Test) { // GIVEN const cluster = new rds.DatabaseCluster(stack, 'cluster', { From 843b480e7a1bc51594d3580d2774d3b9a4eec2fb Mon Sep 17 00:00:00 2001 From: Hsing-Hui Hsu Date: Tue, 16 Feb 2021 11:26:48 -0800 Subject: [PATCH 12/20] feat(ecs): support Fargate and Fargate spot capacity providers (#12893) Fixes #5850 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-ecs-fargate-capacity-providers.md | 121 +++++ packages/@aws-cdk/aws-ecs/README.md | 47 ++ .../@aws-cdk/aws-ecs/lib/base/base-service.ts | 22 +- packages/@aws-cdk/aws-ecs/lib/cluster.ts | 65 ++- .../aws-ecs/lib/fargate/fargate-service.ts | 2 + .../integ.app-mesh-proxy-config.expected.json | 4 +- .../test/ec2/integ.bottlerocket.expected.json | 4 +- .../test/ec2/integ.clb-host-nw.expected.json | 4 +- .../integ.firelens-s3-config.expected.json | 4 +- .../test/ec2/integ.lb-awsvpc-nw.expected.json | 4 +- .../test/ec2/integ.lb-bridge-nw.expected.json | 4 +- .../test/ec2/integ.sd-awsvpc-nw.expected.json | 4 +- .../test/ec2/integ.sd-bridge-nw.expected.json | 4 +- .../test/ec2/integ.spot-drain.expected.json | 8 +- .../integ.capacity-providers.expected.json | 473 ++++++++++++++++++ .../test/fargate/integ.capacity-providers.ts | 37 ++ .../test/fargate/test.fargate-service.ts | 85 ++++ .../@aws-cdk/aws-ecs/test/test.ecs-cluster.ts | 49 ++ 18 files changed, 918 insertions(+), 23 deletions(-) create mode 100644 design/aws-ecs/aws-ecs-fargate-capacity-providers.md create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.expected.json create mode 100644 packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.ts diff --git a/design/aws-ecs/aws-ecs-fargate-capacity-providers.md b/design/aws-ecs/aws-ecs-fargate-capacity-providers.md new file mode 100644 index 0000000000000..66451ece2843a --- /dev/null +++ b/design/aws-ecs/aws-ecs-fargate-capacity-providers.md @@ -0,0 +1,121 @@ +# Fargate Spot Capacity Provider support in the CDK + +## Objective + +Since Capacity Providers are now supported in CloudFormation, incorporating support for Fargate Spot capacity has been one of the [top asks](https://github.com/aws/aws-cdk/issues?q=is%3Aissue+is%3Aopen+label%3A%40aws-cdk%2Faws-ecs+sort%3Areactions-%2B1-desc) for the ECS CDK module, with over 60 customer reactions. While there are still some outstanding issues regarding capacity provider support in general, specifically regarding cyclic workflows with named clusters (See: [CFN issue](http://%20https//github.com/aws/containers-roadmap/issues/631#issuecomment-702580141)), we should be able to move ahead with supporting `FARGATE` and `FARGATE_SPOT` capacity providers with our existing FargateService construct. + +See: https://github.com/aws/aws-cdk/issues/5850 + +## CloudFormation Requirements + +### Cluster + +A list of capacity providers (specifically, `FARGATE` and `FARGATE_SPOT`) need to be specified on the cluster itself as part of the [CapacityProviders](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-capacityproviders) field. + +Additionally, there is a [DefaultCapacityProviderStrategy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-cluster.html#cfn-ecs-cluster-defaultcapacityproviderstrategy) on the cluster. While it is considered best practice to specify one if using capacity providers, this may not be necessary when only using Fargate capacity providers. + +### Service + +The [CapacityProviderStrategy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-capacityproviderstrategy) field will need to be added to the Service construct. This would be a list of capacity provider strategies (aka [CapacityProviderStrategyItem](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html) in CFN) used for the service. + +_Note_: It may be more readable to name the `CapacityProviderStrategy` field on the service to *CapacityProviderStrategies*, which would be a list of *CapacityProviderStrategy* objects that correspond to the CFN `CapacityProviderStrategyItem`. + + +## Proposed solution + +### User Experience + +The most straightforward solution would be to add the *capacityProviders* field on cluster, which the customer would have to set to the Fargate capacity providers (`FARGATE` and `FARGATE_SPOT`), and then specify the *capacityProviderStrategies* field on the FargateService with one or more strategies that use the Fargate capacity providers. + +Example: + +```ts +const stack = new cdk.Stack(); +const vpc = new ec2.Vpc(stack, 'MyVpc', {}); +const cluster = new ecs.Cluster(stack, 'EcsCluster', { + vpc, + *capacityProviders: ['FARGATE', 'FARGATE_SPOT'],* +}); + +const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + +const container = taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, +}); +container.addPortMappings({ containerPort: 8000 }); + +new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + *capacityProviderStrategies**: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + } + ],* +}); +``` + +The type for the *capacityProviders* field on a *Cluster* would be a list of string literals. An alternative that ensures type safety is to have `FARGATE` and `FARGATE_SPOT` as enum values; however, this would make it potentially more difficult to support Autoscaling Group capacity providers in the future, since [capacity providers](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-capacity-providers.html) of that type would have be specified by their capacity provider name (as a string literal). + +The type for the *capacityProviderStrategies* field on a *Service* would be a list of [*CapacityProviderStrategy*](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html) objects, taking the form: + +{"[Base](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html#cfn-ecs-service-capacityproviderstrategyitem-base)" : Integer, "[CapacityProvider](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html#cfn-ecs-service-capacityproviderstrategyitem-capacityprovider)" : String, "[Weight](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-capacityproviderstrategyitem.html#cfn-ecs-service-capacityproviderstrategyitem-weight)" : Integer } + +*Base* and *Weight* fields will be *optional*; *CapacityProvider* is *required*. I.e.: + +```ts +/** + * A Capacity Provider strategy to use for the service. + */ +export interface CapacityProviderStrategy { + /** + * The name of the Capacity Provider. Currently only FARGATE and FARGATE_SPOT are supported. + */ + readonly capacityProvider: string; + + /** + * The base value designates how many tasks, at a minimum, to run on the specified capacity provider. Only one + * capacity provider in a capacity provider strategy can have a base defined. If no value is specified, the default + * value of 0 is used. + * + * @default - none + */ + readonly base?: number; + + /** + * The weight value designates the relative percentage of the total number of tasks launched that should use the + * specified +capacity provider. The weight value is taken into consideration after the base value, if defined, is satisfied. + * + * @default - 0 + */ + readonly weight?: number; +} + +``` +This new field would be added to the BaseService, not only for better extensibility when we add support for ASG capacity providers, but also to facilitate construction, since the FargateService extends the BaseService and would necessarily call super into the BaseService constructor. + +Implications Setting Launch Type + +Since it can be reasonably assumed that any CapacityProvideStrategies defined on the Service are what the customer intends to use on the Service, the LaunchType will *not* be set on the Service if CapacityProvideStrategies are specified. This is similar to how the LaunchType field is unset if the service uses an external DeploymentController (https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-ecs/lib/base/base-service.ts#L374). + +On the other hand, this intent would not be as obvious with Default Capacity Provider Strategies defined a cluster. A *defaultCapacityProviderStrategy* specified on a cluster is used for any service that does not specify either a launchType or its own CapacityProviderStrategies. From the point of view of the ECS APIs, similar to how custom CapacityProvideStrategies defined on the Service are expected to supersede the defaultCapacityProviderStrategy on a cluster, the expected behavior for an ECS Service that specifies a launchType is for it to also ignore the Cluster’s defaultCapacityProviderStrategy. + +However, since the two Service constructs in the CDK (Ec2Service and FargateService) do not support having the launchType field passed in explicitly, it would not possible to infer whether the intent of the customer using one of these Service constructs is to use the implied launchType (currently set under the hood in the service’s constructor (https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-ecs/lib/fargate/fargate-service.ts#L155)) or the defaultCapacityProviderStrategy. For this reason, we will not be adding the defaultCapacityProviderStrategy field on the Cluster construct for this iteration. + +_*Note*_: Future for support will be dependent on a re-design of the existing Service strategies. This will be treated in v2 of the ECS modules, likely with a single Service L2 construct and deprecation of the Ec2Service and FargateService constructs. + + +### Alternatives: +One alternative considered was to provide a more magical experience by populating the capacityProviders field under the hood (for example, by modifying the cluster if capacityProviderStrategies is set on a FargateService). However, there is the slight disadvantage of this being a less consistent behavior with how ASG capacity providers will be set in the future, and would break from the general pattern of setting resource fields at construction time. Furthermore, given that the cluster field on a service is of type ICluster, this may make it prohibitively difficult/impossible to provide the magical experience of modifying fields on the Cluster from the service. In the case where an ICluster is defined in a different stack, its properties cannot be modified from the stack where the Service is defined at all. For this reason, we will have to enforce the capacityProviders field being set explicitly on the Cluster construct. + +For future extensibility, we can however add an `addCapacityProvider` method on the Cluster resource, to allow modifying the cluster CapacityProviders field post-construction. + +Another option would be to create a new FargateCluster resource, that would have the two Fargate capacity providers set by default. The main advantage with this alternative would be that it would be consistent with the current Console experience, which sets the Fargate capacity providers for you if you choose the “Networking Only” cluster template via the cluster wizard. The downside is that it would be a more restrictive resource model that would go back on the decision to have a single generic ECS Cluster resource that could potentially contain both Fargate and EC2 services or tasks. Given that we are moving towards more generic versions of ECS resources, this is not a preferable solution. That being said, in the current iteration we can set the Fargate Capacity Providers on the cluster by default, but put them behind a feature flag, which we would be able to remove in the v2 version of the ECS module. Using the feature flag would ensure that there would not be a diff in the generated CFN template for existing customers defining ECS clusters in their stack who redeploy using an updated version of the CDK. + diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index f2056229c6bf5..438f63e14e009 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -670,3 +670,50 @@ taskDefinition.addContainer('TheContainer', { }) }); ``` + +## Capacity Providers + +Currently, only `FARGATE` and `FARGATE_SPOT` capacity providers are supported. + +To enable capacity providers on your cluster, set the `capacityProviders` field +to [`FARGATE`, `FARGATE_SPOT`]. Then, specify capacity provider strategies on +the `capacityProviderStrategies` field for your Fargate Service. + +```ts +import * as cdk from '@aws-cdk/core'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '../../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ-capacity-provider'); + +const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2 }); + +const cluster = new ecs.Cluster(stack, 'FargateCPCluster', { + vpc, + capacityProviders: ['FARGATE', 'FARGATE_SPOT'], +}); + +const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + +taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), +}); + +new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + capacityProviderStrategies: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + } + ], +}); + +app.synth(); +``` diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index 5c5160a849835..8e2483f98838f 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -8,7 +8,7 @@ import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import { Annotations, Duration, IResolvable, IResource, Lazy, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { LoadBalancerTargetOptions, NetworkMode, TaskDefinition } from '../base/task-definition'; -import { ICluster } from '../cluster'; +import { ICluster, CapacityProviderStrategy } from '../cluster'; import { Protocol } from '../container-definition'; import { CfnService } from '../ecs.generated'; import { ScalableTaskCount } from './scalable-task-count'; @@ -181,6 +181,14 @@ export interface BaseServiceOptions { * @default - disabled */ readonly circuitBreaker?: DeploymentCircuitBreaker; + + /** + * A list of Capacity Provider strategies used to place a service. + * + * @default - undefined + * + */ + readonly capacityProviderStrategies?: CapacityProviderStrategy[]; } /** @@ -191,6 +199,10 @@ export interface BaseServiceProps extends BaseServiceOptions { /** * The launch type on which to run your service. * + * LaunchType will be omitted if capacity provider strategies are specified on the service. + * + * @see - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-capacityproviderstrategy + * * Valid values are: LaunchType.ECS or LaunchType.FARGATE */ readonly launchType: LaunchType; @@ -356,6 +368,11 @@ export abstract class BaseService extends Resource this.taskDefinition = taskDefinition; + // launchType will set to undefined if using external DeploymentController or capacityProviderStrategies + const launchType = props.deploymentController?.type === DeploymentControllerType.EXTERNAL || + props.capacityProviderStrategies !== undefined ? + undefined : props.launchType; + this.resource = new CfnService(this, 'Service', { desiredCount: props.desiredCount, serviceName: this.physicalName, @@ -371,7 +388,8 @@ export abstract class BaseService extends Resource propagateTags: props.propagateTags === PropagatedTagSource.NONE ? undefined : props.propagateTags, enableEcsManagedTags: props.enableECSManagedTags ?? false, deploymentController: props.deploymentController, - launchType: props.deploymentController?.type === DeploymentControllerType.EXTERNAL ? undefined : props.launchType, + launchType: launchType, + capacityProviderStrategy: props.capacityProviderStrategies, healthCheckGracePeriodSeconds: this.evaluateHealthGracePeriod(props.healthCheckGracePeriod), /* role: never specified, supplanted by Service Linked Role */ networkConfiguration: Lazy.any({ produce: () => this.networkConfiguration }, { omitEmptyArray: true }), diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index ca84679e7b970..c60fc9f4b1dee 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as ssm from '@aws-cdk/aws-ssm'; -import { Duration, IResource, Resource, Stack } from '@aws-cdk/core'; +import { Duration, Lazy, IResource, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { InstanceDrainHook } from './drain-hook/instance-drain-hook'; import { ECSMetrics } from './ecs-canned-metrics.generated'; @@ -48,6 +48,13 @@ export interface ClusterProps { */ readonly capacity?: AddCapacityOptions; + /** + * The capacity providers to add to the cluster + * + * @default - None. Currently only FARGATE and FARGATE_SPOT are supported. + */ + readonly capacityProviders?: string[]; + /** * If true CloudWatch Container Insights will be enabled for the cluster * @@ -101,6 +108,13 @@ export class Cluster extends Resource implements ICluster { */ public readonly clusterName: string; + /** + * The capacity providers associated with the cluster. + * + * Currently only FARGATE and FARGATE_SPOT are supported. + */ + private _capacityProviders: string[] = []; + /** * The AWS Cloud Map namespace to associate with the cluster. */ @@ -134,9 +148,12 @@ export class Cluster extends Resource implements ICluster { clusterSettings = [{ name: 'containerInsights', value: props.containerInsights ? ContainerInsights.ENABLED : ContainerInsights.DISABLED }]; } + this._capacityProviders = props.capacityProviders ?? []; + const cluster = new CfnCluster(this, 'Resource', { clusterName: this.physicalName, clusterSettings, + capacityProviders: Lazy.list({ produce: () => this._capacityProviders }, { omitEmpty: true }), }); this.clusterArn = this.getResourceArnAttribute(cluster.attrArn, { @@ -148,6 +165,7 @@ export class Cluster extends Resource implements ICluster { this.vpc = props.vpc || new ec2.Vpc(this, 'Vpc', { maxAzs: 2 }); + this._defaultCloudMapNamespace = props.defaultCloudMapNamespace !== undefined ? this.addDefaultCloudMapNamespace(props.defaultCloudMapNamespace) : undefined; @@ -323,6 +341,21 @@ export class Cluster extends Resource implements ICluster { } } + /** + * addCapacityProvider adds the name of a capacityProvider to the list of supproted capacityProviders for a cluster. + * + * @param provider the capacity provider to add to this cluster. + */ + public addCapacityProvider(provider: string) { + if (!(provider === 'FARGATE' || provider === 'FARGATE_SPOT')) { + throw new Error('CapacityProvider not supported'); + } + + if (!this._capacityProviders.includes(provider)) { + this._capacityProviders.push(provider); + } + } + private configureWindowsAutoScalingGroup(autoScalingGroup: autoscaling.AutoScalingGroup, options: AddAutoScalingGroupCapacityOptions = {}) { // clear the cache of the agent autoScalingGroup.addUserData('Remove-Item -Recurse C:\\ProgramData\\Amazon\\ECS\\Cache'); @@ -934,3 +967,33 @@ enum ContainerInsights { */ DISABLED = 'disabled', } + +/** + * A Capacity Provider strategy to use for the service. + * + * NOTE: defaultCapacityProviderStrategy on cluster not currently supported. + */ +export interface CapacityProviderStrategy { + /** + * The name of the Capacity Provider. Currently only FARGATE and FARGATE_SPOT are supported. + */ + readonly capacityProvider: string; + + /** + * The base value designates how many tasks, at a minimum, to run on the specified capacity provider. Only one + * capacity provider in a capacity provider strategy can have a base defined. If no value is specified, the default + * value of 0 is used. + * + * @default - none + */ + readonly base?: number; + + /** + * The weight value designates the relative percentage of the total number of tasks launched that should use the + * specified +capacity provider. The weight value is taken into consideration after the base value, if defined, is satisfied. + * + * @default - 0 + */ + readonly weight?: number; +} diff --git a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts index 01a9f75665c57..1db94fc5286e0 100644 --- a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts @@ -67,6 +67,7 @@ export interface FargateServiceProps extends BaseServiceOptions { * @default PropagatedTagSource.NONE */ readonly propagateTaskTagsFrom?: PropagatedTagSource; + } /** @@ -153,6 +154,7 @@ export class FargateService extends BaseService implements IFargateService { ...props, desiredCount: props.desiredCount, launchType: LaunchType.FARGATE, + capacityProviderStrategies: props.capacityProviderStrategies, propagateTags: propagateTagsFromSource, enableECSManagedTags: props.enableECSManagedTags, }, { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json index 176bf38d788a5..7a40a11d952ca 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json index 3644a517b73af..23ba70a23584d 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json @@ -692,14 +692,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterbottlerocketasgDrainECSHookFunctionServiceRole2F16AFAB", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -707,6 +705,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json index 67289e175fa8b..3a323b0d36eff 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json @@ -719,14 +719,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -734,6 +732,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json index d76ccbf580d80..967d38891c487 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json index a8f0ceeeebb15..90fd28f84cef2 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json index 2b0faf9e340f1..0737785f5fea4 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json @@ -719,14 +719,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -734,6 +732,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json index 3cc8789e3021a..b4e2c72807b0e 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json index 49e99b166b764..ef42895037361 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json @@ -698,14 +698,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -713,6 +711,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json index ae30eab9d2419..77acf122d0168 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json @@ -700,14 +700,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterasgSpotDrainECSHookFunctionServiceRole8EEDDFE0", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -715,6 +713,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", @@ -1181,14 +1181,12 @@ "Code": { "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n while has_tasks(cluster, instance_arn):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\n\ndef has_tasks(cluster, instance_arn):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n tasks = instance['runningTasksCount'] + instance['pendingTasksCount']\n print('Instance %s has %s tasks' % (instance_arn, tasks))\n\n return tasks > 0\n\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" }, - "Handler": "index.lambda_handler", "Role": { "Fn::GetAtt": [ "EcsClusterasgOdDrainECSHookFunctionServiceRoleFC088D55", "Arn" ] }, - "Runtime": "python3.6", "Environment": { "Variables": { "CLUSTER": { @@ -1196,6 +1194,8 @@ } } }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.expected.json new file mode 100644 index 0000000000000..c0281dc8e14ae --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.expected.json @@ -0,0 +1,473 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ-capacity-provider/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "FargateCPCluster668E71F2": { + "Type": "AWS::ECS::Cluster", + "Properties": { + "CapacityProviders": [ + "FARGATE", + "FARGATE_SPOT" + ] + } + }, + "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", + "Name": "web" + } + ], + "Cpu": "256", + "Family": "awsecsintegcapacityproviderTaskDef80D341CB", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + } + } + }, + "FargateServiceAC2B3B85": { + "Type": "AWS::ECS::Service", + "Properties": { + "CapacityProviderStrategy": [ + { + "CapacityProvider": "FARGATE_SPOT", + "Weight": 2 + }, + { + "CapacityProvider": "FARGATE", + "Weight": 1 + } + ], + "Cluster": { + "Ref": "FargateCPCluster668E71F2" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "EnableECSManagedTags": false, + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "FargateServiceSecurityGroup0A0E79CB", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + } + }, + "TaskDefinition": { + "Ref": "TaskDef54694570" + } + } + }, + "FargateServiceSecurityGroup0A0E79CB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ-capacity-provider/FargateService/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.ts b/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.ts new file mode 100644 index 0000000000000..673b15284a577 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.capacity-providers.ts @@ -0,0 +1,37 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as ecs from '../../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ-capacity-provider'); + +const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2 }); + +const cluster = new ecs.Cluster(stack, 'FargateCPCluster', { + vpc, + capacityProviders: ['FARGATE', 'FARGATE_SPOT'], +}); + +const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + +taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), +}); + +new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + capacityProviderStrategies: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + }, + ], +}); + +app.synth(); + diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts b/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts index 85ddcd6a07176..ebb36580d19ba 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts @@ -110,6 +110,91 @@ export = { test.done(); }, + 'does not set launchType when capacity provider strategies specified'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { + vpc, + capacityProviders: ['FARGATE', 'FARGATE_SPOT'], + }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + + const container = taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + container.addPortMappings({ containerPort: 8000 }); + + new ecs.FargateService(stack, 'FargateService', { + cluster, + taskDefinition, + capacityProviderStrategies: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + }, + ], + }); + + // THEN + expect(stack).to(haveResource('AWS::ECS::Cluster', { + CapacityProviders: ['FARGATE', 'FARGATE_SPOT'], + })); + + expect(stack).to(haveResource('AWS::ECS::Service', { + TaskDefinition: { + Ref: 'FargateTaskDefC6FB60B4', + }, + Cluster: { + Ref: 'EcsCluster97242B84', + }, + DeploymentConfiguration: { + MaximumPercent: 200, + MinimumHealthyPercent: 50, + }, + // no launch type + CapacityProviderStrategy: [ + { + CapacityProvider: 'FARGATE_SPOT', + Weight: 2, + }, + { + CapacityProvider: 'FARGATE', + Weight: 1, + }, + ], + EnableECSManagedTags: false, + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'FargateServiceSecurityGroup0A0E79CB', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'MyVpcPrivateSubnet1Subnet5057CF7E', + }, + { + Ref: 'MyVpcPrivateSubnet2Subnet0040C983', + }, + ], + }, + }, + })); + + test.done(); + }, + 'with custom cloudmap namespace'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts b/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts index 71a5fc23081d4..7741c6b5bdb9f 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts +++ b/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts @@ -1666,6 +1666,7 @@ export = { ); test.done(); }, + 'throws when machineImage and machineImageType both specified'(test: Test) { // GIVEN const app = new cdk.App(); @@ -1682,4 +1683,52 @@ export = { }, /You can only specify either machineImage or machineImageType, not both./); test.done(); }, + + 'allows specifying capacityProviders'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); + + // WHEN + new ecs.Cluster(stack, 'EcsCluster', { capacityProviders: ['FARGATE_SPOT'] }); + + // THEN + expect(stack).to(haveResource('AWS::ECS::Cluster', { + CapacityProviders: ['FARGATE_SPOT'], + })); + + test.done(); + }, + + 'allows adding capacityProviders post-construction'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); + const cluster = new ecs.Cluster(stack, 'EcsCluster'); + + // WHEN + cluster.addCapacityProvider('FARGATE'); + cluster.addCapacityProvider('FARGATE'); // does not add twice + + // THEN + expect(stack).to(haveResource('AWS::ECS::Cluster', { + CapacityProviders: ['FARGATE'], + })); + + test.done(); + }, + + 'throws for unsupported capacity providers'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); + const cluster = new ecs.Cluster(stack, 'EcsCluster'); + + // THEN + test.throws(() => { + cluster.addCapacityProvider('HONK'); + }, /CapacityProvider not supported/); + + test.done(); + }, }; From 8bc82328217f6d37028aada4088ff6d6d5f25b49 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 16 Feb 2021 20:24:04 +0000 Subject: [PATCH 13/20] chore(deps): bump aws-sdk from 2.844.0 to 2.845.0 (#13089) Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.844.0 to 2.845.0. - [Release notes](https://github.com/aws/aws-sdk-js/releases) - [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js/compare/v2.844.0...v2.845.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-cloudfront-origins/package.json | 2 +- packages/@aws-cdk/aws-cloudfront/package.json | 2 +- packages/@aws-cdk/aws-cloudtrail/package.json | 2 +- packages/@aws-cdk/aws-codebuild/package.json | 2 +- packages/@aws-cdk/aws-codecommit/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-eks/package.json | 2 +- packages/@aws-cdk/aws-events-targets/package.json | 2 +- packages/@aws-cdk/aws-logs/package.json | 2 +- packages/@aws-cdk/aws-route53/package.json | 2 +- packages/@aws-cdk/aws-sqs/package.json | 2 +- packages/@aws-cdk/custom-resources/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- yarn.lock | 8 ++++---- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index 01046b4b76db3..8e2a945533280 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -71,7 +71,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "pkglint": "0.0.0" diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index b062987931755..d1d19cc5e15fd 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -72,7 +72,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 3846c59bcb320..463ce9de07f1e 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -72,7 +72,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index c2586a4ba8651..30c4250d22fcd 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -78,7 +78,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 69d4fbdccb3bc..da8f664ed11c7 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -78,7 +78,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 4018b684050db..1e486af00be00 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -73,7 +73,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/jest": "^26.0.20", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 46f695fbca027..b11ebda6c655e 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -73,7 +73,7 @@ "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", "@types/yaml": "1.9.6", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 55e9a40fcb596..900cf3a01723b 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -74,7 +74,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index fbb9fbf369e37..8ef0ebaff9a1a 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -72,7 +72,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index df2977cc84608..23004220fd985 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -73,7 +73,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 860f3aca46971..0fd93cb8fd1c5 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -73,7 +73,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 863c0dbc8af47..afc7639b5fab8 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -78,7 +78,7 @@ "@types/aws-lambda": "^8.10.72", "@types/fs-extra": "^8.1.1", "@types/sinon": "^9.0.10", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index d7932d97aac66..dc91f1cbcd3c4 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -73,7 +73,7 @@ "@aws-cdk/region-info": "0.0.0", "@aws-cdk/yaml-cfn": "0.0.0", "archiver": "^5.2.0", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "camelcase": "^6.2.0", "cdk-assets": "0.0.0", "colors": "^1.4.0", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 550424d5ebdb4..43509a12fb16a 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -47,7 +47,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "archiver": "^5.2.0", - "aws-sdk": "^2.844.0", + "aws-sdk": "^2.845.0", "glob": "^7.1.6", "yargs": "^16.2.0" }, diff --git a/yarn.lock b/yarn.lock index dcd1837827e30..d93520bbcbbae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2259,10 +2259,10 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.844.0: - version "2.844.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.844.0.tgz#0d90279f9d224fd5c218a8b5cef4cb4c3949fd8a" - integrity sha512-8RMVGRhJ+s5xITDgR2bAVwuq/U2dhFhk83x4O7G4Sav/UxeXgmMfa6YU5P6CSDCq80ikBZVLb1bBVuW75h2nKQ== +aws-sdk@^2.637.0, aws-sdk@^2.845.0: + version "2.845.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.845.0.tgz#d1f932577dc1a1dcb34a35f81af97b221b741a42" + integrity sha512-lIOsMK6X6tyIXUB8rzYimklpFHMu96+cbWlDQkbRc5hymzSjPVY7L2LGP+PyCRjQHEnJUOk2EWswUIozhZy59A== dependencies: buffer "4.9.2" events "1.1.1" From 615390291b87a87f65cf34a9670911a5b1a1c13c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 17 Feb 2021 00:19:36 +0000 Subject: [PATCH 14/20] chore(deps): bump eslint-plugin-jest from 24.1.3 to 24.1.4 (#13092) Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 24.1.3 to 24.1.4. - [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases) - [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/master/CHANGELOG.md) - [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v24.1.3...v24.1.4) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- tools/cdk-build-tools/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 18a98dd004198..830e4beef05bd 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -48,7 +48,7 @@ "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.1.3", + "eslint-plugin-jest": "^24.1.4", "fs-extra": "^9.1.0", "jest": "^26.6.3", "jsii": "^1.21.0", diff --git a/yarn.lock b/yarn.lock index d93520bbcbbae..e4ad78c0d74e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3936,10 +3936,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@^24.1.3: - version "24.1.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.3.tgz#fa3db864f06c5623ff43485ca6c0e8fc5fe8ba0c" - integrity sha512-dNGGjzuEzCE3d5EPZQ/QGtmlMotqnYWD/QpCZ1UuZlrMAdhG5rldh0N0haCvhGnUkSeuORS5VNROwF9Hrgn3Lg== +eslint-plugin-jest@^24.1.4: + version "24.1.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.4.tgz#3025163e94c9819d3817815bd618fbf5c62c157c" + integrity sha512-Xly8okNrsR6xwo94SqvdH8eCyHoK7AegEK+6Me63eY/60Q8iZr6Y81WhtqktrEOHu9Q4188Cj9CfMU6H9P5JBA== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" From 5be09b99df160cfe8343b10c052eea6c94c4d471 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 17 Feb 2021 06:01:11 +0000 Subject: [PATCH 15/20] chore(deps): bump eslint-plugin-jest from 24.1.4 to 24.1.5 (#13096) Bumps [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) from 24.1.4 to 24.1.5. - [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases) - [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/master/CHANGELOG.md) - [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v24.1.4...v24.1.5) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- tools/cdk-build-tools/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 830e4beef05bd..8b2a6236620e9 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -48,7 +48,7 @@ "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.1.4", + "eslint-plugin-jest": "^24.1.5", "fs-extra": "^9.1.0", "jest": "^26.6.3", "jsii": "^1.21.0", diff --git a/yarn.lock b/yarn.lock index e4ad78c0d74e4..bfc36ea7eb75a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3936,10 +3936,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@^24.1.4: - version "24.1.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.4.tgz#3025163e94c9819d3817815bd618fbf5c62c157c" - integrity sha512-Xly8okNrsR6xwo94SqvdH8eCyHoK7AegEK+6Me63eY/60Q8iZr6Y81WhtqktrEOHu9Q4188Cj9CfMU6H9P5JBA== +eslint-plugin-jest@^24.1.5: + version "24.1.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.5.tgz#1e866a9f0deac587d0a3d5d7cefe99815a580de2" + integrity sha512-FIP3lwC8EzEG+rOs1y96cOJmMVpdFNreoDJv29B5vIupVssRi8zrSY3QadogT0K3h1Y8TMxJ6ZSAzYUmFCp2hg== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" From 996e69dd6d33a3478f88a6e32afeebc4fd0e7ec5 Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Wed, 17 Feb 2021 08:43:41 +0100 Subject: [PATCH 16/20] feat(ecs-patterns): Add support for taskSubnets and securityGroups on QueueProcessingFagateService (#12604) Fixes #12603 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ecs-patterns/README.md | 13 + .../queue-processing-fargate-service.ts | 17 + ...ing-fargate-service-isolated.expected.json | 1201 +++++++++++++++++ ...eue-processing-fargate-service-isolated.ts | 56 + ...e-processing-fargate-service.expected.json | 838 ++++++++++++ .../integ.queue-processing-fargate-service.ts | 20 + .../test.queue-processing-fargate-service.ts | 58 + .../test/sqs-reader/Dockerfile | 10 + .../aws-ecs-patterns/test/sqs-reader/index.py | 22 + 9 files changed, 2235 insertions(+) create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.ts create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/Dockerfile create mode 100644 packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/index.py diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index 8289145b4fb04..c52f35bb65f02 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -394,6 +394,7 @@ const loadBalancedFargateService = new ApplicationLoadBalancedFargateService(sta }); ``` + ### Set deployment configuration on QueueProcessingService ```ts @@ -412,6 +413,18 @@ const queueProcessingFargateService = new QueueProcessingFargateService(stack, ' }); ``` +### Set taskSubnets and securityGroups on QueueProcessingFargateService + +```ts +const queueProcessingFargateService = new QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + securityGroups: [securityGroup], + taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, +}); +``` + ### Select specific vpc subnets for ApplicationLoadBalancedFargateService ```ts diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts index 68d0278c3e203..8ba7fed3f5e76 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts @@ -1,3 +1,4 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { Construct } from 'constructs'; import { QueueProcessingServiceBase, QueueProcessingServiceBaseProps } from '../base/queue-processing-service-base'; @@ -66,6 +67,20 @@ export interface QueueProcessingFargateServiceProps extends QueueProcessingServi * @default - QueueProcessingContainer */ readonly containerName?: string; + + /** + * The subnets to associate with the service. + * + * @default - Public subnets if `assignPublicIp` is set, otherwise the first available one of Private, Isolated, Public, in that order. + */ + readonly taskSubnets?: ec2.SubnetSelection; + + /** + * The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. + * + * @default - A new security group is created. + */ + readonly securityGroups?: ec2.ISecurityGroup[]; } /** @@ -117,6 +132,8 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase { enableECSManagedTags: props.enableECSManagedTags, platformVersion: props.platformVersion, deploymentController: props.deploymentController, + securityGroups: props.securityGroups, + vpcSubnets: props.taskSubnets, }); this.configureAutoscalingForService(this.service); this.grantPermissionsToService(this.service); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json new file mode 100644 index 0000000000000..d19d9c6a9fbb9 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.expected.json @@ -0,0 +1,1201 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/24", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.1.0/24", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCIsolatedSubnet1SubnetEBD00FC6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.2.0/24", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/IsolatedSubnet1" + } + ] + } + }, + "VPCIsolatedSubnet1RouteTableEB156210": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/IsolatedSubnet1" + } + ] + } + }, + "VPCIsolatedSubnet1RouteTableAssociationA2D18F7C": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCIsolatedSubnet1RouteTableEB156210" + }, + "SubnetId": { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + } + } + }, + "VPCIsolatedSubnet2Subnet4B1C8CAA": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.3.0/24", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/IsolatedSubnet2" + } + ] + } + }, + "VPCIsolatedSubnet2RouteTable9B4F78DC": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC/IsolatedSubnet2" + } + ] + } + }, + "VPCIsolatedSubnet2RouteTableAssociation7BF8E0EB": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCIsolatedSubnet2RouteTable9B4F78DC" + }, + "SubnetId": { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "VPCS3Endpoint18C9C7CA": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".s3" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "RouteTableIds": [ + { + "Ref": "VPCIsolatedSubnet1RouteTableEB156210" + }, + { + "Ref": "VPCIsolatedSubnet2RouteTable9B4F78DC" + } + ], + "VpcEndpointType": "Gateway" + } + }, + "VPCSqsEndpointSecurityGroupAE06A78D": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/VPC/SqsEndpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCSqsEndpoint9A40D77F": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".sqs" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VPCSqsEndpointSecurityGroupAE06A78D", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VPCEcrEndpointSecurityGroup50ED8BA4": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/VPC/EcrEndpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCEcrEndpointB4F98F37": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".ecr.api" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VPCEcrEndpointSecurityGroup50ED8BA4", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VPCEcrImageEndpointSecurityGroup83621638": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/VPC/EcrImageEndpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCEcrImageEndpointD55381DC": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".ecr.dkr" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VPCEcrImageEndpointSecurityGroup83621638", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/VPC/CloudWatchLogsEndpoint/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue-isolated/VPC" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCCloudWatchLogsEndpointE175AF65": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".logs" + ] + ] + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ], + "VpcEndpointType": "Interface" + } + }, + "MyCustomSGDE27C661": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue-isolated/MyCustomSG", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "IsolatedQueueServiceEcsProcessingDeadLetterQueue7CC1D07D": { + "Type": "AWS::SQS::Queue", + "Properties": { + "MessageRetentionPeriod": 1209600 + } + }, + "IsolatedQueueServiceEcsProcessingQueueCCE172F1": { + "Type": "AWS::SQS::Queue", + "Properties": { + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingDeadLetterQueue7CC1D07D", + "Arn" + ] + }, + "maxReceiveCount": 3 + } + } + }, + "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleCFCB7511": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleDefaultPolicyD52E156B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:ReceiveMessage", + "sqs:ChangeMessageVisibility", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleDefaultPolicyD52E156B", + "Roles": [ + { + "Ref": "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleCFCB7511" + } + ] + } + }, + "IsolatedQueueServiceQueueProcessingTaskDef0F0CE105": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Environment": [ + { + "Name": "QUEUE_NAME", + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "QueueName" + ] + } + } + ], + "Essential": true, + "Image": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/aws-cdk/assets:3a8ba3ad06ed212b075efa3157fb407649c5996812bc64eeb5209e220aab4be5" + ] + ] + }, + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "IsolatedQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupAEB959E6" + }, + "awslogs-stream-prefix": "IsolatedQueueService", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "Name": "QueueProcessingContainer" + } + ], + "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "IsolatedQueueServiceQueueProcessingTaskDefExecutionRole1D7ACC77", + "Arn" + ] + }, + "Family": "awsecspatternsqueueisolatedIsolatedQueueServiceQueueProcessingTaskDef27DBAF49", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "IsolatedQueueServiceQueueProcessingTaskDefTaskRoleCFCB7511", + "Arn" + ] + } + } + }, + "IsolatedQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupAEB959E6": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "IsolatedQueueServiceQueueProcessingTaskDefExecutionRole1D7ACC77": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "IsolatedQueueServiceQueueProcessingTaskDefExecutionRoleDefaultPolicy5667D265": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/aws-cdk/assets" + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "IsolatedQueueServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupAEB959E6", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "IsolatedQueueServiceQueueProcessingTaskDefExecutionRoleDefaultPolicy5667D265", + "Roles": [ + { + "Ref": "IsolatedQueueServiceQueueProcessingTaskDefExecutionRole1D7ACC77" + } + ] + } + }, + "IsolatedQueueServiceQueueProcessingFargateServiceE868AEE1": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "MyCustomSGDE27C661", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCIsolatedSubnet1SubnetEBD00FC6" + }, + { + "Ref": "VPCIsolatedSubnet2Subnet4B1C8CAA" + } + ] + } + }, + "TaskDefinition": { + "Ref": "IsolatedQueueServiceQueueProcessingTaskDef0F0CE105" + } + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetB06FD17D": { + "Type": "AWS::ApplicationAutoScaling::ScalableTarget", + "Properties": { + "MaxCapacity": 2, + "MinCapacity": 1, + "ResourceId": { + "Fn::Join": [ + "", + [ + "service/", + { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "/", + { + "Fn::GetAtt": [ + "IsolatedQueueServiceQueueProcessingFargateServiceE868AEE1", + "Name" + ] + } + ] + ] + }, + "RoleARN": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService" + ] + ] + }, + "ScalableDimension": "ecs:service:DesiredCount", + "ServiceNamespace": "ecs" + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling2B518D9D": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueisolatedIsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling8B2FB6C4", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetB06FD17D" + }, + "TargetTrackingScalingPolicyConfiguration": { + "PredefinedMetricSpecification": { + "PredefinedMetricType": "ECSServiceAverageCPUUtilization" + }, + "TargetValue": 50 + } + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy960D4BA1": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueisolatedIsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy5EFC8D1B", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetB06FD17D" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalUpperBound": 0, + "ScalingAdjustment": -1 + } + ] + } + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerAlarm88D1A0F9": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "LessThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy960D4BA1" + } + ], + "AlarmDescription": "Lower threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 0 + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicyFAB35025": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueisolatedIsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy51E582BF", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetB06FD17D" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalLowerBound": 0, + "MetricIntervalUpperBound": 400, + "ScalingAdjustment": 1 + }, + { + "MetricIntervalLowerBound": 400, + "ScalingAdjustment": 5 + } + ] + } + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperAlarm351987F5": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "IsolatedQueueServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicyFAB35025" + } + ], + "AlarmDescription": "Upper threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 100 + }, + "DependsOn": [ + "VPCCloudWatchLogsEndpointE175AF65", + "VPCCloudWatchLogsEndpointSecurityGroup967DBC94", + "VPCEcrEndpointB4F98F37", + "VPCEcrEndpointSecurityGroup50ED8BA4", + "VPCEcrImageEndpointD55381DC", + "VPCEcrImageEndpointSecurityGroup83621638", + "VPCSqsEndpoint9A40D77F", + "VPCSqsEndpointSecurityGroupAE06A78D" + ] + }, + "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3": { + "Type": "AWS::ECS::Cluster" + } + }, + "Outputs": { + "IsolatedQueueServiceSQSDeadLetterQueue43D346B9": { + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingDeadLetterQueue7CC1D07D", + "QueueName" + ] + } + }, + "IsolatedQueueServiceSQSDeadLetterQueueArnCE7C60F2": { + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingDeadLetterQueue7CC1D07D", + "Arn" + ] + } + }, + "IsolatedQueueServiceSQSQueueA65E2641": { + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "QueueName" + ] + } + }, + "IsolatedQueueServiceSQSQueueArn571FDB86": { + "Value": { + "Fn::GetAtt": [ + "IsolatedQueueServiceEcsProcessingQueueCCE172F1", + "Arn" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.ts new file mode 100644 index 0000000000000..f985ac8c9d564 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-isolated.ts @@ -0,0 +1,56 @@ +import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { App, Stack } from '@aws-cdk/core'; + +import { QueueProcessingFargateService } from '../../lib'; + +const app = new App(); +const stack = new Stack(app, 'aws-ecs-patterns-queue-isolated'); +const vpc = new ec2.Vpc(stack, 'VPC', { + maxAzs: 2, + subnetConfiguration: [ + { + cidrMask: 24, + name: 'Public', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'Isolated', + subnetType: ec2.SubnetType.ISOLATED, + }, + ], +}); + + +vpc.addS3Endpoint('S3Endpoint', [{ subnetType: ec2.SubnetType.ISOLATED }]); + +const securityGroup = new ec2.SecurityGroup(stack, 'MyCustomSG', { + vpc, +}); + +const queueProcessing = new QueueProcessingFargateService(stack, 'IsolatedQueueService', { + vpc, + memoryLimitMiB: 512, + image: new ecs.AssetImage(path.join(__dirname, '..', 'sqs-reader')), + securityGroups: [securityGroup], + taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, +}); + +queueProcessing.service.node.addDependency( + vpc.addInterfaceEndpoint('SqsEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.SQS, + }), + vpc.addInterfaceEndpoint('EcrEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.ECR, + }), + vpc.addInterfaceEndpoint('EcrImageEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER, + }), + vpc.addInterfaceEndpoint('CloudWatchLogsEndpoint', { + service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS, + }), +); + +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json new file mode 100644 index 0000000000000..3fd9825b7db3b --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.expected.json @@ -0,0 +1,838 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-patterns-queue/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "QueueProcessingServiceEcsProcessingDeadLetterQueueD47A7C6B": { + "Type": "AWS::SQS::Queue", + "Properties": { + "MessageRetentionPeriod": 1209600 + } + }, + "QueueProcessingServiceEcsProcessingQueue552F0B37": { + "Type": "AWS::SQS::Queue", + "Properties": { + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingDeadLetterQueueD47A7C6B", + "Arn" + ] + }, + "maxReceiveCount": 3 + } + } + }, + "QueueProcessingServiceQueueProcessingTaskDefTaskRole782B79A6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "QueueProcessingServiceQueueProcessingTaskDefTaskRoleDefaultPolicyAE808B19": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:ReceiveMessage", + "sqs:ChangeMessageVisibility", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "QueueProcessingServiceQueueProcessingTaskDefTaskRoleDefaultPolicyAE808B19", + "Roles": [ + { + "Ref": "QueueProcessingServiceQueueProcessingTaskDefTaskRole782B79A6" + } + ] + } + }, + "QueueProcessingServiceQueueProcessingTaskDef4982F68B": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Environment": [ + { + "Name": "QUEUE_NAME", + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "QueueName" + ] + } + } + ], + "Essential": true, + "Image": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/aws-cdk/assets:3a8ba3ad06ed212b075efa3157fb407649c5996812bc64eeb5209e220aab4be5" + ] + ] + }, + "LogConfiguration": { + "LogDriver": "awslogs", + "Options": { + "awslogs-group": { + "Ref": "QueueProcessingServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCC92448A" + }, + "awslogs-stream-prefix": "QueueProcessingService", + "awslogs-region": { + "Ref": "AWS::Region" + } + } + }, + "Name": "QueueProcessingContainer" + } + ], + "Cpu": "256", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingTaskDefExecutionRole37838985", + "Arn" + ] + }, + "Family": "awsecspatternsqueueQueueProcessingServiceQueueProcessingTaskDef2D9F8C2B", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingTaskDefTaskRole782B79A6", + "Arn" + ] + } + } + }, + "QueueProcessingServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCC92448A": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "QueueProcessingServiceQueueProcessingTaskDefExecutionRole37838985": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "QueueProcessingServiceQueueProcessingTaskDefExecutionRoleDefaultPolicyA83D332D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/aws-cdk/assets" + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupCC92448A", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "QueueProcessingServiceQueueProcessingTaskDefExecutionRoleDefaultPolicyA83D332D", + "Roles": [ + { + "Ref": "QueueProcessingServiceQueueProcessingTaskDefExecutionRole37838985" + } + ] + } + }, + "QueueProcessingServiceQueueProcessingFargateService0340DB9F": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "DesiredCount": 1, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingFargateServiceSecurityGroup8FDF413D", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ] + } + }, + "TaskDefinition": { + "Ref": "QueueProcessingServiceQueueProcessingTaskDef4982F68B" + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceSecurityGroup8FDF413D": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-patterns-queue/QueueProcessingService/QueueProcessingFargateService/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetA9D54444": { + "Type": "AWS::ApplicationAutoScaling::ScalableTarget", + "Properties": { + "MaxCapacity": 2, + "MinCapacity": 1, + "ResourceId": { + "Fn::Join": [ + "", + [ + "service/", + { + "Ref": "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3" + }, + "/", + { + "Fn::GetAtt": [ + "QueueProcessingServiceQueueProcessingFargateService0340DB9F", + "Name" + ] + } + ] + ] + }, + "RoleARN": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService" + ] + ] + }, + "ScalableDimension": "ecs:service:DesiredCount", + "ServiceNamespace": "ecs" + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling330150E9": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueQueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetCpuScaling374CE648", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetA9D54444" + }, + "TargetTrackingScalingPolicyConfiguration": { + "PredefinedMetricSpecification": { + "PredefinedMetricType": "ECSServiceAverageCPUUtilization" + }, + "TargetValue": 50 + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy332E2644": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueQueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy74582401", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetA9D54444" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalUpperBound": 0, + "ScalingAdjustment": -1 + } + ] + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerAlarm20C30A06": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "LessThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingLowerPolicy332E2644" + } + ], + "AlarmDescription": "Lower threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 0 + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy84DD739A": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecspatternsqueueQueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy23C5F983", + "PolicyType": "StepScaling", + "ScalingTargetId": { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetA9D54444" + }, + "StepScalingPolicyConfiguration": { + "AdjustmentType": "ChangeInCapacity", + "MetricAggregationType": "Maximum", + "StepAdjustments": [ + { + "MetricIntervalLowerBound": 0, + "MetricIntervalUpperBound": 400, + "ScalingAdjustment": 1 + }, + { + "MetricIntervalLowerBound": 400, + "ScalingAdjustment": 5 + } + ] + } + } + }, + "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperAlarm2660BEDF": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmActions": [ + { + "Ref": "QueueProcessingServiceQueueProcessingFargateServiceTaskCountTargetQueueMessagesVisibleScalingUpperPolicy84DD739A" + } + ], + "AlarmDescription": "Upper threshold scaling alarm", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "QueueName" + ] + } + } + ], + "MetricName": "ApproximateNumberOfMessagesVisible", + "Namespace": "AWS/SQS", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 100 + } + }, + "EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3": { + "Type": "AWS::ECS::Cluster" + } + }, + "Outputs": { + "QueueProcessingServiceSQSDeadLetterQueueE9058015": { + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingDeadLetterQueueD47A7C6B", + "QueueName" + ] + } + }, + "QueueProcessingServiceSQSDeadLetterQueueArnF7C6D3A8": { + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingDeadLetterQueueD47A7C6B", + "Arn" + ] + } + }, + "QueueProcessingServiceSQSQueue1AD9CD9C": { + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "QueueName" + ] + } + }, + "QueueProcessingServiceSQSQueueArn8C4AE4AE": { + "Value": { + "Fn::GetAtt": [ + "QueueProcessingServiceEcsProcessingQueue552F0B37", + "Arn" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts new file mode 100644 index 0000000000000..540b8d2302e9a --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service.ts @@ -0,0 +1,20 @@ +import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { App, Stack } from '@aws-cdk/core'; + +import { QueueProcessingFargateService } from '../../lib'; + +const app = new App(); +const stack = new Stack(app, 'aws-ecs-patterns-queue'); +const vpc = new ec2.Vpc(stack, 'VPC', { + maxAzs: 2, +}); + +new QueueProcessingFargateService(stack, 'QueueProcessingService', { + vpc, + memoryLimitMiB: 512, + image: new ecs.AssetImage(path.join(__dirname, '..', 'sqs-reader')), +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts index a0c09d572343f..0bee7da1c51f3 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts @@ -310,4 +310,62 @@ export = { test.done(); }, + + 'can set custom networking options'(test: Test) { + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { + subnetConfiguration: [ + { + cidrMask: 24, + name: 'Public', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'Isolated', + subnetType: ec2.SubnetType.ISOLATED, + }, + ], + }); + const securityGroup = new ec2.SecurityGroup(stack, 'MyCustomSG', { + vpc, + }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + securityGroups: [securityGroup], + taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. + expect(stack).to(haveResource('AWS::ECS::Service', { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'MyCustomSGDE27C661', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6', + }, + { + Ref: 'VPCIsolatedSubnet2Subnet4B1C8CAA', + }, + ], + }, + }, + })); + + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/Dockerfile b/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/Dockerfile new file mode 100644 index 0000000000000..e6618640549e2 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.6 + +RUN pip3 install boto3 + +ENV QUEUE_NAME $QUEUE_NAME + +WORKDIR /src +ADD . /src + +CMD python3 index.py diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/index.py b/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/index.py new file mode 100644 index 0000000000000..8b53f5149cb24 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/sqs-reader/index.py @@ -0,0 +1,22 @@ +#!/usr/bin/python +import os +import boto3 + +QUEUE_NAME = os.environ.get('QUEUE_NAME') +print('QUEUE_NAME ' + QUEUE_NAME) + +if __name__ == '__main__': + client = boto3.client('sqs') + queue_url = client.get_queue_url(QueueName=QUEUE_NAME)['QueueUrl'] + print('queue_url ' + queue_url) + while True: + response = client.receive_message( + QueueUrl=queue_url, + WaitTimeSeconds=10, + ) + if response and 'Messages' in response: + for msg in response['Messages']: + print(msg['Body']) + entries = [{'Id': x['MessageId'], 'ReceiptHandle': x['ReceiptHandle']} for x in response['Messages']] + client.delete_message_batch(QueueUrl=queue_url, Entries=entries) + From 74347dda062dd3d9acd61cbd454e9259f5d79bbf Mon Sep 17 00:00:00 2001 From: Hsing-Hui Hsu Date: Wed, 17 Feb 2021 02:42:15 -0800 Subject: [PATCH 17/20] docs: fix typos in DESIGN_GUIDELINES (#13097) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- DESIGN_GUIDELINES.md | 54 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/DESIGN_GUIDELINES.md b/DESIGN_GUIDELINES.md index 6a3da024723c4..e6cebe9f434c6 100644 --- a/DESIGN_GUIDELINES.md +++ b/DESIGN_GUIDELINES.md @@ -199,7 +199,7 @@ the fact that the Bucket class needs the ARN or that it needs to request encryption permissions are not the user's concern, and the API of the Bucket class should not “leak” these implementation details. In the future, the Bucket class can decide to interact differently with the **key** and this won't require -expanding it's surface area. It also allows the **Key** class to change it's +expanding its surface area. It also allows the **Key** class to change its behavior (i.e. add an IAM action to enable encryption of certain types of keys) without affecting the API of the consumer. @@ -207,7 +207,7 @@ without affecting the API of the consumer. Using object references instead of attribute references provides a richer API, but also introduces an inherent challenge: how do we reference constructs that -are not defined inside the same app (“**owned**” by the app). These could be +are not defined inside the same app (“**owned**” by the app)? These could be resources that were created by some other AWS CDK app, via the AWS console, etc. We call these **“unowned” constructs.** @@ -272,7 +272,7 @@ as “props” (to distinguish them from JavaScript object properties). Props are the most important aspect of designing a construct. Props are the entry point of the construct. They should reflect the entire surface area of the service through semantics that are intuitive to how developers perceive the -service and it's capabilities. +service and its capabilities. When designing the props of an AWS resource, consult the AWS Console experience for creating this resource. Service teams spend a lot of energy thinking about @@ -300,7 +300,7 @@ API. In almost all cases, a richer object-oriented API can be exposed to encapsulate the low-level surface [_awslint:props-no-cfn-types_]. Do not use the **Token** type. It provides zero type safety, and is a functional -interface that may not translate cleanly in other JSII runtimes: ergo it should +interface that may not translate cleanly in other JSII runtimes. Therefore, it should be avoided wherever possible [_awslint:props-no-tokens_]. **deCDK** allows users to synthesize CDK stacks through a CloudFormation-like @@ -308,7 +308,7 @@ be avoided wherever possible [_awslint:props-no-tokens_]. like CloudFormation resources. Technically, this means that when a construct is defined, users supply an ID, type and a set of properties. In order to allow users to instantiate all AWS Construct Library constructs through the - deCDK syntax, we pose restrictions on prop types _[awslint:props-decdk]_: + deCDK syntax, we impose restrictions on prop types _[awslint:props-decdk]_: * Primitives (string, number, boolean, date) * Collections (list, map) @@ -390,7 +390,7 @@ item). It just means that you can remove redundant context from the property names. For example, there is no need to repeat the resource type, the property type or indicate that this is a "configuration". -For example prefer “readCapacity” versus “readCapacityUnits”. +For example, prefer “readCapacity” versus “readCapacityUnits”. #### Naming @@ -546,7 +546,7 @@ be treated as an opaque token, the JSDoc “@returns” annotation should begin When an app defines a construct or resource, it specifies its provisioning configuration upon initialization. For example, when an SQS queue is defined, -it's visibility timeout can be configured. +its visibility timeout can be configured. Naturally, when constructs are imported (unowned), the importing app does not have control over its configuration (e.g. you cannot change the visibility @@ -609,17 +609,17 @@ consistency and interoperability, we allow mutating methods to be exposed on the interface. For example, **grant** methods are exposed on the construct interface and not on the concrete class. In most cases, when you grant a permission on an AWS resource, the *principal's* policy needs to be updated, which mutates the -consumer . However, there are certain cases where a *resource policy* must be +consumer. However, there are certain cases where a *resource policy* must be updated. However, if the resource is unowned, it doesn't make sense (or even impossible) to update its policy (there is usually a 1:1 relationship between a -resource and a resource policy). In such a case, we decided that grant methods -will simply skip any changes to resource policies, but will issue attach a +resource and a resource policy). In such cases, we decided that grant methods +will simply skip any changes to resource policies, but will attach a **permission notice** to the app, which will be printed when the stack is synthesized by the toolkit. ### Factories -In most AWS services, there's a one or more resource which can be referred to as +In most AWS services, there are one or more resources which can be referred to as “primary resources” (normally one), while other resources exposed by the service can be considered “secondary resources”. @@ -687,7 +687,7 @@ their app. The signature of all “from” methods should adhere to the following rules _[awslint:from-signature]_: -* First argument must be **scope** of type **Construct** +* First argument must be **scope** of type **Construct**. * Second argument is a **string**. This string will be used to determine the ID of the new construct. If the import method uses some value that is promised to be unique within the stack scope (such as ARN, export name), @@ -697,8 +697,8 @@ _[awslint:from-signature]_: #### “from” Methods Resource constructs should export static “from” methods for importing unowned -resources given one more of it's physical attributes such as ARN, name, etc. All -constructs should have at least one fromXxx method _[awslint:from-method]_: +resources given one more of its physical attributes such as ARN, name, etc. All +constructs should have at least one "fromXxx" method _[awslint:from-method]_: ```ts static fromFooArn(scope: Construct, id: string, bucketArn: string): IFoo; @@ -713,7 +713,7 @@ static fromFooName(scope: Construct, id: string, bucketName: string): IFoo; doesn't have unresolved tokens (using **Token.unresolved**). Preferably, they can use **Stack.parseArn** to achieve this purpose. -If a resource has an ARN attribute it should implement at least a **fromFooArn** +If a resource has an ARN attribute, it should implement at least a **fromFooArn** import method [_awslint:from-arn_]. To implement **fromAttribute** methods, use the abstract base class construct as @@ -769,7 +769,7 @@ interface FooProps { } ``` -The construct interface should expose a **role**property, and extends +The construct interface should expose a **role** property, and extends **iam.IGrantable** _[awslint:role-property]_: ```ts @@ -793,7 +793,7 @@ interface IFoo { } ``` -If the construct is unowned this method should no-op and issue a **permissions +If the construct is unowned, this method should no-op and issue a **permissions notice** (TODO) to the user indicating that they should ensure that the role of this resource should have the specified permission. @@ -947,7 +947,7 @@ suffix and adhere to the following rules _[awslint:metrics-method-signature]:_ * Name should be “metricXxx” where “Xxx” is the official metric name * Accepts a single “options” argument of type **MetricOptions** -* Returns a **Metric** object. +* Returns a **Metric** object ```ts interface IFunction { @@ -1001,7 +1001,7 @@ extend **ec2.IConnectable** _[awslint:connectable-interface]_. ### Integrations -Many AWS services offer “integrations” to other services. For example, AWS +Many AWS services offer “integrations” with other services. For example, AWS CodePipeline has actions that can trigger AWS Lambda functions, ECS tasks, CodeBuild projects and more. AWS Lambda can be triggered by a variety of event sources, AWS CloudWatch event rules can trigger many types of targets, SNS can @@ -1017,7 +1017,7 @@ the central service and can be triggered by multiple event sources. Integrations are an abstract concept, not necessarily a specific mechanism. For example, each AWS Lambda event source is implemented in a different way (SNS, -Bucket notifications, CloudWatch events, etc), but conceptually, *some*users +Bucket notifications, CloudWatch events, etc), but conceptually, *some* users like to think about AWS Lambda as the “center”. It is also completely legitimate to have multiple ways to connect two services on AWS. To trigger an AWS Lambda function from an SNS topic, you could either use the integration or the SNS APIs @@ -1102,7 +1102,7 @@ export class Table { } ``` Persistent resources must have a **removalPolicy** prop, defaults to -**Orphan**_[awslint:state-removal-policy-prop]_: +**Orphan** _[awslint:state-removal-policy-prop]_: ```ts import { RemovalPolicy } from '@aws-cdk/cdk'; @@ -1179,14 +1179,14 @@ implementation of AWS constructs. not one that you made up and you force them to learn. * Multiple ways of achieving the same thing is legitimate. * Constantly maintain the invariants. -* Fewer “if statements” the better. +* The fewer “if statements” the better. ### Construct IDs Construct IDs (the second argument passed to all constructs when they are defined) are used to formulate resource logical IDs which must be **stable** across updates. The logical ID of a resource is calculated based on the **full -path** of it's construct in the construct scope hierarchy. This means that any +path** of its construct in the construct scope hierarchy. This means that any change to a logical ID in this path will invalidate all the logical IDs within this scope. This will result in **replacements of all underlying resources** within the next update, which is extremely undesirable. @@ -1196,7 +1196,7 @@ construct. Therefore, when implementing constructs, you should treat the construct hierarchy and all construct IDs as part of the **external contract** of the -construct. Any chance to either should be considered and called out as a +construct. Any change to either should be considered and called out as a breaking change. There is no need to concatenate logical IDs. If you find yourself needing to @@ -1226,10 +1226,10 @@ Error since all errors in the CDK are unrecoverable): * Include a descriptive message * Include the value provided * Include the expected/allowed values -* No need to include information that can be obtained from the stack trace. -* No need to add a period at the end of error messages. +* No need to include information that can be obtained from the stack trace +* No need to add a period at the end of error messages -#### Avoid Errors if Possible +#### Avoid Errors If Possible Always prefer to do the right thing for the user instead of raising an error. Only fail if the user has explicitly specified bad configuration. For From 72c22dc39c1fa69905cfd0d3259b429e1c5b8447 Mon Sep 17 00:00:00 2001 From: Pahud Hsieh Date: Wed, 17 Feb 2021 19:31:14 +0800 Subject: [PATCH 18/20] feat(eks): support Kubernetes 1.19 (#13094) Support KubernetesVersion 1.19 Fixed: #13093 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-eks/README.md | 24 +++--- packages/@aws-cdk/aws-eks/lib/cluster.ts | 5 ++ .../test/example.ssh-into-nodes.lit.ts | 2 +- ...teg.eks-cluster-handlers-vpc.expected.json | 4 +- .../test/integ.eks-cluster-handlers-vpc.ts | 4 +- ...eks-cluster-private-endpoint.expected.json | 78 +++++++++--------- .../integ.eks-cluster-private-endpoint.ts | 2 +- .../test/integ.eks-cluster.expected.json | 80 +++++++++---------- .../aws-eks/test/integ.eks-cluster.ts | 6 +- .../test/integ.fargate-cluster.expected.json | 78 +++++++++--------- .../aws-eks/test/integ.fargate-cluster.ts | 2 +- .../@aws-cdk/aws-eks/test/test.cluster.ts | 18 ++--- .../@aws-cdk/aws-eks/test/test.fargate.ts | 2 +- .../@aws-cdk/aws-eks/test/test.nodegroup.ts | 2 +- 14 files changed, 155 insertions(+), 152 deletions(-) diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index efe50404a2ffa..ee758461b986f 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -49,7 +49,7 @@ This example defines an Amazon EKS cluster with the following configuration: ```ts // provisiong a cluster const cluster = new eks.Cluster(this, 'hello-eks', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); // apply a kubernetes manifest to the cluster @@ -142,7 +142,7 @@ Creating a new cluster is done using the `Cluster` or `FargateCluster` construct ```ts new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); ``` @@ -150,7 +150,7 @@ You can also use `FargateCluster` to provision a cluster that uses only fargate ```ts new eks.FargateCluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); ``` @@ -174,7 +174,7 @@ At cluster instantiation time, you can customize the number of instances and the ```ts new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, defaultCapacity: 5, defaultCapacityInstance: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.SMALL), }); @@ -186,7 +186,7 @@ Additional customizations are available post instantiation. To apply them, set t ```ts const cluster = new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, defaultCapacity: 0, }); @@ -322,7 +322,7 @@ The following code defines an Amazon EKS cluster with a default Fargate Profile ```ts const cluster = new eks.FargateCluster(this, 'MyCluster', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); ``` @@ -381,7 +381,7 @@ You can also configure the cluster to use an auto-scaling group as the default c ```ts cluster = new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, defaultCapacityType: eks.DefaultCapacityType.EC2, }); ``` @@ -461,7 +461,7 @@ You can configure the [cluster endpoint access](https://docs.aws.amazon.com/eks/ ```ts const cluster = new eks.Cluster(this, 'hello-eks', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, endpointAccess: eks.EndpointAccess.PRIVATE // No access outside of your VPC. }); ``` @@ -474,7 +474,7 @@ You can specify the VPC of the cluster using the `vpc` and `vpcSubnets` properti const vpc = new ec2.Vpc(this, 'Vpc'); new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, vpc, vpcSubnets: [{ subnetType: ec2.SubnetType.PRIVATE }] }); @@ -513,7 +513,7 @@ You can configure the environment of this function by specifying it at cluster i ```ts const cluster = new eks.Cluster(this, 'hello-eks', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, clusterHandlerEnvironment: { 'http_proxy': 'http://proxy.myproxy.com' } @@ -530,7 +530,7 @@ You can configure the environment of this function by specifying it at cluster i ```ts const cluster = new eks.Cluster(this, 'hello-eks', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, kubectlEnvironment: { 'http_proxy': 'http://proxy.myproxy.com' } @@ -620,7 +620,7 @@ When you create a cluster, you can specify a `mastersRole`. The `Cluster` constr ```ts const role = new iam.Role(...); new eks.Cluster(this, 'HelloEKS', { - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, mastersRole: role, }); ``` diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index 706a23720c157..c578b90fa388b 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -634,6 +634,11 @@ export class KubernetesVersion { */ public static readonly V1_18 = KubernetesVersion.of('1.18'); + /** + * Kubernetes version 1.19 + */ + public static readonly V1_19 = KubernetesVersion.of('1.19'); + /** * Custom cluster version * @param version custom version number diff --git a/packages/@aws-cdk/aws-eks/test/example.ssh-into-nodes.lit.ts b/packages/@aws-cdk/aws-eks/test/example.ssh-into-nodes.lit.ts index ac924ac20038d..14780774ca44f 100644 --- a/packages/@aws-cdk/aws-eks/test/example.ssh-into-nodes.lit.ts +++ b/packages/@aws-cdk/aws-eks/test/example.ssh-into-nodes.lit.ts @@ -10,7 +10,7 @@ class EksClusterStack extends cdk.Stack { const cluster = new eks.Cluster(this, 'EKSCluster', { vpc, - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); /// !show diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json index 82488919bedb9..50e88fe3277d0 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json @@ -832,7 +832,7 @@ ] }, "Config": { - "version": "1.18", + "version": "1.19", "roleArn": { "Fn::GetAtt": [ "EksAllHandlersInVpcStackRoleC36F09F0", @@ -1427,4 +1427,4 @@ "Description": "Artifact hash for asset \"11ba420a0c99f0c77f563fb974e76d6110b4445114137af1fe1b69b0d366d2d7\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts index ec9fe15d081da..cd1682a30d318 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.ts @@ -3,7 +3,7 @@ import { App } from '@aws-cdk/core'; import * as eks from '../lib'; import { TestStack } from './util'; -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; class EksAllHandlersInVpcStack extends TestStack { @@ -22,4 +22,4 @@ const app = new App(); new EksAllHandlersInVpcStack(app, 'aws-cdk-eks-handlers-in-vpc-test'); -app.synth(); \ No newline at end of file +app.synth(); diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json index f76e62c73ee73..b8246afd2d180 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json @@ -772,7 +772,7 @@ ] }, "Config": { - "version": "1.18", + "version": "1.19", "roleArn": { "Fn::GetAtt": [ "ClusterRoleFA261979", @@ -1062,7 +1062,7 @@ }, "/", { - "Ref": "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3Bucket9E737267" + "Ref": "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3BucketA8C94679" }, "/", { @@ -1072,7 +1072,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3VersionKeyD5E002BC" + "Ref": "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3VersionKey3777DB64" } ] } @@ -1085,7 +1085,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3VersionKeyD5E002BC" + "Ref": "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3VersionKey3777DB64" } ] } @@ -1129,7 +1129,7 @@ }, "/", { - "Ref": "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3Bucket8FBFE327" + "Ref": "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3Bucket686DCA97" }, "/", { @@ -1139,7 +1139,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3VersionKeyF5A05918" + "Ref": "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3VersionKey7EDC0140" } ] } @@ -1152,7 +1152,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3VersionKeyF5A05918" + "Ref": "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3VersionKey7EDC0140" } ] } @@ -1195,17 +1195,17 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket4A0D6BE2Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73" + "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketFD6C4D26Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey6D9B8A02Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61" + "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey69E4725CRef": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3BucketD44FB215Ref": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket5323F34ARef": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C30661CRef": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey548D79B4Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, "referencetoawscdkeksclusterprivateendpointtestVpcFCD064BFRef": { "Ref": "Vpc8378EB38" @@ -1299,53 +1299,53 @@ "Type": "String", "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", - "Description": "S3 bucket for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { "Type": "String", - "Description": "S3 key for asset version \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1ArtifactHashC9FD06BA": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { "Type": "String", - "Description": "Artifact hash for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { "Type": "String", - "Description": "S3 bucket for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { "Type": "String", - "Description": "S3 key for asset version \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fArtifactHash7E705796": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { "Type": "String", - "Description": "Artifact hash for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3Bucket9E737267": { + "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3BucketA8C94679": { "Type": "String", - "Description": "S3 bucket for asset \"84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08be\"" + "Description": "S3 bucket for asset \"75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609\"" }, - "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beS3VersionKeyD5E002BC": { + "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609S3VersionKey3777DB64": { "Type": "String", - "Description": "S3 key for asset version \"84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08be\"" + "Description": "S3 key for asset version \"75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609\"" }, - "AssetParameters84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08beArtifactHashDF0A0444": { + "AssetParameters75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609ArtifactHash14CC8C95": { "Type": "String", - "Description": "Artifact hash for asset \"84ba29b05aaf6a233dbb97b37e48eb1300f9d014f270252e29a8b2c22d6a08be\"" + "Description": "Artifact hash for asset \"75667ab2bbef2c8efc57fb73bf352f345af1d471fb09cb11f5b7bc27d009b609\"" }, - "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3Bucket8FBFE327": { + "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3Bucket686DCA97": { "Type": "String", - "Description": "S3 bucket for asset \"2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0\"" + "Description": "S3 bucket for asset \"eb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519\"" }, - "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0S3VersionKeyF5A05918": { + "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519S3VersionKey7EDC0140": { "Type": "String", - "Description": "S3 key for asset version \"2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0\"" + "Description": "S3 key for asset version \"eb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519\"" }, - "AssetParameters2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0ArtifactHashDFBC9DE7": { + "AssetParameterseb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519ArtifactHashE5817DEB": { "Type": "String", - "Description": "Artifact hash for asset \"2e2ec0fae5975d4ee5f3580e522c46615c1bd344e0302bc5d2df7501b7bb1ad0\"" + "Description": "Artifact hash for asset \"eb49ce353c5ff251ebe2c3225fe00fb3e9a68fcd8b10207e63a36bfc6e981519\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.ts index 0a0c9a61230e9..a9cb68866e5d8 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.ts @@ -5,7 +5,7 @@ import { App } from '@aws-cdk/core'; import * as eks from '../lib'; import { TestStack } from './util'; -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; class EksClusterStack extends TestStack { diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json index 5c0b4bf402a5b..2aea23262228e 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json @@ -949,7 +949,7 @@ ] }, "Config": { - "version": "1.18", + "version": "1.19", "roleArn": { "Fn::GetAtt": [ "ClusterRoleFA261979", @@ -1683,7 +1683,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t2.medium", "IamInstanceProfile": { @@ -1994,7 +1994,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "m6g.medium", "IamInstanceProfile": { @@ -2305,7 +2305,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsservicebottlerocketawsk8s118x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsservicebottlerocketawsk8s119x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t3.small", "IamInstanceProfile": { @@ -2630,7 +2630,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t3.large", "IamInstanceProfile": { @@ -2974,7 +2974,7 @@ "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "inf1.2xlarge", "IamInstanceProfile": { @@ -3277,6 +3277,7 @@ } ], "AmiType": "AL2_x86_64", + "CapacityType": "SPOT", "ForceUpdateEnabled": true, "InstanceTypes": [ "c5.large", @@ -3287,8 +3288,7 @@ "DesiredSize": 3, "MaxSize": 3, "MinSize": 3 - }, - "CapacityType": "SPOT" + } } }, "ClusterNodegroupextrangarmNodeGroupRoleADF5749F": { @@ -3840,7 +3840,7 @@ }, "/", { - "Ref": "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3Bucket1CB7A187" + "Ref": "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3Bucket862E8D6F" }, "/", { @@ -3850,7 +3850,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3VersionKey7C13F243" + "Ref": "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3VersionKey9466BE3D" } ] } @@ -3863,7 +3863,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3VersionKey7C13F243" + "Ref": "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3VersionKey9466BE3D" } ] } @@ -3907,7 +3907,7 @@ }, "/", { - "Ref": "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3Bucket0B8E3806" + "Ref": "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3BucketF9C7C3C5" }, "/", { @@ -3917,7 +3917,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3VersionKey862F0970" + "Ref": "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3VersionKey950894D5" } ] } @@ -3930,7 +3930,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3VersionKey862F0970" + "Ref": "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3VersionKey950894D5" } ] } @@ -4002,7 +4002,7 @@ "Properties": { "LaunchTemplateData": { "ImageId": { - "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" }, "InstanceType": "t3.small", "UserData": { @@ -4347,13 +4347,13 @@ ] } }, - "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "ServicePingerFunctionServiceRole3120191B", "Arn" ] }, + "Handler": "index.handler", "Runtime": "python3.6", "Timeout": 600, "VpcConfig": { @@ -4480,14 +4480,12 @@ ] } }, - "Handler": "framework.onEvent", "Role": { "Fn::GetAtt": [ "ServicePingerProviderframeworkonEventServiceRole3DB083B7", "Arn" ] }, - "Runtime": "nodejs10.x", "Description": "AWS CDK resource provider framework - onEvent (aws-cdk-eks-cluster-test/ServicePinger/Provider)", "Environment": { "Variables": { @@ -4499,6 +4497,8 @@ } } }, + "Handler": "framework.onEvent", + "Runtime": "nodejs10.x", "Timeout": 900 }, "DependsOn": [ @@ -4727,49 +4727,45 @@ "Type": "String", "Description": "Artifact hash for asset \"5f49893093e1ad14831626016699156d48da5f0890f19eb930bc3c46cf5f636d\"" }, - "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3Bucket1CB7A187": { + "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3Bucket862E8D6F": { "Type": "String", - "Description": "S3 bucket for asset \"a69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0c\"" + "Description": "S3 bucket for asset \"264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daa\"" }, - "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cS3VersionKey7C13F243": { + "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaS3VersionKey9466BE3D": { "Type": "String", - "Description": "S3 key for asset version \"a69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0c\"" + "Description": "S3 key for asset version \"264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daa\"" }, - "AssetParametersa69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0cArtifactHashBADE945D": { + "AssetParameters264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daaArtifactHashC5F5158C": { "Type": "String", - "Description": "Artifact hash for asset \"a69aadbed84d554dd9f2eb7987ffe5d8f76b53a86f1909059df07050e57bef0c\"" + "Description": "Artifact hash for asset \"264acf17cbf0c643f47bec1f4dbaed805e3bd1bad3f018c093d16fb936227daa\"" }, - "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3Bucket0B8E3806": { + "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3BucketF9C7C3C5": { "Type": "String", - "Description": "S3 bucket for asset \"6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8\"" + "Description": "S3 bucket for asset \"9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabc\"" }, - "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8S3VersionKey862F0970": { + "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcS3VersionKey950894D5": { "Type": "String", - "Description": "S3 key for asset version \"6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8\"" + "Description": "S3 key for asset version \"9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabc\"" }, - "AssetParameters6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8ArtifactHashAAFBAA4D": { + "AssetParameters9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabcArtifactHash5984E3CE": { "Type": "String", - "Description": "Artifact hash for asset \"6b9ad3782e5bfd49d7a58fc915b6151dbed2e24d824730d7720bc8237ba252c8\"" - }, - "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { - "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.18/amazon-linux-2/recommended/image_id" + "Description": "Artifact hash for asset \"9f954a0baf5cb008231906c33569617ace43f4b2c804d16d0d4bae15fe9dfabc\"" }, - "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.18/amazon-linux-2-arm64/recommended/image_id" + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id" }, - "SsmParameterValueawsservicebottlerocketawsk8s118x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/bottlerocket/aws-k8s-1.18/x86_64/latest/image_id" + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2-arm64/recommended/image_id" }, - "SsmParameterValueawsserviceeksoptimizedami118amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "SsmParameterValueawsservicebottlerocketawsk8s119x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.18/amazon-linux-2-gpu/recommended/image_id" + "Default": "/aws/service/bottlerocket/aws-k8s-1.19/x86_64/latest/image_id" }, - "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", - "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2-gpu/recommended/image_id" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts index 12c7334bd96a5..080cd744a57f0 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts @@ -35,7 +35,7 @@ class EksClusterStack extends TestStack { vpc: this.vpc, mastersRole, defaultCapacity: 2, - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, secretsEncryptionKey, }); @@ -187,7 +187,9 @@ class EksClusterStack extends TestStack { ); const lt = new ec2.CfnLaunchTemplate(this, 'LaunchTemplate', { launchTemplateData: { - imageId: new eks.EksOptimizedImage().getImage(this).imageId, + imageId: new eks.EksOptimizedImage({ + kubernetesVersion: eks.KubernetesVersion.V1_19.version, + }).getImage(this).imageId, instanceType: new ec2.InstanceType('t3.small').toString(), userData: Fn.base64(userData.render()), }, diff --git a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json index 5d6efed26b63f..631236f803499 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json @@ -842,7 +842,7 @@ ] }, "Config": { - "version": "1.18", + "version": "1.19", "roleArn": { "Fn::GetAtt": [ "FargateClusterRole8E36B33A", @@ -1139,7 +1139,7 @@ }, "/", { - "Ref": "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3BucketDA5FB24D" + "Ref": "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3Bucket01B07207" }, "/", { @@ -1149,7 +1149,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3VersionKey798A3941" + "Ref": "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3VersionKey3EEF52BA" } ] } @@ -1162,7 +1162,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3VersionKey798A3941" + "Ref": "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3VersionKey3EEF52BA" } ] } @@ -1206,7 +1206,7 @@ }, "/", { - "Ref": "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3BucketF39EF776" + "Ref": "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3BucketDCD73A4E" }, "/", { @@ -1216,7 +1216,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3VersionKeyE6E734A4" + "Ref": "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3VersionKey796F5C1B" } ] } @@ -1229,7 +1229,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3VersionKeyE6E734A4" + "Ref": "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3VersionKey796F5C1B" } ] } @@ -1272,17 +1272,17 @@ "ClusterSecurityGroupId" ] }, - "referencetoawscdkeksfargateclustertestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket9D3BB190Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73" + "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket4F20F642Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" }, - "referencetoawscdkeksfargateclustertestAssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey3BB3C6F5Ref": { - "Ref": "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61" + "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyB82BAEF8Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksfargateclustertestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket99BFDD36Ref": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15" + "referencetoawscdkeksfargateclustertestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket9ED34BB4Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" }, - "referencetoawscdkeksfargateclustertestAssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKeyEEC9E8C1Ref": { - "Ref": "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78" + "referencetoawscdkeksfargateclustertestAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyFE6D1F78Ref": { + "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" }, "referencetoawscdkeksfargateclustertestFargateClusterDefaultVpcBD3C976FRef": { "Ref": "FargateClusterDefaultVpcE69D3A13" @@ -1376,53 +1376,53 @@ "Type": "String", "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3Bucket6DACDE73": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", - "Description": "S3 bucket for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1S3VersionKey015AEA61": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { "Type": "String", - "Description": "S3 key for asset version \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersefd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1ArtifactHashC9FD06BA": { + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { "Type": "String", - "Description": "Artifact hash for asset \"efd72738f046105c96299fb31b3da40320e71ee9cf74bc37720042898403e2a1\"" + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3Bucket7EE7EA15": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { "Type": "String", - "Description": "S3 bucket for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fS3VersionKey6C948E78": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { "Type": "String", - "Description": "S3 key for asset version \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersb61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449fArtifactHash7E705796": { + "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { "Type": "String", - "Description": "Artifact hash for asset \"b61858bbf1a0be803552e3efa9647befd728156696dff1b413b7b2fd4da1449f\"" + "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" }, - "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3BucketDA5FB24D": { + "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3Bucket01B07207": { "Type": "String", - "Description": "S3 bucket for asset \"ae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48\"" + "Description": "S3 bucket for asset \"3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1\"" }, - "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48S3VersionKey798A3941": { + "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1S3VersionKey3EEF52BA": { "Type": "String", - "Description": "S3 key for asset version \"ae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48\"" + "Description": "S3 key for asset version \"3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1\"" }, - "AssetParametersae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48ArtifactHash865DB842": { + "AssetParameters3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1ArtifactHash812ED4D5": { "Type": "String", - "Description": "Artifact hash for asset \"ae946640aaf0743990584e4a1cf45ddebbaddcaf60611f572e80100a02162f48\"" + "Description": "Artifact hash for asset \"3d252d05ccf0ae2934dd20707e8a709b466b2b8ea00c04ee8735667f90b17ac1\"" }, - "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3BucketF39EF776": { + "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3BucketDCD73A4E": { "Type": "String", - "Description": "S3 bucket for asset \"7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98d\"" + "Description": "S3 bucket for asset \"37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13\"" }, - "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dS3VersionKeyE6E734A4": { + "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13S3VersionKey796F5C1B": { "Type": "String", - "Description": "S3 key for asset version \"7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98d\"" + "Description": "S3 key for asset version \"37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13\"" }, - "AssetParameters7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98dArtifactHash93FFAA4A": { + "AssetParameters37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13ArtifactHash8F2277C1": { "Type": "String", - "Description": "Artifact hash for asset \"7449e3c4cf21a811d1d6612d2f1a806025f018320ebc8c1d8037eb34f0d0e98d\"" + "Description": "Artifact hash for asset \"37d93b8a35af568f83ecce5e05c6f06adaa06c68b84dfad9c3d82f57cd54ff13\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.ts b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.ts index a97389ce4622e..957b60ee23e3b 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.ts @@ -3,7 +3,7 @@ import { App } from '@aws-cdk/core'; import * as eks from '../lib'; import { TestStack } from './util'; -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; class EksFargateClusterStack extends TestStack { diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 7e7f01d7ede84..0f8ad05549bdd 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -17,7 +17,7 @@ import { testFixture, testFixtureNoVpc } from './util'; /* eslint-disable max-len */ -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; export = { @@ -85,7 +85,7 @@ export = { vpc: vpc, vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }, { subnetType: ec2.SubnetType.PRIVATE }], defaultCapacity: 0, - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }), /cannot select multiple subnet groups/); test.done(); @@ -97,7 +97,7 @@ export = { vpc: vpc, vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }], defaultCapacity: 0, - version: eks.KubernetesVersion.V1_18, + version: eks.KubernetesVersion.V1_19, }); // THEN @@ -629,7 +629,7 @@ export = { expect(stack).to(haveResourceLike('Custom::AWSCDK-EKS-Cluster', { Config: { roleArn: { 'Fn::GetAtt': ['ClusterRoleFA261979', 'Arn'] }, - version: '1.18', + version: '1.19', resourcesVpcConfig: { securityGroupIds: [{ 'Fn::GetAtt': ['ClusterControlPlaneSecurityGroupD274242C', 'GroupId'] }], subnetIds: [ @@ -1462,7 +1462,7 @@ export = { const { app, stack } = testFixtureNoVpc(); // WHEN - new eks.EksOptimizedImage({ kubernetesVersion: '1.18' }).getImage(stack); + new eks.EksOptimizedImage({ kubernetesVersion: '1.19' }).getImage(stack); // THEN const assembly = app.synth(); @@ -1473,7 +1473,7 @@ export = { ), 'EKS STANDARD AMI should be in ssm parameters'); test.ok(Object.entries(parameters).some( ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && - (v as any).Default.includes('/1.18/'), + (v as any).Default.includes('/1.19/'), ), 'kubernetesVersion should be in ssm parameters'); test.done(); }, @@ -1611,7 +1611,7 @@ export = { const { app, stack } = testFixtureNoVpc(); // WHEN - new BottleRocketImage({ kubernetesVersion: '1.18' }).getImage(stack); + new BottleRocketImage({ kubernetesVersion: '1.19' }).getImage(stack); // THEN const assembly = app.synth(); @@ -1622,7 +1622,7 @@ export = { ), 'BottleRocket AMI should be in ssm parameters'); test.ok(Object.entries(parameters).some( ([k, v]) => k.startsWith('SsmParameterValueawsservicebottlerocketaws') && - (v as any).Default.includes('/aws-k8s-1.18/'), + (v as any).Default.includes('/aws-k8s-1.19/'), ), 'kubernetesVersion should be in ssm parameters'); test.done(); }, @@ -1643,7 +1643,7 @@ export = { Config: { name: 'my-cluster-name', roleArn: { 'Fn::GetAtt': ['MyClusterRoleBA20FE72', 'Arn'] }, - version: '1.18', + version: '1.19', resourcesVpcConfig: { securityGroupIds: [ { 'Fn::GetAtt': ['MyClusterControlPlaneSecurityGroup6B658F79', 'GroupId'] }, diff --git a/packages/@aws-cdk/aws-eks/test/test.fargate.ts b/packages/@aws-cdk/aws-eks/test/test.fargate.ts index a606a5cfe7496..ba1ec4009d1d1 100644 --- a/packages/@aws-cdk/aws-eks/test/test.fargate.ts +++ b/packages/@aws-cdk/aws-eks/test/test.fargate.ts @@ -5,7 +5,7 @@ import { Stack, Tags } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as eks from '../lib'; -const CLUSTER_VERSION = eks.KubernetesVersion.V1_16; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; export = { 'can be added to a cluster'(test: Test) { diff --git a/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts b/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts index 241482d469c65..0599c349f6190 100644 --- a/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts +++ b/packages/@aws-cdk/aws-eks/test/test.nodegroup.ts @@ -7,7 +7,7 @@ import { testFixture } from './util'; /* eslint-disable max-len */ -const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; +const CLUSTER_VERSION = eks.KubernetesVersion.V1_19; export = { From cc2831238d965950dad74607ac0199b75b4bc459 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Wed, 17 Feb 2021 12:36:19 +0000 Subject: [PATCH 19/20] fix(cloudfront): bucket policy for Origin Access Identities is overly permissive (#13087) For both `CloudFrontWebDistribution` and `Distribution`, if an origin access identity (OAI) is used to access a S3 bucket origin, the default `bucket.grantRead()` method is used to grant read access to the bucket for the OAI. `grantRead` will create a statement in the bucket policy that grants: `s3:GetObject*`, `s3:GetBucket*`, and `s3:List*` to the OAI. The [official documentation](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html) in the developer guide states that to allow the OAI to read objects in the bucket, only `s3:GetObject` is necessary. The impact of the additional permissions is that if a user navigates to the root of the distribution (e.g., https://d12345abcdef.cloudfront.net/) *AND* no default root object (e.g., index.html) is set for the distribution, the user will receive an XML list of the objects in the bucket. This is likely undesired behavior. This same policy has been the behavior for OAI + S3 buckets since the first introduction of the `CloudFrontWebDistribution` construct years ago. However, the `CloudFrontWebDistribution` also always defaults the root object to 'index.html' (see #3486 for discussion on that). The side-effect of this is that unless the user selects to use an OAI and overrides the default root object to an empty string, visiting the root will result either in valid content or an AccessDenied message. However, since the `Distribution` constructs do *not* default the root object, exposing the bucket index becomes much more likely. This change restricts the permissions granted to the OAI user to just the necessary `s3:GetObject` permissions. fixes #13086 --- **NOTE:** This PR corrects the behavior without introducing a new feature flag. Any customers who rely on the bucket listing behavior would be broken by this change. However, I anticipate that represents a very small minority, versus the number of customers who may accidentally expose their bucket contents. I would very much like to have a discussion about whether this is the correct choice. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-cloudfront-origins/lib/s3-origin.ts | 14 ++++- .../aws-cloudfront-origins/package.json | 6 ++- .../test/integ.origin-group.expected.json | 40 +++++--------- .../test/integ.s3-origin.expected.json | 40 +++++--------- .../test/s3-origin.test.ts | 4 ++ .../aws-cloudfront/lib/web-distribution.ts | 12 +++-- .../test/integ.cloudfront-s3.expected.json | 40 +++++--------- .../test/web-distribution.test.ts | 54 +++++++++++++++++++ 8 files changed, 125 insertions(+), 85 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts index 518e3e728ec1a..a0ac4037d9741 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/lib/s3-origin.ts @@ -1,4 +1,5 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; +import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { HttpOrigin } from './http-origin'; @@ -68,7 +69,7 @@ class S3BucketOrigin extends cloudfront.OriginBase { public bind(scope: Construct, options: cloudfront.OriginBindOptions): cloudfront.OriginBindConfig { if (!this.originAccessIdentity) { // Using a bucket from another stack creates a cyclic reference with - // the bucket taking a dependency on the generated S3CanonicalUserId when `grantRead` is called, + // the bucket taking a dependency on the generated S3CanonicalUserId for the grant principal, // and the distribution having a dependency on the bucket's domain name. // Fix this by parenting the OAI in the bucket's stack when cross-stack usage is detected. const bucketStack = cdk.Stack.of(this.bucket); @@ -79,7 +80,16 @@ class S3BucketOrigin extends cloudfront.OriginBase { this.originAccessIdentity = new cloudfront.OriginAccessIdentity(oaiScope, oaiId, { comment: `Identity for ${options.originId}`, }); - this.bucket.grantRead(this.originAccessIdentity); + + // Used rather than `grantRead` because `grantRead` will grant overly-permissive policies. + // Only GetObject is needed to retrieve objects for the distribution. + // This also excludes KMS permissions; currently, OAI only supports SSE-S3 for buckets. + // Source: https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/ + this.bucket.addToResourcePolicy(new iam.PolicyStatement({ + resources: [this.bucket.arnForObjects('*')], + actions: ['s3:GetObject'], + principals: [this.originAccessIdentity.grantPrincipal], + })); } return super.bind(scope, options); } diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index 8e2a945533280..02e293de5f675 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -79,6 +79,7 @@ "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.2.0" @@ -88,8 +89,9 @@ "@aws-cdk/core": "0.0.0", "constructs": "^3.2.0", "@aws-cdk/aws-cloudfront": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0" + "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json index 8e123f87338d4..ecd2096329404 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json @@ -14,11 +14,7 @@ "PolicyDocument": { "Statement": [ { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], + "Action": "s3:GetObject", "Effect": "Allow", "Principal": { "CanonicalUser": { @@ -28,28 +24,20 @@ ] } }, - "Resource": [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" ] - } - ] + ] + } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json index 5eb310b5b92d7..25461aa9cf7de 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json @@ -14,11 +14,7 @@ "PolicyDocument": { "Statement": [ { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], + "Action": "s3:GetObject", "Effect": "Allow", "Principal": { "CanonicalUser": { @@ -28,28 +24,20 @@ ] } }, - "Resource": [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" ] - } - ] + ] + } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts index 54f9861685945..a502dd5cf4f46 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/s3-origin.test.ts @@ -87,9 +87,13 @@ describe('With bucket', () => { expect(stack).toHaveResourceLike('AWS::S3::BucketPolicy', { PolicyDocument: { Statement: [{ + Action: 's3:GetObject', Principal: { CanonicalUser: { 'Fn::GetAtt': ['DistOrigin1S3Origin87D64058', 'S3CanonicalUserId'] }, }, + Resource: { + 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Bucket83908E77', 'Arn'] }, '/*']], + }, }], }, }); diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index f191813dada2b..a678c82ba6087 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -1027,9 +1027,15 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu // first case for backwards compatibility if (originConfig.s3OriginSource.originAccessIdentity) { // grant CloudFront OriginAccessIdentity read access to S3 bucket - originConfig.s3OriginSource.s3BucketSource.grantRead( - originConfig.s3OriginSource.originAccessIdentity, - ); + // Used rather than `grantRead` because `grantRead` will grant overly-permissive policies. + // Only GetObject is needed to retrieve objects for the distribution. + // This also excludes KMS permissions; currently, OAI only supports SSE-S3 for buckets. + // Source: https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/ + originConfig.s3OriginSource.s3BucketSource.addToResourcePolicy(new iam.PolicyStatement({ + resources: [originConfig.s3OriginSource.s3BucketSource.arnForObjects('*')], + actions: ['s3:GetObject'], + principals: [originConfig.s3OriginSource.originAccessIdentity.grantPrincipal], + })); s3OriginConfig = { originAccessIdentity: `origin-access-identity/cloudfront/${originConfig.s3OriginSource.originAccessIdentity.originAccessIdentityName}`, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json index 8f6357e72272e..72ed767994cc0 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json @@ -14,11 +14,7 @@ "PolicyDocument": { "Statement": [ { - "Action": [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], + "Action": "s3:GetObject", "Effect": "Allow", "Principal": { "AWS": { @@ -37,28 +33,20 @@ ] } }, - "Resource": [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "Bucket83908E77", - "Arn" - ] - }, - "/*" - ] - ] - } - ] + ] + } } ], "Version": "2012-10-17" diff --git a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts index 8eea2cad5bc92..d24c7aa1220dc 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -10,6 +10,7 @@ import { GeoRestriction, KeyGroup, LambdaEdgeEventType, + OriginAccessIdentity, PublicKey, SecurityPolicyProtocol, SSLMethod, @@ -197,6 +198,59 @@ nodeunitShim({ test.done(); }, + 'distribution with bucket and OAI'(test: Test) { + const stack = new cdk.Stack(); + const s3BucketSource = new s3.Bucket(stack, 'Bucket'); + const originAccessIdentity = new OriginAccessIdentity(stack, 'OAI'); + + new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { + originConfigs: [{ + s3OriginSource: { s3BucketSource, originAccessIdentity }, + behaviors: [{ isDefaultBehavior: true }], + }], + }); + + expect(stack).to(haveResourceLike('AWS::CloudFront::Distribution', { + DistributionConfig: { + Origins: [ + { + ConnectionAttempts: 3, + ConnectionTimeout: 10, + DomainName: { + 'Fn::GetAtt': [ + 'Bucket83908E77', + 'RegionalDomainName', + ], + }, + Id: 'origin1', + S3OriginConfig: { + OriginAccessIdentity: { + 'Fn::Join': ['', ['origin-access-identity/cloudfront/', { Ref: 'OAIE1EFC67F' }]], + }, + }, + }, + ], + }, + })); + + expect(stack).to(haveResourceLike('AWS::S3::BucketPolicy', { + PolicyDocument: { + Statement: [{ + Action: 's3:GetObject', + Principal: { + CanonicalUser: { 'Fn::GetAtt': ['OAIE1EFC67F', 'S3CanonicalUserId'] }, + }, + Resource: { + 'Fn::Join': ['', [{ 'Fn::GetAtt': ['Bucket83908E77', 'Arn'] }, '/*']], + }, + }], + }, + })); + + test.done(); + }, + + 'distribution with trusted signers on default distribution'(test: Test) { const stack = new cdk.Stack(); const sourceBucket = new s3.Bucket(stack, 'Bucket'); From c9bd7fe742f2b5a6adccece2338fdc38c2c8e92f Mon Sep 17 00:00:00 2001 From: Eli Polonsky Date: Wed, 17 Feb 2021 15:35:05 +0200 Subject: [PATCH 20/20] chore: fix issue assignment worfklows should to use tagged versions (#13105) --- .github/workflows/issue-label-assign.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index 9e2f2ce7e3e34..aeb59183b0ef7 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -11,7 +11,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: Naturalclar/issue-action@f229cda + - uses: Naturalclar/issue-action@v2.0.2 with: github-token: "${{ secrets.GITHUB_TOKEN }}" title-or-body: 'title'