From 797edbdca81dcabe78ad141e1b08cb3ed4d45cd2 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Wed, 24 Nov 2021 12:16:00 +0000 Subject: [PATCH 01/82] chore(rds): undeprecated APIs whose migration will cause interruption (#17683) All deprecated APIs will be removed from CDKv2. Migrating from `SnapshotCredentials.fromGeneratedPassword()` to its documented alternative will modify the RDS instance in ways that may impact usability of the resource. This API must not be deprecated. The alternative APIs to the `DatabaseInstanceEngine` APIs refereced in this PR will cause the [CFN EngineVersion][1] to be modified. Modification of this property causes [some interruption][2] to the resource. This may cause "some interruption" to users' running applications. [1]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html#cfn-rds-dbinstance-engineversion [2]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-some-interrupt ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- DEPRECATED_APIs.md | 10 ---------- deprecated_apis.txt | 10 ---------- .../@aws-cdk/aws-rds/lib/instance-engine.ts | 18 +++++++++--------- packages/@aws-cdk/aws-rds/lib/props.ts | 4 +--- 4 files changed, 10 insertions(+), 32 deletions(-) diff --git a/DEPRECATED_APIs.md b/DEPRECATED_APIs.md index de3f69163db65..c39b41d8ad275 100644 --- a/DEPRECATED_APIs.md +++ b/DEPRECATED_APIs.md @@ -600,20 +600,10 @@ | @aws-cdk/aws-dynamodb | Table.​grantListStreams() | Use {@link #grantTableListStreams} for more granular permission | | @aws-cdk/aws-dynamodb | Table.​metricSystemErrors() | use `metricSystemErrorsForOperations`. | | @aws-cdk/aws-dynamodb | TableOptions.​serverSideEncryption | This property is deprecated. In order to obtain the same behavior as enabling this, set the `encryption` property to `TableEncryption.AWS_MANAGED` instead. | -| @aws-cdk/aws-rds | Credentials.​fromUsername() | use `fromGeneratedSecret()` or `fromPassword()` for new Clusters and Instances. Note that switching from `fromUsername()` to `fromGeneratedSecret()` or `fromPassword()` for already deployed Clusters or Instances will result in their replacement! | | @aws-cdk/aws-rds | CredentialsFromUsernameOptions | supporting API `fromUsername()` has been deprecated. See deprecation notice of the API. | | @aws-cdk/aws-rds | CredentialsFromUsernameOptions.​password | supporting API `fromUsername()` has been deprecated. See deprecation notice of the API. | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​MARIADB | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link mariaDb()} method | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​MYSQL | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link mysql()} method | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​ORACLE_​EE | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link oracleEe()} method | | @aws-cdk/aws-rds | DatabaseInstanceEngine.​ORACLE_​SE | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | | @aws-cdk/aws-rds | DatabaseInstanceEngine.​ORACLE_​SE1 | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​ORACLE_​SE2 | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link oracleSe2()} method | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​POSTGRES | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link postgres()} method | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​SQL_​SERVER_​EE | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link sqlServerEe()} method | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​SQL_​SERVER_​EX | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link sqlServerEx()} method | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​SQL_​SERVER_​SE | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link sqlServerSe()} method | -| @aws-cdk/aws-rds | DatabaseInstanceEngine.​SQL_​SERVER_​WEB | using unversioned engines is an availability risk. We recommend using versioned engines created using the {@link sqlServerWeb()} method | | @aws-cdk/aws-rds | DatabaseInstanceEngine.​oracleSe() | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | | @aws-cdk/aws-rds | DatabaseInstanceEngine.​oracleSe1() | instances can no longer be created with this engine. See https://forums.aws.amazon.com/ann.jspa?annID=7341 | | @aws-cdk/aws-rds | DatabaseInstanceNewProps.​vpcPlacement | use `vpcSubnets` | diff --git a/deprecated_apis.txt b/deprecated_apis.txt index 433d6fe5438eb..aa0ae3918b0d6 100644 --- a/deprecated_apis.txt +++ b/deprecated_apis.txt @@ -599,17 +599,8 @@ constructs.Node#uniqueId @aws-cdk/aws-rds.Credentials#fromUsername @aws-cdk/aws-rds.CredentialsFromUsernameOptions @aws-cdk/aws-rds.CredentialsFromUsernameOptions#password -@aws-cdk/aws-rds.DatabaseInstanceEngine#MARIADB -@aws-cdk/aws-rds.DatabaseInstanceEngine#MYSQL -@aws-cdk/aws-rds.DatabaseInstanceEngine#ORACLE_EE @aws-cdk/aws-rds.DatabaseInstanceEngine#ORACLE_SE @aws-cdk/aws-rds.DatabaseInstanceEngine#ORACLE_SE1 -@aws-cdk/aws-rds.DatabaseInstanceEngine#ORACLE_SE2 -@aws-cdk/aws-rds.DatabaseInstanceEngine#POSTGRES -@aws-cdk/aws-rds.DatabaseInstanceEngine#SQL_SERVER_EE -@aws-cdk/aws-rds.DatabaseInstanceEngine#SQL_SERVER_EX -@aws-cdk/aws-rds.DatabaseInstanceEngine#SQL_SERVER_SE -@aws-cdk/aws-rds.DatabaseInstanceEngine#SQL_SERVER_WEB @aws-cdk/aws-rds.DatabaseInstanceEngine#oracleSe @aws-cdk/aws-rds.DatabaseInstanceEngine#oracleSe1 @aws-cdk/aws-rds.DatabaseInstanceNewProps#vpcPlacement @@ -721,7 +712,6 @@ constructs.Node#uniqueId @aws-cdk/aws-rds.PostgresEngineVersion#VER_9_6_6 @aws-cdk/aws-rds.PostgresEngineVersion#VER_9_6_8 @aws-cdk/aws-rds.PostgresEngineVersion#VER_9_6_9 -@aws-cdk/aws-rds.SnapshotCredentials#fromGeneratedPassword @aws-cdk/aws-rds.SqlServerEngineVersion#VER_15_00_4043_23_V1 @aws-cdk/aws-autoscaling.BlockDevice#mappingEnabled @aws-cdk/aws-autoscaling.CommonAutoScalingGroupProps#notificationsTopic diff --git a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts index 81deab4cabbf4..21edeeaaed63d 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts @@ -1572,7 +1572,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'mariadb' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link mariaDb()} method */ public static readonly MARIADB: IInstanceEngine = new MariaDbInstanceEngine(); @@ -1580,7 +1580,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'mysql' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link mysql()} method */ public static readonly MYSQL: IInstanceEngine = new MySqlInstanceEngine(); @@ -1588,7 +1588,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'oracle-ee' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link oracleEe()} method */ public static readonly ORACLE_EE: IInstanceEngine = new OracleEeInstanceEngine(); @@ -1596,7 +1596,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'oracle-se2' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link oracleSe2()} method */ public static readonly ORACLE_SE2: IInstanceEngine = new OracleSe2InstanceEngine(); @@ -1618,7 +1618,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'postgres' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link postgres()} method */ public static readonly POSTGRES: IInstanceEngine = new PostgresInstanceEngine(); @@ -1626,7 +1626,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'sqlserver-ee' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link sqlServerEe()} method */ public static readonly SQL_SERVER_EE: IInstanceEngine = new SqlServerEeInstanceEngine(); @@ -1634,7 +1634,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'sqlserver-se' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link sqlServerSe()} method */ public static readonly SQL_SERVER_SE: IInstanceEngine = new SqlServerSeInstanceEngine(); @@ -1642,7 +1642,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'sqlserver-ex' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link sqlServerEx()} method */ public static readonly SQL_SERVER_EX: IInstanceEngine = new SqlServerExInstanceEngine(); @@ -1650,7 +1650,7 @@ export class DatabaseInstanceEngine { /** * The unversioned 'sqlserver-web' instance engine. * - * @deprecated using unversioned engines is an availability risk. + * NOTE: using unversioned engines is an availability risk. * We recommend using versioned engines created using the {@link sqlServerWeb()} method */ public static readonly SQL_SERVER_WEB: IInstanceEngine = new SqlServerWebInstanceEngine(); diff --git a/packages/@aws-cdk/aws-rds/lib/props.ts b/packages/@aws-cdk/aws-rds/lib/props.ts index 75f8402b16d68..4a8883df504e3 100644 --- a/packages/@aws-cdk/aws-rds/lib/props.ts +++ b/packages/@aws-cdk/aws-rds/lib/props.ts @@ -346,9 +346,7 @@ export abstract class SnapshotCredentials { * * Note - The username must match the existing master username of the snapshot. * - * @deprecated use `fromGeneratedSecret()` for new Clusters and Instances. - * Note that switching from `fromGeneratedPassword()` to `fromGeneratedSecret()` for already deployed - * Clusters or Instances will update their master password. + * NOTE: use `fromGeneratedSecret()` for new Clusters and Instances. */ public static fromGeneratedPassword(username: string, options: SnapshotCredentialsFromGeneratedPasswordOptions = {}): SnapshotCredentials { return { From 5710fe5a80cd4cc6ef415ec624a3399e86a3e603 Mon Sep 17 00:00:00 2001 From: cyuste Date: Wed, 24 Nov 2021 14:40:59 +0100 Subject: [PATCH 02/82] feat(custom-resources): fixed Lambda function name (#17670) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/custom-resources/README.md | 19 +++++++++++++++ .../lib/provider-framework/provider.ts | 14 +++++++++-- .../test/provider-framework/provider.test.ts | 24 +++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/custom-resources/README.md b/packages/@aws-cdk/custom-resources/README.md index 90892fb7906c7..2c15ba9141e17 100644 --- a/packages/@aws-cdk/custom-resources/README.md +++ b/packages/@aws-cdk/custom-resources/README.md @@ -347,6 +347,25 @@ This sample demonstrates the following concepts: * Non-intrinsic physical IDs * Implemented in Python + +### Customizing Provider Function name + +In multi-account environments or when the custom resource may be re-utilized across several +stacks it may be useful to manually set a name for the Provider Function Lambda and therefore +have a predefined service token ARN. + +```ts + +const myProvider = new cr.Provider(this, 'MyProvider', { + onEventHandler: onEvent, + isCompleteHandler: isComplete, + logRetention: logs.RetentionDays.ONE_DAY, + role: myRole, + providerFunctionName: 'the-lambda-name', // Optional +}); + +``` + ## Custom Resources for AWS APIs Sometimes a single API call can fill the gap in the CloudFormation coverage. In diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts index c2f7ef69c98bb..2c94cad1dbf3c 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts @@ -115,6 +115,15 @@ export interface ProviderProps { * @default - A default role will be created. */ readonly role?: iam.IRole; + + /** + * Provider Lambda name. + * + * The provider lambda function name. + * + * @default - CloudFormation default name from unique physical ID + */ + readonly providerFunctionName?: string; } /** @@ -165,7 +174,7 @@ export class Provider extends CoreConstruct implements ICustomResourceProvider { this.role = props.role; - const onEventFunction = this.createFunction(consts.FRAMEWORK_ON_EVENT_HANDLER_NAME); + const onEventFunction = this.createFunction(consts.FRAMEWORK_ON_EVENT_HANDLER_NAME, props.providerFunctionName); if (this.isCompleteHandler) { const isCompleteFunction = this.createFunction(consts.FRAMEWORK_IS_COMPLETE_HANDLER_NAME); @@ -198,7 +207,7 @@ export class Provider extends CoreConstruct implements ICustomResourceProvider { }; } - private createFunction(entrypoint: string) { + private createFunction(entrypoint: string, name?: string) { const fn = new lambda.Function(this, `framework-${entrypoint}`, { code: lambda.Code.fromAsset(RUNTIME_HANDLER_PATH), description: `AWS CDK resource provider framework - ${entrypoint} (${this.node.path})`.slice(0, 256), @@ -210,6 +219,7 @@ export class Provider extends CoreConstruct implements ICustomResourceProvider { vpcSubnets: this.vpcSubnets, securityGroups: this.securityGroups, role: this.role, + functionName: name, }); fn.addEnvironment(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, this.onEventHandler.functionArn); diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts index e9cfa0b5e6867..724c76425a1ee 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/provider.test.ts @@ -397,3 +397,27 @@ describe('role', () => { }); }); }); + +describe('name', () => { + it('uses custom name when present', () => { + // GIVEN + const stack = new Stack(); + const providerFunctionName = 'test-name'; + + // WHEN + new cr.Provider(stack, 'MyProvider', { + onEventHandler: new lambda.Function(stack, 'MyHandler', { + code: lambda.Code.fromAsset(path.join(__dirname, './integration-test-fixtures/s3-file-handler')), + handler: 'index.onEvent', + runtime: lambda.Runtime.NODEJS_10_X, + }), + providerFunctionName, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + FunctionName: providerFunctionName, + }); + }); +}); + From 5e4a21959e67ff967d163fce6b0405a053bafdc2 Mon Sep 17 00:00:00 2001 From: bmmin Date: Wed, 24 Nov 2021 15:29:30 +0100 Subject: [PATCH 03/82] fix(pipelines): stack outputs used in stackSteps not recognized (#17311) fixes #17272 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/helpers-internal/pipeline-queries.ts | 3 + .../helpers-internal/pipeline-queries.test.ts | 99 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/pipeline-queries.test.ts diff --git a/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-queries.ts b/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-queries.ts index d3306e4e0a934..4df521b44260a 100644 --- a/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-queries.ts +++ b/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-queries.ts @@ -17,6 +17,9 @@ export class PipelineQueries { steps.push(...wave.pre, ...wave.post); for (const stage of wave.stages) { steps.push(...stage.pre, ...stage.post); + for (const stackDeployment of stage.stacks) { + steps.push(...stackDeployment.pre, ...stackDeployment.changeSet, ...stackDeployment.post); + } } } diff --git a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/pipeline-queries.test.ts b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/pipeline-queries.test.ts new file mode 100644 index 0000000000000..a859cf98d1bce --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/pipeline-queries.test.ts @@ -0,0 +1,99 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import '@aws-cdk/assert-internal/jest'; +import * as cdkp from '../../../lib'; +import { PipelineQueries } from '../../../lib/helpers-internal/pipeline-queries'; +import { AppWithOutput, TestApp } from '../../testhelpers/test-app'; + +let app: TestApp; + +beforeEach(() => { + app = new TestApp(); +}); + +afterEach(() => { + app.cleanup(); +}); + +describe('pipeline-queries', () => { + + describe('stackOutputsReferenced', () => { + let blueprint: Blueprint; + let stageDeployment: cdkp.StageDeployment; + let step: cdkp.ShellStep; + let queries: PipelineQueries; + let stackDeployment: cdkp.StackDeployment; + let outputName: string | undefined; + beforeEach(() => { + blueprint = new Blueprint(app, 'Bp', { + synth: new cdkp.ShellStep('Synth', { + input: cdkp.CodePipelineSource.gitHub('test/test', 'main'), + commands: ['build'], + }), + }); + const stage = new AppWithOutput(app, 'CrossAccount'); + outputName = 'MyOutput'; + stageDeployment = blueprint.addStage(stage); + stackDeployment = stageDeployment.stacks[0]; + expect(stackDeployment).not.toBeUndefined(); + step = new cdkp.ShellStep('test', { + input: cdkp.CodePipelineSource.gitHub('test/test', 'main'), + commands: ['build'], + envFromCfnOutputs: { + INPUT: stage.theOutput, + }, + }); + queries = new PipelineQueries(blueprint); + }); + + const cases = [ + { + description: 'output referenced in stage pre step', + additionalSetup: () => stageDeployment.addPre(step), + expectedResultGetter: () => [outputName], + }, + { + description: 'output referenced in stage post step', + additionalSetup: () => stageDeployment.addPost(step), + expectedResultGetter: () => [outputName], + }, + { + description: 'output referenced in stack pre step', + additionalSetup: () => stackDeployment.addStackSteps([step], [], []), + expectedResultGetter: () => [outputName], + }, + { + description: 'output referenced in stack changeSet step', + additionalSetup: () => stackDeployment.addStackSteps([], [step], []), + expectedResultGetter: () => [outputName], + }, + { + description: 'output referenced in stack post step', + additionalSetup: () => stackDeployment.addStackSteps([], [], [step]), + expectedResultGetter: () => [outputName], + }, + { + description: 'output not referenced', + additionalSetup: () => { }, + expectedResultGetter: () => [], + }, + + ]; + + cases.forEach(testCase => { + test(testCase.description, () => { + //WHEN + testCase.additionalSetup(); + + //THEN + expect(queries.stackOutputsReferenced(stackDeployment)).toEqual(testCase.expectedResultGetter()); + }); + }); + + }); +}); + + +class Blueprint extends cdkp.PipelineBase { + protected doBuildPipeline(): void { + } +} \ No newline at end of file From 29b379cdc49dd396f793782b91d3eca215446a48 Mon Sep 17 00:00:00 2001 From: nom3ad <19239479+nom3ad@users.noreply.github.com> Date: Wed, 24 Nov 2021 20:42:08 +0530 Subject: [PATCH 04/82] feat(iam): support `fromGroupName()` for IAM groups (#17243) IAM Policies and Users already support import by name. Extending same for Groups ---- *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-iam/README.md | 29 ++++++++++++++--- packages/@aws-cdk/aws-iam/lib/group.ts | 18 +++++++++++ packages/@aws-cdk/aws-iam/test/group.test.ts | 33 +++++++++++++++----- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/packages/@aws-cdk/aws-iam/README.md b/packages/@aws-cdk/aws-iam/README.md index a81b25d53e6ba..66d720ba8a708 100644 --- a/packages/@aws-cdk/aws-iam/README.md +++ b/packages/@aws-cdk/aws-iam/README.md @@ -329,7 +329,7 @@ Identity Pools Developer Guide]. The following examples defines an OpenID Connect provider. Two client IDs (audiences) are will be able to send authentication requests to -https://openid/connect. +. ```ts const provider = new iam.OpenIdConnectProvider(this, 'MyProvider', { @@ -439,6 +439,26 @@ const user = iam.User.fromUserAttributes(this, 'MyImportedUserByAttributes', { }); ``` +## Groups + +An IAM user group is a collection of IAM users. User groups let you specify permissions for multiple users. + +```ts +const group = new iam.Group(this, 'MyGroup'); +``` + +To import an existing group by ARN: + +```ts +const group = iam.Group.fromGroupArn(this, 'MyImportedGroupByArn', 'arn:aws:iam::account-id:group/group-name'); +``` + +To import an existing group by name [with path](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-friendly-names): + +```ts +const group = iam.Group.fromGroupName(this, 'MyImportedGroupByName', 'group-name'); +``` + To add a user to a group (both for a new and imported user/group): ```ts @@ -450,12 +470,11 @@ user.addToGroup(group); group.addUser(user); ``` - ## Features - * Policy name uniqueness is enforced. If two policies by the same name are attached to the same +* Policy name uniqueness is enforced. If two policies by the same name are attached to the same principal, the attachment will fail. - * Policy names are not required - the CDK logical ID will be used and ensured to be unique. - * Policies are validated during synthesis to ensure that they have actions, and that policies +* Policy names are not required - the CDK logical ID will be used and ensured to be unique. +* Policies are validated during synthesis to ensure that they have actions, and that policies attached to IAM principals specify relevant resources, while policies attached to resources specify which IAM principals they apply to. diff --git a/packages/@aws-cdk/aws-iam/lib/group.ts b/packages/@aws-cdk/aws-iam/lib/group.ts index 1fb4fac6b2fe4..350a447b517f5 100644 --- a/packages/@aws-cdk/aws-iam/lib/group.ts +++ b/packages/@aws-cdk/aws-iam/lib/group.ts @@ -156,6 +156,24 @@ export class Group extends GroupBase { return new Import(scope, id); } + /** + * Import an existing group by given name (with path). + * This method has same caveats of `fromGroupArn` + * + * @param scope construct scope + * @param id construct id + * @param groupName the groupName (path included) of the existing group to import + */ + static fromGroupName(scope: Construct, id: string, groupName: string) { + const groupArn = Stack.of(scope).formatArn({ + service: 'iam', + region: '', + resource: 'group', + resourceName: groupName, + }); + return Group.fromGroupArn(scope, id, groupArn); + } + public readonly groupName: string; public readonly groupArn: string; diff --git a/packages/@aws-cdk/aws-iam/test/group.test.ts b/packages/@aws-cdk/aws-iam/test/group.test.ts index d8b7c6fb47913..6fc7129a3a1d9 100644 --- a/packages/@aws-cdk/aws-iam/test/group.test.ts +++ b/packages/@aws-cdk/aws-iam/test/group.test.ts @@ -27,15 +27,15 @@ describe('IAM groups', () => { { MyGroupCBA54B1B: { Type: 'AWS::IAM::Group' }, User1E278A736: - { - Type: 'AWS::IAM::User', - Properties: { Groups: [{ Ref: 'MyGroupCBA54B1B' }] }, - }, + { + Type: 'AWS::IAM::User', + Properties: { Groups: [{ Ref: 'MyGroupCBA54B1B' }] }, + }, User21F1486D1: - { - Type: 'AWS::IAM::User', - Properties: { Groups: [{ Ref: 'MyGroupCBA54B1B' }] }, - }, + { + Type: 'AWS::IAM::User', + Properties: { Groups: [{ Ref: 'MyGroupCBA54B1B' }] }, + }, }, }); }); @@ -56,4 +56,21 @@ describe('IAM groups', () => { ], }); }); + + test('groups imported by group name have valid arn', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const group1 = Group.fromGroupName(stack, 'imported-group1', 'MyGroupName1'); + const group2 = Group.fromGroupName(stack, 'imported-group2', 'division/MyGroupName2'); + + // THEN + expect(stack.resolve(group1.groupArn)).toStrictEqual({ + 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::', { Ref: 'AWS::AccountId' }, ':group/MyGroupName1']], + }); + expect(stack.resolve(group2.groupArn)).toStrictEqual({ + 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::', { Ref: 'AWS::AccountId' }, ':group/division/MyGroupName2']], + }); + }); }); From cda66013afa6f8aa16d802bb2ab08dab1e5124cf Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Wed, 24 Nov 2021 16:54:18 +0100 Subject: [PATCH 05/82] fix(core): bundling skipped with --exclusively option and stacks under stage (#17210) We were comparing bundling stacks of the form `Stage/Stack` with stack names of the form `Stage-Stack`. For stacks with `NodejsFunction`s this leads to assets containing the whole CDK project because when bundling is skipped the asset references the source directory which is the project root. Closes #12898 Closes #15346 ---- *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/asset-staging.ts | 3 +- packages/@aws-cdk/core/test/staging.test.ts | 34 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/core/lib/asset-staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts index c948bc377c9a6..5ecafd9d3da56 100644 --- a/packages/@aws-cdk/core/lib/asset-staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -189,7 +189,8 @@ export class AssetStaging extends CoreConstruct { if (props.bundling) { // Check if we actually have to bundle for this stack const bundlingStacks: string[] = this.node.tryGetContext(cxapi.BUNDLING_STACKS) ?? ['*']; - skip = !bundlingStacks.find(pattern => minimatch(Stack.of(this).stackName, pattern)); + // bundlingStacks is of the form `Stage/Stack`, convert it to `Stage-Stack` before comparing to stack name + skip = !bundlingStacks.find(pattern => minimatch(Stack.of(this).stackName, pattern.replace('/', '-'))); const bundling = props.bundling; stageThisAsset = () => this.stageByBundling(bundling, skip); } else { diff --git a/packages/@aws-cdk/core/test/staging.test.ts b/packages/@aws-cdk/core/test/staging.test.ts index 9c2c0a0f111b1..6b2bd8e76e9e4 100644 --- a/packages/@aws-cdk/core/test/staging.test.ts +++ b/packages/@aws-cdk/core/test/staging.test.ts @@ -859,8 +859,42 @@ describe('staging', () => { expect(asset.stagedPath).toEqual(directory); expect(asset.relativeStagedPath(stack)).toEqual(directory); expect(asset.assetHash).toEqual('f66d7421aa2d044a6c1f60ddfc76dc78571fcd8bd228eb48eb394e2dbad94a5c'); + }); + + test('correctly skips bundling with stack under stage', () => { + // GIVEN + const app = new App(); + + const stage = new Stage(app, 'Stage'); + stage.node.setContext(cxapi.BUNDLING_STACKS, ['Stage/Stack1']); + + const stack1 = new Stack(stage, 'Stack1'); + const stack2 = new Stack(stage, 'Stack2'); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1'); + new AssetStaging(stack1, 'Asset', { + sourcePath: directory, + assetHashType: AssetHashType.OUTPUT, + bundling: { + image: DockerImage.fromRegistry('alpine'), + command: [DockerStubCommand.SUCCESS], + }, + }); + + new AssetStaging(stack2, 'Asset', { + sourcePath: directory, + assetHashType: AssetHashType.OUTPUT, + bundling: { + image: DockerImage.fromRegistry('alpine'), + command: [DockerStubCommand.MULTIPLE_FILES], + }, + }); + const dockerStubInput = readDockerStubInputConcat(); + // Docker ran for the asset in Stack1 + expect(dockerStubInput).toMatch(DockerStubCommand.SUCCESS); + // DOcker did not run for the asset in Stack2 + expect(dockerStubInput).not.toMatch(DockerStubCommand.MULTIPLE_FILES); }); test('bundling still occurs with partial wildcard', () => { From 01382921f979b944df1917964f080ce311e99ad2 Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Wed, 24 Nov 2021 09:36:35 -0700 Subject: [PATCH 06/82] feat(ec2): add r6i instances (#17663) New R6I instances just got released: https://aws.amazon.com/about-aws/whats-new/2021/11/amazon-ec2-r6i-instances/ Docs have already been updated: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-instancetype ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/instance-types.ts | 10 ++++++++++ packages/@aws-cdk/aws-ec2/test/instance.test.ts | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index ec5f2b91e17e7..5fafb03327873 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -118,6 +118,16 @@ export enum InstanceClass { */ R5 = 'r5', + /** + * Memory optimized instances, 6th generation with Intel Xeon Scalable processors (3rd generation processors code named Ice Lake) + */ + MEMORY6_INTEL = 'r6i', + + /** + * Memory optimized instances, 6th generation with Intel Xeon Scalable processors (3rd generation processors code named Ice Lake) + */ + R6I = 'r6i', + /** * Memory optimized instances for high performance computing, 5th generation */ diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index 4a0f40ae1df8f..21f7277200a99 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -138,7 +138,7 @@ describe('instance', () => { }); test('instance architecture is correctly discerned for x86-64 instance', () => { // GIVEN - const sampleInstanceClasses = ['c5', 'm5ad', 'r5n', 'm6', 't3a']; // A sample of x86-64 instance classes + const sampleInstanceClasses = ['c5', 'm5ad', 'r5n', 'm6', 't3a', 'r6i']; // A sample of x86-64 instance classes for (const instanceClass of sampleInstanceClasses) { // WHEN From ea0acff28c3f64c9511fdd580f52211df9460a45 Mon Sep 17 00:00:00 2001 From: Ayush Goyal Date: Wed, 24 Nov 2021 22:48:30 +0530 Subject: [PATCH 07/82] feat(cloudfront): Add support for response headers policy (#17359) feat(cloudfront): Add support for response headers policy closes #17290 Notes: ~1. Currently the CFNSpec is not up-to-date with the latest available cloudformation changes for `ResponseHeadersPolicyId` in `AWS::CloudFront::Distribution CacheBehavior`. Some aspects of the same are added to the PR but are left commented. Would update the PR once the spec is updated.~ Refs: 1. https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-response-headers.html 2. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-responseheaderspolicy.html 3. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-cachebehavior.html#cfn-cloudfront-distribution-cachebehavior-responseheaderspolicyid ---- *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-cloudfront/README.md | 52 ++ .../aws-cloudfront/lib/distribution.ts | 8 + packages/@aws-cdk/aws-cloudfront/lib/index.ts | 1 + .../lib/private/cache-behavior.ts | 1 + .../lib/response-headers-policy.ts | 456 ++++++++++++++++++ packages/@aws-cdk/aws-cloudfront/package.json | 5 +- .../integ.distribution-policies.expected.json | 41 +- .../test/integ.distribution-policies.ts | 14 + .../test/response-headers-policy.test.ts | 146 ++++++ 9 files changed, 722 insertions(+), 2 deletions(-) create mode 100644 packages/@aws-cdk/aws-cloudfront/lib/response-headers-policy.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/test/response-headers-policy.test.ts diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index e10f5c39d596b..e87a4f9b56617 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -260,6 +260,58 @@ new cloudfront.Distribution(this, 'myDistCustomPolicy', { }); ``` +### Customizing Response Headers with Response Headers Policies + +You can configure CloudFront to add one or more HTTP headers to the responses that it sends to viewers (web browsers or other clients), without making any changes to the origin or writing any code. +To specify the headers that CloudFront adds to HTTP responses, you use a response headers policy. CloudFront adds the headers regardless of whether it serves the object from the cache or has to retrieve the object from the origin. If the origin response includes one or more of the headers that’s in a response headers policy, the policy can specify whether CloudFront uses the header it received from the origin or overwrites it with the one in the policy. +See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-response-headers.html + +```ts +// Using an existing managed response headers policy +declare const bucketOrigin: origins.S3Origin; +new cloudfront.Distribution(this, 'myDistManagedPolicy', { + defaultBehavior: { + origin: bucketOrigin, + responseHeadersPolicy: cloudfront.ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS, + }, +}); + +// Creating a custom response headers policy -- all parameters optional +const myResponseHeadersPolicy = new cloudfront.ResponseHeadersPolicy(this, 'ResponseHeadersPolicy', { + responseHeadersPolicyName: 'MyPolicy', + comment: 'A default policy', + corsBehavior: { + accessControlAllowCredentials: false, + accessControlAllowHeaders: ['X-Custom-Header-1', 'X-Custom-Header-2'], + accessControlAllowMethods: ['GET', 'POST'], + accessControlAllowOrigins: ['*'], + accessControlExposeHeaders: ['X-Custom-Header-1', 'X-Custom-Header-2'], + accessControlMaxAge: Duration.seconds(600), + originOverride: true, + }, + customHeadersBehavior: { + customHeaders: [ + { header: 'X-Amz-Date', value: 'some-value', override: true }, + { header: 'X-Amz-Security-Token', value: 'some-value', override: false }, + ], + }, + securityHeadersBehavior: { + contentSecurityPolicy: { contentSecurityPolicy: 'default-src https:;', override: true }, + contentTypeOptions: { override: true }, + frameOptions: { frameOption: cloudfront.HeadersFrameOption.DENY, override: true }, + referrerPolicy: { referrerPolicy: cloudfront.HeadersReferrerPolicy.NO_REFERRER, override: true }, + strictTransportSecurity: { accessControlMaxAge: Duration.seconds(600), includeSubdomains: true, override: true }, + xssProtection: { protection: true, modeBlock: true, reportUri: 'https://example.com/csp-report', override: true }, + }, +}); +new cloudfront.Distribution(this, 'myDistCustomPolicy', { + defaultBehavior: { + origin: bucketOrigin, + responseHeadersPolicy: myResponseHeadersPolicy, + }, +}); +``` + ### Validating signed URLs or signed cookies with Trusted Key Groups CloudFront Distribution supports validating signed URLs or signed cookies using key groups. diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index 517a73bcc8917..c593edd9efec7 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -12,6 +12,7 @@ import { IKeyGroup } from './key-group'; import { IOrigin, OriginBindConfig, OriginBindOptions } from './origin'; import { IOriginRequestPolicy } from './origin-request-policy'; import { CacheBehavior } from './private/cache-behavior'; +import { IResponseHeadersPolicy } from './response-headers-policy'; // v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch. // eslint-disable-next-line @@ -700,6 +701,13 @@ export interface AddBehaviorOptions { */ readonly originRequestPolicy?: IOriginRequestPolicy; + /** + * The response headers policy for this behavior. The response headers policy determines which headers are included in responses + * + * @default - none + */ + readonly responseHeadersPolicy?: IResponseHeadersPolicy; + /** * Set this to true to indicate you want to distribute media files in the Microsoft Smooth Streaming format using this behavior. * diff --git a/packages/@aws-cdk/aws-cloudfront/lib/index.ts b/packages/@aws-cdk/aws-cloudfront/lib/index.ts index 74b5b4644919c..e5abe99c0bfbd 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/index.ts @@ -7,6 +7,7 @@ export * from './origin'; export * from './origin-access-identity'; export * from './origin-request-policy'; export * from './public-key'; +export * from './response-headers-policy'; export * from './web-distribution'; export * as experimental from './experimental'; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/private/cache-behavior.ts b/packages/@aws-cdk/aws-cloudfront/lib/private/cache-behavior.ts index 4e6f71589bb7e..43d31bd976f40 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/private/cache-behavior.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/private/cache-behavior.ts @@ -48,6 +48,7 @@ export class CacheBehavior { cachePolicyId: (this.props.cachePolicy ?? CachePolicy.CACHING_OPTIMIZED).cachePolicyId, compress: this.props.compress ?? true, originRequestPolicyId: this.props.originRequestPolicy?.originRequestPolicyId, + responseHeadersPolicyId: this.props.responseHeadersPolicy?.responseHeadersPolicyId, smoothStreaming: this.props.smoothStreaming, viewerProtocolPolicy: this.props.viewerProtocolPolicy ?? ViewerProtocolPolicy.ALLOW_ALL, functionAssociations: this.props.functionAssociations?.map(association => ({ diff --git a/packages/@aws-cdk/aws-cloudfront/lib/response-headers-policy.ts b/packages/@aws-cdk/aws-cloudfront/lib/response-headers-policy.ts new file mode 100644 index 0000000000000..4e974454b3925 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/lib/response-headers-policy.ts @@ -0,0 +1,456 @@ +import { Duration, Names, Resource } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnResponseHeadersPolicy } from './cloudfront.generated'; + +/** + * Represents a response headers policy. + */ +export interface IResponseHeadersPolicy { + /** + * The ID of the response headers policy + * @attribute + **/ + readonly responseHeadersPolicyId: string; +} + +/** + * Properties for creating a Response Headers Policy + */ +export interface ResponseHeadersPolicyProps { + /** + * A unique name to identify the response headers policy. + * + * @default - generated from the `id` + */ + readonly responseHeadersPolicyName?: string; + + /** + * A comment to describe the response headers policy. + * + * @default - no comment + */ + readonly comment?: string; + + /** + * A configuration for a set of HTTP response headers that are used for cross-origin resource sharing (CORS). + * + * @default - no cors behavior + */ + readonly corsBehavior?: ResponseHeadersCorsBehavior; + + /** + * A configuration for a set of custom HTTP response headers. + * + * @default - no custom headers behavior + */ + readonly customHeadersBehavior?: ResponseCustomHeadersBehavior; + + /** + * A configuration for a set of security-related HTTP response headers. + * + * @default - no security headers behavior + */ + readonly securityHeadersBehavior?: ResponseSecurityHeadersBehavior; +} + +/** + * A Response Headers Policy configuration + * + * @resource AWS::CloudFront::ResponseHeadersPolicy + */ +export class ResponseHeadersPolicy extends Resource implements IResponseHeadersPolicy { + + /** Use this managed policy to allow simple CORS requests from any origin. */ + public static readonly CORS_ALLOW_ALL_ORIGINS = ResponseHeadersPolicy.fromManagedResponseHeadersPolicy('60669652-455b-4ae9-85a4-c4c02393f86c'); + /** Use this managed policy to allow CORS requests from any origin, including preflight requests. */ + public static readonly CORS_ALLOW_ALL_ORIGINS_WITH_PREFLIGHT = ResponseHeadersPolicy.fromManagedResponseHeadersPolicy('5cc3b908-e619-4b99-88e5-2cf7f45965bd'); + /** Use this managed policy to add a set of security headers to all responses that CloudFront sends to viewers. */ + public static readonly SECURITY_HEADERS = ResponseHeadersPolicy.fromManagedResponseHeadersPolicy('67f7725c-6f97-4210-82d7-5512b31e9d03'); + /** Use this managed policy to allow simple CORS requests from any origin and add a set of security headers to all responses that CloudFront sends to viewers. */ + public static readonly CORS_ALLOW_ALL_ORIGINS_AND_SECURITY_HEADERS = ResponseHeadersPolicy.fromManagedResponseHeadersPolicy('e61eb60c-9c35-4d20-a928-2b84e02af89c'); + /** Use this managed policy to allow CORS requests from any origin, including preflight requests, and add a set of security headers to all responses that CloudFront sends to viewers. */ + public static readonly CORS_ALLOW_ALL_ORIGINS_WITH_PREFLIGHT_AND_SECURITY_HEADERS = ResponseHeadersPolicy.fromManagedResponseHeadersPolicy('eaab4381-ed33-4a86-88ca-d9558dc6cd63'); + + /** + * Import an existing Response Headers Policy from its ID. + */ + public static fromResponseHeadersPolicyId(scope: Construct, id: string, responseHeadersPolicyId: string): IResponseHeadersPolicy { + class Import extends Resource implements IResponseHeadersPolicy { + public readonly responseHeadersPolicyId = responseHeadersPolicyId; + } + return new Import(scope, id); + } + + private static fromManagedResponseHeadersPolicy(managedResponseHeadersPolicyId: string): IResponseHeadersPolicy { + return new class implements IResponseHeadersPolicy { + public readonly responseHeadersPolicyId = managedResponseHeadersPolicyId; + }; + } + + public readonly responseHeadersPolicyId: string; + + constructor(scope: Construct, id: string, props: ResponseHeadersPolicyProps = {}) { + super(scope, id, { + physicalName: props.responseHeadersPolicyName, + }); + + const responseHeadersPolicyName = props.responseHeadersPolicyName ?? Names.uniqueId(this); + + const resource = new CfnResponseHeadersPolicy(this, 'Resource', { + responseHeadersPolicyConfig: { + name: responseHeadersPolicyName, + comment: props.comment, + corsConfig: props.corsBehavior ? this._renderCorsConfig(props.corsBehavior) : undefined, + customHeadersConfig: props.customHeadersBehavior ? this._renderCustomHeadersConfig(props.customHeadersBehavior) : undefined, + securityHeadersConfig: props.securityHeadersBehavior ? this._renderSecurityHeadersConfig(props.securityHeadersBehavior) : undefined, + }, + }); + + this.responseHeadersPolicyId = resource.ref; + } + + private _renderCorsConfig(behavior: ResponseHeadersCorsBehavior): CfnResponseHeadersPolicy.CorsConfigProperty { + return { + accessControlAllowCredentials: behavior.accessControlAllowCredentials, + accessControlAllowHeaders: { items: behavior.accessControlAllowHeaders }, + accessControlAllowMethods: { items: behavior.accessControlAllowMethods }, + accessControlAllowOrigins: { items: behavior.accessControlAllowOrigins }, + accessControlExposeHeaders: behavior.accessControlExposeHeaders ? { items: behavior.accessControlExposeHeaders } : undefined, + accessControlMaxAgeSec: behavior.accessControlMaxAge ? behavior.accessControlMaxAge.toSeconds() : undefined, + originOverride: behavior.originOverride, + }; + } + + private _renderCustomHeadersConfig(behavior: ResponseCustomHeadersBehavior): CfnResponseHeadersPolicy.CustomHeadersConfigProperty { + return { + items: behavior.customHeaders, + }; + } + + private _renderSecurityHeadersConfig(behavior: ResponseSecurityHeadersBehavior): CfnResponseHeadersPolicy.SecurityHeadersConfigProperty { + return { + contentSecurityPolicy: behavior.contentSecurityPolicy, + contentTypeOptions: behavior.contentTypeOptions, + frameOptions: behavior.frameOptions, + referrerPolicy: behavior.referrerPolicy, + strictTransportSecurity: behavior.strictTransportSecurity ? { + ...behavior.strictTransportSecurity, + accessControlMaxAgeSec: behavior.strictTransportSecurity.accessControlMaxAge.toSeconds(), + }: undefined, + xssProtection: behavior.xssProtection, + }; + } +} + +/** + * Configuration for a set of HTTP response headers that are used for cross-origin resource sharing (CORS). + * CloudFront adds these headers to HTTP responses that it sends for CORS requests that match a cache behavior + * associated with this response headers policy. + */ +export interface ResponseHeadersCorsBehavior { + /** + * A Boolean that CloudFront uses as the value for the Access-Control-Allow-Credentials HTTP response header. + */ + readonly accessControlAllowCredentials: boolean; + + /** + * A list of HTTP header names that CloudFront includes as values for the Access-Control-Allow-Headers HTTP response header. + * You can specify `['*']` to allow all headers. + */ + readonly accessControlAllowHeaders: string[]; + + /** + * A list of HTTP methods that CloudFront includes as values for the Access-Control-Allow-Methods HTTP response header. + */ + readonly accessControlAllowMethods: string[]; + + /** + * A list of origins (domain names) that CloudFront can use as the value for the Access-Control-Allow-Origin HTTP response header. + * You can specify `['*']` to allow all origins. + */ + readonly accessControlAllowOrigins: string[]; + + /** + * A list of HTTP headers that CloudFront includes as values for the Access-Control-Expose-Headers HTTP response header. + * You can specify `['*']` to expose all headers. + * + * @default - no headers exposed + */ + readonly accessControlExposeHeaders?: string[]; + + /** + * A number that CloudFront uses as the value for the Access-Control-Max-Age HTTP response header. + * + * @default - no max age + */ + readonly accessControlMaxAge?: Duration; + + /** + * A Boolean that determines whether CloudFront overrides HTTP response headers received from the origin with the ones specified in this response headers policy. + */ + readonly originOverride: boolean; +} + +/** + * Configuration for a set of HTTP response headers that are sent for requests that match a cache behavior + * that’s associated with this response headers policy. + */ +export interface ResponseCustomHeadersBehavior { + /** + * The list of HTTP response headers and their values. + */ + readonly customHeaders: ResponseCustomHeader[]; +} + +/** + * An HTTP response header name and its value. + * CloudFront includes this header in HTTP responses that it sends for requests that match a cache behavior that’s associated with this response headers policy. + */ +export interface ResponseCustomHeader { + /** + * The HTTP response header name. + */ + readonly header: string; + + /** + * A Boolean that determines whether CloudFront overrides a response header with the same name + * received from the origin with the header specified here. + */ + readonly override: boolean; + + /** + * The value for the HTTP response header. + */ + readonly value: string; +} + +/** + * Configuration for a set of security-related HTTP response headers. + * CloudFront adds these headers to HTTP responses that it sends for requests that match a cache behavior + * associated with this response headers policy. + */ +export interface ResponseSecurityHeadersBehavior { + /** + * The policy directives and their values that CloudFront includes as values for the Content-Security-Policy HTTP response header. + * + * @default - no content security policy + */ + readonly contentSecurityPolicy?: ResponseHeadersContentSecurityPolicy; + + /** + * Determines whether CloudFront includes the X-Content-Type-Options HTTP response header with its value set to nosniff. + * + * @default - no content type options + */ + readonly contentTypeOptions?: ResponseHeadersContentTypeOptions; + + /** + * Determines whether CloudFront includes the X-Frame-Options HTTP response header and the header’s value. + * + * @default - no frame options + */ + readonly frameOptions?: ResponseHeadersFrameOptions; + + /** + * Determines whether CloudFront includes the Referrer-Policy HTTP response header and the header’s value. + * + * @default - no referrer policy + */ + readonly referrerPolicy?: ResponseHeadersReferrerPolicy; + + /** + * Determines whether CloudFront includes the Strict-Transport-Security HTTP response header and the header’s value. + * + * @default - no strict transport security + */ + readonly strictTransportSecurity?: ResponseHeadersStrictTransportSecurity; + + /** + * Determines whether CloudFront includes the X-XSS-Protection HTTP response header and the header’s value. + * + * @default - no xss protection + */ + readonly xssProtection?: ResponseHeadersXSSProtection; +} + +/** + * The policy directives and their values that CloudFront includes as values for the Content-Security-Policy HTTP response header. + */ +export interface ResponseHeadersContentSecurityPolicy { + /** + * The policy directives and their values that CloudFront includes as values for the Content-Security-Policy HTTP response header. + */ + readonly contentSecurityPolicy: string; + + /** + * A Boolean that determines whether CloudFront overrides the Content-Security-Policy HTTP response header + * received from the origin with the one specified in this response headers policy. + */ + readonly override: boolean; +} + +/** + * Determines whether CloudFront includes the X-Content-Type-Options HTTP response header with its value set to nosniff. + */ +export interface ResponseHeadersContentTypeOptions { + /** + * A Boolean that determines whether CloudFront overrides the X-Content-Type-Options HTTP response header + * received from the origin with the one specified in this response headers policy. + */ + readonly override: boolean; +} + +/** + * Determines whether CloudFront includes the X-Frame-Options HTTP response header and the header’s value. + */ +export interface ResponseHeadersFrameOptions { + /** + * The value of the X-Frame-Options HTTP response header. + */ + readonly frameOption: HeadersFrameOption; + + /** + * A Boolean that determines whether CloudFront overrides the X-Frame-Options HTTP response header + * received from the origin with the one specified in this response headers policy. + */ + readonly override: boolean; +} + +/** + * Determines whether CloudFront includes the Referrer-Policy HTTP response header and the header’s value. + */ +export interface ResponseHeadersReferrerPolicy { + /** + * The value of the Referrer-Policy HTTP response header. + */ + readonly referrerPolicy: HeadersReferrerPolicy; + + /** + * A Boolean that determines whether CloudFront overrides the Referrer-Policy HTTP response header + * received from the origin with the one specified in this response headers policy. + */ + readonly override: boolean; +} + +/** + * Determines whether CloudFront includes the Strict-Transport-Security HTTP response header and the header’s value. + */ +export interface ResponseHeadersStrictTransportSecurity { + /** + * A number that CloudFront uses as the value for the max-age directive in the Strict-Transport-Security HTTP response header. + */ + readonly accessControlMaxAge: Duration; + + /** + * A Boolean that determines whether CloudFront includes the includeSubDomains directive in the Strict-Transport-Security HTTP response header. + * + * @default false + */ + readonly includeSubdomains?: boolean; + + /** + * A Boolean that determines whether CloudFront overrides the Strict-Transport-Security HTTP response header + * received from the origin with the one specified in this response headers policy. + */ + readonly override: boolean; + + /** + * A Boolean that determines whether CloudFront includes the preload directive in the Strict-Transport-Security HTTP response header. + * + * @default false + */ + readonly preload?: boolean; +} + +/** + * Determines whether CloudFront includes the X-XSS-Protection HTTP response header and the header’s value. + */ +export interface ResponseHeadersXSSProtection { + /** + * A Boolean that determines whether CloudFront includes the mode=block directive in the X-XSS-Protection header. + * + * @default false + */ + readonly modeBlock?: boolean; + + /** + * A Boolean that determines whether CloudFront overrides the X-XSS-Protection HTTP response header + * received from the origin with the one specified in this response headers policy. + */ + readonly override: boolean; + + /** + * A Boolean that determines the value of the X-XSS-Protection HTTP response header. + * When this setting is true, the value of the X-XSS-Protection header is 1. + * When this setting is false, the value of the X-XSS-Protection header is 0. + */ + readonly protection: boolean; + + /** + * A reporting URI, which CloudFront uses as the value of the report directive in the X-XSS-Protection header. + * You cannot specify a ReportUri when ModeBlock is true. + * + * @default - no report uri + */ + readonly reportUri?: string; +} + +/** + * Enum representing possible values of the X-Frame-Options HTTP response header. + */ +export enum HeadersFrameOption { + /** + * The page can only be displayed in a frame on the same origin as the page itself. + */ + DENY = 'DENY', + + /** + * The page can only be displayed in a frame on the specified origin. + */ + SAMEORIGIN = 'SAMEORIGIN', +} + +/** + * Enum representing possible values of the Referrer-Policy HTTP response header. + */ +export enum HeadersReferrerPolicy { + /** + * The referrer policy is not set. + */ + NO_REFERRER = 'no-referrer', + + /** + * The referrer policy is no-referrer-when-downgrade. + */ + NO_REFERRER_WHEN_DOWNGRADE = 'no-referrer-when-downgrade', + + /** + * The referrer policy is origin. + */ + ORIGIN = 'origin', + + /** + * The referrer policy is origin-when-cross-origin. + */ + ORIGIN_WHEN_CROSS_ORIGIN = 'origin-when-cross-origin', + + /** + * The referrer policy is same-origin. + */ + SAME_ORIGIN = 'same-origin', + + /** + * The referrer policy is strict-origin. + */ + STRICT_ORIGIN = 'strict-origin', + + /** + * The referrer policy is strict-origin-when-cross-origin. + */ + STRICT_ORIGIN_WHEN_CROSS_ORIGIN = 'strict-origin-when-cross-origin', + + /** + * The referrer policy is unsafe-url. + */ + UNSAFE_URL = 'unsafe-url', +} diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index b0fdf92f48da2..145e02736b1f7 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -169,7 +169,10 @@ "resource-attribute:@aws-cdk/aws-cloudfront.KeyGroup.keyGroupLastModifiedTime", "resource-attribute:@aws-cdk/aws-cloudfront.PublicKey.publicKeyCreatedTime", "resource-attribute:@aws-cdk/aws-cloudfront.OriginAccessIdentity.cloudFrontOriginAccessIdentityId", - "resource-attribute:@aws-cdk/aws-cloudfront.Function.functionMetadataFunctionArn" + "resource-attribute:@aws-cdk/aws-cloudfront.Function.functionMetadataFunctionArn", + "construct-interface-extends-iconstruct:@aws-cdk/aws-cloudfront.IResponseHeadersPolicy", + "resource-interface-extends-resource:@aws-cdk/aws-cloudfront.IResponseHeadersPolicy", + "resource-attribute:@aws-cdk/aws-cloudfront.ResponseHeadersPolicy.responseHeadersPolicyLastModifiedTime" ] }, "awscdkio": { diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-policies.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-policies.expected.json index bf8b74f747b46..a09b1d2e38f09 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-policies.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-policies.expected.json @@ -12,8 +12,8 @@ "CookiesConfig": { "CookieBehavior": "none" }, - "EnableAcceptEncodingGzip": false, "EnableAcceptEncodingBrotli": false, + "EnableAcceptEncodingGzip": false, "HeadersConfig": { "HeaderBehavior": "none" }, @@ -44,6 +44,42 @@ } } }, + "ResponseHeadersPolicy13DBF9E0": { + "Type": "AWS::CloudFront::ResponseHeadersPolicy", + "Properties": { + "ResponseHeadersPolicyConfig": { + "CorsConfig": { + "AccessControlAllowCredentials": false, + "AccessControlAllowHeaders": { + "Items": [ + "X-Custom-Header-1", + "X-Custom-Header-2" + ] + }, + "AccessControlAllowMethods": { + "Items": [ + "GET", + "POST" + ] + }, + "AccessControlAllowOrigins": { + "Items": [ + "*" + ] + }, + "AccessControlExposeHeaders": { + "Items": [ + "X-Custom-Header-1", + "X-Custom-Header-2" + ] + }, + "AccessControlMaxAgeSec": 600, + "OriginOverride": true + }, + "Name": "ACustomResponseHeadersPolicy" + } + } + }, "DistB3B78991": { "Type": "AWS::CloudFront::Distribution", "Properties": { @@ -56,6 +92,9 @@ "OriginRequestPolicyId": { "Ref": "OriginRequestPolicy3EFDB4FA" }, + "ResponseHeadersPolicyId": { + "Ref": "ResponseHeadersPolicy13DBF9E0" + }, "TargetOriginId": "integdistributionpoliciesDistOrigin17849EF2C", "ViewerProtocolPolicy": "allow-all" }, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-policies.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-policies.ts index 8da36a18129a4..681c579a2eb45 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-policies.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-policies.ts @@ -14,11 +14,25 @@ const originRequestPolicy = new cloudfront.OriginRequestPolicy(stack, 'OriginReq headerBehavior: cloudfront.OriginRequestHeaderBehavior.all('CloudFront-Forwarded-Proto'), }); +const responseHeadersPolicy = new cloudfront.ResponseHeadersPolicy(stack, 'ResponseHeadersPolicy', { + responseHeadersPolicyName: 'ACustomResponseHeadersPolicy', + corsBehavior: { + accessControlAllowCredentials: false, + accessControlAllowHeaders: ['X-Custom-Header-1', 'X-Custom-Header-2'], + accessControlAllowMethods: ['GET', 'POST'], + accessControlAllowOrigins: ['*'], + accessControlExposeHeaders: ['X-Custom-Header-1', 'X-Custom-Header-2'], + accessControlMaxAge: cdk.Duration.seconds(600), + originOverride: true, + }, +}); + new cloudfront.Distribution(stack, 'Dist', { defaultBehavior: { origin: new TestOrigin('www.example.com'), cachePolicy, originRequestPolicy, + responseHeadersPolicy, }, }); diff --git a/packages/@aws-cdk/aws-cloudfront/test/response-headers-policy.test.ts b/packages/@aws-cdk/aws-cloudfront/test/response-headers-policy.test.ts new file mode 100644 index 0000000000000..926b17d85a219 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/response-headers-policy.test.ts @@ -0,0 +1,146 @@ +import '@aws-cdk/assert-internal/jest'; +import { App, Duration, Stack } from '@aws-cdk/core'; +import { HeadersFrameOption, HeadersReferrerPolicy, ResponseHeadersPolicy } from '../lib'; + +describe('ResponseHeadersPolicy', () => { + let app: App; + let stack: Stack; + + beforeEach(() => { + app = new App(); + stack = new Stack(app, 'Stack', { + env: { account: '123456789012', region: 'testregion' }, + }); + }); + + test('import existing policy by id', () => { + const responseHeadersPolicyId = '344f6fe5-7ce5-4df0-a470-3f14177c549c'; + const responseHeadersPolicy = ResponseHeadersPolicy.fromResponseHeadersPolicyId(stack, 'MyPolicy', responseHeadersPolicyId); + expect(responseHeadersPolicy.responseHeadersPolicyId).toEqual(responseHeadersPolicyId); + }); + + test('managed policies are provided', () => { + expect(ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS.responseHeadersPolicyId).toEqual('60669652-455b-4ae9-85a4-c4c02393f86c'); + expect(ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS_WITH_PREFLIGHT.responseHeadersPolicyId).toEqual('5cc3b908-e619-4b99-88e5-2cf7f45965bd'); + expect(ResponseHeadersPolicy.SECURITY_HEADERS.responseHeadersPolicyId).toEqual('67f7725c-6f97-4210-82d7-5512b31e9d03'); + expect(ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS_AND_SECURITY_HEADERS.responseHeadersPolicyId).toEqual('e61eb60c-9c35-4d20-a928-2b84e02af89c'); + expect(ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS_WITH_PREFLIGHT_AND_SECURITY_HEADERS.responseHeadersPolicyId).toEqual('eaab4381-ed33-4a86-88ca-d9558dc6cd63'); + }); + + test('minimal example', () => { + new ResponseHeadersPolicy(stack, 'ResponseHeadersPolicy'); + + expect(stack).toHaveResource('AWS::CloudFront::ResponseHeadersPolicy', { + ResponseHeadersPolicyConfig: { + Name: 'StackResponseHeadersPolicy7B76F936', + }, + }); + }); + + test('maximum example', () => { + new ResponseHeadersPolicy(stack, 'ResponseHeadersPolicy', { + responseHeadersPolicyName: 'MyPolicy', + comment: 'A default policy', + corsBehavior: { + accessControlAllowCredentials: false, + accessControlAllowHeaders: ['X-Custom-Header-1', 'X-Custom-Header-2'], + accessControlAllowMethods: ['GET', 'POST'], + accessControlAllowOrigins: ['*'], + accessControlExposeHeaders: ['X-Custom-Header-1', 'X-Custom-Header-2'], + accessControlMaxAge: Duration.seconds(600), + originOverride: true, + }, + customHeadersBehavior: { + customHeaders: [ + { header: 'X-Custom-Header-1', value: 'application/json', override: true }, + { header: 'X-Custom-Header-2', value: '0', override: false }, + ], + }, + securityHeadersBehavior: { + contentSecurityPolicy: { contentSecurityPolicy: 'default-src https:;', override: true }, + contentTypeOptions: { override: true }, + frameOptions: { frameOption: HeadersFrameOption.DENY, override: true }, + referrerPolicy: { referrerPolicy: HeadersReferrerPolicy.NO_REFERRER, override: true }, + strictTransportSecurity: { accessControlMaxAge: Duration.seconds(600), includeSubdomains: true, override: true }, + xssProtection: { protection: true, modeBlock: true, reportUri: 'https://example.com/csp-report', override: true }, + }, + }); + + expect(stack).toHaveResource('AWS::CloudFront::ResponseHeadersPolicy', { + ResponseHeadersPolicyConfig: { + Comment: 'A default policy', + CorsConfig: { + AccessControlAllowCredentials: false, + AccessControlAllowHeaders: { + Items: [ + 'X-Custom-Header-1', + 'X-Custom-Header-2', + ], + }, + AccessControlAllowMethods: { + Items: [ + 'GET', + 'POST', + ], + }, + AccessControlAllowOrigins: { + Items: [ + '*', + ], + }, + AccessControlExposeHeaders: { + Items: [ + 'X-Custom-Header-1', + 'X-Custom-Header-2', + ], + }, + AccessControlMaxAgeSec: 600, + OriginOverride: true, + }, + CustomHeadersConfig: { + Items: [ + { + Header: 'X-Custom-Header-1', + Override: true, + Value: 'application/json', + }, + { + Header: 'X-Custom-Header-2', + Override: false, + Value: '0', + }, + ], + }, + Name: 'MyPolicy', + SecurityHeadersConfig: { + ContentSecurityPolicy: { + ContentSecurityPolicy: 'default-src https:;', + Override: true, + }, + ContentTypeOptions: { + Override: true, + }, + FrameOptions: { + FrameOption: 'DENY', + Override: true, + }, + ReferrerPolicy: { + Override: true, + ReferrerPolicy: 'no-referrer', + }, + StrictTransportSecurity: { + AccessControlMaxAgeSec: 600, + IncludeSubdomains: true, + Override: true, + }, + XSSProtection: { + ModeBlock: true, + Override: true, + Protection: true, + ReportUri: 'https://example.com/csp-report', + }, + }, + }, + }); + }); +}); From 6c7550b9ce57029e97c50732bb054f3b4490809c Mon Sep 17 00:00:00 2001 From: AWS CDK Automation <43080478+aws-cdk-automation@users.noreply.github.com> Date: Wed, 24 Nov 2021 23:30:59 +0530 Subject: [PATCH 08/82] chore: npm-check-updates && yarn upgrade (#17687) Ran npm-check-updates and yarn upgrade to keep the `yarn.lock` file up-to-date. --- .../ecs-service-extensions/package.json | 2 +- packages/@aws-cdk/alexa-ask/package.json | 2 +- packages/@aws-cdk/app-delivery/package.json | 2 +- .../@aws-cdk/assert-internal/package.json | 2 +- packages/@aws-cdk/assert/package.json | 2 +- packages/@aws-cdk/assertions/package.json | 2 +- packages/@aws-cdk/assets/package.json | 2 +- .../@aws-cdk/aws-accessanalyzer/package.json | 2 +- packages/@aws-cdk/aws-acmpca/package.json | 2 +- packages/@aws-cdk/aws-amazonmq/package.json | 2 +- packages/@aws-cdk/aws-amplify/package.json | 2 +- packages/@aws-cdk/aws-apigateway/package.json | 2 +- .../aws-apigatewayv2-authorizers/package.json | 2 +- .../package.json | 2 +- .../@aws-cdk/aws-apigatewayv2/package.json | 2 +- packages/@aws-cdk/aws-appconfig/package.json | 2 +- packages/@aws-cdk/aws-appflow/package.json | 2 +- .../@aws-cdk/aws-appintegrations/package.json | 2 +- .../aws-applicationautoscaling/package.json | 2 +- .../aws-applicationinsights/package.json | 2 +- packages/@aws-cdk/aws-appmesh/package.json | 2 +- packages/@aws-cdk/aws-apprunner/package.json | 2 +- packages/@aws-cdk/aws-appstream/package.json | 2 +- packages/@aws-cdk/aws-appsync/package.json | 2 +- packages/@aws-cdk/aws-aps/package.json | 2 +- packages/@aws-cdk/aws-athena/package.json | 2 +- .../@aws-cdk/aws-auditmanager/package.json | 2 +- .../aws-autoscaling-common/package.json | 2 +- .../aws-autoscaling-hooktargets/package.json | 2 +- .../@aws-cdk/aws-autoscaling/package.json | 2 +- .../aws-autoscalingplans/package.json | 2 +- packages/@aws-cdk/aws-backup/package.json | 2 +- packages/@aws-cdk/aws-batch/package.json | 2 +- packages/@aws-cdk/aws-budgets/package.json | 2 +- packages/@aws-cdk/aws-cassandra/package.json | 2 +- packages/@aws-cdk/aws-ce/package.json | 2 +- .../aws-certificatemanager/package.json | 2 +- packages/@aws-cdk/aws-chatbot/package.json | 2 +- packages/@aws-cdk/aws-cloud9/package.json | 2 +- .../@aws-cdk/aws-cloudformation/package.json | 2 +- .../aws-cloudfront-origins/package.json | 2 +- packages/@aws-cdk/aws-cloudfront/package.json | 2 +- packages/@aws-cdk/aws-cloudtrail/package.json | 2 +- .../aws-cloudwatch-actions/package.json | 2 +- packages/@aws-cdk/aws-cloudwatch/package.json | 2 +- .../@aws-cdk/aws-codeartifact/package.json | 2 +- packages/@aws-cdk/aws-codebuild/package.json | 2 +- packages/@aws-cdk/aws-codecommit/package.json | 2 +- packages/@aws-cdk/aws-codedeploy/package.json | 2 +- .../aws-codeguruprofiler/package.json | 2 +- .../aws-codegurureviewer/package.json | 2 +- .../aws-codepipeline-actions/package.json | 2 +- .../@aws-cdk/aws-codepipeline/package.json | 2 +- packages/@aws-cdk/aws-codestar/package.json | 2 +- .../aws-codestarconnections/package.json | 2 +- .../aws-codestarnotifications/package.json | 2 +- packages/@aws-cdk/aws-cognito/package.json | 2 +- packages/@aws-cdk/aws-config/package.json | 2 +- packages/@aws-cdk/aws-connect/package.json | 2 +- packages/@aws-cdk/aws-cur/package.json | 2 +- .../aws-customerprofiles/package.json | 2 +- packages/@aws-cdk/aws-databrew/package.json | 2 +- .../@aws-cdk/aws-datapipeline/package.json | 2 +- packages/@aws-cdk/aws-datasync/package.json | 2 +- packages/@aws-cdk/aws-dax/package.json | 2 +- packages/@aws-cdk/aws-detective/package.json | 2 +- packages/@aws-cdk/aws-devopsguru/package.json | 2 +- .../aws-directoryservice/package.json | 2 +- packages/@aws-cdk/aws-dlm/package.json | 2 +- packages/@aws-cdk/aws-dms/package.json | 2 +- packages/@aws-cdk/aws-docdb/package.json | 2 +- .../@aws-cdk/aws-dynamodb-global/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-ec2/package.json | 2 +- packages/@aws-cdk/aws-ecr-assets/package.json | 2 +- packages/@aws-cdk/aws-ecr/package.json | 2 +- .../@aws-cdk/aws-ecs-patterns/package.json | 2 +- packages/@aws-cdk/aws-ecs/package.json | 2 +- packages/@aws-cdk/aws-efs/package.json | 2 +- packages/@aws-cdk/aws-eks-legacy/package.json | 2 +- packages/@aws-cdk/aws-eks/package.json | 6 +- .../@aws-cdk/aws-elasticache/package.json | 2 +- .../aws-elasticbeanstalk/package.json | 2 +- .../aws-elasticloadbalancing/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../aws-elasticloadbalancingv2/package.json | 2 +- .../@aws-cdk/aws-elasticsearch/package.json | 2 +- packages/@aws-cdk/aws-emr/package.json | 2 +- .../@aws-cdk/aws-emrcontainers/package.json | 2 +- .../@aws-cdk/aws-events-targets/package.json | 2 +- packages/@aws-cdk/aws-events/package.json | 2 +- .../@aws-cdk/aws-eventschemas/package.json | 2 +- packages/@aws-cdk/aws-finspace/package.json | 2 +- packages/@aws-cdk/aws-fis/package.json | 2 +- packages/@aws-cdk/aws-fms/package.json | 2 +- .../@aws-cdk/aws-frauddetector/package.json | 2 +- packages/@aws-cdk/aws-fsx/package.json | 2 +- packages/@aws-cdk/aws-gamelift/package.json | 2 +- .../package.json | 2 +- .../aws-globalaccelerator/package.json | 2 +- packages/@aws-cdk/aws-glue/package.json | 2 +- packages/@aws-cdk/aws-greengrass/package.json | 2 +- .../@aws-cdk/aws-greengrassv2/package.json | 2 +- .../@aws-cdk/aws-groundstation/package.json | 2 +- packages/@aws-cdk/aws-guardduty/package.json | 2 +- packages/@aws-cdk/aws-healthlake/package.json | 2 +- packages/@aws-cdk/aws-iam/package.json | 2 +- .../@aws-cdk/aws-imagebuilder/package.json | 2 +- packages/@aws-cdk/aws-inspector/package.json | 2 +- .../@aws-cdk/aws-iot-actions/package.json | 2 +- packages/@aws-cdk/aws-iot/package.json | 2 +- packages/@aws-cdk/aws-iot1click/package.json | 2 +- .../@aws-cdk/aws-iotanalytics/package.json | 2 +- .../aws-iotcoredeviceadvisor/package.json | 2 +- packages/@aws-cdk/aws-iotevents/package.json | 2 +- .../@aws-cdk/aws-iotfleethub/package.json | 2 +- .../@aws-cdk/aws-iotsitewise/package.json | 2 +- .../@aws-cdk/aws-iotthingsgraph/package.json | 2 +- .../@aws-cdk/aws-iotwireless/package.json | 2 +- packages/@aws-cdk/aws-ivs/package.json | 2 +- packages/@aws-cdk/aws-kendra/package.json | 2 +- packages/@aws-cdk/aws-kinesis/package.json | 2 +- .../aws-kinesisanalytics-flink/package.json | 2 +- .../aws-kinesisanalytics/package.json | 2 +- .../package.json | 2 +- .../@aws-cdk/aws-kinesisfirehose/package.json | 2 +- packages/@aws-cdk/aws-kms/package.json | 2 +- .../@aws-cdk/aws-lakeformation/package.json | 2 +- .../aws-lambda-destinations/package.json | 2 +- .../aws-lambda-event-sources/package.json | 2 +- packages/@aws-cdk/aws-lambda-go/package.json | 2 +- .../@aws-cdk/aws-lambda-nodejs/package.json | 4 +- .../@aws-cdk/aws-lambda-python/package.json | 2 +- packages/@aws-cdk/aws-lambda/package.json | 2 +- .../@aws-cdk/aws-licensemanager/package.json | 2 +- packages/@aws-cdk/aws-lightsail/package.json | 2 +- packages/@aws-cdk/aws-location/package.json | 2 +- .../aws-logs-destinations/package.json | 2 +- packages/@aws-cdk/aws-logs/package.json | 2 +- .../aws-lookoutequipment/package.json | 2 +- .../@aws-cdk/aws-lookoutmetrics/package.json | 2 +- .../@aws-cdk/aws-lookoutvision/package.json | 2 +- packages/@aws-cdk/aws-macie/package.json | 2 +- .../aws-managedblockchain/package.json | 2 +- .../@aws-cdk/aws-mediaconnect/package.json | 2 +- .../@aws-cdk/aws-mediaconvert/package.json | 2 +- packages/@aws-cdk/aws-medialive/package.json | 2 +- .../@aws-cdk/aws-mediapackage/package.json | 2 +- packages/@aws-cdk/aws-mediastore/package.json | 2 +- packages/@aws-cdk/aws-memorydb/package.json | 2 +- packages/@aws-cdk/aws-msk/package.json | 2 +- packages/@aws-cdk/aws-mwaa/package.json | 2 +- packages/@aws-cdk/aws-neptune/package.json | 2 +- .../@aws-cdk/aws-networkfirewall/package.json | 2 +- .../@aws-cdk/aws-networkmanager/package.json | 2 +- .../@aws-cdk/aws-nimblestudio/package.json | 2 +- .../aws-opensearchservice/package.json | 2 +- packages/@aws-cdk/aws-opsworks/package.json | 2 +- packages/@aws-cdk/aws-opsworkscm/package.json | 2 +- packages/@aws-cdk/aws-panorama/package.json | 2 +- packages/@aws-cdk/aws-pinpoint/package.json | 2 +- .../@aws-cdk/aws-pinpointemail/package.json | 2 +- packages/@aws-cdk/aws-qldb/package.json | 2 +- packages/@aws-cdk/aws-quicksight/package.json | 2 +- packages/@aws-cdk/aws-ram/package.json | 2 +- packages/@aws-cdk/aws-rds/package.json | 2 +- packages/@aws-cdk/aws-redshift/package.json | 2 +- .../@aws-cdk/aws-rekognition/package.json | 2 +- .../@aws-cdk/aws-resourcegroups/package.json | 2 +- packages/@aws-cdk/aws-robomaker/package.json | 2 +- .../aws-route53-patterns/package.json | 2 +- .../@aws-cdk/aws-route53-targets/package.json | 2 +- packages/@aws-cdk/aws-route53/package.json | 2 +- .../aws-route53recoverycontrol/package.json | 2 +- .../aws-route53recoveryreadiness/package.json | 2 +- .../@aws-cdk/aws-route53resolver/package.json | 2 +- packages/@aws-cdk/aws-s3-assets/package.json | 2 +- .../@aws-cdk/aws-s3-deployment/package.json | 2 +- .../aws-s3-notifications/package.json | 2 +- packages/@aws-cdk/aws-s3/package.json | 2 +- .../@aws-cdk/aws-s3objectlambda/package.json | 2 +- packages/@aws-cdk/aws-s3outposts/package.json | 2 +- packages/@aws-cdk/aws-sagemaker/package.json | 2 +- packages/@aws-cdk/aws-sam/package.json | 2 +- packages/@aws-cdk/aws-sdb/package.json | 2 +- .../@aws-cdk/aws-secretsmanager/package.json | 2 +- .../@aws-cdk/aws-securityhub/package.json | 2 +- .../@aws-cdk/aws-servicecatalog/package.json | 2 +- .../package.json | 2 +- .../aws-servicediscovery/package.json | 2 +- .../@aws-cdk/aws-ses-actions/package.json | 2 +- packages/@aws-cdk/aws-ses/package.json | 2 +- packages/@aws-cdk/aws-signer/package.json | 2 +- .../aws-sns-subscriptions/package.json | 2 +- packages/@aws-cdk/aws-sns/package.json | 2 +- packages/@aws-cdk/aws-sqs/package.json | 2 +- packages/@aws-cdk/aws-ssm/package.json | 2 +- .../@aws-cdk/aws-ssmcontacts/package.json | 2 +- .../@aws-cdk/aws-ssmincidents/package.json | 2 +- packages/@aws-cdk/aws-sso/package.json | 2 +- .../aws-stepfunctions-tasks/package.json | 2 +- .../@aws-cdk/aws-stepfunctions/package.json | 2 +- packages/@aws-cdk/aws-synthetics/package.json | 2 +- packages/@aws-cdk/aws-timestream/package.json | 2 +- packages/@aws-cdk/aws-transfer/package.json | 2 +- packages/@aws-cdk/aws-waf/package.json | 2 +- .../@aws-cdk/aws-wafregional/package.json | 2 +- packages/@aws-cdk/aws-wafv2/package.json | 2 +- packages/@aws-cdk/aws-wisdom/package.json | 2 +- packages/@aws-cdk/aws-workspaces/package.json | 2 +- packages/@aws-cdk/aws-xray/package.json | 2 +- .../@aws-cdk/cdk-assets-schema/package.json | 2 +- packages/@aws-cdk/cfnspec/package.json | 2 +- .../cloud-assembly-schema/package.json | 4 +- .../@aws-cdk/cloudformation-diff/package.json | 2 +- .../cloudformation-include/package.json | 2 +- packages/@aws-cdk/core/package.json | 2 +- .../@aws-cdk/custom-resources/package.json | 2 +- packages/@aws-cdk/cx-api/package.json | 2 +- .../example-construct-library/package.json | 2 +- .../@aws-cdk/lambda-layer-awscli/package.json | 2 +- .../lambda-layer-kubectl/package.json | 2 +- .../package.json | 2 +- packages/@aws-cdk/pipelines/package.json | 2 +- packages/@aws-cdk/region-info/package.json | 2 +- packages/@aws-cdk/yaml-cfn/package.json | 2 +- .../@monocdk-experiment/assert/package.json | 2 +- .../rewrite-imports/package.json | 2 +- packages/aws-cdk-migration/package.json | 2 +- packages/aws-cdk/package.json | 8 +- packages/awslint/package.json | 2 +- packages/cdk-assets/package.json | 2 +- packages/cdk-dasm/package.json | 4 +- packages/decdk/package.json | 2 +- tools/@aws-cdk/cdk-build-tools/package.json | 4 +- tools/@aws-cdk/cdk-release/package.json | 2 +- tools/@aws-cdk/cfn2ts/package.json | 4 +- tools/@aws-cdk/eslint-plugin/package.json | 4 +- .../@aws-cdk/individual-pkg-gen/package.json | 2 +- tools/@aws-cdk/pkglint/package.json | 2 +- tools/@aws-cdk/prlint/package.json | 2 +- tools/@aws-cdk/yarn-cling/package.json | 2 +- yarn.lock | 436 ++++++++---------- 244 files changed, 452 insertions(+), 492 deletions(-) diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/package.json b/packages/@aws-cdk-containers/ecs-service-extensions/package.json index 49e48a3f2fa9c..3677b75e224d2 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/package.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/package.json @@ -37,7 +37,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/aws-autoscaling": "0.0.0", diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index 562bde75e3b81..c375bab31a3e0 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index 2f7f766ae2406..edfdea0c2cee7 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -65,7 +65,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "fast-check": "^2.19.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/assert-internal/package.json b/packages/@aws-cdk/assert-internal/package.json index 89d3b53aebc0d..5b0cf68df42d0 100644 --- a/packages/@aws-cdk/assert-internal/package.json +++ b/packages/@aws-cdk/assert-internal/package.json @@ -26,7 +26,7 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1", "ts-jest": "^27.0.7" }, diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index 14783485e9e32..093567d66de12 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -37,7 +37,7 @@ "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-cdk-migration": "0.0.0", "constructs": "^3.3.69", "jest": "^27.3.1", diff --git a/packages/@aws-cdk/assertions/package.json b/packages/@aws-cdk/assertions/package.json index 1b515143d4d58..23151e13b8898 100644 --- a/packages/@aws-cdk/assertions/package.json +++ b/packages/@aws-cdk/assertions/package.json @@ -65,7 +65,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^9.0.13", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "constructs": "^3.3.69", "jest": "^27.3.1", "ts-jest": "^27.0.7" diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index c099d2edc4c02..e5e952ed57663 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -73,7 +73,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/sinon": "^9.0.11", "aws-cdk": "0.0.0", "jest": "^27.3.1", diff --git a/packages/@aws-cdk/aws-accessanalyzer/package.json b/packages/@aws-cdk/aws-accessanalyzer/package.json index 67e9594bf1c0d..6ecb0ec375882 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/package.json +++ b/packages/@aws-cdk/aws-accessanalyzer/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-acmpca/package.json b/packages/@aws-cdk/aws-acmpca/package.json index 4dd5abf981e07..e63b1a1157bc5 100644 --- a/packages/@aws-cdk/aws-acmpca/package.json +++ b/packages/@aws-cdk/aws-acmpca/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-amazonmq/package.json b/packages/@aws-cdk/aws-amazonmq/package.json index 0cf6fab9471d8..4d2faba7936fa 100644 --- a/packages/@aws-cdk/aws-amazonmq/package.json +++ b/packages/@aws-cdk/aws-amazonmq/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index 4b14568aada7d..aa5e8cb02ca74 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/yaml": "1.9.6" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index d20ad7f17d5f5..8324c62c0b143 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index 8465cb5e8a9a5..e4dae38af4135 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index 203793018a92a..87b5a43c1f9cb 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -81,7 +81,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index 121096724bdfd..6e12d9613fa27 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -82,7 +82,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index 17cf252cab7b8..453ee2d7ee87b 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-appflow/package.json b/packages/@aws-cdk/aws-appflow/package.json index fb4531d38dec4..d662bbcb347cb 100644 --- a/packages/@aws-cdk/aws-appflow/package.json +++ b/packages/@aws-cdk/aws-appflow/package.json @@ -75,7 +75,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appintegrations/package.json b/packages/@aws-cdk/aws-appintegrations/package.json index e95a579a6ed4e..6a3ec67dcdea2 100644 --- a/packages/@aws-cdk/aws-appintegrations/package.json +++ b/packages/@aws-cdk/aws-appintegrations/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index 17bfd09967f88..91ae830bb2ca6 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "fast-check": "^2.19.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json index fd197aa6c9dd3..c41c3964d45c3 100644 --- a/packages/@aws-cdk/aws-applicationinsights/package.json +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index 0bf1fc94a030d..c5c0d9f304141 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -89,7 +89,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-apprunner/package.json b/packages/@aws-cdk/aws-apprunner/package.json index 89e2e15bd2e4b..8daa46ac8d724 100644 --- a/packages/@aws-cdk/aws-apprunner/package.json +++ b/packages/@aws-cdk/aws-apprunner/package.json @@ -82,7 +82,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ecr": "0.0.0", diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index 2f99c4ac8f6b5..07cfbc2facf63 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index 814bfb98e9600..a402e2d58bc00 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-aps/package.json b/packages/@aws-cdk/aws-aps/package.json index 43022f3b9104d..ce01bfd038a3e 100644 --- a/packages/@aws-cdk/aws-aps/package.json +++ b/packages/@aws-cdk/aws-aps/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index 6c69107b932ea..78a3fc7be9911 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-auditmanager/package.json b/packages/@aws-cdk/aws-auditmanager/package.json index 35f9b576f80c2..72056b745c96a 100644 --- a/packages/@aws-cdk/aws-auditmanager/package.json +++ b/packages/@aws-cdk/aws-auditmanager/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index a089ff8919749..1937563214c83 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -68,7 +68,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "fast-check": "^2.19.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index b481a4de56eab..bc732e95f42a3 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -70,7 +70,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index dfdb08ad1ac2b..f56a6111ac7f6 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index 302cfbebd1dc2..5cc5af877100b 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 459075165dc90..0e1e552e15db4 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index 68faf56d0e656..aa57512f3be36 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index 19686d9d20009..63db174d263bb 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index a98df550ff629..90f6bc335bd18 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index dc1b5be1a0743..9c72038371be8 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index 8faea6a4fdd7f..659b98eb834b6 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-acmpca": "0.0.0", diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index d71dea40ebb2a..efe5c1e39ad75 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index 874f3d618f1f6..8c434124da5b8 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-codecommit": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index 60046c3442b29..04b8f6eb93f79 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index c46b318a4d610..64298d1a43a83 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -75,7 +75,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 145e02736b1f7..560eefe3e854c 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index cae3b5dcf27cc..05c02f580f8b6 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "colors": "^1.4.0", "jest": "^27.3.1" diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 62a23e4c89e14..35b735a3764d1 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -70,7 +70,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index b02f9e882b51a..8705abaaed106 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-codeartifact/package.json b/packages/@aws-cdk/aws-codeartifact/package.json index 6ad2e9c887a85..d6ff28dc1b6d3 100644 --- a/packages/@aws-cdk/aws-codeartifact/package.json +++ b/packages/@aws-cdk/aws-codeartifact/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 3d1609d9665b4..f46603eedf48c 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -90,7 +90,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 9f40eabeaf1e9..181e7f627a041 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-codedeploy/package.json b/packages/@aws-cdk/aws-codedeploy/package.json index 52636610a2453..dada37c5cf7f2 100644 --- a/packages/@aws-cdk/aws-codedeploy/package.json +++ b/packages/@aws-cdk/aws-codedeploy/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index d5da8cc3123b0..c83bfc85306d0 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json index 70318450a5a94..ddc4dab7bf420 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/package.json +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index aa3c6a125a362..b5b1ec6c0a0d0 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -82,7 +82,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/lodash": "^4.14.177", "jest": "^27.3.1", "lodash": "^4.17.21" diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index 84f28a8804685..38438ad00c61b 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -90,7 +90,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index c07b029163b37..85cd5a408b921 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-s3": "0.0.0", diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index 93ad273d92f34..d4189eb77ec89 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index 08a772cb69dbb..2dd20cb2c9b05 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index 89e8c16900564..2e72772c1c43d 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/punycode": "^2.1.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index d52985a5561bf..d8654df2f6305 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-connect/package.json b/packages/@aws-cdk/aws-connect/package.json index dfc68b783399d..ac75d47895514 100644 --- a/packages/@aws-cdk/aws-connect/package.json +++ b/packages/@aws-cdk/aws-connect/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-cur/package.json b/packages/@aws-cdk/aws-cur/package.json index a6b6436c1e289..c17803344f565 100644 --- a/packages/@aws-cdk/aws-cur/package.json +++ b/packages/@aws-cdk/aws-cur/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-customerprofiles/package.json b/packages/@aws-cdk/aws-customerprofiles/package.json index 25c30a3e9b3bc..717eda9dee83f 100644 --- a/packages/@aws-cdk/aws-customerprofiles/package.json +++ b/packages/@aws-cdk/aws-customerprofiles/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-databrew/package.json b/packages/@aws-cdk/aws-databrew/package.json index 16afbe12cff84..acd0f10ef451c 100644 --- a/packages/@aws-cdk/aws-databrew/package.json +++ b/packages/@aws-cdk/aws-databrew/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index 594bd86ef375f..d59036075a0a1 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-datasync/package.json b/packages/@aws-cdk/aws-datasync/package.json index a8534ef967112..c0349de237aa4 100644 --- a/packages/@aws-cdk/aws-datasync/package.json +++ b/packages/@aws-cdk/aws-datasync/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index 99246561f2d53..6a180b888c0f6 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index 0dc643180b84b..e844cca4e6587 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-devopsguru/package.json b/packages/@aws-cdk/aws-devopsguru/package.json index 13d92fc5f5779..f79e524f0e302 100644 --- a/packages/@aws-cdk/aws-devopsguru/package.json +++ b/packages/@aws-cdk/aws-devopsguru/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index f2160c4bac892..d3a7c9e583209 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index 0d4b4c73ca54f..ac1bed18c542f 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index f4f20b0130875..f74d5e6e8636c 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index d60317ab084a9..a7ae5c843b031 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb-global/package.json b/packages/@aws-cdk/aws-dynamodb-global/package.json index c84dcc4073b42..af467a5fdd3fd 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/package.json @@ -60,7 +60,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "peerDependencies": { diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index d63167cf3d5de..e8de899e9a81f 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.4.0", diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 00190b44dd5f8..cc287b37731f3 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index 42e33d793d481..d9884fd313561 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -70,7 +70,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/proxyquire": "^1.3.28", "aws-cdk": "0.0.0", "jest": "^27.3.1", diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index c9039866abcc0..bc4e518ac3666 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index 96a5eccecc75f..4ac502ceb6670 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index dc6c57ffe9285..749af21363023 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/proxyquire": "^1.3.28", "jest": "^27.3.1", "proxyquire": "^2.1.3" diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index d7ab7e62a5dcb..6ab9f630d9c60 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks-legacy/package.json b/packages/@aws-cdk/aws-eks-legacy/package.json index 919122fed89d2..5f28779d5d3a4 100644 --- a/packages/@aws-cdk/aws-eks-legacy/package.json +++ b/packages/@aws-cdk/aws-eks-legacy/package.json @@ -82,7 +82,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 1eae2b3fbb4d0..72f63980b3229 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -85,12 +85,12 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/sinon": "^9.0.11", "@types/yaml": "1.9.6", "aws-sdk": "^2.848.0", - "cdk8s": "^1.0.0", - "cdk8s-plus-21": "^1.0.0-beta.38", + "cdk8s": "^1.1.42", + "cdk8s-plus-21": "^1.0.0-beta.44", "jest": "^27.3.1", "sinon": "^9.2.4" }, diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index 5cf8e0a657b51..e6ed98edbb9a3 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index f41a30fdec4f0..5752d05303360 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index 874f90e6ec065..fb6b19aeb74dc 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index 249d3a00ae197..e51ebff77991f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index 6fc1ac8745fcd..f90b5a33b4d01 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-ecs-patterns": "0.0.0" diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index d2a9b352b4163..b20b9b8dc9534 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 0ddd787d22acb..73b7bafbe8b41 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index eecd4c1b8d633..eed831575d4d4 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-emrcontainers/package.json b/packages/@aws-cdk/aws-emrcontainers/package.json index 22fc0ab192946..acb848b8537f1 100644 --- a/packages/@aws-cdk/aws-emrcontainers/package.json +++ b/packages/@aws-cdk/aws-emrcontainers/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 1184651b4e9a3..073c3e2475c46 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.4.0", "jest": "^27.3.1" diff --git a/packages/@aws-cdk/aws-events/package.json b/packages/@aws-cdk/aws-events/package.json index 7159bada50ee2..ea49dc6609ef1 100644 --- a/packages/@aws-cdk/aws-events/package.json +++ b/packages/@aws-cdk/aws-events/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index 75146a5702dcf..2519229df0210 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-finspace/package.json b/packages/@aws-cdk/aws-finspace/package.json index 5def58d6b4891..e0ceee21687c8 100644 --- a/packages/@aws-cdk/aws-finspace/package.json +++ b/packages/@aws-cdk/aws-finspace/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fis/package.json b/packages/@aws-cdk/aws-fis/package.json index eea1d73756d0b..6f1c8403c703b 100644 --- a/packages/@aws-cdk/aws-fis/package.json +++ b/packages/@aws-cdk/aws-fis/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index d1cf232ce73f2..4059f9d6fd54f 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-frauddetector/package.json b/packages/@aws-cdk/aws-frauddetector/package.json index 2fc9ebd4499dd..2aa6f52f38db5 100644 --- a/packages/@aws-cdk/aws-frauddetector/package.json +++ b/packages/@aws-cdk/aws-frauddetector/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index 2f4c3e0ef958f..c502f72a5f465 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 2dcde9763ab6e..183269e840777 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json index e55ed3d2ef079..70c4e891763a6 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json @@ -73,7 +73,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.4.0", "jest": "^27.3.1" diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index b73aa3b9537f2..60cf16e7f10bc 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index b4325ec0a648b..53626f159b6fc 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index c27f163e140a5..039b0f7b121c0 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-greengrassv2/package.json b/packages/@aws-cdk/aws-greengrassv2/package.json index 850c26982bab5..84617dc1706c6 100644 --- a/packages/@aws-cdk/aws-greengrassv2/package.json +++ b/packages/@aws-cdk/aws-greengrassv2/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-groundstation/package.json b/packages/@aws-cdk/aws-groundstation/package.json index b5ba37d753aea..579d1cbbdf63f 100644 --- a/packages/@aws-cdk/aws-groundstation/package.json +++ b/packages/@aws-cdk/aws-groundstation/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index 4c0f7383bab1d..ce3691441d42e 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-healthlake/package.json b/packages/@aws-cdk/aws-healthlake/package.json index 43a53367da896..b6afc75d8b64a 100644 --- a/packages/@aws-cdk/aws-healthlake/package.json +++ b/packages/@aws-cdk/aws-healthlake/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index e448eaf64cec0..3945176a00ce4 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/sinon": "^9.0.11", "jest": "^27.3.1", "sinon": "^9.2.4" diff --git a/packages/@aws-cdk/aws-imagebuilder/package.json b/packages/@aws-cdk/aws-imagebuilder/package.json index c359b498792a6..cb7bd4966ac33 100644 --- a/packages/@aws-cdk/aws-imagebuilder/package.json +++ b/packages/@aws-cdk/aws-imagebuilder/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index fc4b526784a77..433bac89fa1b6 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot-actions/package.json b/packages/@aws-cdk/aws-iot-actions/package.json index b996897b7719d..8deede8b080c3 100644 --- a/packages/@aws-cdk/aws-iot-actions/package.json +++ b/packages/@aws-cdk/aws-iot-actions/package.json @@ -75,7 +75,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "constructs": "^3.3.69", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index ffd0b7cca83c7..f1444af6bca1d 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index e08bd2197a70a..437477bad2455 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index c1a2fb2404f99..0aca49562ccb7 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json b/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json index da47e538939c6..e7882cffb091d 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 50b9f8f02b5d8..7c69ce3fe3da5 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotfleethub/package.json b/packages/@aws-cdk/aws-iotfleethub/package.json index c05eb0a4e3463..14ebd656515af 100644 --- a/packages/@aws-cdk/aws-iotfleethub/package.json +++ b/packages/@aws-cdk/aws-iotfleethub/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotsitewise/package.json b/packages/@aws-cdk/aws-iotsitewise/package.json index 619858772f08f..11d005fe1ece6 100644 --- a/packages/@aws-cdk/aws-iotsitewise/package.json +++ b/packages/@aws-cdk/aws-iotsitewise/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index 3f6774f372140..4df6b533355e9 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotwireless/package.json b/packages/@aws-cdk/aws-iotwireless/package.json index e1acaffcb83a8..b347d3d8f778c 100644 --- a/packages/@aws-cdk/aws-iotwireless/package.json +++ b/packages/@aws-cdk/aws-iotwireless/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ivs/package.json b/packages/@aws-cdk/aws-ivs/package.json index a1f452ba38783..845d20b12229e 100644 --- a/packages/@aws-cdk/aws-ivs/package.json +++ b/packages/@aws-cdk/aws-ivs/package.json @@ -89,7 +89,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json index 94a8499035a1c..3a5eb91dada5f 100644 --- a/packages/@aws-cdk/aws-kendra/package.json +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index 1641e48f910f7..5c41d6378214e 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json index 1f4a026686416..8f6e212f0a670 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index 36a2b60ede671..0c0804c9727a6 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json index a872462d82cf8..f847c08041608 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index 64c30be1210e3..468daf9d47aa0 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index e38c467b3b4f7..1d2162e38683c 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index df8b5c9f6f22b..e0dd166743305 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 12108477a91de..0cd618e2232f4 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package.json b/packages/@aws-cdk/aws-lambda-event-sources/package.json index 3bd4375cc9d24..f713affc4a99b 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/package.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/package.json @@ -75,7 +75,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-lambda-go/package.json b/packages/@aws-cdk/aws-lambda-go/package.json index 5df9aae607538..6c82e15eed727 100644 --- a/packages/@aws-cdk/aws-lambda-go/package.json +++ b/packages/@aws-cdk/aws-lambda-go/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index b0dfb32289dff..cebd05f25b1a9 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -76,9 +76,9 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "delay": "5.0.0", - "esbuild": "^0.13.14" + "esbuild": "^0.13.15" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-python/package.json b/packages/@aws-cdk/aws-lambda-python/package.json index 6cfec00d17893..d2ae8bfb8d4e7 100644 --- a/packages/@aws-cdk/aws-lambda-python/package.json +++ b/packages/@aws-cdk/aws-lambda-python/package.json @@ -75,7 +75,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 93b724cdc1282..aeeec8e06559a 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -90,7 +90,7 @@ "@aws-cdk/cfnspec": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/lodash": "^4.14.177", "jest": "^27.3.1", "lodash": "^4.17.21" diff --git a/packages/@aws-cdk/aws-licensemanager/package.json b/packages/@aws-cdk/aws-licensemanager/package.json index 937f71dc91629..6ff8f00cb60cb 100644 --- a/packages/@aws-cdk/aws-licensemanager/package.json +++ b/packages/@aws-cdk/aws-licensemanager/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lightsail/package.json b/packages/@aws-cdk/aws-lightsail/package.json index 926c902210254..d577b74448e78 100644 --- a/packages/@aws-cdk/aws-lightsail/package.json +++ b/packages/@aws-cdk/aws-lightsail/package.json @@ -81,7 +81,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-location/package.json b/packages/@aws-cdk/aws-location/package.json index f69267cda2085..17d950bc136bb 100644 --- a/packages/@aws-cdk/aws-location/package.json +++ b/packages/@aws-cdk/aws-location/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index 308d6ec0085c6..916a1b55e0f84 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index a865bde5c1dae..28f430b688ccb 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.4.0", diff --git a/packages/@aws-cdk/aws-lookoutequipment/package.json b/packages/@aws-cdk/aws-lookoutequipment/package.json index a7f0b5af8190d..d59dc1960c96c 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/package.json +++ b/packages/@aws-cdk/aws-lookoutequipment/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutmetrics/package.json b/packages/@aws-cdk/aws-lookoutmetrics/package.json index 32a7ad91634f7..fcafae216f42b 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/package.json +++ b/packages/@aws-cdk/aws-lookoutmetrics/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutvision/package.json b/packages/@aws-cdk/aws-lookoutvision/package.json index 3b078e5fbc87d..fd64ea05542dd 100644 --- a/packages/@aws-cdk/aws-lookoutvision/package.json +++ b/packages/@aws-cdk/aws-lookoutvision/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-macie/package.json b/packages/@aws-cdk/aws-macie/package.json index 366b44cc1436d..c435dfbe95e6a 100644 --- a/packages/@aws-cdk/aws-macie/package.json +++ b/packages/@aws-cdk/aws-macie/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index 0d3ab22610d09..cbea43ff7e7ed 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediaconnect/package.json b/packages/@aws-cdk/aws-mediaconnect/package.json index 5ea1c867f5c9c..29d305f1c45b4 100644 --- a/packages/@aws-cdk/aws-mediaconnect/package.json +++ b/packages/@aws-cdk/aws-mediaconnect/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index db46b10c78796..be49a311a7951 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index 899730b583263..b1e3ca8e9260a 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediapackage/package.json b/packages/@aws-cdk/aws-mediapackage/package.json index ea1fbb7346c47..7630c6c3f9338 100644 --- a/packages/@aws-cdk/aws-mediapackage/package.json +++ b/packages/@aws-cdk/aws-mediapackage/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index 8123929e5cb85..03e130c867a4c 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-memorydb/package.json b/packages/@aws-cdk/aws-memorydb/package.json index 375bc1a8f27c0..2d4c661126fb2 100644 --- a/packages/@aws-cdk/aws-memorydb/package.json +++ b/packages/@aws-cdk/aws-memorydb/package.json @@ -81,7 +81,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index 0a38efe4bd9c7..49af99f7c9544 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-mwaa/package.json b/packages/@aws-cdk/aws-mwaa/package.json index d683008ab9a71..9fdf1cc3689db 100644 --- a/packages/@aws-cdk/aws-mwaa/package.json +++ b/packages/@aws-cdk/aws-mwaa/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index f56fd6e5ce9ba..9ea7c1dc27705 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-networkfirewall/package.json b/packages/@aws-cdk/aws-networkfirewall/package.json index 0ee80543d4a43..795561d0abf28 100644 --- a/packages/@aws-cdk/aws-networkfirewall/package.json +++ b/packages/@aws-cdk/aws-networkfirewall/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index 76ed9c07d1319..9b0252be4cdd5 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-nimblestudio/package.json b/packages/@aws-cdk/aws-nimblestudio/package.json index 38e31a93dc9cd..4b489613e5b9a 100644 --- a/packages/@aws-cdk/aws-nimblestudio/package.json +++ b/packages/@aws-cdk/aws-nimblestudio/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-opensearchservice/package.json b/packages/@aws-cdk/aws-opensearchservice/package.json index 24c01f69d0dd7..cb7bea7e5e0b4 100644 --- a/packages/@aws-cdk/aws-opensearchservice/package.json +++ b/packages/@aws-cdk/aws-opensearchservice/package.json @@ -89,7 +89,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index a1b33b0f27bb7..54f88b61a607d 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 585aa90ea1aa8..583647ba83fc3 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-panorama/package.json b/packages/@aws-cdk/aws-panorama/package.json index 22a1909e75848..6ed613253198d 100644 --- a/packages/@aws-cdk/aws-panorama/package.json +++ b/packages/@aws-cdk/aws-panorama/package.json @@ -81,7 +81,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index 22a56b42fa12c..f819b0945b053 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index 5b6ce5aa42d53..d8588bf884fca 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index 17a656d77cf56..d20ee60754447 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-quicksight/package.json b/packages/@aws-cdk/aws-quicksight/package.json index 95786e26228ea..6a591c143a85a 100644 --- a/packages/@aws-cdk/aws-quicksight/package.json +++ b/packages/@aws-cdk/aws-quicksight/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index 233fbad9667e2..2f4c7a792c293 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index a9c66bfb3f081..ff0c8887035a9 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index 67c6a888bfa71..ebd675daea110 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-rekognition/package.json b/packages/@aws-cdk/aws-rekognition/package.json index af21be79fbf82..30956b54c44fb 100644 --- a/packages/@aws-cdk/aws-rekognition/package.json +++ b/packages/@aws-cdk/aws-rekognition/package.json @@ -81,7 +81,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index b36c4174ef01e..b7624761212f6 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index 5c8ad4dae7731..58e20a0b7e87b 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index d8c12460322a6..b46814cca796b 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index a65e4a0372abf..c34f047fcbeb8 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -79,7 +79,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index aabd22c95363b..d786d2c492cdf 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/package.json b/packages/@aws-cdk/aws-route53recoverycontrol/package.json index 9c1c49bad1887..30202a7ee547c 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/package.json +++ b/packages/@aws-cdk/aws-route53recoverycontrol/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/package.json b/packages/@aws-cdk/aws-route53recoveryreadiness/package.json index 46ded25804f91..221b8584c0e36 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/package.json +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index 8a9ff2e0cbc1a..a249530cccf09 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index d7df92e0c25b4..084b0968e7306 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -75,7 +75,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/assets": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index c9f0d392e22e4..1101a604a650f 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -83,7 +83,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index e49109b6c0a6d..98661e9f4802b 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -68,7 +68,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index f8153d202545d..678089d230535 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-s3objectlambda/package.json b/packages/@aws-cdk/aws-s3objectlambda/package.json index 047a32f22af59..54db2b52dc4fe 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/package.json +++ b/packages/@aws-cdk/aws-s3objectlambda/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-s3outposts/package.json b/packages/@aws-cdk/aws-s3outposts/package.json index 7ac9ab32c9976..2e04d5bd82659 100644 --- a/packages/@aws-cdk/aws-s3outposts/package.json +++ b/packages/@aws-cdk/aws-s3outposts/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index 254b0c58aeb17..5d7a3ad04f8cb 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 0fa9799b59819..8bb339eea77f9 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1", "ts-jest": "^27.0.7" }, diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index 70bd66f85a880..786e120914404 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index d0dca489a6e95..2b8a496efdffc 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index bb36e474a4b74..3e29438e9e791 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index 23561d640ded2..bd597180a56cd 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json index a3293914c1027..0da24cca81ef4 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json @@ -81,7 +81,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index 95acef90ab7cf..a6955cc2af798 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -80,7 +80,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index cee511a94f85e..8389e4aa81c65 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -70,7 +70,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 4fe47750df28b..f5814f087f682 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index dfca263103745..e0c3a66833452 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -78,7 +78,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index 6f8a4f5a2b9cc..f956889838f5d 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index b5f4039c63744..b0678ed201f46 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index af74b209b3931..c671706627909 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0", "jest": "^27.3.1" }, diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index cdf17bfb69c1c..d70e3279daad8 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-ssmcontacts/package.json b/packages/@aws-cdk/aws-ssmcontacts/package.json index 603c082e46845..a886fc2903395 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/package.json +++ b/packages/@aws-cdk/aws-ssmcontacts/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ssmincidents/package.json b/packages/@aws-cdk/aws-ssmincidents/package.json index dfbe2be486b87..537f57269969d 100644 --- a/packages/@aws-cdk/aws-ssmincidents/package.json +++ b/packages/@aws-cdk/aws-ssmincidents/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json index 38e6621ed0fa0..2f24ecd575f36 100644 --- a/packages/@aws-cdk/aws-sso/package.json +++ b/packages/@aws-cdk/aws-sso/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index f1e8f3d215ed4..09bfee9d4f4f0 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -90,7 +90,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index 40cea293bc09f..f8bd77b981dc2 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -84,7 +84,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index 745f97fc21261..95ea3307e1823 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -86,7 +86,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-timestream/package.json b/packages/@aws-cdk/aws-timestream/package.json index 9aa39709df395..252484a673f49 100644 --- a/packages/@aws-cdk/aws-timestream/package.json +++ b/packages/@aws-cdk/aws-timestream/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index cc1d96d9fb22e..e213292d647b1 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index 401458b6f509a..1f8abd7413335 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index 9daf58db6d53c..92f5f997825db 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index 4c689f62396f0..f1077a51389fd 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -85,7 +85,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wisdom/package.json b/packages/@aws-cdk/aws-wisdom/package.json index aa12d6e4aa992..ab4a5c4f1aa37 100644 --- a/packages/@aws-cdk/aws-wisdom/package.json +++ b/packages/@aws-cdk/aws-wisdom/package.json @@ -88,7 +88,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index 151f94ddb9dad..a19a5749ac5f7 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -76,7 +76,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-xray/package.json b/packages/@aws-cdk/aws-xray/package.json index 7a5d9bfb5c5cd..19980bffb77f4 100644 --- a/packages/@aws-cdk/aws-xray/package.json +++ b/packages/@aws-cdk/aws-xray/package.json @@ -87,7 +87,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index 1d0ab53e1cd4d..3114522af167f 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -54,7 +54,7 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "repository": { diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index c871edefcaa16..828529273ae87 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -32,7 +32,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/md5": "^2.3.1", "fast-json-patch": "^2.2.1", "jest": "^27.3.1", diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index e341cacf324ea..b10afb22968b4 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -62,12 +62,12 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/mock-fs": "^4.13.1", "@types/semver": "^7.3.9", "jest": "^27.3.1", "mock-fs": "^4.14.0", - "typescript-json-schema": "^0.51.0" + "typescript-json-schema": "^0.52.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 1e9b1c5a412ca..20919ad4e721b 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -34,7 +34,7 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/string-width": "^4.0.1", "fast-check": "^2.19.0", "jest": "^27.3.1", diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index fcaecdf08c0c5..b83e767b993c7 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -432,7 +432,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1", "ts-jest": "^27.0.7" }, diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 578fac2dbbff0..0cae11f2236f5 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -180,7 +180,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/lodash": "^4.14.177", "@types/minimatch": "^3.0.5", "@types/node": "^10.17.60", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index b41dc9d64ceed..1b0c23ae27053 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -82,7 +82,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/aws-lambda": "^8.10.85", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.4.0", diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 0a842759dd30e..f971aeb080c53 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -68,7 +68,7 @@ "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/mock-fs": "^4.13.1", "@types/semver": "^7.3.9", "jest": "^27.3.1", diff --git a/packages/@aws-cdk/example-construct-library/package.json b/packages/@aws-cdk/example-construct-library/package.json index 7554004c160fc..19c5440b36e6f 100644 --- a/packages/@aws-cdk/example-construct-library/package.json +++ b/packages/@aws-cdk/example-construct-library/package.json @@ -70,7 +70,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/lambda-layer-awscli/package.json b/packages/@aws-cdk/lambda-layer-awscli/package.json index 1a66cd1bae0fb..18d0bd9fd6346 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/package.json +++ b/packages/@aws-cdk/lambda-layer-awscli/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/lambda-layer-kubectl/package.json b/packages/@aws-cdk/lambda-layer-kubectl/package.json index b62ace7ad6246..518916736ec18 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/package.json +++ b/packages/@aws-cdk/lambda-layer-kubectl/package.json @@ -77,7 +77,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "pkglint": { diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json index 7be547ea61a57..c27f3db4b11dd 100644 --- a/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json @@ -70,7 +70,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1" }, "dependencies": { diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index ec3538c30b4c9..417acf6d16b3a 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -41,7 +41,7 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "aws-sdk": "^2.848.0" }, "peerDependencies": { diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index d78a75e84d00d..66139d405ce53 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -56,7 +56,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "fs-extra": "^9.1.0" }, "repository": { diff --git a/packages/@aws-cdk/yaml-cfn/package.json b/packages/@aws-cdk/yaml-cfn/package.json index 2b125cf83c224..f249ff713dc54 100644 --- a/packages/@aws-cdk/yaml-cfn/package.json +++ b/packages/@aws-cdk/yaml-cfn/package.json @@ -72,7 +72,7 @@ "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/yaml": "^1.9.7", "jest": "^27.3.1" }, diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index 4c973ee798190..36f71083427f7 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -34,7 +34,7 @@ "license": "Apache-2.0", "devDependencies": { "@monocdk-experiment/rewrite-imports": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/node": "^10.17.60", "@aws-cdk/cdk-build-tools": "0.0.0", "constructs": "^3.3.69", diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index a9d9e2dd0d77d..ed968b6376e81 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -36,7 +36,7 @@ }, "devDependencies": { "@types/glob": "^7.2.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/node": "^10.17.60", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0" diff --git a/packages/aws-cdk-migration/package.json b/packages/aws-cdk-migration/package.json index 4b1fa845c3229..73d72e6a0b5c6 100644 --- a/packages/aws-cdk-migration/package.json +++ b/packages/aws-cdk-migration/package.json @@ -39,7 +39,7 @@ }, "devDependencies": { "@types/glob": "^7.2.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/node": "^10.17.60", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0" diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index d870b6d31a8b5..238e2567af258 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -42,7 +42,7 @@ "@types/archiver": "^5.3.0", "@types/fs-extra": "^8.1.2", "@types/glob": "^7.2.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/minimatch": "^3.0.5", "@types/mockery": "^1.4.30", "@types/node": "^10.17.60", @@ -50,7 +50,7 @@ "@types/semver": "^7.3.9", "@types/sinon": "^9.0.11", "@types/table": "^6.0.0", - "@types/uuid": "^8.3.1", + "@types/uuid": "^8.3.3", "@types/wrap-ansi": "^3.0.0", "@types/yargs": "^15.0.14", "aws-sdk-mock": "^5.4.0", @@ -71,7 +71,7 @@ "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "@jsii/check-node": "1.44.2", + "@jsii/check-node": "1.46.0", "archiver": "^5.3.0", "aws-sdk": "^2.979.0", "camelcase": "^6.2.1", @@ -86,7 +86,7 @@ "promptly": "^3.2.0", "proxy-agent": "^5.0.0", "semver": "^7.3.5", - "source-map-support": "^0.5.20", + "source-map-support": "^0.5.21", "table": "^6.7.3", "uuid": "^8.3.2", "wrap-ansi": "^7.0.0", diff --git a/packages/awslint/package.json b/packages/awslint/package.json index abb313970f7c0..5599c2897f4d6 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/yargs": "^15.0.14", "@aws-cdk/pkglint": "0.0.0", "typescript": "~3.9.10", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index e92c49df3412b..17f5f60098edd 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -32,7 +32,7 @@ "devDependencies": { "@types/archiver": "^5.3.0", "@types/glob": "^7.2.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/mime": "^2.0.3", "@types/mock-fs": "^4.13.1", "@types/node": "^10.17.60", diff --git a/packages/cdk-dasm/package.json b/packages/cdk-dasm/package.json index b26d769698217..760fff809d44e 100644 --- a/packages/cdk-dasm/package.json +++ b/packages/cdk-dasm/package.json @@ -28,11 +28,11 @@ }, "license": "Apache-2.0", "dependencies": { - "codemaker": "^1.44.2", + "codemaker": "^1.46.0", "yaml": "1.10.2" }, "devDependencies": { - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/yaml": "1.9.7", "jest": "^27.3.1", "typescript": "~3.9.10" diff --git a/packages/decdk/package.json b/packages/decdk/package.json index d6b07cedf4d6c..4c387008f7bf6 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -254,7 +254,7 @@ }, "devDependencies": { "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/yaml": "1.9.7", "@types/yargs": "^15.0.14", "jest": "^27.3.1", diff --git a/tools/@aws-cdk/cdk-build-tools/package.json b/tools/@aws-cdk/cdk-build-tools/package.json index f388be9b33df7..8b174a75e68fd 100644 --- a/tools/@aws-cdk/cdk-build-tools/package.json +++ b/tools/@aws-cdk/cdk-build-tools/package.json @@ -37,7 +37,7 @@ "devDependencies": { "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/semver": "^7.3.9", "@types/yargs": "^15.0.14" }, @@ -59,7 +59,7 @@ "jsii": "^1.46.0", "jsii-pacmak": "^1.46.0", "jsii-reflect": "^1.46.0", - "markdownlint-cli": "^0.29.0", + "markdownlint-cli": "^0.30.0", "nyc": "^15.1.0", "semver": "^7.3.5", "ts-jest": "^27.0.7", diff --git a/tools/@aws-cdk/cdk-release/package.json b/tools/@aws-cdk/cdk-release/package.json index 9b308c8891716..0436933fb0c1b 100644 --- a/tools/@aws-cdk/cdk-release/package.json +++ b/tools/@aws-cdk/cdk-release/package.json @@ -32,7 +32,7 @@ "@aws-cdk/pkglint": "0.0.0", "@types/changelog-parser": "^2.7.1", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/yargs": "^15.0.14", "jest": "^27.3.1" }, diff --git a/tools/@aws-cdk/cfn2ts/package.json b/tools/@aws-cdk/cfn2ts/package.json index 7e386255d5681..e95e96fbe2ca7 100644 --- a/tools/@aws-cdk/cfn2ts/package.json +++ b/tools/@aws-cdk/cfn2ts/package.json @@ -32,7 +32,7 @@ "license": "Apache-2.0", "dependencies": { "@aws-cdk/cfnspec": "0.0.0", - "codemaker": "^1.44.2", + "codemaker": "^1.46.0", "fast-json-patch": "^3.1.0", "fs-extra": "^9.1.0", "yargs": "^16.2.0" @@ -41,7 +41,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/yargs": "^15.0.14", "jest": "^27.3.1" }, diff --git a/tools/@aws-cdk/eslint-plugin/package.json b/tools/@aws-cdk/eslint-plugin/package.json index 06c52ff0197af..fa10beaba83a7 100644 --- a/tools/@aws-cdk/eslint-plugin/package.json +++ b/tools/@aws-cdk/eslint-plugin/package.json @@ -16,10 +16,10 @@ "devDependencies": { "@types/eslint": "^7.29.0", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/node": "^10.17.60", "@types/estree": "*", - "eslint-plugin-rulesdir": "^0.2.0", + "eslint-plugin-rulesdir": "^0.2.1", "jest": "^27.3.1", "typescript": "~3.9.10" }, diff --git a/tools/@aws-cdk/individual-pkg-gen/package.json b/tools/@aws-cdk/individual-pkg-gen/package.json index 68e10ccfca040..f0fa0b30642a7 100644 --- a/tools/@aws-cdk/individual-pkg-gen/package.json +++ b/tools/@aws-cdk/individual-pkg-gen/package.json @@ -29,7 +29,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", - "@types/jest": "^27.0.2" + "@types/jest": "^27.0.3" }, "dependencies": { "aws-cdk-migration": "0.0.0", diff --git a/tools/@aws-cdk/pkglint/package.json b/tools/@aws-cdk/pkglint/package.json index 7bb152feb4287..1c3a934d1952c 100644 --- a/tools/@aws-cdk/pkglint/package.json +++ b/tools/@aws-cdk/pkglint/package.json @@ -40,7 +40,7 @@ "@aws-cdk/eslint-plugin": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/glob": "^7.2.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/semver": "^7.3.9", "@types/yargs": "^15.0.14", "@typescript-eslint/eslint-plugin": "^4.33.0", diff --git a/tools/@aws-cdk/prlint/package.json b/tools/@aws-cdk/prlint/package.json index a493c31a3921a..b9a3760d8373f 100644 --- a/tools/@aws-cdk/prlint/package.json +++ b/tools/@aws-cdk/prlint/package.json @@ -21,7 +21,7 @@ "devDependencies": { "@types/fs-extra": "^9.0.13", "@types/glob": "^7.2.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "jest": "^27.3.1", "make-runnable": "^1.3.10", "typescript": "~3.9.10" diff --git a/tools/@aws-cdk/yarn-cling/package.json b/tools/@aws-cdk/yarn-cling/package.json index f34bbccc4b8af..1e91bb79f89e8 100644 --- a/tools/@aws-cdk/yarn-cling/package.json +++ b/tools/@aws-cdk/yarn-cling/package.json @@ -38,7 +38,7 @@ }, "devDependencies": { "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.2", + "@types/jest": "^27.0.3", "@types/node": "^10.17.60", "@types/semver": "^7.3.9", "@types/yarnpkg__lockfile": "^1.1.5", diff --git a/yarn.lock b/yarn.lock index 31fe57fd14f06..dbd4409b992d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -752,14 +752,6 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" -"@jsii/check-node@1.44.2": - version "1.44.2" - resolved "https://registry.npmjs.org/@jsii/check-node/-/check-node-1.44.2.tgz#d7786e7ca739cc9a5cd2cd3f1b93c4375ff884e8" - integrity sha512-rVwrKXkuV4qmo0TmPbYMAu2SCC80xPDzY7cS+TDx80wfU5Dcr66lhpUW04hWcYwrVsUYXxtEYLxAbzeNYeJeoA== - dependencies: - chalk "^4.1.2" - semver "^7.3.5" - "@jsii/check-node@1.46.0": version "1.46.0" resolved "https://registry.npmjs.org/@jsii/check-node/-/check-node-1.46.0.tgz#4825c26f0cd4515015e950ab17df63df07abadfb" @@ -1886,10 +1878,10 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/jest@^27.0.2": - version "27.0.2" - resolved "https://registry.npmjs.org/@types/jest/-/jest-27.0.2.tgz#ac383c4d4aaddd29bbf2b916d8d105c304a5fcd7" - integrity sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA== +"@types/jest@^27.0.3": + version "27.0.3" + resolved "https://registry.npmjs.org/@types/jest/-/jest-27.0.3.tgz#0cf9dfe9009e467f70a342f0f94ead19842a783a" + integrity sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg== dependencies: jest-diff "^27.0.0" pretty-format "^27.0.0" @@ -1944,9 +1936,9 @@ integrity sha512-uv53RrNdhbkV/3VmVCtfImfYCWC3GTTRn3R11Whni3EJ+gb178tkZBVNj2edLY5CMrB749dQi+SJkg87jsN8UQ== "@types/node@*", "@types/node@>= 8", "@types/node@^16.9.2": - version "16.11.7" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" - integrity sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw== + version "16.11.10" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz#2e3ad0a680d96367103d3e670d41c2fed3da61ae" + integrity sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA== "@types/node@^10.17.60": version "10.17.60" @@ -2021,10 +2013,10 @@ dependencies: table "*" -"@types/uuid@^8.3.1": - version "8.3.1" - resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" - integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg== +"@types/uuid@^8.3.3": + version "8.3.3" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.3.tgz#c6a60686d953dbd1b1d45e66f4ecdbd5d471b4d0" + integrity sha512-0LbEEx1zxrYB3pgpd1M5lEhLcXjKJnYghvhTRgaBeUivLHMDM1TzF3IJ6hXU2+8uA4Xz+5BA63mtZo5DjVT8iA== "@types/wrap-ansi@^3.0.0": version "3.0.0" @@ -2196,9 +2188,9 @@ acorn@^7.1.1, acorn@^7.4.0: integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== acorn@^8.2.4, acorn@^8.4.1: - version "8.5.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" - integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== + version "8.6.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" + integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== add-stream@^1.0.0: version "1.0.0" @@ -2240,9 +2232,9 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1: - version "8.8.1" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.8.1.tgz#e73dd88eeb4b10bbcd82bee136e6fbe801664d18" - integrity sha512-6CiMNDrzv0ZR916u2T+iRunnD60uWmNn8SkdB44/6stVORUg0aAkWO7PkOhpCmjmW8f2I/G/xnowD66fxGyQJg== + version "8.8.2" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb" + integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -2526,9 +2518,9 @@ aws-sdk-mock@^5.4.0: traverse "^0.6.6" aws-sdk@^2.596.0, aws-sdk@^2.848.0, aws-sdk@^2.928.0, aws-sdk@^2.979.0: - version "2.1030.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1030.0.tgz#24a856af3d2b8b37c14a8f59974993661c66fd82" - integrity sha512-to0STOb8DsSGuSsUb/WCbg/UFnMGfIYavnJH5ZlRCHzvCFjTyR+vfE8ku+qIZvfFM4+5MNTQC/Oxfun2X/TuyA== + version "2.1035.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1035.0.tgz#89a34c5b1e76e8304201036bf5258bceeebf4137" + integrity sha512-BjSGGZIQE/SCLDgj2T4AhtBG4A4NgXhV/Z/I/E7Mst/RpOepTqZGznUbgXTvO+Z3gKqx33jJa6mS7ZxStCb/Wg== dependencies: buffer "4.9.2" events "1.1.1" @@ -2775,7 +2767,7 @@ buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= -buffer-from@1.x, buffer-from@^1.0.0: +buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== @@ -2920,17 +2912,17 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -cdk8s-plus-21@^1.0.0-beta.38: - version "1.0.0-beta.38" - resolved "https://registry.npmjs.org/cdk8s-plus-21/-/cdk8s-plus-21-1.0.0-beta.38.tgz#8dbe9d0941014e883819d506be0140a688c0f2ed" - integrity sha512-cIL0R5QbvKLnmBGLLheX//tsPgMa0yXheyOzA+3eJourn8/c3QXr+ZXyw125zGgMbTQBRxvwHoy84EPVBiyqGQ== +cdk8s-plus-21@^1.0.0-beta.44: + version "1.0.0-beta.44" + resolved "https://registry.npmjs.org/cdk8s-plus-21/-/cdk8s-plus-21-1.0.0-beta.44.tgz#87eda022cf827dc950db1def42f470d46d64e356" + integrity sha512-3W7nUwSQesmWi4DDU47xjlEb74HK1QJ567JInNJYsgfKpgN+MJvq+J8lP+Ok4qkGZRpw91P6r9T2U9JO2zQdVg== dependencies: minimatch "^3.0.4" -cdk8s@^1.00.0: - version "1.1.36" - resolved "https://registry.npmjs.org/cdk8s/-/cdk8s-1.1.36.tgz#18f4650bf1302f8db533d1380913db4187a965fb" - integrity sha512-LpjVRmypar0PCBxhbTOZ/nnWiI4L7pxSsQJ8k06uSjnVkcGVZLcPxF9kxoKCClp0/6+9MsEYdB6+GZ3h24JKZw== +cdk8s@^1.1.42: + version "1.1.42" + resolved "https://registry.npmjs.org/cdk8s/-/cdk8s-1.1.42.tgz#0cd078ece1e4cd85685d7e8bfeb185f2503631ed" + integrity sha512-jK56rKeOMHRjMfnKUvU34GzQPzW+tplOBu5wpEr++cJhg3YUPwmFp5m7/53yaIUk2jLHYodxacA8wSaP14fJRw== dependencies: fast-json-patch "^2.2.1" follow-redirects "^1.14.5" @@ -3007,9 +2999,9 @@ ci-info@^2.0.0: integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== ci-info@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" - integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== + version "3.3.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== cjs-module-lexer@^0.6.0: version "0.6.0" @@ -3104,15 +3096,6 @@ co@^4.6.0: resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= -codemaker@^1.44.2: - version "1.44.2" - resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.44.2.tgz#620b093f36d3fc989776abe2b8f1fed8cabcb7c4" - integrity sha512-yS9//oDu07/TXyIsuQRqfqzB8z9Z9hq9sz/kxK5+ibUDiMr4q/k9HDn9UuK+OZPo0wisffYJCxe/9UjrETiy9Q== - dependencies: - camelcase "^6.2.0" - decamelize "^5.0.1" - fs-extra "^9.1.0" - codemaker@^1.46.0: version "1.46.0" resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.46.0.tgz#9889188c8085e3b1a1058c4f8e1f1b9458177e8c" @@ -3179,10 +3162,10 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@~8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/commander/-/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8" - integrity sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA== +commander@~8.3.0: + version "8.3.0" + resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== commondir@^1.0.1: version "1.0.1" @@ -3891,9 +3874,9 @@ ecc-jsbn@~0.1.1: safer-buffer "^2.1.0" electron-to-chromium@^1.3.896: - version "1.3.900" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.900.tgz#5be2c5818a2a012c511b4b43e87b6ab7a296d4f5" - integrity sha512-SuXbQD8D4EjsaBaJJxySHbC+zq8JrFfxtb4GIr4E9n1BcROyMcRrJCYQNpJ9N+Wjf5mFp7Wp0OHykd14JNEzzQ== + version "1.4.0" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.0.tgz#7456192519838f881e35e4038bf4ad2c36353e63" + integrity sha512-+oXCt6SaIu8EmFTPx8wNGSB0tHQ5biDscnlf6Uxuz17e9CjzMRtGk9B8705aMPnj0iWr3iC74WuIkngCsLElmA== emittery@^0.7.1: version "0.7.2" @@ -4022,113 +4005,113 @@ es6-error@^4.0.1: resolved "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild-android-arm64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.14.tgz#c85083ece26be3d67e6c720e088968a98409e023" - integrity sha512-Q+Xhfp827r+ma8/DJgpMRUbDZfefsk13oePFEXEIJ4gxFbNv5+vyiYXYuKm43/+++EJXpnaYmEnu4hAKbAWYbA== - -esbuild-darwin-64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.14.tgz#8e4e237ad847cc54a1d3a5caee26a746b9f0b81f" - integrity sha512-YmOhRns6QBNSjpVdTahi/yZ8dscx9ai7a6OY6z5ACgOuQuaQ2Qk2qgJ0/siZ6LgD0gJFMV8UINFV5oky5TFNQQ== - -esbuild-darwin-arm64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.14.tgz#b3b5ebd40b2cb06ee0f6fb342dd4bdcca54ad273" - integrity sha512-Lp00VTli2jqZghSa68fx3fEFCPsO1hK59RMo1PRap5RUjhf55OmaZTZYnCDI0FVlCtt+gBwX5qwFt4lc6tI1xg== - -esbuild-freebsd-64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.14.tgz#175ecb2fa8141428cf70ea2d5f4c27534bad53e0" - integrity sha512-BKosI3jtvTfnmsCW37B1TyxMUjkRWKqopR0CE9AF2ratdpkxdR24Vpe3gLKNyWiZ7BE96/SO5/YfhbPUzY8wKw== - -esbuild-freebsd-arm64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.14.tgz#a7d64e41d1fa581f8db7775e5200f18e67d70c4d" - integrity sha512-yd2uh0yf+fWv5114+SYTl4/1oDWtr4nN5Op+PGxAkMqHfYfLjFKpcxwCo/QOS/0NWqPVE8O41IYZlFhbEN2B8Q== - -esbuild-linux-32@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.14.tgz#14bdd4f6b6cfd35c65c835894651ba335c2117da" - integrity sha512-a8rOnS1oWSfkkYWXoD2yXNV4BdbDKA7PNVQ1klqkY9SoSApL7io66w5H44mTLsfyw7G6Z2vLlaLI2nz9MMAowA== - -esbuild-linux-64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.14.tgz#7fd56851b2982fdd0cd8447ee9858c2c5711708a" - integrity sha512-yPZSoMs9W2MC3Dw+6kflKt5FfQm6Dicex9dGIr1OlHRsn3Hm7yGMUTctlkW53KknnZdOdcdd5upxvbxqymczVQ== - -esbuild-linux-arm64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.14.tgz#a55634d70679ba509adeafd68eebb9fd1ec5af6c" - integrity sha512-Lvo391ln9PzC334e+jJ2S0Rt0cxP47eoH5gFyv/E8HhOnEJTvm7A+RRnMjjHnejELacTTfYgFGQYPjLsi/jObQ== - -esbuild-linux-arm@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.14.tgz#bb96a99677e608b31ff61f37564326d38e846ca2" - integrity sha512-8chZE4pkKRvJ/M/iwsNQ1KqsRg2RyU5eT/x2flNt/f8F2TVrDreR7I0HEeCR50wLla3B1C3wTIOzQBmjuc6uWg== - -esbuild-linux-mips64le@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.14.tgz#6a55362a8fd1e593dea2ecc41877beed8b8184b9" - integrity sha512-MZhgxbmrWbpY3TOE029O6l5tokG9+Yoj2hW7vdit/d/VnmneqeGrSHADuDL6qXM8L5jaCiaivb4VhsyVCpdAbQ== - -esbuild-linux-ppc64le@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.14.tgz#9e0048587ece0a7f184ab147f20d077098045e7f" - integrity sha512-un7KMwS7fX1Un6BjfSZxTT8L5cV/8Uf4SAhM7WYy2XF8o8TI+uRxxD03svZnRNIPsN2J5cl6qV4n7Iwz+yhhVw== - -esbuild-netbsd-64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.14.tgz#dcab16a4bbcfa16e2e8535dadc5f64fdc891c63b" - integrity sha512-5ekKx/YbOmmlTeNxBjh38Uh5TGn5C4uyqN17i67k18pS3J+U2hTVD7rCxcFcRS1AjNWumkVL3jWqYXadFwMS0Q== - -esbuild-openbsd-64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.14.tgz#3c7453b155ebb68dc34d5aec3bd6505337bdda08" - integrity sha512-9bzvwewHjct2Cv5XcVoE1yW5YTW12Sk838EYfA46abgnhxGoFSD1mFcaztp5HHC43AsF+hQxbSFG/RilONARUA== - -esbuild-sunos-64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.14.tgz#85addf5fef6b5db154a955d4f2e88953359d75ce" - integrity sha512-mjMrZB76M6FmoiTvj/RGWilrioR7gVwtFBRVugr9qLarXMIU1W/pQx+ieEOtflrW61xo8w1fcxyHsVVGRvoQ0w== - -esbuild-windows-32@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.14.tgz#f77f98f30a5c636c44db2428ecdf9bcbbaedb1a7" - integrity sha512-GZa6mrx2rgfbH/5uHg0Rdw50TuOKbdoKCpEBitzmG5tsXBdce+cOL+iFO5joZc6fDVCLW3Y6tjxmSXRk/v20Hg== - -esbuild-windows-64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.14.tgz#bc778674c40d65150d12385e0f23eb3a0badbd0d" - integrity sha512-Lsgqah24bT7ClHjLp/Pj3A9wxjhIAJyWQcrOV4jqXAFikmrp2CspA8IkJgw7HFjx6QrJuhpcKVbCAe/xw0i2yw== - -esbuild-windows-arm64@0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.14.tgz#91a8dad35ab2c4dd27cd83860742955b25a354d7" - integrity sha512-KP8FHVlWGhM7nzYtURsGnskXb/cBCPTfj0gOKfjKq2tHtYnhDZywsUG57nk7TKhhK0fL11LcejHG3LRW9RF/9A== - -esbuild@^0.13.14: - version "0.13.14" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.13.14.tgz#98a3f7f42809abdc2b57c84565d0f713382dc1a5" - integrity sha512-xu4D+1ji9x53ocuomcY+KOrwAnWzhBu/wTEjpdgZ8I1c8i5vboYIeigMdzgY1UowYBKa2vZgVgUB32bu7gkxeg== +esbuild-android-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz#3fc3ff0bab76fe35dd237476b5d2b32bb20a3d44" + integrity sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg== + +esbuild-darwin-64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz#8e9169c16baf444eacec60d09b24d11b255a8e72" + integrity sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ== + +esbuild-darwin-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz#1b07f893b632114f805e188ddfca41b2b778229a" + integrity sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ== + +esbuild-freebsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz#0b8b7eca1690c8ec94c75680c38c07269c1f4a85" + integrity sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA== + +esbuild-freebsd-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz#2e1a6c696bfdcd20a99578b76350b41db1934e52" + integrity sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ== + +esbuild-linux-32@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz#6fd39f36fc66dd45b6b5f515728c7bbebc342a69" + integrity sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g== + +esbuild-linux-64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz#9cb8e4bcd7574e67946e4ee5f1f1e12386bb6dd3" + integrity sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA== + +esbuild-linux-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz#3891aa3704ec579a1b92d2a586122e5b6a2bfba1" + integrity sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA== + +esbuild-linux-arm@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz#8a00e99e6a0c6c9a6b7f334841364d8a2b4aecfe" + integrity sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA== + +esbuild-linux-mips64le@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz#36b07cc47c3d21e48db3bb1f4d9ef8f46aead4f7" + integrity sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg== + +esbuild-linux-ppc64le@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz#f7e6bba40b9a11eb9dcae5b01550ea04670edad2" + integrity sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ== + +esbuild-netbsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz#a2fedc549c2b629d580a732d840712b08d440038" + integrity sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w== + +esbuild-openbsd-64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz#b22c0e5806d3a1fbf0325872037f885306b05cd7" + integrity sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g== + +esbuild-sunos-64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz#d0b6454a88375ee8d3964daeff55c85c91c7cef4" + integrity sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw== + +esbuild-windows-32@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz#c96d0b9bbb52f3303322582ef8e4847c5ad375a7" + integrity sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw== + +esbuild-windows-64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz#1f79cb9b1e1bb02fb25cd414cb90d4ea2892c294" + integrity sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ== + +esbuild-windows-arm64@0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz#482173070810df22a752c686509c370c3be3b3c3" + integrity sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA== + +esbuild@^0.13.15: + version "0.13.15" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz#db56a88166ee373f87dbb2d8798ff449e0450cdf" + integrity sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw== optionalDependencies: - esbuild-android-arm64 "0.13.14" - esbuild-darwin-64 "0.13.14" - esbuild-darwin-arm64 "0.13.14" - esbuild-freebsd-64 "0.13.14" - esbuild-freebsd-arm64 "0.13.14" - esbuild-linux-32 "0.13.14" - esbuild-linux-64 "0.13.14" - esbuild-linux-arm "0.13.14" - esbuild-linux-arm64 "0.13.14" - esbuild-linux-mips64le "0.13.14" - esbuild-linux-ppc64le "0.13.14" - esbuild-netbsd-64 "0.13.14" - esbuild-openbsd-64 "0.13.14" - esbuild-sunos-64 "0.13.14" - esbuild-windows-32 "0.13.14" - esbuild-windows-64 "0.13.14" - esbuild-windows-arm64 "0.13.14" + esbuild-android-arm64 "0.13.15" + esbuild-darwin-64 "0.13.15" + esbuild-darwin-arm64 "0.13.15" + esbuild-freebsd-64 "0.13.15" + esbuild-freebsd-arm64 "0.13.15" + esbuild-linux-32 "0.13.15" + esbuild-linux-64 "0.13.15" + esbuild-linux-arm "0.13.15" + esbuild-linux-arm64 "0.13.15" + esbuild-linux-mips64le "0.13.15" + esbuild-linux-ppc64le "0.13.15" + esbuild-netbsd-64 "0.13.15" + esbuild-openbsd-64 "0.13.15" + esbuild-sunos-64 "0.13.15" + esbuild-windows-32 "0.13.15" + esbuild-windows-64 "0.13.15" + esbuild-windows-arm64 "0.13.15" escalade@^3.1.1: version "3.1.1" @@ -4258,10 +4241,10 @@ eslint-plugin-promise@^4.3.1: resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" integrity sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ== -eslint-plugin-rulesdir@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.2.0.tgz#0d729e3f11bcb1a18d9b724a29a6d1a082ac2d62" - integrity sha512-PPQPCsPkzF3upl1862swPA1bmDAAHKHmJJ4JTHJ11JCVCU4sycB0K5LLA/Rwr6r4VbnpScvUvHV4hqfdjvFmhQ== +eslint-plugin-rulesdir@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.2.1.tgz#e246bb9657e68eb0a30680c60775f40aa829ec0b" + integrity sha512-t7rQvEyfE4JZJu6dPl4/uVr6Fr0fxopBhzVbtq3isfOHMKdlIe9xW/5CtIaWZI0E1U+wzAk0lEnZC8laCD5YLA== eslint-plugin-standard@^4.1.0: version "4.1.0" @@ -5317,7 +5300,7 @@ ignore@^4.0.6: resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8, ignore@^5.1.9, ignore@~5.1.8: +ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8, ignore@^5.1.9, ignore@~5.1.9: version "5.1.9" resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== @@ -6537,7 +6520,7 @@ jest-snapshot@^27.3.1: pretty-format "^27.3.1" semver "^7.3.2" -jest-util@^26.1.0, jest-util@^26.6.2: +jest-util@^26.6.2: version "26.6.2" resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== @@ -6838,13 +6821,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -6885,11 +6861,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - jsonparse@^1.2.0, jsonparse@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -7065,9 +7036,9 @@ line-reader@^0.2.4: integrity sha1-xDkrWH3qOFgMlnhXDm6OSfzlJiI= lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== linkify-it@^3.0.1: version "3.0.3" @@ -7216,7 +7187,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -7362,16 +7333,16 @@ markdown-it@12.2.0: mdurl "^1.0.1" uc.micro "^1.0.5" -markdownlint-cli@^0.29.0: - version "0.29.0" - resolved "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.29.0.tgz#3c56686fd00ace4b68c9cfa3a34a7a9dfdef1417" - integrity sha512-SEXRUT1ri9sXV8xQK88vjGAgmz2X9rxEG2tXdDZMljzW8e++LNTO9zzBBStx3JQWrTDoGTPHNrcurbuiyF97gw== +markdownlint-cli@^0.30.0: + version "0.30.0" + resolved "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.30.0.tgz#4ec0ab85a491eb161182e5c26eff308bf90f18f3" + integrity sha512-NiG8iERjwsRZtJAIyLMDdYL2O3bJVn3fUxzDl+6Iv61/YYz9H9Nzgke/v0/cW9HfGvgZHhbfI19LFMp6gbKdyw== dependencies: - commander "~8.2.0" + commander "~8.3.0" deep-extend "~0.6.0" get-stdin "~8.0.0" glob "~7.2.0" - ignore "~5.1.8" + ignore "~5.1.9" js-yaml "^4.1.0" jsonc-parser "~3.0.0" lodash.differencewith "~4.5.0" @@ -7609,11 +7580,6 @@ mkdirp-infer-owner@^2.0.0: infer-owner "^1.0.4" mkdirp "^1.0.3" -mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - mkdirp@^0.5.1, mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -7621,6 +7587,11 @@ mkdirp@^0.5.1, mkdirp@^0.5.5: dependencies: minimist "^1.2.5" +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mock-fs@^4.14.0: version "4.14.0" resolved "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" @@ -9147,6 +9118,11 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" +safe-stable-stringify@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.2.0.tgz#26a52f13a6988de16a0d88e20248f38e8a7d840c" + integrity sha512-C6AuMdYPuPV/P1leplHNu0lgc2LAElq/g3TdoksDCIVtBhr78o/CH03bt/9SKqugFbKU9CUjsNlCu0fjtQzQUw== + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -9279,9 +9255,9 @@ side-channel@^1.0.3, side-channel@^1.0.4: object-inspect "^1.9.0" signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.5" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" - integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== + version "3.0.6" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== sinon@^11.1.1: version "11.1.2" @@ -9381,9 +9357,9 @@ socks-proxy-agent@5, socks-proxy-agent@^5.0.0: socks "^2.3.3" socks-proxy-agent@^6.0.0: - version "6.1.0" - resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" - integrity sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg== + version "6.1.1" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" + integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== dependencies: agent-base "^6.0.2" debug "^4.3.1" @@ -9431,10 +9407,10 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.17, source-map-support@^0.5.20, source-map-support@^0.5.6: - version "0.5.20" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== +source-map-support@^0.5.17, source-map-support@^0.5.21, source-map-support@^0.5.6: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -9761,7 +9737,7 @@ symbol-tree@^3.2.4: resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@*, table@^6.0.9, table@^6.7.2, table@^6.7.3: +table@*, table@^6.0.9, table@^6.7.3: version "6.7.3" resolved "https://registry.npmjs.org/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7" integrity sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw== @@ -9987,22 +9963,6 @@ trim-newlines@^3.0.0: resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -ts-jest@^26.5.6: - version "26.5.6" - resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" - integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - jest-util "^26.1.0" - json5 "2.x" - lodash "4.x" - make-error "1.x" - mkdirp "1.x" - semver "7.x" - yargs-parser "20.x" - ts-jest@^27.0.7: version "27.0.7" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.7.tgz#fb7c8c8cb5526ab371bc1b23d06e745652cca2d0" @@ -10053,9 +10013,9 @@ ts-node@^9.1.1: yn "3.1.1" tsconfig-paths@^3.11.0, tsconfig-paths@^3.9.0: - version "3.11.0" - resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36" - integrity sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA== + version "3.12.0" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" + integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" @@ -10157,17 +10117,17 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-json-schema@^0.51.0: - version "0.51.0" - resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.51.0.tgz#e2abff69b8564c98c0edef2c13d55ef10fd71427" - integrity sha512-POhWbUNs2oaBti1W9k/JwS+uDsaZD9J/KQiZ/iXRQEOD0lTn9VmshIls9tn+A9X6O+smPjeEz5NEy6WTkCCzrQ== +typescript-json-schema@^0.52.0: + version "0.52.0" + resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.52.0.tgz#954560ec90e5486e8f7a5b7706ec59286a708e29" + integrity sha512-3ZdHzx116gZ+D9LmMl5/+d1G3Rpt8baWngKzepYWHnXbAa8Winv64CmFRqLlMKneE1c40yugYDFcWdyX1FjGzQ== dependencies: "@types/json-schema" "^7.0.9" "@types/node" "^16.9.2" glob "^7.1.7" - json-stable-stringify "^1.0.1" + safe-stable-stringify "^2.2.0" ts-node "^10.2.1" - typescript "~4.2.3" + typescript "~4.4.4" yargs "^17.1.1" typescript@~3.8.3: @@ -10180,10 +10140,10 @@ typescript@~3.9.10: resolved "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== -typescript@~4.2.3: - version "4.2.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" - integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== +typescript@~4.4.4: + version "4.4.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" + integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" @@ -10622,9 +10582,9 @@ write-pkg@^4.0.0: write-json-file "^3.2.0" ws@^7.4.6: - version "7.5.5" - resolved "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" - integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== + version "7.5.6" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== xml-js@^1.6.11: version "1.6.11" From b432822ae45e329a900293eb43712fa4a1d74aa5 Mon Sep 17 00:00:00 2001 From: Julian Michel Date: Wed, 24 Nov 2021 19:43:42 +0100 Subject: [PATCH 09/82] feat(s3): support Transfer Acceleration (#17636) Add support for S3 [Transfer Acceleration](https://docs.aws.amazon.com/AmazonS3/latest/userguide/transfer-acceleration.html). This PR introduces: - New boolean property `transferAcceleration` to enable Transfer Acceleration. - New operation `transferAccelerationUrlForObject()` to get HTTPS endpoint for Transfer Acceleration. Closes #12570. ---- *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/README.md | 19 +++ packages/@aws-cdk/aws-s3/lib/bucket.ts | 55 ++++++ packages/@aws-cdk/aws-s3/test/bucket.test.ts | 169 +++++++++++++++++++ 3 files changed, 243 insertions(+) diff --git a/packages/@aws-cdk/aws-s3/README.md b/packages/@aws-cdk/aws-s3/README.md index b666ee14b44d5..57d9369a274a7 100644 --- a/packages/@aws-cdk/aws-s3/README.md +++ b/packages/@aws-cdk/aws-s3/README.md @@ -463,3 +463,22 @@ const bucket = new s3.Bucket(this, 'MyTempFileBucket', { switching this to `false` in a CDK version *before* `1.126.0` will lead to all objects in the bucket being deleted. Be sure to update your bucket resources by deploying with CDK version `1.126.0` or later **before** switching this value to `false`. + +## Transfer Acceleration + +[Transfer Acceleration](https://docs.aws.amazon.com/AmazonS3/latest/userguide/transfer-acceleration.html) can be configured to enable fast, easy, and secure transfers of files over long distances: + +```ts +const bucket = new s3.Bucket(this, 'MyBucket', { + transferAcceleration: true, +}); +``` + +To access the bucket that is enabled for Transfer Acceleration, you must use a special endpoint. The URL can be generated using method `transferAccelerationUrlForObject`: + +```ts +const bucket = new s3.Bucket(this, 'MyBucket', { + transferAcceleration: true, +}); +bucket.transferAccelerationUrlForObject('objectname'); +``` diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index ce8dafd5a69aa..673a1b4f5b561 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -115,6 +115,20 @@ export interface IBucket extends IResource { */ urlForObject(key?: string): string; + /** + * The https Transfer Acceleration URL of an S3 object. Specify `dualStack: true` at the options + * for dual-stack endpoint (connect to the bucket over IPv6). For example: + * + * - `https://bucket.s3-accelerate.amazonaws.com` + * - `https://bucket.s3-accelerate.amazonaws.com/key` + * + * @param key The S3 key of the object. If not specified, the URL of the + * bucket is returned. + * @param options Options for generating URL. + * @returns an TransferAccelerationUrl token + */ + transferAccelerationUrlForObject(key?: string, options?: TransferAccelerationUrlOptions): string; + /** * The virtual hosted-style URL of an S3 object. Specify `regional: false` at * the options for non-regional URL. For example: @@ -623,6 +637,27 @@ export abstract class BucketBase extends Resource implements IBucket { return this.urlJoin(prefix, this.bucketName, key); } + /** + * The https Transfer Acceleration URL of an S3 object. Specify `dualStack: true` at the options + * for dual-stack endpoint (connect to the bucket over IPv6). For example: + * + * - `https://bucket.s3-accelerate.amazonaws.com` + * - `https://bucket.s3-accelerate.amazonaws.com/key` + * + * @param key The S3 key of the object. If not specified, the URL of the + * bucket is returned. + * @param options Options for generating URL. + * @returns an TransferAccelerationUrl token + */ + public transferAccelerationUrlForObject(key?: string, options?: TransferAccelerationUrlOptions): string { + const dualStack = options?.dualStack ? '.dualstack' : ''; + const prefix = `https://${this.bucketName}.s3-accelerate${dualStack}.amazonaws.com/`; + if (typeof key !== 'string') { + return this.urlJoin(prefix); + } + return this.urlJoin(prefix, key); + } + /** * The virtual hosted-style URL of an S3 object. Specify `regional: false` at * the options for non-regional URL. For example: @@ -1369,6 +1404,13 @@ export interface BucketProps { * */ readonly objectOwnership?: ObjectOwnership; + + /** + * Whether this bucket should have transfer acceleration turned on or not. + * + * @default false + */ + readonly transferAcceleration?: boolean; } /** @@ -1535,6 +1577,7 @@ export class Bucket extends BucketBase { loggingConfiguration: this.parseServerAccessLogs(props), inventoryConfigurations: Lazy.any({ produce: () => this.parseInventoryConfiguration() }), ownershipControls: this.parseOwnershipControls(props), + accelerateConfiguration: props.transferAcceleration ? { accelerationStatus: 'Enabled' } : undefined, }); this._resource = resource; @@ -2330,6 +2373,18 @@ export interface VirtualHostedStyleUrlOptions { readonly regional?: boolean; } +/** + * Options for creating a Transfer Acceleration URL. + */ +export interface TransferAccelerationUrlOptions { + /** + * Dual-stack support to connect to the bucket over IPv6. + * + * @default - false + */ + readonly dualStack?: boolean; +} + function mapOrUndefined(list: T[] | undefined, callback: (element: T) => U): U[] | undefined { if (!list || list.length === 0) { return undefined; diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index 67d263aa60ea5..04f15cf302bda 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -2479,4 +2479,173 @@ describe('bucket', () => { autoDeleteObjects: true, })).toThrow(/Cannot use \'autoDeleteObjects\' property on a bucket without setting removal policy to \'DESTROY\'/); }); + + test('bucket with transfer acceleration turned on', () => { + const stack = new cdk.Stack(); + new s3.Bucket(stack, 'MyBucket', { + transferAcceleration: true, + }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyBucketF68F3FF0': { + 'Type': 'AWS::S3::Bucket', + 'Properties': { + 'AccelerateConfiguration': { + 'AccelerationStatus': 'Enabled', + }, + }, + 'DeletionPolicy': 'Retain', + 'UpdateReplacePolicy': 'Retain', + }, + }, + }); + + }); + + test('transferAccelerationUrlForObject returns a token with the S3 URL of the token', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const bucketWithRegion = s3.Bucket.fromBucketAttributes(stack, 'RegionalBucket', { + bucketArn: 'arn:aws:s3:::explicit-region-bucket', + region: 'us-west-2', + }); + + new cdk.CfnOutput(stack, 'BucketURL', { value: bucket.transferAccelerationUrlForObject() }); + new cdk.CfnOutput(stack, 'MyFileURL', { value: bucket.transferAccelerationUrlForObject('my/file.txt') }); + new cdk.CfnOutput(stack, 'YourFileURL', { value: bucket.transferAccelerationUrlForObject('/your/file.txt') }); // "/" is optional + new cdk.CfnOutput(stack, 'RegionBucketURL', { value: bucketWithRegion.transferAccelerationUrlForObject() }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyBucketF68F3FF0': { + 'Type': 'AWS::S3::Bucket', + 'DeletionPolicy': 'Retain', + 'UpdateReplacePolicy': 'Retain', + }, + }, + 'Outputs': { + 'BucketURL': { + 'Value': { + 'Fn::Join': [ + '', + [ + 'https://', + { + 'Ref': 'MyBucketF68F3FF0', + }, + '.s3-accelerate.amazonaws.com/', + ], + ], + }, + }, + 'MyFileURL': { + 'Value': { + 'Fn::Join': [ + '', + [ + 'https://', + { + 'Ref': 'MyBucketF68F3FF0', + }, + '.s3-accelerate.amazonaws.com/my/file.txt', + ], + ], + }, + }, + 'YourFileURL': { + 'Value': { + 'Fn::Join': [ + '', + [ + 'https://', + { + 'Ref': 'MyBucketF68F3FF0', + }, + '.s3-accelerate.amazonaws.com/your/file.txt', + ], + ], + }, + }, + 'RegionBucketURL': { + 'Value': 'https://explicit-region-bucket.s3-accelerate.amazonaws.com/', + }, + }, + }); + + + }); + + test('transferAccelerationUrlForObject with dual stack option returns a token with the S3 URL of the token', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const bucketWithRegion = s3.Bucket.fromBucketAttributes(stack, 'RegionalBucket', { + bucketArn: 'arn:aws:s3:::explicit-region-bucket', + region: 'us-west-2', + }); + + new cdk.CfnOutput(stack, 'BucketURL', { value: bucket.transferAccelerationUrlForObject(undefined, { dualStack: true }) }); + new cdk.CfnOutput(stack, 'MyFileURL', { value: bucket.transferAccelerationUrlForObject('my/file.txt', { dualStack: true }) }); + new cdk.CfnOutput(stack, 'YourFileURL', { value: bucket.transferAccelerationUrlForObject('/your/file.txt', { dualStack: true }) }); // "/" is optional + new cdk.CfnOutput(stack, 'RegionBucketURL', { value: bucketWithRegion.transferAccelerationUrlForObject(undefined, { dualStack: true }) }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyBucketF68F3FF0': { + 'Type': 'AWS::S3::Bucket', + 'DeletionPolicy': 'Retain', + 'UpdateReplacePolicy': 'Retain', + }, + }, + 'Outputs': { + 'BucketURL': { + 'Value': { + 'Fn::Join': [ + '', + [ + 'https://', + { + 'Ref': 'MyBucketF68F3FF0', + }, + '.s3-accelerate.dualstack.amazonaws.com/', + ], + ], + }, + }, + 'MyFileURL': { + 'Value': { + 'Fn::Join': [ + '', + [ + 'https://', + { + 'Ref': 'MyBucketF68F3FF0', + }, + '.s3-accelerate.dualstack.amazonaws.com/my/file.txt', + ], + ], + }, + }, + 'YourFileURL': { + 'Value': { + 'Fn::Join': [ + '', + [ + 'https://', + { + 'Ref': 'MyBucketF68F3FF0', + }, + '.s3-accelerate.dualstack.amazonaws.com/your/file.txt', + ], + ], + }, + }, + 'RegionBucketURL': { + 'Value': 'https://explicit-region-bucket.s3-accelerate.dualstack.amazonaws.com/', + }, + }, + }); + + + }); }); From f2bf322e043ced0193a1b47ae4abd370b095ec1c Mon Sep 17 00:00:00 2001 From: Avani Mande Date: Wed, 24 Nov 2021 12:18:43 -0800 Subject: [PATCH 10/82] feat(stepfunctions-tasks): add 'Emr on Eks' tasks (#17103) This CDK feature adds support for Emr on Eks by implementing API service integrations for the following three APIs. This PR adds three tasks which support Emr on Eks: 1) [Create Virtual Cluster](https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_CreateVirtualCluster.html) 2) [ Start a job run](https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_StartJobRun.html) 3) [Delete virtual cluster ](https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_DeleteVirtualCluster.html) Continuation of #15262 by @matthewsvu and @BenChaimberg: Closes #15234. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-stepfunctions-tasks/README.md | 167 ++ .../emrcontainers/create-virtual-cluster.ts | 146 ++ .../emrcontainers/delete-virtual-cluster.ts | 74 + .../lib/emrcontainers/start-job-run.ts | 681 +++++ .../emrcontainers/utils/role-policy/index.py | 16 + .../aws-stepfunctions-tasks/lib/index.ts | 3 + .../aws-stepfunctions-tasks/package.json | 6 + .../create-virtual-cluster.test.ts | 215 ++ .../delete-virtual-cluster.test.ts | 228 ++ ...nteg.job-submission-workflow.expected.json | 1809 +++++++++++++ .../integ.job-submission-workflow.ts | 90 + .../integ.start-job-run.expected.json | 2254 +++++++++++++++++ .../test/emrcontainers/integ.start-job-run.ts | 100 + .../test/emrcontainers/start-job-run.test.ts | 998 ++++++++ 14 files changed, 6787 insertions(+) create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/create-virtual-cluster.ts create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/delete-virtual-cluster.ts create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/start-job-run.ts create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/utils/role-policy/index.py create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/create-virtual-cluster.test.ts create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/delete-virtual-cluster.test.ts create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.expected.json create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.ts create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.expected.json create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.ts create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/start-job-run.test.ts diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 2f5d463067a35..59adc3517e704 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -60,6 +60,10 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw - [Cancel Step](#cancel-step) - [Modify Instance Fleet](#modify-instance-fleet) - [Modify Instance Group](#modify-instance-group) + - [EMR on EKS](#emr-on-eks) + - [Create Virtual Cluster](#create-virtual-cluster) + - [Delete Virtual Cluster](#delete-virtual-cluster) + - [Start Job Run](#start-job-run) - [EKS](#eks) - [Call](#call) - [EventBridge](#eventbridge) @@ -783,6 +787,169 @@ new tasks.EmrModifyInstanceGroupByName(this, 'Task', { }); ``` +## EMR on EKS + +Step Functions supports Amazon EMR on EKS through the service integration pattern. +The service integration APIs correspond to Amazon EMR on EKS APIs, but differ in the parameters that are used. + +[Read more](https://docs.aws.amazon.com/step-functions/latest/dg/connect-emr-eks.html) about the differences when using these service integrations. + +[Setting up](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up.html) the EKS cluster is required. + +### Create Virtual Cluster + +The [CreateVirtualCluster](https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_CreateVirtualCluster.html) API creates a single virtual cluster that's mapped to a single Kubernetes namespace. + +The EKS cluster containing the Kubernetes namespace where the virtual cluster will be mapped can be passed in from the task input. + +```ts +new tasks.EmrContainersCreateVirtualCluster(this, 'Create a Virtual Cluster', { + eksCluster: tasks.EksClusterInput.fromTaskInput(sfn.TaskInput.fromText('clusterId')), +}); +``` + +The EKS cluster can also be passed in directly. + +```ts +import * as eks from '@aws-cdk/aws-eks'; + +declare const eksCluster: eks.Cluster; + +new tasks.EmrContainersCreateVirtualCluster(this, 'Create a Virtual Cluster', { + eksCluster: tasks.EksClusterInput.fromCluster(eksCluster), +}); +``` + +By default, the Kubernetes namespace that a virtual cluster maps to is "default", but a specific namespace within an EKS cluster can be selected. + +```ts +new tasks.EmrContainersCreateVirtualCluster(this, 'Create a Virtual Cluster', { + eksCluster: tasks.EksClusterInput.fromTaskInput(sfn.TaskInput.fromText('clusterId')), + eksNamespace: 'specified-namespace', +}); +``` + +### Delete Virtual Cluster + +The [DeleteVirtualCluster](https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_DeleteVirtualCluster.html) API deletes a virtual cluster. + +```ts +new tasks.EmrContainersDeleteVirtualCluster(this, 'Delete a Virtual Cluster', { + virtualClusterId: sfn.TaskInput.fromJsonPathAt('$.virtualCluster'), +}); +``` + +### Start Job Run + +The [StartJobRun](https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_StartJobRun.html) API starts a job run. A job is a unit of work that you submit to Amazon EMR on EKS for execution. The work performed by the job can be defined by a Spark jar, PySpark script, or SparkSQL query. A job run is an execution of the job on the virtual cluster. + +Required setup: + + - If not done already, follow the [steps](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up.html) to setup EMR on EKS and [create an EKS Cluster](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-eks-readme.html#quick-start). + - Enable [Cluster access](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-cluster-access.html) + - Enable [IAM Role access](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-enable-IAM.html) + +The following actions must be performed if the virtual cluster ID is supplied from the task input. Otherwise, if it is supplied statically in the state machine definition, these actions will be done automatically. + + - Create an [IAM role](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iam.Role.html) + - Update the [Role Trust Policy](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-trust-policy.html) of the Job Execution Role. + +The job can be configured with spark submit parameters: + +```ts +new tasks.EmrContainersStartJobRun(this, 'EMR Containers Start Job Run', { + virtualCluster: tasks.VirtualClusterInput.fromVirtualClusterId('de92jdei2910fwedz'), + releaseLabel: tasks.ReleaseLabel.EMR_6_2_0, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'), + sparkSubmitParameters: '--conf spark.executor.instances=2 --conf spark.executor.memory=2G --conf spark.executor.cores=2 --conf spark.driver.cores=1', + }, + }, +}); +``` + +Configuring the job can also be done via application configuration: + +```ts +new tasks.EmrContainersStartJobRun(this, 'EMR Containers Start Job Run', { + virtualCluster: tasks.VirtualClusterInput.fromVirtualClusterId('de92jdei2910fwedz'), + releaseLabel: tasks.ReleaseLabel.EMR_6_2_0, + jobName: 'EMR-Containers-Job', + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'), + }, + }, + applicationConfig: [{ + classification: tasks.Classification.SPARK_DEFAULTS, + properties: { + 'spark.executor.instances': '1', + 'spark.executor.memory': '512M', + }, + }], +}); +``` + +Job monitoring can be enabled if `monitoring.logging` is set true. This automatically generates an S3 bucket and CloudWatch logs. + +```ts +new tasks.EmrContainersStartJobRun(this, 'EMR Containers Start Job Run', { + virtualCluster: tasks.VirtualClusterInput.fromVirtualClusterId('de92jdei2910fwedz'), + releaseLabel: tasks.ReleaseLabel.EMR_6_2_0, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'), + sparkSubmitParameters: '--conf spark.executor.instances=2 --conf spark.executor.memory=2G --conf spark.executor.cores=2 --conf spark.driver.cores=1', + }, + }, + monitoring: { + logging: true, + }, +}); +``` + +Otherwise, providing monitoring for jobs with existing log groups and log buckets is also available. + +```ts +import * as logs from '@aws-cdk/aws-logs'; + +const logGroup = new logs.LogGroup(this, 'Log Group'); +const logBucket = new s3.Bucket(this, 'S3 Bucket') + +new tasks.EmrContainersStartJobRun(this, 'EMR Containers Start Job Run', { + virtualCluster: tasks.VirtualClusterInput.fromVirtualClusterId('de92jdei2910fwedz'), + releaseLabel: tasks.ReleaseLabel.EMR_6_2_0, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'), + sparkSubmitParameters: '--conf spark.executor.instances=2 --conf spark.executor.memory=2G --conf spark.executor.cores=2 --conf spark.driver.cores=1', + }, + }, + monitoring: { + logGroup: logGroup, + logBucket: logBucket, + }, +}); +``` + +Users can provide their own existing Job Execution Role. + +```ts +new tasks.EmrContainersStartJobRun(this, 'EMR Containers Start Job Run', { + virtualCluster:tasks.VirtualClusterInput.fromTaskInput(sfn.TaskInput.fromJsonPathAt('$.VirtualClusterId')), + releaseLabel: tasks.ReleaseLabel.EMR_6_2_0, + jobName: 'EMR-Containers-Job', + executionRole: iam.Role.fromRoleArn(this, 'Job-Execution-Role', 'arn:aws:iam::xxxxxxxxxxxx:role/JobExecutionRole'), + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'), + sparkSubmitParameters: '--conf spark.executor.instances=2 --conf spark.executor.memory=2G --conf spark.executor.cores=2 --conf spark.driver.cores=1', + }, + }, +}); +``` + ## EKS Step Functions supports Amazon EKS through the service integration pattern. diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/create-virtual-cluster.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/create-virtual-cluster.ts new file mode 100644 index 0000000000000..cb9458ef01e44 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/create-virtual-cluster.ts @@ -0,0 +1,146 @@ +import * as eks from '@aws-cdk/aws-eks'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; + +/** + * Class for supported types of EMR Containers' Container Providers + */ +enum ContainerProviderTypes { + + /** + * Supported container provider type for a EKS Cluster + */ + EKS = 'EKS' +} + +/** + * Class that supports methods which return the EKS cluster name depending on input type. + */ +export class EksClusterInput { + + /** + * Specify an existing EKS Cluster as the name for this Cluster + */ + static fromCluster(cluster: eks.ICluster): EksClusterInput { + return new EksClusterInput(cluster.clusterName); + } + + /** + * Specify a Task Input as the name for this Cluster + */ + static fromTaskInput(taskInput: sfn.TaskInput): EksClusterInput { + return new EksClusterInput(taskInput.value); + } + + /** + * Initializes the clusterName + * + * @param clusterName The name of the EKS Cluster + */ + private constructor(readonly clusterName: string) { } +} + +/** + * Properties to define a EMR Containers CreateVirtualCluster Task on an EKS cluster + */ +export interface EmrContainersCreateVirtualClusterProps extends sfn.TaskStateBaseProps { + + /** + * EKS Cluster or task input that contains the name of the cluster + */ + readonly eksCluster: EksClusterInput; + + /** + * The namespace of an EKS cluster + * + * @default - 'default' + */ + readonly eksNamespace?: string; + + /** + * Name of the virtual cluster that will be created. + * + * @default - the name of the state machine execution that runs this task and state name + */ + readonly virtualClusterName?: string; + + /** + * The tags assigned to the virtual cluster + * + * @default {} + */ + readonly tags?: { [key: string]: string }; +} + +/** + * Task that creates an EMR Containers virtual cluster from an EKS cluster + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-emr-eks.html + */ +export class EmrContainersCreateVirtualCluster extends sfn.TaskStateBase { + + private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ + sfn.IntegrationPattern.REQUEST_RESPONSE, + ]; + + protected readonly taskMetrics?: sfn.TaskMetricsConfig; + protected readonly taskPolicies?: iam.PolicyStatement[]; + + private readonly integrationPattern: sfn.IntegrationPattern; + + constructor(scope: Construct, id: string, private readonly props: EmrContainersCreateVirtualClusterProps) { + super(scope, id, props); + this.integrationPattern = props.integrationPattern ?? sfn.IntegrationPattern.REQUEST_RESPONSE; + validatePatternSupported(this.integrationPattern, EmrContainersCreateVirtualCluster.SUPPORTED_INTEGRATION_PATTERNS); + + this.taskPolicies = this.createPolicyStatements(); + } + + /** + * @internal + */ + protected _renderTask(): any { + return { + Resource: integrationResourceArn('emr-containers', 'createVirtualCluster', this.integrationPattern), + Parameters: sfn.FieldUtils.renderObject({ + Name: this.props.virtualClusterName ?? sfn.JsonPath.stringAt('States.Format(\'{}/{}\', $$.Execution.Name, $$.State.Name)'), + ContainerProvider: { + Id: this.props.eksCluster.clusterName, + Info: { + EksInfo: { + Namespace: this.props.eksNamespace ?? 'default', + }, + }, + Type: ContainerProviderTypes.EKS, + }, + Tags: this.props.tags, + }), + }; + }; + + private createPolicyStatements(): iam.PolicyStatement[] { + return [ + new iam.PolicyStatement({ + resources: ['*'], // We need * permissions for creating a virtual cluster https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-iam.html + actions: ['emr-containers:CreateVirtualCluster'], + }), + new iam.PolicyStatement({ + resources: [ + Stack.of(this).formatArn({ + service: 'iam', + region: '', + resource: 'role/aws-service-role/emr-containers.amazonaws.com', + resourceName: 'AWSServiceRoleForAmazonEMRContainers', + }), + ], + actions: ['iam:CreateServiceLinkedRole'], + conditions: { + StringLike: { 'iam:AWSServiceName': 'emr-containers.amazonaws.com' }, + }, + }), + ]; + } +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/delete-virtual-cluster.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/delete-virtual-cluster.ts new file mode 100644 index 0000000000000..b4e0e9c45e2ce --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/delete-virtual-cluster.ts @@ -0,0 +1,74 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; + +/** + * Properties to define a EMR Containers DeleteVirtualCluster Task + */ +export interface EmrContainersDeleteVirtualClusterProps extends sfn.TaskStateBaseProps { + + /** + * The ID of the virtual cluster that will be deleted. + */ + readonly virtualClusterId: sfn.TaskInput; +} + +/** + * Deletes an EMR Containers virtual cluster as a Task. + * + * @see https://docs.amazonaws.cn/en_us/step-functions/latest/dg/connect-emr-eks.html + */ +export class EmrContainersDeleteVirtualCluster extends sfn.TaskStateBase { + + private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ + sfn.IntegrationPattern.REQUEST_RESPONSE, + sfn.IntegrationPattern.RUN_JOB, + ]; + + protected readonly taskMetrics?: sfn.TaskMetricsConfig; + protected readonly taskPolicies?: iam.PolicyStatement[]; + + private readonly integrationPattern: sfn.IntegrationPattern; + + constructor(scope: Construct, id: string, private readonly props: EmrContainersDeleteVirtualClusterProps) { + super(scope, id, props); + this.integrationPattern = props.integrationPattern ?? sfn.IntegrationPattern.REQUEST_RESPONSE; + + validatePatternSupported(this.integrationPattern, EmrContainersDeleteVirtualCluster.SUPPORTED_INTEGRATION_PATTERNS); + + this.taskPolicies = this.createPolicyStatements(); + } + + /** + * @internal + */ + protected _renderTask(): any { + return { + Resource: integrationResourceArn('emr-containers', 'deleteVirtualCluster', this.integrationPattern), + Parameters: sfn.FieldUtils.renderObject({ + Id: this.props.virtualClusterId.value, + }), + }; + }; + + private createPolicyStatements(): iam.PolicyStatement[] { + const actions = ['emr-containers:DeleteVirtualCluster']; + if (this.integrationPattern === sfn.IntegrationPattern.RUN_JOB) { + actions.push('emr-containers:DescribeVirtualCluster'); + } + + return [new iam.PolicyStatement({ + resources: [ + cdk.Stack.of(this).formatArn({ + arnFormat: cdk.ArnFormat.SLASH_RESOURCE_SLASH_RESOURCE_NAME, + service: 'emr-containers', + resource: 'virtualclusters', + resourceName: sfn.JsonPath.isEncodedJsonPath(this.props.virtualClusterId.value) ? '*' : this.props.virtualClusterId.value, + }), + ], + actions: actions, + })]; + } +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/start-job-run.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/start-job-run.ts new file mode 100644 index 0000000000000..3b4289cc5345a --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/start-job-run.ts @@ -0,0 +1,681 @@ +import * as path from 'path'; +import * as iam from '@aws-cdk/aws-iam'; +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 sfn from '@aws-cdk/aws-stepfunctions'; +import { TaskInput } from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as cr from '@aws-cdk/custom-resources'; +import * as awscli from '@aws-cdk/lambda-layer-awscli'; +import { Construct } from 'constructs'; +import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; + +/** + * The props for a EMR Containers StartJobRun Task. + */ +export interface EmrContainersStartJobRunProps extends sfn.TaskStateBaseProps { + /** + * The ID of the virtual cluster where the job will be run + */ + readonly virtualCluster: VirtualClusterInput; + + /** + * The name of the job run. + * + * @default - No job run name + */ + readonly jobName?: string; + + /** + * The execution role for the job run. + * + * If `virtualClusterId` is from a JSON input path, an execution role must be provided. + * If an execution role is provided, follow the documentation to update the role trust policy. + * @see https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-trust-policy.html + * + * @default - Automatically generated only when the provided `virtualClusterId` is not an encoded JSON path + */ + readonly executionRole?: iam.IRole; + + /** + * The Amazon EMR release version to use for the job run. + */ + readonly releaseLabel: ReleaseLabel; + + /** + * The configurations for the application running in the job run. + * + * Maximum of 100 items + * + * @see https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_Configuration.html + * + * @default - No application config + */ + readonly applicationConfig?: ApplicationConfiguration[]; + + /** + * The job driver for the job run. + * + * @see https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_JobDriver.html + */ + readonly jobDriver: JobDriver; + + /** + * Configuration for monitoring the job run + * + * @see https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_MonitoringConfiguration.html + * + * @default - logging enabled and resources automatically generated if `monitoring.logging` is set to `true` + */ + readonly monitoring?: Monitoring; + + /** + * The tags assigned to job runs. + * + * @default - None + */ + readonly tags?: { [key: string]: string }; +} + +/** + * Starts a job run. + * + * A job is a unit of work that you submit to Amazon EMR on EKS for execution. + * The work performed by the job can be defined by a Spark jar, PySpark script, or SparkSQL query. + * A job run is an execution of the job on the virtual cluster. + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-emr-eks.html + */ +export class EmrContainersStartJobRun extends sfn.TaskStateBase implements iam.IGrantable { + private static readonly SUPPORTED_INTEGRATION_PATTERNS: sfn.IntegrationPattern[] = [ + sfn.IntegrationPattern.REQUEST_RESPONSE, + sfn.IntegrationPattern.RUN_JOB, + ]; + + protected readonly taskMetrics?: sfn.TaskMetricsConfig; + protected readonly taskPolicies?: iam.PolicyStatement[]; + + public readonly grantPrincipal: iam.IPrincipal; + private role: iam.IRole; + private readonly logGroup?: logs.ILogGroup; + private readonly logBucket?: s3.IBucket; + private readonly integrationPattern: sfn.IntegrationPattern; + + constructor(scope: Construct, id: string, private readonly props: EmrContainersStartJobRunProps) { + super(scope, id, props); + this.integrationPattern = props.integrationPattern ?? sfn.IntegrationPattern.RUN_JOB; + validatePatternSupported(this.integrationPattern, EmrContainersStartJobRun.SUPPORTED_INTEGRATION_PATTERNS); + + if (this.props.applicationConfig) { + this.validateAppConfig(this.props.applicationConfig); + } + + if (this.props.jobDriver.sparkSubmitJobDriver) { + this.validateSparkSubmitJobDriver(props.jobDriver.sparkSubmitJobDriver); + } + + if (this.props.executionRole === undefined + && sfn.JsonPath.isEncodedJsonPath(props.virtualCluster.id)) { + throw new Error('Execution role cannot be undefined when the virtual cluster ID is not a concrete value. Provide an execution role with the correct trust policy'); + } + + this.logGroup = this.assignLogGroup(); + this.logBucket = this.assignLogBucket(); + this.role = this.props.executionRole ?? this.createJobExecutionRole(); + this.grantPrincipal = this.role; + + this.grantMonitoringPolicies(); + + this.taskPolicies = this.createPolicyStatements(); + } + + /** + * @internal + */ + protected _renderTask(): any { + return { + Resource: integrationResourceArn('emr-containers', 'startJobRun', this.integrationPattern), + Parameters: sfn.FieldUtils.renderObject({ + VirtualClusterId: this.props.virtualCluster.id, + Name: this.props.jobName, + ExecutionRoleArn: this.role.roleArn, + ReleaseLabel: this.props.releaseLabel.label, + JobDriver: { + SparkSubmitJobDriver: { + EntryPoint: this.props.jobDriver.sparkSubmitJobDriver?.entryPoint.value, + EntryPointArguments: this.props.jobDriver.sparkSubmitJobDriver?.entryPointArguments?.value, + SparkSubmitParameters: this.props.jobDriver.sparkSubmitJobDriver?.sparkSubmitParameters, + }, + }, + ConfigurationOverrides: { + ApplicationConfiguration: cdk.listMapper(this.applicationConfigPropertyToJson)(this.props.applicationConfig), + MonitoringConfiguration: { + CloudWatchMonitoringConfiguration: this.logGroup ? { + LogGroupName: this.logGroup.logGroupName, + LogStreamNamePrefix: this.props.monitoring!.logStreamNamePrefix, + } : undefined, + PersistentAppUI: (this.props.monitoring?.persistentAppUI === false) + ? 'DISABLED' + : 'ENABLED', + S3MonitoringConfiguration: this.logBucket ? { + LogUri: this.logBucket.s3UrlForObject(), + } : undefined, + }, + }, + Tags: this.props.tags, + }), + }; + } + + /** + * Render the EMR Containers ConfigurationProperty as JSON + */ + private applicationConfigPropertyToJson = (property: ApplicationConfiguration) => { + return { + Classification: cdk.stringToCloudFormation(property.classification.classificationStatement), + Properties: property.properties ? cdk.objectToCloudFormation(property.properties) : undefined, + Configurations: property.nestedConfig ? cdk.listMapper(this.applicationConfigPropertyToJson)(property.nestedConfig) : undefined, + }; + } + + private validateAppConfigPropertiesLength(appConfig: ApplicationConfiguration) { + if (appConfig?.properties === undefined) { + return; + } else if (Object.keys(appConfig.properties).length > 100) { + throw new Error(`Application configuration properties must have 100 or fewer entries. Received ${Object.keys(appConfig.properties).length}`); + } + } + + private validatePropertiesNestedAppConfigBothNotUndefined(appConfig: ApplicationConfiguration) { + if (appConfig?.properties === undefined && appConfig?.nestedConfig === undefined) { + throw new Error('Application configuration must have either properties or nested app configurations defined.'); + } + } + + private validateAppConfig(config?: ApplicationConfiguration[]) { + if (config === undefined) { + return; + } else if (config.length > 100) { + throw new Error(`Application configuration array must have 100 or fewer entries. Received ${config.length}`); + } else { + config.forEach(element => this.validateAppConfig(element.nestedConfig)); + config.forEach(element => this.validateAppConfigPropertiesLength(element)); + config.forEach(element => this.validatePropertiesNestedAppConfigBothNotUndefined(element)); + } + } + + private isArrayOfStrings(value: any): boolean { + return Array.isArray(value) && value.every(item => typeof item === 'string'); + } + + private validateEntryPointArguments (entryPointArguments:sfn.TaskInput) { + if (typeof entryPointArguments.value === 'string' && !sfn.JsonPath.isEncodedJsonPath(entryPointArguments.value)) { + throw new Error(`Entry point arguments must be a string array or encoded JSON path, but received a non JSON path string'); + .`); + } + if (!this.isArrayOfStrings(entryPointArguments.value)) { + throw new Error(`Entry point arguments must be a string array or encoded JSON path but received ${typeof entryPointArguments.value}.`); + } + } + + private validateEntryPointArgumentsLength (entryPointArguments:sfn.TaskInput) { + if (this.isArrayOfStrings(entryPointArguments.value) + && (entryPointArguments.value.length > 10280 || entryPointArguments.value.length < 1)) { + throw new Error(`Entry point arguments must be a string array between 1 and 10280 in length. Received ${entryPointArguments.value.length}.`); + } + } + + private validateSparkSubmitParametersLength (sparkSubmitParameters : string) { + if (sparkSubmitParameters.length > 102400 || sparkSubmitParameters.length < 1) { + throw new Error(`Spark submit parameters must be between 1 and 102400 characters in length. Received ${sparkSubmitParameters.length}.`); + } + } + private validateEntryPoint (entryPoint: TaskInput) { + if (!sfn.JsonPath.isEncodedJsonPath(entryPoint.value) && (entryPoint.value.length > 256|| entryPoint.value.length < 1)) { + throw new Error(`Entry point must be between 1 and 256 characters in length. Received ${entryPoint.value.length}.`); + } + } + + private validateSparkSubmitJobDriver (driver:SparkSubmitJobDriver) { + this.validateEntryPoint(driver.entryPoint); + if (driver.entryPointArguments) { + this.validateEntryPointArguments(driver.entryPointArguments); + this.validateEntryPointArgumentsLength(driver.entryPointArguments); + } + if (driver.sparkSubmitParameters) { + this.validateSparkSubmitParametersLength(driver.sparkSubmitParameters); + } + } + + private assignLogGroup = () : any => { + if (this.props.monitoring?.logGroup) { + return (this.props.monitoring?.logGroup); + } else { + return (this.props.monitoring?.logging ? new logs.LogGroup(this, 'Monitoring Log Group') : undefined); + } + } + + private assignLogBucket = () : any => { + if (this.props.monitoring?.logBucket) { + return (this.props.monitoring?.logBucket); + } else { + return (this.props.monitoring?.logging ? new s3.Bucket(this, 'Monitoring Bucket') : undefined); + } + } + + // https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/creating-job-execution-role.html + private createJobExecutionRole(): iam.Role { + const jobExecutionRole = new iam.Role(this, 'Job-Execution-Role', { + assumedBy: new iam.CompositePrincipal( + new iam.ServicePrincipal('emr-containers.amazonaws.com'), + new iam.ServicePrincipal('states.amazonaws.com'), + ), + }); + + this.logBucket?.grantReadWrite(jobExecutionRole); + this.logGroup?.grantWrite(jobExecutionRole); + this.logGroup?.grant(jobExecutionRole, 'logs:DescribeLogStreams'); + + jobExecutionRole.addToPrincipalPolicy( + new iam.PolicyStatement({ + resources: [ + 'arn:aws:logs:*:*:*', + ], + actions: [ + 'logs:DescribeLogGroups', + ], + }), + ); + + this.updateRoleTrustPolicy(jobExecutionRole); + + return jobExecutionRole; + } + private grantMonitoringPolicies() { + + this.logBucket?.grantReadWrite(this.role); + this.logGroup?.grantWrite(this.role); + this.logGroup?.grant(this.role, 'logs:DescribeLogStreams'); + + this.role.addToPrincipalPolicy( + new iam.PolicyStatement({ + resources: [ + 'arn:aws:logs:*:*:*', + ], + actions: [ + 'logs:DescribeLogGroups', + ], + }), + ); + } + + /** + * If an execution role is not provided by user, the automatically generated job execution role must create a trust relationship + * between itself and the identity of the EMR managed service account in order to run jobs on the Kubernetes namespace. + * + * This cannot occur if the user provided virtualClusterId is within an encoded JSON path. + * + * The trust relationship can be created by updating the trust policy of the job execution role. + * + * @param role the automatically generated job execution role + */ + private updateRoleTrustPolicy(role: iam.Role) { + const eksClusterInfo = new cr.AwsCustomResource(this, 'GetEksClusterInfo', { + onCreate: { + service: 'EMRcontainers', + action: 'describeVirtualCluster', + parameters: { + id: this.props.virtualCluster.id, + }, + outputPaths: ['virtualCluster.containerProvider.info.eksInfo.namespace', 'virtualCluster.containerProvider.id'], + physicalResourceId: cr.PhysicalResourceId.of('id'), + }, + policy: cr.AwsCustomResourcePolicy.fromSdkCalls({ + resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE, + }), + }); + /* We make use of custom resources to call update-roll-trust-policy as this command is only available through + * aws cli because this is only used during the initial setup and is not available through the sdk. + * https://awscli.amazonaws.com/v2/documentation/api/latest/reference/emr-containers/update-role-trust-policy.html + * Commands available through SDK: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EMRcontainers.html + * Commands available through CLI: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/emr-containers/index.html + */ + const cliLayer = new awscli.AwsCliLayer(this, 'awsclilayer'); + const shellCliLambda = new lambda.SingletonFunction(this, 'Call Update-Role-Trust-Policy', { + uuid: '8693BB64-9689-44B6-9AAF-B0CC9EB8757C', + runtime: lambda.Runtime.PYTHON_3_6, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, 'utils/role-policy')), + timeout: cdk.Duration.seconds(30), + memorySize: 256, + layers: [cliLayer], + }); + shellCliLambda.addToRolePolicy( + new iam.PolicyStatement({ + resources: [ + cdk.Stack.of(this).formatArn({ + service: 'eks', + resource: 'cluster', + resourceName: eksClusterInfo.getResponseField('virtualCluster.containerProvider.id'), + }), + ], + actions: [ + 'eks:DescribeCluster', + ], + }), + ); + shellCliLambda.addToRolePolicy( + new iam.PolicyStatement({ + resources: [role.roleArn], + actions: [ + 'iam:GetRole', + 'iam:UpdateAssumeRolePolicy', + ], + }), + ); + const provider = new cr.Provider(this, 'CustomResourceProvider', { + onEventHandler: shellCliLambda, + }); + new cdk.CustomResource(this, 'Custom Resource', { + properties: { + eksNamespace: eksClusterInfo.getResponseField('virtualCluster.containerProvider.info.eksInfo.namespace'), + eksClusterId: eksClusterInfo.getResponseField('virtualCluster.containerProvider.id'), + roleName: role.roleName, + }, + serviceToken: provider.serviceToken, + }); + } + + private createPolicyStatements(): iam.PolicyStatement[] { + const policyStatements = [ + new iam.PolicyStatement({ + resources: [ + cdk.Stack.of(this).formatArn({ + arnFormat: cdk.ArnFormat.SLASH_RESOURCE_SLASH_RESOURCE_NAME, + service: 'emr-containers', + resource: 'virtualclusters', + resourceName: sfn.JsonPath.isEncodedJsonPath(this.props.virtualCluster.id) ? '*' : this.props.virtualCluster.id, // Need wild card for dynamic start job run https://docs.aws.amazon.com/step-functions/latest/dg/emr-eks-iam.html + }), + ], + actions: ['emr-containers:StartJobRun'], + conditions: { + StringEquals: { + 'emr-containers:ExecutionRoleArn': this.role.roleArn, + }, + }, + }), + ]; + + if (this.integrationPattern === sfn.IntegrationPattern.RUN_JOB) { + policyStatements.push( + new iam.PolicyStatement({ + resources: [ + cdk.Stack.of(this).formatArn({ + arnFormat: cdk.ArnFormat.SLASH_RESOURCE_SLASH_RESOURCE_NAME, + service: 'emr-containers', + resource: 'virtualclusters', + resourceName: sfn.JsonPath.isEncodedJsonPath(this.props.virtualCluster.id) ? '*' : `${this.props.virtualCluster.id}/jobruns/*`, // Need wild card for dynamic start job run https://docs.aws.amazon.com/step-functions/latest/dg/emr-eks-iam.html + }), + ], + actions: [ + 'emr-containers:DescribeJobRun', + 'emr-containers:CancelJobRun', + ], + }), + ); + } + + return policyStatements; + } +} + +/** + * The information about job driver for Spark submit. + */ +export interface SparkSubmitJobDriver { + /** + * The entry point of job application. + * + * Length Constraints: Minimum length of 1. Maximum length of 256. + */ + readonly entryPoint: sfn.TaskInput; + + /** + * The arguments for a job application in a task input object containing an array of strings + * + * Length Constraints: Minimum length of 1. Maximum length of 10280. + * @type sfn.TaskInput which expects payload as an array of strings + * + * @default - No arguments defined + */ + readonly entryPointArguments?: sfn.TaskInput; + + /** + * The Spark submit parameters that are used for job runs. + * + * Length Constraints: Minimum length of 1. Maximum length of 102400. + * + * @default - No spark submit parameters + */ + readonly sparkSubmitParameters?: string; +} + +/** + * Specify the driver that the EMR Containers job runs on. + * The job driver is used to provide an input for the job that will be run. + */ +export interface JobDriver { + /** + * The job driver parameters specified for spark submit. + * + * @see https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/API_SparkSubmitJobDriver.html + * + */ + readonly sparkSubmitJobDriver: SparkSubmitJobDriver; +} + +/** + * The classification within a EMR Containers application configuration. + * Class can be extended to add other classifications. + * For example, new Classification('xxx-yyy'); + */ +export class Classification { + /** + * Sets the maximizeResourceAllocation property to true or false. + * When true, Amazon EMR automatically configures spark-defaults properties based on cluster hardware configuration. + * + * For more info: + * @see https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-spark-configure.html#emr-spark-maximizeresourceallocation + */ + static readonly SPARK = new Classification('spark'); + + /** + * Sets values in the spark-defaults.conf file. + * + * For more info: + * @see https://spark.apache.org/docs/latest/configuration.html + */ + static readonly SPARK_DEFAULTS = new Classification('spark-defaults'); + + /** + * Sets values in the spark-env.sh file. + * + * For more info: + * @see https://spark.apache.org/docs/latest/configuration.html#environment-variables + */ + static readonly SPARK_ENV = new Classification('spark-env'); + + /** + * Sets values in the hive-site.xml for Spark. + */ + static readonly SPARK_HIVE_SITE = new Classification('spark-hive-site'); + + /** + * Sets values in the log4j.properties file. + * + * For more settings and info: + * @see https://github.com/apache/spark/blob/master/conf/log4j.properties.template + */ + static readonly SPARK_LOG4J = new Classification('spark-log4j'); + + /** + * Sets values in the metrics.properties file. + * + * For more settings and info: + * @see https://github.com/apache/spark/blob/master/conf/metrics.properties.template + */ + static readonly SPARK_METRICS = new Classification('spark-metrics'); + + /** + * Creates a new Classification + * + * @param classificationStatement A literal string in case a new EMR classification is released, if not already defined. + */ + constructor(public readonly classificationStatement: string) { } +} + +/** + * A configuration specification to be used when provisioning virtual clusters, + * which can include configurations for applications and software bundled with Amazon EMR on EKS. + * + * A configuration consists of a classification, properties, and optional nested configurations. + * A classification refers to an application-specific configuration file. + * Properties are the settings you want to change in that file. + * @see https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps.html + */ +export interface ApplicationConfiguration { + /** + * The classification within a configuration. + * + * Length Constraints: Minimum length of 1. Maximum length of 1024. + */ + readonly classification: Classification; + + /** + * A list of additional configurations to apply within a configuration object. + * + * Array Members: Maximum number of 100 items. + * + * @default - No other configurations + */ + readonly nestedConfig?: ApplicationConfiguration[]; + + /** + * A set of properties specified within a configuration classification. + * + * Map Entries: Maximum number of 100 items. + * + * @default - No properties + */ + readonly properties?: { [key: string]: string }; +} + +/** + * Configuration setting for monitoring. + */ +export interface Monitoring { + /** + * Enable logging for this job. + * + * If set to true, will automatically create a Cloudwatch Log Group and S3 bucket. + * This will be set to `true` implicitly if values are provided for `logGroup` or `logBucket`. + * + * @default true - true if values are provided for `logGroup` or `logBucket`, false otherwise + */ + readonly logging?: boolean + + /** + * A log group for CloudWatch monitoring. + * + * You can configure your jobs to send log information to CloudWatch Logs. + * + * @default - if `logging` is manually set to `true` and a `logGroup` is not provided, a `logGroup` will be automatically generated`. + */ + readonly logGroup?: logs.ILogGroup; + + /** + * A log stream name prefix for Cloudwatch monitoring. + * + * @default - Log streams created in this log group have no default prefix + */ + readonly logStreamNamePrefix?: string; + + /** + * Amazon S3 Bucket for monitoring log publishing. + * + * You can configure your jobs to send log information to Amazon S3. + * + * @default - if `logging` is manually set to `true` and a `logBucket` is not provided, a `logBucket` will be automatically generated`. + */ + readonly logBucket?: s3.IBucket; + + /** + * Monitoring configurations for the persistent application UI. + * + * @default true + */ + readonly persistentAppUI?: boolean; +} + +/** + * The Amazon EMR release version to use for the job run. + * + * Can be extended to include new EMR releases + * + * For example, `new ReleaseLabel('emr-x.xx.x-latest');` + */ +export class ReleaseLabel { + /** + * EMR Release version 5.32.0 + */ + static readonly EMR_5_32_0 = new ReleaseLabel('emr-5.32.0-latest'); + + /** + * EMR Release version 5.33.0 + */ + static readonly EMR_5_33_0 = new ReleaseLabel('emr-5.33.0-latest'); + + /** + * EMR Release version 6.2.0 + */ + static readonly EMR_6_2_0 = new ReleaseLabel('emr-6.2.0-latest'); + + /** + * EMR Release version 6.3.0 + */ + static readonly EMR_6_3_0 = new ReleaseLabel('emr-6.3.0-latest'); + + /** + * Initializes the label string. + * + * @param label A literal string that contains the release-version ex. 'emr-x.x.x-latest' + */ + constructor(public readonly label: string) { } +} + +/** + * Class that returns a virtual cluster's id depending on input type + */ +export class VirtualClusterInput { + /** + * Input for a virtualClusterId from a Task Input + */ + static fromTaskInput(taskInput: sfn.TaskInput): VirtualClusterInput { + return new VirtualClusterInput(taskInput.value); + } + + /** + * Input for virtualClusterId from a literal string + */ + static fromVirtualClusterId(virtualClusterId: string): VirtualClusterInput { + return new VirtualClusterInput(virtualClusterId); + } + + /** + * Initializes the virtual cluster ID. + * + * @param id The VirtualCluster Id + */ + private constructor(public readonly id: string) { } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/utils/role-policy/index.py b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/utils/role-policy/index.py new file mode 100644 index 0000000000000..c99c73c685d06 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/emrcontainers/utils/role-policy/index.py @@ -0,0 +1,16 @@ +import subprocess as sp +import os +import logging + +#https://github.com/aws/aws-cdk/tree/master/packages/%40aws-cdk/aws-stepfunctions#custom-state +def handler(event, context): + logger = logging.getLogger() + logger.setLevel(logging.INFO) + command = f"/opt/awscli/aws emr-containers update-role-trust-policy --cluster-name {event['ResourceProperties']['eksClusterId']} --namespace {event['ResourceProperties']['eksNamespace']} --role-name {event['ResourceProperties']['roleName']}" + if event['RequestType'] == 'Create' or event['RequestType'] == 'Update' : + try: + res = sp.check_output(command, shell=True) + logger.info(f"Successfully ran {command}") + except Exception as e: + logger.info(f"ERROR: {str(e)}") + \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts index 0c089eee35bae..04fd1846f1d08 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts @@ -29,6 +29,9 @@ export * from './emr/emr-add-step'; export * from './emr/emr-cancel-step'; export * from './emr/emr-modify-instance-fleet-by-name'; export * from './emr/emr-modify-instance-group-by-name'; +export * from './emrcontainers/create-virtual-cluster'; +export * from './emrcontainers/delete-virtual-cluster'; +export * from './emrcontainers/start-job-run'; export * from './glue/run-glue-job-task'; export * from './glue/start-job-run'; export * from './batch/run-batch-job'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 09bfee9d4f4f0..a3b11eeb6b71b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -107,11 +107,14 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", + "@aws-cdk/lambda-layer-awscli": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", @@ -129,11 +132,14 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", + "@aws-cdk/lambda-layer-awscli": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/create-virtual-cluster.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/create-virtual-cluster.test.ts new file mode 100644 index 0000000000000..d7b6a3d925626 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/create-virtual-cluster.test.ts @@ -0,0 +1,215 @@ +import { Template } from '@aws-cdk/assertions'; +import * as eks from '@aws-cdk/aws-eks'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Stack } from '@aws-cdk/core'; +import { EmrContainersCreateVirtualCluster, EksClusterInput } from '../../lib/emrcontainers/create-virtual-cluster'; + +const emrContainersVirtualClusterName = 'EMR Containers Virtual Cluster'; +let stack: Stack; +let clusterId: string; + +beforeEach(() => { + stack = new Stack(); + clusterId = 'test-eks'; +}); + +describe('Invoke emr-containers CreateVirtualCluster with ', () => { + test('only required properties', () => { + // WHEN + const task = new EmrContainersCreateVirtualCluster(stack, 'Task', { + eksCluster: EksClusterInput.fromTaskInput(sfn.TaskInput.fromText(clusterId)), + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::emr-containers:createVirtualCluster', + ], + ], + }, + End: true, + Parameters: { + 'Name.$': "States.Format('{}/{}', $$.Execution.Name, $$.State.Name)", + 'ContainerProvider': { + Id: clusterId, + Info: { + EksInfo: { + Namespace: 'default', + }, + }, + Type: 'EKS', + }, + }, + }); + }); + + test('all required/non-required properties', () => { + // WHEN + const task = new EmrContainersCreateVirtualCluster(stack, 'Task', { + virtualClusterName: emrContainersVirtualClusterName, + eksCluster: EksClusterInput.fromTaskInput(sfn.TaskInput.fromText(clusterId)), + eksNamespace: 'namespace', + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + Name: emrContainersVirtualClusterName, + ContainerProvider: { + Id: clusterId, + Info: { + EksInfo: { + Namespace: 'namespace', + }, + }, + }, + }, + }); + }); + + test('clusterId from payload', () => { + // WHEN + const task = new EmrContainersCreateVirtualCluster(stack, 'Task', { + eksCluster: EksClusterInput.fromTaskInput(sfn.TaskInput.fromJsonPathAt('$.ClusterId')), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + ContainerProvider: { + 'Id.$': '$.ClusterId', + }, + }, + }); + }); + + test('with an existing EKS cluster', () => { + // WHEN + const eksCluster = new eks.Cluster(stack, 'EKS Cluster', { + version: eks.KubernetesVersion.V1_20, + }); + + const task = new EmrContainersCreateVirtualCluster(stack, 'Task', { + eksCluster: EksClusterInput.fromCluster(eksCluster), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + ContainerProvider: { + Id: { + Ref: 'EKSClusterEDAD5FD1', + }, + }, + }, + }); + }); + + test('Tags', () => { + // WHEN + const task = new EmrContainersCreateVirtualCluster(stack, 'Task', { + eksCluster: EksClusterInput.fromTaskInput(sfn.TaskInput.fromText(clusterId)), + tags: { + key: 'value', + }, + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + Tags: { + key: 'value', + }, + }, + }); + }); +}); + +test('Permitted role actions included for CreateVirtualCluster if service integration pattern is REQUEST_RESPONSE', () => { + // WHEN + const task = new EmrContainersCreateVirtualCluster(stack, 'Task', { + virtualClusterName: emrContainersVirtualClusterName, + eksCluster: EksClusterInput.fromTaskInput(sfn.TaskInput.fromText(clusterId)), + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: 'emr-containers:CreateVirtualCluster', + Effect: 'Allow', + Resource: '*', + }, + { + Action: 'iam:CreateServiceLinkedRole', + Condition: { + StringLike: { + 'iam:AWSServiceName': 'emr-containers.amazonaws.com', + }, + }, + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':role/aws-service-role/emr-containers.amazonaws.com/AWSServiceRoleForAmazonEMRContainers', + ], + ], + }, + }], + }, + }); +}); + +test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration pattern', () => { + expect(() => { + new EmrContainersCreateVirtualCluster(stack, 'EMR Containers CreateVirtualCluster Job', { + virtualClusterName: emrContainersVirtualClusterName, + eksCluster: EksClusterInput.fromTaskInput(sfn.TaskInput.fromText(clusterId)), + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + }); + }).toThrow(/Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE. Received: WAIT_FOR_TASK_TOKEN/); +}); + +test('Task throws if RUN_JOB is supplied as service integration pattern', () => { + expect(() => { + new EmrContainersCreateVirtualCluster(stack, 'EMR Containers CreateVirtualCluster Job', { + virtualClusterName: emrContainersVirtualClusterName, + eksCluster: EksClusterInput.fromTaskInput(sfn.TaskInput.fromText(clusterId)), + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + }); + }).toThrow(/Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE. Received: RUN_JOB/); +}); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/delete-virtual-cluster.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/delete-virtual-cluster.test.ts new file mode 100644 index 0000000000000..484e3f21c342e --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/delete-virtual-cluster.test.ts @@ -0,0 +1,228 @@ +import { Template } from '@aws-cdk/assertions'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Stack } from '@aws-cdk/core'; +import { EmrContainersDeleteVirtualCluster } from '../../lib/emrcontainers/delete-virtual-cluster'; + +let stack: Stack; +let virtualClusterId: string; + +beforeEach(() => { + stack = new Stack(); + virtualClusterId = 'x01f27i9a7cv1td52keaktr6j'; +}); + +describe('Invoke EMR Containers Delete Virtual cluster with ', () => { + test('a valid cluster ID', () => { + // WHEN + const task = new EmrContainersDeleteVirtualCluster(stack, 'Task', { + virtualClusterId: sfn.TaskInput.fromText(virtualClusterId), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::emr-containers:deleteVirtualCluster', + ], + ], + }, + End: true, + Parameters: { + Id: virtualClusterId, + }, + }); + }); + + test('a RUN_JOB call', () => { + // WHEN + const task = new EmrContainersDeleteVirtualCluster(stack, 'Task', { + virtualClusterId: sfn.TaskInput.fromText(virtualClusterId), + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::emr-containers:deleteVirtualCluster.sync', + ], + ], + }, + End: true, + Parameters: { + Id: virtualClusterId, + }, + }); + }); + + test('passing in JSON Path', () => { + // WHEN + const task = new EmrContainersDeleteVirtualCluster(stack, 'Task', { + virtualClusterId: sfn.TaskInput.fromJsonPathAt('$.VirtualClusterId'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + 'Id.$': '$.VirtualClusterId', + }, + }); + }); +}); + +describe('Valid policy statements and resources are passed ', () => { + test('to the state machine with a REQUEST_RESPONSE call', () => { + // WHEN + const task = new EmrContainersDeleteVirtualCluster(stack, 'Task', { + virtualClusterId: sfn.TaskInput.fromText(virtualClusterId), + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: 'emr-containers:DeleteVirtualCluster', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':emr-containers:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + `:/virtualclusters/${virtualClusterId}`, + ], + ], + }, + }], + }, + }); + }); + + test('to the state machine with a RUN_JOB call', () => { + // WHEN + const task = new EmrContainersDeleteVirtualCluster(stack, 'Task', { + virtualClusterId: sfn.TaskInput.fromText(virtualClusterId), + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: [ + 'emr-containers:DeleteVirtualCluster', + 'emr-containers:DescribeVirtualCluster', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':emr-containers:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + `:/virtualclusters/${virtualClusterId}`, + ], + ], + }, + }], + }, + }); + }); + + test('when the virtual cluster ID is from a payload', () => { + // WHEN + const task = new EmrContainersDeleteVirtualCluster(stack, 'Task', { + virtualClusterId: sfn.TaskInput.fromJsonPathAt('$.ClusterId'), + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: [ + 'emr-containers:DeleteVirtualCluster', + 'emr-containers:DescribeVirtualCluster', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':emr-containers:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':/virtualclusters/*', + ], + ], + }, + }], + }, + }); + }); +}); + + +test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration pattern', () => { + expect(() => { + new EmrContainersDeleteVirtualCluster(stack, 'EMR Containers DeleteVirtualCluster Job', { + virtualClusterId: sfn.TaskInput.fromText(virtualClusterId), + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + }); + }).toThrow(/Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE,RUN_JOB. Received: WAIT_FOR_TASK_TOKEN/); +}); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.expected.json new file mode 100644 index 0000000000000..a3b99bf3fb6ed --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.expected.json @@ -0,0 +1,1809 @@ +{ + "Resources": { + "integrationtesteksclusterDefaultVpc395E1A86": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTableAssociation4831B6A7": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317" + } + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1DefaultRoute33CE7FC3": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcIGW9ADAFE6F" + } + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317" + }, + "AllocationId": { + "Fn::GetAtt": [ + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableAssociation62710C52": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11" + } + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2DefaultRoute253A231E": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcIGW9ADAFE6F" + } + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11" + }, + "AllocationId": { + "Fn::GetAtt": [ + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTableAssociation14A23BAF": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D" + } + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3DefaultRouteB0117918": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcIGW9ADAFE6F" + } + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D" + }, + "AllocationId": { + "Fn::GetAtt": [ + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTableAssociation7482DD1E": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet1DefaultRouteCC99A72C": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableAssociation99F934D5": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet2DefaultRoute50FF167F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableAssociationB70598F3": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet3DefaultRoute6DE23E60": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1" + } + } + }, + "integrationtesteksclusterDefaultVpcIGW9ADAFE6F": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-all-services-integ/integration-test-eks-cluster/DefaultVpc" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "InternetGatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcIGW9ADAFE6F" + } + } + }, + "integrationtesteksclusterRole03F70AF0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "eks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSClusterPolicy" + ] + ] + } + ] + } + }, + "integrationtesteksclusterControlPlaneSecurityGroup6E92F333": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "EKS Control Plane Security Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + } + } + }, + "integrationtesteksclusterCreationRoleB98FE02A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcIGW9ADAFE6F", + "integrationtesteksclusterDefaultVpcPrivateSubnet1DefaultRouteCC99A72C", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTableAssociation7482DD1E", + "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB", + "integrationtesteksclusterDefaultVpcPrivateSubnet2DefaultRoute50FF167F", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableAssociation99F934D5", + "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8", + "integrationtesteksclusterDefaultVpcPrivateSubnet3DefaultRoute6DE23E60", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableAssociationB70598F3", + "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1", + "integrationtesteksclusterDefaultVpcPublicSubnet1DefaultRoute33CE7FC3", + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B", + "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTableAssociation4831B6A7", + "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317", + "integrationtesteksclusterDefaultVpcPublicSubnet2DefaultRoute253A231E", + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43", + "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableAssociation62710C52", + "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11", + "integrationtesteksclusterDefaultVpcPublicSubnet3DefaultRouteB0117918", + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59", + "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTableAssociation14A23BAF", + "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D", + "integrationtesteksclusterDefaultVpc395E1A86", + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterCreationRoleDefaultPolicy5417802D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "integrationtesteksclusterRole03F70AF0", + "Arn" + ] + } + }, + { + "Action": [ + "eks:CreateCluster", + "eks:DescribeCluster", + "eks:DescribeUpdate", + "eks:DeleteCluster", + "eks:UpdateClusterVersion", + "eks:UpdateClusterConfig", + "eks:CreateFargateProfile", + "eks:TagResource", + "eks:UntagResource" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + }, + { + "Action": [ + "eks:DescribeFargateProfile", + "eks:DeleteFargateProfile" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "iam:GetRole", + "iam:listAttachedRolePolicies" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "iam:CreateServiceLinkedRole", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "integrationtesteksclusterCreationRoleDefaultPolicy5417802D", + "Roles": [ + { + "Ref": "integrationtesteksclusterCreationRoleB98FE02A" + } + ] + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcIGW9ADAFE6F", + "integrationtesteksclusterDefaultVpcPrivateSubnet1DefaultRouteCC99A72C", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTableAssociation7482DD1E", + "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB", + "integrationtesteksclusterDefaultVpcPrivateSubnet2DefaultRoute50FF167F", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableAssociation99F934D5", + "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8", + "integrationtesteksclusterDefaultVpcPrivateSubnet3DefaultRoute6DE23E60", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableAssociationB70598F3", + "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1", + "integrationtesteksclusterDefaultVpcPublicSubnet1DefaultRoute33CE7FC3", + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B", + "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTableAssociation4831B6A7", + "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317", + "integrationtesteksclusterDefaultVpcPublicSubnet2DefaultRoute253A231E", + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43", + "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableAssociation62710C52", + "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11", + "integrationtesteksclusterDefaultVpcPublicSubnet3DefaultRouteB0117918", + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59", + "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTableAssociation14A23BAF", + "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D", + "integrationtesteksclusterDefaultVpc395E1A86", + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterE5C0ED98": { + "Type": "Custom::AWSCDK-EKS-Cluster", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454", + "Outputs.awsstepfunctionstasksemrcontainersallservicesintegawscdkawseksClusterResourceProviderframeworkonEventFF3F425BArn" + ] + }, + "Config": { + "version": "1.21", + "roleArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterRole03F70AF0", + "Arn" + ] + }, + "resourcesVpcConfig": { + "subnetIds": [ + { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1" + } + ], + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "integrationtesteksclusterControlPlaneSecurityGroup6E92F333", + "GroupId" + ] + } + ], + "endpointPublicAccess": true, + "endpointPrivateAccess": true + } + }, + "AssumeRoleArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "AttributesRevision": 2 + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcIGW9ADAFE6F", + "integrationtesteksclusterDefaultVpcPrivateSubnet1DefaultRouteCC99A72C", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTableAssociation7482DD1E", + "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB", + "integrationtesteksclusterDefaultVpcPrivateSubnet2DefaultRoute50FF167F", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableAssociation99F934D5", + "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8", + "integrationtesteksclusterDefaultVpcPrivateSubnet3DefaultRoute6DE23E60", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableAssociationB70598F3", + "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1", + "integrationtesteksclusterDefaultVpcPublicSubnet1DefaultRoute33CE7FC3", + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B", + "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTableAssociation4831B6A7", + "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317", + "integrationtesteksclusterDefaultVpcPublicSubnet2DefaultRoute253A231E", + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43", + "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableAssociation62710C52", + "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11", + "integrationtesteksclusterDefaultVpcPublicSubnet3DefaultRouteB0117918", + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59", + "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTableAssociation14A23BAF", + "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D", + "integrationtesteksclusterDefaultVpc395E1A86", + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204", + "integrationtesteksclusterCreationRoleDefaultPolicy5417802D", + "integrationtesteksclusterCreationRoleB98FE02A" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integrationtesteksclusterKubectlReadyBarrier0D4A21B0": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "aws:cdk:eks:kubectl-ready" + }, + "DependsOn": [ + "integrationtesteksclusterCreationRoleDefaultPolicy5417802D", + "integrationtesteksclusterCreationRoleB98FE02A", + "integrationtesteksclusterE5C0ED98" + ] + }, + "integrationtesteksclusterMastersRole63B9B0BF": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "integrationtesteksclusterAwsAuthmanifestAEF9C6DF": { + "Type": "Custom::AWSCDK-EKS-KubernetesResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awsstepfunctionstasksemrcontainersallservicesintegawscdkawseksKubectlProviderframeworkonEvent3B33A326Arn" + ] + }, + "Manifest": { + "Fn::Join": [ + "", + [ + "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c89f1e1be2a935f1b46af591dd13f7d1a5d084570d\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "integrationtesteksclusterMastersRole63B9B0BF", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"", + { + "Fn::GetAtt": [ + "integrationtesteksclusterMastersRole63B9B0BF", + "Arn" + ] + }, + "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "integrationtesteksclusterNodegroupDefaultCapacityNodeGroupRole75D45BA7", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" + ] + ] + }, + "ClusterName": { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + "RoleArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "PruneLabel": "aws.cdk.eks/prune-c89f1e1be2a935f1b46af591dd13f7d1a5d084570d", + "Overwrite": true + }, + "DependsOn": [ + "integrationtesteksclusterKubectlReadyBarrier0D4A21B0" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integrationtesteksclusterNodegroupDefaultCapacityNodeGroupRole75D45BA7": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSWorkerNodePolicy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKS_CNI_Policy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + ] + ] + } + ] + } + }, + "integrationtesteksclusterNodegroupDefaultCapacity536CF32C": { + "Type": "AWS::EKS::Nodegroup", + "Properties": { + "ClusterName": { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + "NodeRole": { + "Fn::GetAtt": [ + "integrationtesteksclusterNodegroupDefaultCapacityNodeGroupRole75D45BA7", + "Arn" + ] + }, + "Subnets": [ + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1" + } + ], + "AmiType": "AL2_x86_64", + "ForceUpdateEnabled": true, + "InstanceTypes": [ + "m5.xlarge" + ], + "ScalingConfig": { + "DesiredSize": 3, + "MaxSize": 3, + "MinSize": 3 + } + } + }, + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945S3BucketC636D050" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945S3VersionKey40C5ADFE" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945S3VersionKey40C5ADFE" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket780F031ARef": { + "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKey8DCA7AE1Ref": { + "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtesteksclusterCreationRole78F8A91EArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3Bucket42FF7F94Ref": { + "Ref": "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3Bucket3B443230" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKeyD44C8135Ref": { + "Ref": "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKeyAA4674FB" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket5978B8B5Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey9D9F3D17Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3BucketDBE4A868" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3VersionKeyDA4E6828" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3VersionKeyDA4E6828" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtestekscluster4FFBB19EArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterE5C0ED98", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtesteksclusterCreationRole78F8A91EArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketFB7BE533Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey533AB384Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtesteksclusterDefaultVpcPrivateSubnet1SubnetFBC220C4Ref": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtesteksclusterDefaultVpcPrivateSubnet2Subnet7E4A5E3BRef": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtesteksclusterDefaultVpcPrivateSubnet3Subnet482649D5Ref": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegintegrationtestekscluster4FFBB19EClusterSecurityGroupId": { + "Fn::GetAtt": [ + "integrationtesteksclusterE5C0ED98", + "ClusterSecurityGroupId" + ] + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket5E7D98B4Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyC4C659E7Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket8CD29A22Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyE130152FRef": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket5978B8B5Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawsstepfunctionstasksemrcontainersallservicesintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey9D9F3D17Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "JobExecutionRoleF19B4342": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "emr-containers.amazonaws.com", + { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "JobExecutionRolePolicy6968CCB9": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + "s3:DeleteObject*", + "s3:PutObject", + "s3:Abort*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "StartaJobRunMonitoringBucket899C33D9", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "StartaJobRunMonitoringBucket899C33D9", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "StartaJobRunMonitoringLogGroupD033B7AF", + "Arn" + ] + } + }, + { + "Action": "logs:DescribeLogStreams", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "StartaJobRunMonitoringLogGroupD033B7AF", + "Arn" + ] + } + }, + { + "Action": "logs:DescribeLogGroups", + "Effect": "Allow", + "Resource": "arn:aws:logs:*:*:*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "JobExecutionRolePolicy6968CCB9", + "Roles": [ + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "/", + { + "Fn::Select": [ + 5, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "JobExecutionRoleF19B4342", + "Arn" + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + }, + "StartaJobRunMonitoringLogGroupD033B7AF": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "StartaJobRunMonitoringBucket899C33D9": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "StateMachineRoleB840431D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StateMachineRoleDefaultPolicyDF1E6607": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "emr-containers:CreateVirtualCluster", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "iam:CreateServiceLinkedRole", + "Condition": { + "StringLike": { + "iam:AWSServiceName": "emr-containers.amazonaws.com" + } + }, + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/aws-service-role/emr-containers.amazonaws.com/AWSServiceRoleForAmazonEMRContainers" + ] + ] + } + }, + { + "Action": "emr-containers:StartJobRun", + "Condition": { + "StringEquals": { + "emr-containers:ExecutionRoleArn": { + "Fn::GetAtt": [ + "JobExecutionRoleF19B4342", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":emr-containers:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":/virtualclusters/*" + ] + ] + } + }, + { + "Action": [ + "emr-containers:DescribeJobRun", + "emr-containers:CancelJobRun" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":emr-containers:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":/virtualclusters/*" + ] + ] + } + }, + { + "Action": "emr-containers:DeleteVirtualCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":emr-containers:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":/virtualclusters/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StateMachineRoleDefaultPolicyDF1E6607", + "Roles": [ + { + "Ref": "StateMachineRoleB840431D" + } + ] + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Create a virtual Cluster\",\"States\":{\"Create a virtual Cluster\":{\"Next\":\"Start a Job Run\",\"Type\":\"Task\",\"ResultPath\":\"$.cluster\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::emr-containers:createVirtualCluster\",\"Parameters\":{\"Name\":\"Virtual-Cluster-Name\",\"ContainerProvider\":{\"Id\":\"", + { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + "\",\"Info\":{\"EksInfo\":{\"Namespace\":\"default\"}},\"Type\":\"EKS\"}}},\"Start a Job Run\":{\"Next\":\"Delete a Virtual Cluster\",\"Type\":\"Task\",\"ResultPath\":\"$.job\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::emr-containers:startJobRun.sync\",\"Parameters\":{\"VirtualClusterId.$\":\"$.cluster.Id\",\"Name\":\"EMR-Containers-Job\",\"ExecutionRoleArn\":\"", + { + "Fn::GetAtt": [ + "JobExecutionRoleF19B4342", + "Arn" + ] + }, + "\",\"ReleaseLabel\":\"emr-6.2.0-latest\",\"JobDriver\":{\"SparkSubmitJobDriver\":{\"EntryPoint\":\"local:///usr/lib/spark/examples/src/main/python/pi.py\",\"EntryPointArguments\":[\"2\"],\"SparkSubmitParameters\":\"--conf spark.driver.memory=512M --conf spark.kubernetes.driver.request.cores=0.2 --conf spark.kubernetes.executor.request.cores=0.2 --conf spark.sql.shuffle.partitions=60 --conf spark.dynamicAllocation.enabled=false\"}},\"ConfigurationOverrides\":{\"ApplicationConfiguration\":[{\"Classification\":\"spark-defaults\",\"Properties\":{\"spark.executor.instances\":\"1\",\"spark.executor.memory\":\"512M\"}}],\"MonitoringConfiguration\":{\"CloudWatchMonitoringConfiguration\":{\"LogGroupName\":\"", + { + "Ref": "StartaJobRunMonitoringLogGroupD033B7AF" + }, + "\"},\"PersistentAppUI\":\"ENABLED\",\"S3MonitoringConfiguration\":{\"LogUri\":\"s3://", + { + "Ref": "StartaJobRunMonitoringBucket899C33D9" + }, + "\"}}}}},\"Delete a Virtual Cluster\":{\"End\":true,\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::emr-containers:deleteVirtualCluster\",\"Parameters\":{\"Id.$\":\"$.job.VirtualClusterId\"}}},\"TimeoutSeconds\":1200}" + ] + ] + } + }, + "DependsOn": [ + "StateMachineRoleDefaultPolicyDF1E6607", + "StateMachineRoleB840431D" + ] + } + }, + "Outputs": { + "integrationtesteksclusterConfigCommandFA814999": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks update-kubeconfig --name ", + { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + " --region ", + { + "Ref": "AWS::Region" + }, + " --role-arn ", + { + "Fn::GetAtt": [ + "integrationtesteksclusterMastersRole63B9B0BF", + "Arn" + ] + } + ] + ] + } + }, + "integrationtesteksclusterGetTokenCommandD7B92682": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks get-token --cluster-name ", + { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + " --region ", + { + "Ref": "AWS::Region" + }, + " --role-arn ", + { + "Fn::GetAtt": [ + "integrationtesteksclusterMastersRole63B9B0BF", + "Arn" + ] + } + ] + ] + } + }, + "stateMachineArn": { + "Value": { + "Ref": "StateMachine2E01A3A5" + } + } + }, + "Parameters": { + "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681": { + "Type": "String", + "Description": "S3 bucket for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + }, + "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791": { + "Type": "String", + "Description": "S3 key for asset version \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + }, + "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665ArtifactHash9EA5AC29": { + "Type": "String", + "Description": "Artifact hash for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + }, + "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3Bucket3B443230": { + "Type": "String", + "Description": "S3 bucket for asset \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + }, + "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKeyAA4674FB": { + "Type": "String", + "Description": "S3 key for asset version \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + }, + "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720ArtifactHash3D7A279D": { + "Type": "String", + "Description": "Artifact hash for asset \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "Type": "String", + "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "Type": "String", + "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "Type": "String", + "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "Type": "String", + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + }, + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "Type": "String", + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + }, + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "Type": "String", + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "Type": "String", + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "Type": "String", + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "Type": "String", + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { + "Type": "String", + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { + "Type": "String", + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { + "Type": "String", + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParameters8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945S3BucketC636D050": { + "Type": "String", + "Description": "S3 bucket for asset \"8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945\"" + }, + "AssetParameters8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945S3VersionKey40C5ADFE": { + "Type": "String", + "Description": "S3 key for asset version \"8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945\"" + }, + "AssetParameters8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945ArtifactHash89120E1C": { + "Type": "String", + "Description": "Artifact hash for asset \"8d0ccbee43ce642958da8926fed939a9fde9d6631e9297740d640c0859ca5945\"" + }, + "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3BucketDBE4A868": { + "Type": "String", + "Description": "S3 bucket for asset \"249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50\"" + }, + "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50S3VersionKeyDA4E6828": { + "Type": "String", + "Description": "S3 key for asset version \"249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50\"" + }, + "AssetParameters249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50ArtifactHashB10F4A4B": { + "Type": "String", + "Description": "Artifact hash for asset \"249207c004483eea61658aceb796afc5f7a8b39d3b2333951c04ac8787af6d50\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.ts new file mode 100644 index 0000000000000..0f59e4e45e46d --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.job-submission-workflow.ts @@ -0,0 +1,90 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as eks from '@aws-cdk/aws-eks'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import { + Classification, VirtualClusterInput, EksClusterInput, EmrContainersDeleteVirtualCluster, + EmrContainersCreateVirtualCluster, EmrContainersStartJobRun, ReleaseLabel, +} from '../../lib'; + +/** + * Stack verification steps: + * Everything in the links below must be setup for the EKS Cluster and Execution Role before running the state machine. + * @see https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-cluster-access.html + * @see https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-enable-IAM.html + * @see https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-trust-policy.html + * + * aws stepfunctions start-execution --state-machine-arn : should return execution arn + * aws stepfunctions describe-execution --execution-arn : should return status as SUCCEEDED + */ + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-emr-containers-all-services-integ'); + +const eksCluster = new eks.Cluster(stack, 'integration-test-eks-cluster', { + version: eks.KubernetesVersion.V1_21, + defaultCapacity: 3, + defaultCapacityInstance: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE), +}); + +const jobExecutionRole = new iam.Role(stack, 'JobExecutionRole', { + assumedBy: new iam.CompositePrincipal( + new iam.ServicePrincipal('emr-containers.amazonaws.com'), + new iam.ServicePrincipal('states.amazonaws.com'), + ), +}); + +const createVirtualCluster = new EmrContainersCreateVirtualCluster(stack, 'Create a virtual Cluster', { + virtualClusterName: 'Virtual-Cluster-Name', + eksCluster: EksClusterInput.fromCluster(eksCluster), + resultPath: '$.cluster', +}); + +const startJobRun = new EmrContainersStartJobRun(stack, 'Start a Job Run', { + virtualCluster: VirtualClusterInput.fromTaskInput(sfn.TaskInput.fromJsonPathAt('$.cluster.Id')), + releaseLabel: ReleaseLabel.EMR_6_2_0, + jobName: 'EMR-Containers-Job', + executionRole: iam.Role.fromRoleArn(stack, 'Job-Execution-Role', jobExecutionRole.roleArn), + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'), + entryPointArguments: sfn.TaskInput.fromObject(['2']), + sparkSubmitParameters: '--conf spark.driver.memory=512M --conf spark.kubernetes.driver.request.cores=0.2 --conf spark.kubernetes.executor.request.cores=0.2 --conf spark.sql.shuffle.partitions=60 --conf spark.dynamicAllocation.enabled=false', + }, + }, + monitoring: { + logging: true, + persistentAppUI: true, + }, + applicationConfig: [{ + classification: Classification.SPARK_DEFAULTS, + properties: { + 'spark.executor.instances': '1', + 'spark.executor.memory': '512M', + }, + }], + resultPath: '$.job', +}); + + +const deleteVirtualCluster = new EmrContainersDeleteVirtualCluster(stack, 'Delete a Virtual Cluster', { + virtualClusterId: sfn.TaskInput.fromJsonPathAt('$.job.VirtualClusterId'), +}); + +const chain = sfn.Chain + .start(createVirtualCluster) + .next(startJobRun) + .next(deleteVirtualCluster); + +const sm = new sfn.StateMachine(stack, 'StateMachine', { + definition: chain, + timeout: cdk.Duration.minutes(20), +}); + +new cdk.CfnOutput(stack, 'stateMachineArn', { + value: sm.stateMachineArn, +}); + + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.expected.json new file mode 100644 index 0000000000000..3ec75b7ba0384 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.expected.json @@ -0,0 +1,2254 @@ +{ + "Resources": { + "integrationtesteksclusterDefaultVpc395E1A86": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTableAssociation4831B6A7": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317" + } + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1DefaultRoute33CE7FC3": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcIGW9ADAFE6F" + } + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317" + }, + "AllocationId": { + "Fn::GetAtt": [ + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableAssociation62710C52": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11" + } + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2DefaultRoute253A231E": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcIGW9ADAFE6F" + } + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11" + }, + "AllocationId": { + "Fn::GetAtt": [ + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTableAssociation14A23BAF": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D" + } + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3DefaultRouteB0117918": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcIGW9ADAFE6F" + } + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D" + }, + "AllocationId": { + "Fn::GetAtt": [ + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "kubernetes.io/role/elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PublicSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PrivateSubnet1" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTableAssociation7482DD1E": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet1DefaultRouteCC99A72C": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PrivateSubnet2" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableAssociation99F934D5": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet2DefaultRoute50FF167F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "Tags": [ + { + "Key": "kubernetes.io/role/internal-elb", + "Value": "1" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc/PrivateSubnet3" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableAssociationB70598F3": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791" + }, + "SubnetId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1" + } + } + }, + "integrationtesteksclusterDefaultVpcPrivateSubnet3DefaultRoute6DE23E60": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1" + } + } + }, + "integrationtesteksclusterDefaultVpcIGW9ADAFE6F": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/integration-test-eks-cluster/DefaultVpc" + } + ] + } + }, + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + }, + "InternetGatewayId": { + "Ref": "integrationtesteksclusterDefaultVpcIGW9ADAFE6F" + } + } + }, + "integrationtesteksclusterRole03F70AF0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "eks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSClusterPolicy" + ] + ] + } + ] + } + }, + "integrationtesteksclusterControlPlaneSecurityGroup6E92F333": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "EKS Control Plane Security Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "integrationtesteksclusterDefaultVpc395E1A86" + } + } + }, + "integrationtesteksclusterCreationRoleB98FE02A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcIGW9ADAFE6F", + "integrationtesteksclusterDefaultVpcPrivateSubnet1DefaultRouteCC99A72C", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTableAssociation7482DD1E", + "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB", + "integrationtesteksclusterDefaultVpcPrivateSubnet2DefaultRoute50FF167F", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableAssociation99F934D5", + "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8", + "integrationtesteksclusterDefaultVpcPrivateSubnet3DefaultRoute6DE23E60", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableAssociationB70598F3", + "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1", + "integrationtesteksclusterDefaultVpcPublicSubnet1DefaultRoute33CE7FC3", + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B", + "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTableAssociation4831B6A7", + "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317", + "integrationtesteksclusterDefaultVpcPublicSubnet2DefaultRoute253A231E", + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43", + "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableAssociation62710C52", + "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11", + "integrationtesteksclusterDefaultVpcPublicSubnet3DefaultRouteB0117918", + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59", + "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTableAssociation14A23BAF", + "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D", + "integrationtesteksclusterDefaultVpc395E1A86", + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterCreationRoleDefaultPolicy5417802D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "integrationtesteksclusterRole03F70AF0", + "Arn" + ] + } + }, + { + "Action": [ + "eks:CreateCluster", + "eks:DescribeCluster", + "eks:DescribeUpdate", + "eks:DeleteCluster", + "eks:UpdateClusterVersion", + "eks:UpdateClusterConfig", + "eks:CreateFargateProfile", + "eks:TagResource", + "eks:UntagResource" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + }, + { + "Action": [ + "eks:DescribeFargateProfile", + "eks:DeleteFargateProfile" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "iam:GetRole", + "iam:listAttachedRolePolicies" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "iam:CreateServiceLinkedRole", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeRouteTables", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "integrationtesteksclusterCreationRoleDefaultPolicy5417802D", + "Roles": [ + { + "Ref": "integrationtesteksclusterCreationRoleB98FE02A" + } + ] + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcIGW9ADAFE6F", + "integrationtesteksclusterDefaultVpcPrivateSubnet1DefaultRouteCC99A72C", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTableAssociation7482DD1E", + "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB", + "integrationtesteksclusterDefaultVpcPrivateSubnet2DefaultRoute50FF167F", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableAssociation99F934D5", + "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8", + "integrationtesteksclusterDefaultVpcPrivateSubnet3DefaultRoute6DE23E60", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableAssociationB70598F3", + "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1", + "integrationtesteksclusterDefaultVpcPublicSubnet1DefaultRoute33CE7FC3", + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B", + "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTableAssociation4831B6A7", + "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317", + "integrationtesteksclusterDefaultVpcPublicSubnet2DefaultRoute253A231E", + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43", + "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableAssociation62710C52", + "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11", + "integrationtesteksclusterDefaultVpcPublicSubnet3DefaultRouteB0117918", + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59", + "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTableAssociation14A23BAF", + "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D", + "integrationtesteksclusterDefaultVpc395E1A86", + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204" + ] + }, + "integrationtesteksclusterE5C0ED98": { + "Type": "Custom::AWSCDK-EKS-Cluster", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454", + "Outputs.awsstepfunctionstasksemrcontainersstartjobrunintegtestawscdkawseksClusterResourceProviderframeworkonEventD439F3D7Arn" + ] + }, + "Config": { + "version": "1.21", + "roleArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterRole03F70AF0", + "Arn" + ] + }, + "resourcesVpcConfig": { + "subnetIds": [ + { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1" + } + ], + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "integrationtesteksclusterControlPlaneSecurityGroup6E92F333", + "GroupId" + ] + } + ], + "endpointPublicAccess": true, + "endpointPrivateAccess": true + } + }, + "AssumeRoleArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "AttributesRevision": 2 + }, + "DependsOn": [ + "integrationtesteksclusterDefaultVpcIGW9ADAFE6F", + "integrationtesteksclusterDefaultVpcPrivateSubnet1DefaultRouteCC99A72C", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTable4A47F4AC", + "integrationtesteksclusterDefaultVpcPrivateSubnet1RouteTableAssociation7482DD1E", + "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB", + "integrationtesteksclusterDefaultVpcPrivateSubnet2DefaultRoute50FF167F", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableD7E59903", + "integrationtesteksclusterDefaultVpcPrivateSubnet2RouteTableAssociation99F934D5", + "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8", + "integrationtesteksclusterDefaultVpcPrivateSubnet3DefaultRoute6DE23E60", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableA2B42791", + "integrationtesteksclusterDefaultVpcPrivateSubnet3RouteTableAssociationB70598F3", + "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1", + "integrationtesteksclusterDefaultVpcPublicSubnet1DefaultRoute33CE7FC3", + "integrationtesteksclusterDefaultVpcPublicSubnet1EIP62A0A17B", + "integrationtesteksclusterDefaultVpcPublicSubnet1NATGatewayC9C984F9", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTable1D5A7569", + "integrationtesteksclusterDefaultVpcPublicSubnet1RouteTableAssociation4831B6A7", + "integrationtesteksclusterDefaultVpcPublicSubnet1Subnet58061317", + "integrationtesteksclusterDefaultVpcPublicSubnet2DefaultRoute253A231E", + "integrationtesteksclusterDefaultVpcPublicSubnet2EIPFC53AC43", + "integrationtesteksclusterDefaultVpcPublicSubnet2NATGatewayE109B761", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableA4C7B327", + "integrationtesteksclusterDefaultVpcPublicSubnet2RouteTableAssociation62710C52", + "integrationtesteksclusterDefaultVpcPublicSubnet2Subnet68EAAF11", + "integrationtesteksclusterDefaultVpcPublicSubnet3DefaultRouteB0117918", + "integrationtesteksclusterDefaultVpcPublicSubnet3EIP33828C59", + "integrationtesteksclusterDefaultVpcPublicSubnet3NATGateway01B2F0F1", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTable51E9DA7C", + "integrationtesteksclusterDefaultVpcPublicSubnet3RouteTableAssociation14A23BAF", + "integrationtesteksclusterDefaultVpcPublicSubnet3Subnet4307D52D", + "integrationtesteksclusterDefaultVpc395E1A86", + "integrationtesteksclusterDefaultVpcVPCGWE4DC2204", + "integrationtesteksclusterCreationRoleDefaultPolicy5417802D", + "integrationtesteksclusterCreationRoleB98FE02A" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integrationtesteksclusterKubectlReadyBarrier0D4A21B0": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "aws:cdk:eks:kubectl-ready" + }, + "DependsOn": [ + "integrationtesteksclusterCreationRoleDefaultPolicy5417802D", + "integrationtesteksclusterCreationRoleB98FE02A", + "integrationtesteksclusterE5C0ED98" + ] + }, + "integrationtesteksclusterMastersRole63B9B0BF": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "integrationtesteksclusterAwsAuthmanifestAEF9C6DF": { + "Type": "Custom::AWSCDK-EKS-KubernetesResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awsstepfunctionstasksemrcontainersstartjobrunintegtestawscdkawseksKubectlProviderframeworkonEvent69C4EA38Arn" + ] + }, + "Manifest": { + "Fn::Join": [ + "", + [ + "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c89091867a17cdada4a752b4f280c4353e38671b20\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "integrationtesteksclusterMastersRole63B9B0BF", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"", + { + "Fn::GetAtt": [ + "integrationtesteksclusterMastersRole63B9B0BF", + "Arn" + ] + }, + "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", + { + "Fn::GetAtt": [ + "integrationtesteksclusterNodegroupDefaultCapacityNodeGroupRole75D45BA7", + "Arn" + ] + }, + "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"arn:aws:iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/AWSServiceRoleForAmazonEMRContainers\\\",\\\"username\\\":\\\"emr-containers\\\",\\\"groups\\\":[]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" + ] + ] + }, + "ClusterName": { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + "RoleArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "PruneLabel": "aws.cdk.eks/prune-c89091867a17cdada4a752b4f280c4353e38671b20", + "Overwrite": true + }, + "DependsOn": [ + "integrationtesteksclusterKubectlReadyBarrier0D4A21B0" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integrationtesteksclusterNodegroupDefaultCapacityNodeGroupRole75D45BA7": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKSWorkerNodePolicy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEKS_CNI_Policy" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + ] + ] + } + ] + } + }, + "integrationtesteksclusterNodegroupDefaultCapacity536CF32C": { + "Type": "AWS::EKS::Nodegroup", + "Properties": { + "ClusterName": { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + "NodeRole": { + "Fn::GetAtt": [ + "integrationtesteksclusterNodegroupDefaultCapacityNodeGroupRole75D45BA7", + "Arn" + ] + }, + "Subnets": [ + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8" + }, + { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1" + } + ], + "AmiType": "AL2_x86_64", + "ForceUpdateEnabled": true, + "InstanceTypes": [ + "m5.xlarge" + ], + "ScalingConfig": { + "DesiredSize": 3, + "MaxSize": 3, + "MinSize": 3 + } + } + }, + "integrationtesteksclustermanifestemrRoleCCE4E328": { + "Type": "Custom::AWSCDK-EKS-KubernetesResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awsstepfunctionstasksemrcontainersstartjobrunintegtestawscdkawseksKubectlProviderframeworkonEvent69C4EA38Arn" + ] + }, + "Manifest": "[{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"Role\",\"metadata\":{\"name\":\"emr-containers\",\"namespace\":\"default\",\"labels\":{\"aws.cdk.eks/prune-c8cef729fffd80e01dd767818967a268148bb13a2a\":\"\"}},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"namespaces\"],\"verbs\":[\"get\"]},{\"apiGroups\":[\"\"],\"resources\":[\"serviceaccounts\",\"services\",\"configmaps\",\"events\",\"pods\",\"pods/log\"],\"verbs\":[\"get\",\"list\",\"watch\",\"describe\",\"create\",\"edit\",\"delete\",\"deletecollection\",\"annotate\",\"patch\",\"label\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"create\",\"patch\",\"delete\",\"watch\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"statefulsets\",\"deployments\"],\"verbs\":[\"get\",\"list\",\"watch\",\"describe\",\"create\",\"edit\",\"delete\",\"annotate\",\"patch\",\"label\"]},{\"apiGroups\":[\"batch\"],\"resources\":[\"jobs\"],\"verbs\":[\"get\",\"list\",\"watch\",\"describe\",\"create\",\"edit\",\"delete\",\"annotate\",\"patch\",\"label\"]},{\"apiGroups\":[\"extensions\"],\"resources\":[\"ingresses\"],\"verbs\":[\"get\",\"list\",\"watch\",\"describe\",\"create\",\"edit\",\"delete\",\"annotate\",\"patch\",\"label\"]},{\"apiGroups\":[\"rbac.authorization.k8s.io\"],\"resources\":[\"roles\",\"rolebindings\"],\"verbs\":[\"get\",\"list\",\"watch\",\"describe\",\"create\",\"edit\",\"delete\",\"deletecollection\",\"annotate\",\"patch\",\"label\"]}]}]", + "ClusterName": { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + "RoleArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "PruneLabel": "aws.cdk.eks/prune-c8cef729fffd80e01dd767818967a268148bb13a2a" + }, + "DependsOn": [ + "integrationtesteksclusterKubectlReadyBarrier0D4A21B0" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integrationtesteksclustermanifestemrRoleBind8B35D2A2": { + "Type": "Custom::AWSCDK-EKS-KubernetesResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B", + "Outputs.awsstepfunctionstasksemrcontainersstartjobrunintegtestawscdkawseksKubectlProviderframeworkonEvent69C4EA38Arn" + ] + }, + "Manifest": "[{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"RoleBinding\",\"metadata\":{\"name\":\"emr-containers\",\"namespace\":\"default\",\"labels\":{\"aws.cdk.eks/prune-c892a3812e60d138dd377a538f9d47aace2a0a8bb6\":\"\"}},\"subjects\":[{\"kind\":\"User\",\"name\":\"emr-containers\",\"apiGroup\":\"rbac.authorization.k8s.io\"}],\"roleRef\":{\"kind\":\"Role\",\"name\":\"emr-containers\",\"apiGroup\":\"rbac.authorization.k8s.io\"}}]", + "ClusterName": { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + "RoleArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "PruneLabel": "aws.cdk.eks/prune-c892a3812e60d138dd377a538f9d47aace2a0a8bb6" + }, + "DependsOn": [ + "integrationtesteksclusterKubectlReadyBarrier0D4A21B0", + "integrationtesteksclustermanifestemrRoleCCE4E328" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "awscdkawseksClusterResourceProviderNestedStackawscdkawseksClusterResourceProviderNestedStackResource9827C454": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591S3BucketC38C4355" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591S3VersionKey31FFCA42" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591S3VersionKey31FFCA42" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket47FE5F69Ref": { + "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB5CD57E0Ref": { + "Ref": "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtesteksclusterCreationRole19DB152EArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3Bucket7AE1E7DBRef": { + "Ref": "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3Bucket3B443230" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKey5842C10ARef": { + "Ref": "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKeyAA4674FB" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket977A6FD0Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey9A35F1EFRef": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "awscdkawseksKubectlProviderNestedStackawscdkawseksKubectlProviderNestedStackResourceA7AEBA6B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3Bucket6FC76F07" + }, + "/", + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3VersionKey396AB4CB" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3VersionKey396AB4CB" + } + ] + } + ] + } + ] + ] + }, + "Parameters": { + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtestekscluster4D8C900FArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterE5C0ED98", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtesteksclusterCreationRole19DB152EArn": { + "Fn::GetAtt": [ + "integrationtesteksclusterCreationRoleB98FE02A", + "Arn" + ] + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket266CDCEARef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey06C0AAD8Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtesteksclusterDefaultVpcPrivateSubnet1SubnetDFF56EB6Ref": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet1Subnet4E00CAFB" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0E779258Ref": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet2Subnet0C3539A8" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtesteksclusterDefaultVpcPrivateSubnet3SubnetA1BAE26ERef": { + "Ref": "integrationtesteksclusterDefaultVpcPrivateSubnet3SubnetD17D4AF1" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestintegrationtestekscluster4D8C900FClusterSecurityGroupId": { + "Fn::GetAtt": [ + "integrationtesteksclusterE5C0ED98", + "ClusterSecurityGroupId" + ] + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketFE6FEB31Ref": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyBE97CFCARef": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketF38DB26BRef": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey1E1E9DA8Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket977A6FD0Ref": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "referencetoawsstepfunctionstasksemrcontainersstartjobrunintegtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKey9A35F1EFRef": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VirtualCluster": { + "Type": "AWS::EMRContainers::VirtualCluster", + "Properties": { + "ContainerProvider": { + "Id": { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + "Info": { + "EksInfo": { + "Namespace": "default" + } + }, + "Type": "EKS" + }, + "Name": "Virtual-Cluster-Name" + }, + "DependsOn": [ + "integrationtesteksclusterAwsAuthmanifestAEF9C6DF", + "integrationtesteksclustermanifestemrRoleBind8B35D2A2" + ] + }, + "StartaJobRunJobExecutionRole157B6BE1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "emr-containers.amazonaws.com", + { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StartaJobRunJobExecutionRoleDefaultPolicyEA7882C0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "logs:DescribeLogGroups", + "Effect": "Allow", + "Resource": "arn:aws:logs:*:*:*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StartaJobRunJobExecutionRoleDefaultPolicyEA7882C0", + "Roles": [ + { + "Ref": "StartaJobRunJobExecutionRole157B6BE1" + } + ] + } + }, + "StartaJobRunGetEksClusterInfoCustomResourcePolicy7AA7B106": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "emr-containers:DescribeVirtualCluster", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StartaJobRunGetEksClusterInfoCustomResourcePolicy7AA7B106", + "Roles": [ + { + "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + } + ] + } + }, + "StartaJobRunGetEksClusterInfoD0E31373": { + "Type": "Custom::AWS", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "AWS679f53fac002430cb0da5b7982bd22872D164C4C", + "Arn" + ] + }, + "Create": { + "Fn::Join": [ + "", + [ + "{\"service\":\"EMRcontainers\",\"action\":\"describeVirtualCluster\",\"parameters\":{\"id\":\"", + { + "Fn::GetAtt": [ + "VirtualCluster", + "Id" + ] + }, + "\"},\"outputPaths\":[\"virtualCluster.containerProvider.info.eksInfo.namespace\",\"virtualCluster.containerProvider.id\"],\"physicalResourceId\":{\"id\":\"id\"}}" + ] + ] + }, + "InstallLatestAwsSdk": true + }, + "DependsOn": [ + "StartaJobRunGetEksClusterInfoCustomResourcePolicy7AA7B106" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "StartaJobRunawsclilayer110EEF0B": { + "Type": "AWS::Lambda::LayerVersion", + "Properties": { + "Content": { + "S3Bucket": { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" + } + ] + } + ] + } + ] + ] + } + }, + "Description": "/opt/awscli/aws" + } + }, + "StartaJobRunCustomResourceProviderframeworkonEventServiceRole1D6E2464": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "StartaJobRunCustomResourceProviderframeworkonEventServiceRoleDefaultPolicy95FB1565": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CB6182A5B", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StartaJobRunCustomResourceProviderframeworkonEventServiceRoleDefaultPolicy95FB1565", + "Roles": [ + { + "Ref": "StartaJobRunCustomResourceProviderframeworkonEventServiceRole1D6E2464" + } + ] + } + }, + "StartaJobRunCustomResourceProviderframeworkonEventAC961165": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F" + } + ] + } + ] + } + ] + ] + } + }, + "Role": { + "Fn::GetAtt": [ + "StartaJobRunCustomResourceProviderframeworkonEventServiceRole1D6E2464", + "Arn" + ] + }, + "Description": "AWS CDK resource provider framework - onEvent (aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test/Start a Job Run/CustomResourceProvider)", + "Environment": { + "Variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CB6182A5B", + "Arn" + ] + } + } + }, + "Handler": "framework.onEvent", + "Runtime": "nodejs12.x", + "Timeout": 900 + }, + "DependsOn": [ + "StartaJobRunCustomResourceProviderframeworkonEventServiceRoleDefaultPolicy95FB1565", + "StartaJobRunCustomResourceProviderframeworkonEventServiceRole1D6E2464" + ] + }, + "StartaJobRunCustomResource3BD90664": { + "Type": "AWS::CloudFormation::CustomResource", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "StartaJobRunCustomResourceProviderframeworkonEventAC961165", + "Arn" + ] + }, + "eksNamespace": { + "Fn::GetAtt": [ + "StartaJobRunGetEksClusterInfoD0E31373", + "virtualCluster.containerProvider.info.eksInfo.namespace" + ] + }, + "eksClusterId": { + "Fn::GetAtt": [ + "StartaJobRunGetEksClusterInfoD0E31373", + "virtualCluster.containerProvider.id" + ] + }, + "roleName": { + "Ref": "StartaJobRunJobExecutionRole157B6BE1" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "AWS679f53fac002430cb0da5b7982bd22872D164C4C": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" + } + ] + } + ] + } + ] + ] + } + }, + "Role": { + "Fn::GetAtt": [ + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs12.x", + "Timeout": 120 + }, + "DependsOn": [ + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + ] + }, + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CServiceRoleF99BDB4C": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CServiceRoleDefaultPolicy87B52EEA": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "eks:DescribeCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":eks:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster/", + { + "Fn::GetAtt": [ + "StartaJobRunGetEksClusterInfoD0E31373", + "virtualCluster.containerProvider.id" + ] + } + ] + ] + } + }, + { + "Action": [ + "iam:GetRole", + "iam:UpdateAssumeRolePolicy" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "StartaJobRunJobExecutionRole157B6BE1", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CServiceRoleDefaultPolicy87B52EEA", + "Roles": [ + { + "Ref": "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CServiceRoleF99BDB4C" + } + ] + } + }, + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CB6182A5B": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParametersb866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680S3Bucket56B5C500" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersb866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680S3VersionKey966662B2" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersb866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680S3VersionKey966662B2" + } + ] + } + ] + } + ] + ] + } + }, + "Role": { + "Fn::GetAtt": [ + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CServiceRoleF99BDB4C", + "Arn" + ] + }, + "Handler": "index.handler", + "Layers": [ + { + "Ref": "StartaJobRunawsclilayer110EEF0B" + } + ], + "MemorySize": 256, + "Runtime": "python3.6", + "Timeout": 30 + }, + "DependsOn": [ + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CServiceRoleDefaultPolicy87B52EEA", + "SingletonLambda8693BB64968944B69AAFB0CC9EB8757CServiceRoleF99BDB4C" + ] + }, + "StateMachineRoleB840431D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StateMachineRoleDefaultPolicyDF1E6607": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "emr-containers:StartJobRun", + "Condition": { + "StringEquals": { + "emr-containers:ExecutionRoleArn": { + "Fn::GetAtt": [ + "StartaJobRunJobExecutionRole157B6BE1", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":emr-containers:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":/virtualclusters/", + { + "Fn::GetAtt": [ + "VirtualCluster", + "Id" + ] + } + ] + ] + } + }, + { + "Action": [ + "emr-containers:DescribeJobRun", + "emr-containers:CancelJobRun" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":emr-containers:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":/virtualclusters/", + { + "Fn::GetAtt": [ + "VirtualCluster", + "Id" + ] + }, + "/jobruns/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StateMachineRoleDefaultPolicyDF1E6607", + "Roles": [ + { + "Ref": "StateMachineRoleB840431D" + } + ] + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Start a Job Run\",\"States\":{\"Start a Job Run\":{\"End\":true,\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::emr-containers:startJobRun.sync\",\"Parameters\":{\"VirtualClusterId\":\"", + { + "Fn::GetAtt": [ + "VirtualCluster", + "Id" + ] + }, + "\",\"Name\":\"EMR-Containers-Job\",\"ExecutionRoleArn\":\"", + { + "Fn::GetAtt": [ + "StartaJobRunJobExecutionRole157B6BE1", + "Arn" + ] + }, + "\",\"ReleaseLabel\":\"emr-6.2.0-latest\",\"JobDriver\":{\"SparkSubmitJobDriver\":{\"EntryPoint\":\"local:///usr/lib/spark/examples/src/main/python/pi.py\",\"EntryPointArguments\":[\"2\"],\"SparkSubmitParameters\":\"--conf spark.driver.memory=512M --conf spark.kubernetes.driver.request.cores=0.2 --conf spark.kubernetes.executor.request.cores=0.2 --conf spark.sql.shuffle.partitions=60 --conf spark.dynamicAllocation.enabled=false\"}},\"ConfigurationOverrides\":{\"MonitoringConfiguration\":{\"PersistentAppUI\":\"ENABLED\"}}}}},\"TimeoutSeconds\":1000}" + ] + ] + } + }, + "DependsOn": [ + "StateMachineRoleDefaultPolicyDF1E6607", + "StateMachineRoleB840431D" + ] + } + }, + "Outputs": { + "integrationtesteksclusterConfigCommandFA814999": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks update-kubeconfig --name ", + { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + " --region ", + { + "Ref": "AWS::Region" + }, + " --role-arn ", + { + "Fn::GetAtt": [ + "integrationtesteksclusterMastersRole63B9B0BF", + "Arn" + ] + } + ] + ] + } + }, + "integrationtesteksclusterGetTokenCommandD7B92682": { + "Value": { + "Fn::Join": [ + "", + [ + "aws eks get-token --cluster-name ", + { + "Ref": "integrationtesteksclusterE5C0ED98" + }, + " --region ", + { + "Ref": "AWS::Region" + }, + " --role-arn ", + { + "Fn::GetAtt": [ + "integrationtesteksclusterMastersRole63B9B0BF", + "Arn" + ] + } + ] + ] + } + }, + "stateMachineArn": { + "Value": { + "Ref": "StateMachine2E01A3A5" + } + } + }, + "Parameters": { + "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3Bucket1B280681": { + "Type": "String", + "Description": "S3 bucket for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + }, + "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665S3VersionKeyB1E02791": { + "Type": "String", + "Description": "S3 key for asset version \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + }, + "AssetParameters26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665ArtifactHash9EA5AC29": { + "Type": "String", + "Description": "Artifact hash for asset \"26ac61b4195cccf80ff73f332788ad7ffaab36d81ce570340a583a8364901665\"" + }, + "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3Bucket3B443230": { + "Type": "String", + "Description": "S3 bucket for asset \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + }, + "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720S3VersionKeyAA4674FB": { + "Type": "String", + "Description": "S3 key for asset version \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + }, + "AssetParameters5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720ArtifactHash3D7A279D": { + "Type": "String", + "Description": "Artifact hash for asset \"5afea6e8e6c743a8d1766f21465e28d471e56bcb95c5970054b0514bc62a3720\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { + "Type": "String", + "Description": "S3 bucket for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3VersionKeyA495226F": { + "Type": "String", + "Description": "S3 key for asset version \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1ArtifactHashA521A16F": { + "Type": "String", + "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" + }, + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { + "Type": "String", + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + }, + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { + "Type": "String", + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + }, + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { + "Type": "String", + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { + "Type": "String", + "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F": { + "Type": "String", + "Description": "S3 key for asset version \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68ArtifactHashD9A515C3": { + "Type": "String", + "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { + "Type": "String", + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { + "Type": "String", + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { + "Type": "String", + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" + }, + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { + "Type": "String", + "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + }, + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { + "Type": "String", + "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + }, + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { + "Type": "String", + "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" + }, + "AssetParametersb866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680S3Bucket56B5C500": { + "Type": "String", + "Description": "S3 bucket for asset \"b866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680\"" + }, + "AssetParametersb866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680S3VersionKey966662B2": { + "Type": "String", + "Description": "S3 key for asset version \"b866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680\"" + }, + "AssetParametersb866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680ArtifactHashE32BBB7E": { + "Type": "String", + "Description": "Artifact hash for asset \"b866fb0fd5a9b4215d1e23188632d74c01f3195f6f9d706134b197b400afb680\"" + }, + "AssetParameters3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591S3BucketC38C4355": { + "Type": "String", + "Description": "S3 bucket for asset \"3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591\"" + }, + "AssetParameters3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591S3VersionKey31FFCA42": { + "Type": "String", + "Description": "S3 key for asset version \"3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591\"" + }, + "AssetParameters3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591ArtifactHash2A3C4E8F": { + "Type": "String", + "Description": "Artifact hash for asset \"3d62bd1f77b829ff043268ba044023fc21ba7d29ffad099d58873aa490a20591\"" + }, + "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3Bucket6FC76F07": { + "Type": "String", + "Description": "S3 bucket for asset \"922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882b\"" + }, + "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bS3VersionKey396AB4CB": { + "Type": "String", + "Description": "S3 key for asset version \"922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882b\"" + }, + "AssetParameters922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882bArtifactHash2918634A": { + "Type": "String", + "Description": "Artifact hash for asset \"922360c7d159ef358ec5feeac54b70297766064bb1dc00b03a7f147d6f3a882b\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.ts new file mode 100644 index 0000000000000..c7db245f5012a --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/integ.start-job-run.ts @@ -0,0 +1,100 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as eks from '@aws-cdk/aws-eks'; +import { AwsAuthMapping } from '@aws-cdk/aws-eks'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import { Aws } from '@aws-cdk/core'; +import { EmrContainersStartJobRun } from '../../lib'; +import { ReleaseLabel, VirtualClusterInput } from '../../lib/emrcontainers/start-job-run'; + +/** + * Stack verification steps: + * Everything in the link below must be setup before running the state machine. + * @see https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-enable-IAM.html + * aws stepfunctions start-execution --state-machine-arn : should return execution arn + * aws stepfunctions describe-execution --execution-arn : should return status as SUCCEEDED + */ + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-emr-containers-start-job-run-integ-test'); + +const eksCluster = new eks.Cluster(stack, 'integration-test-eks-cluster', { + version: eks.KubernetesVersion.V1_21, + defaultCapacity: 3, + defaultCapacityInstance: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE), +}); + +const virtualCluster = new cdk.CfnResource(stack, 'Virtual Cluster', { + type: 'AWS::EMRContainers::VirtualCluster', + properties: { + ContainerProvider: { + Id: eksCluster.clusterName, + Info: { + EksInfo: { + Namespace: 'default', + }, + }, + Type: 'EKS', + }, + Name: 'Virtual-Cluster-Name', + }, +}); + +const emrRole = eksCluster.addManifest('emrRole', { + apiVersion: 'rbac.authorization.k8s.io/v1', + kind: 'Role', + metadata: { name: 'emr-containers', namespace: 'default' }, + rules: [ + { apiGroups: [''], resources: ['namespaces'], verbs: ['get'] }, + { apiGroups: [''], resources: ['serviceaccounts', 'services', 'configmaps', 'events', 'pods', 'pods/log'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'deletecollection', 'annotate', 'patch', 'label'] }, + { apiGroups: [''], resources: ['secrets'], verbs: ['create', 'patch', 'delete', 'watch'] }, + { apiGroups: ['apps'], resources: ['statefulsets', 'deployments'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'annotate', 'patch', 'label'] }, + { apiGroups: ['batch'], resources: ['jobs'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'annotate', 'patch', 'label'] }, + { apiGroups: ['extensions'], resources: ['ingresses'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'annotate', 'patch', 'label'] }, + { apiGroups: ['rbac.authorization.k8s.io'], resources: ['roles', 'rolebindings'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'deletecollection', 'annotate', 'patch', 'label'] }, + ], +}); + +const emrRoleBind = eksCluster.addManifest('emrRoleBind', { + apiVersion: 'rbac.authorization.k8s.io/v1', + kind: 'RoleBinding', + metadata: { name: 'emr-containers', namespace: 'default' }, + subjects: [{ kind: 'User', name: 'emr-containers', apiGroup: 'rbac.authorization.k8s.io' }], + roleRef: { kind: 'Role', name: 'emr-containers', apiGroup: 'rbac.authorization.k8s.io' }, +}); + +emrRoleBind.node.addDependency(emrRole); + +const emrServiceRole = iam.Role.fromRoleArn(stack, 'emrServiceRole', 'arn:aws:iam::'+Aws.ACCOUNT_ID+':role/AWSServiceRoleForAmazonEMRContainers'); +const authMapping: AwsAuthMapping = { groups: [], username: 'emr-containers' }; +eksCluster.awsAuth.addRoleMapping(emrServiceRole, authMapping); + +virtualCluster.node.addDependency(emrRoleBind); +virtualCluster.node.addDependency(eksCluster.awsAuth); + +const startJobRunJob = new EmrContainersStartJobRun(stack, 'Start a Job Run', { + virtualCluster: VirtualClusterInput.fromVirtualClusterId(virtualCluster.getAtt('Id').toString()), + releaseLabel: ReleaseLabel.EMR_6_2_0, + jobName: 'EMR-Containers-Job', + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'), + entryPointArguments: sfn.TaskInput.fromObject(['2']), + sparkSubmitParameters: '--conf spark.driver.memory=512M --conf spark.kubernetes.driver.request.cores=0.2 --conf spark.kubernetes.executor.request.cores=0.2 --conf spark.sql.shuffle.partitions=60 --conf spark.dynamicAllocation.enabled=false', + }, + }, +}); + +const chain = sfn.Chain.start(startJobRunJob); + +const sm = new sfn.StateMachine(stack, 'StateMachine', { + definition: chain, + timeout: cdk.Duration.seconds(1000), +}); + +new cdk.CfnOutput(stack, 'stateMachineArn', { + value: sm.stateMachineArn, +}); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/start-job-run.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/start-job-run.test.ts new file mode 100644 index 0000000000000..63dbfdc6eee48 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/start-job-run.test.ts @@ -0,0 +1,998 @@ +import { Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; +import * as logs from '@aws-cdk/aws-logs'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Stack } from '@aws-cdk/core'; +import { EmrContainersStartJobRun, VirtualClusterInput, ReleaseLabel, ApplicationConfiguration, Classification, EmrContainersStartJobRunProps } from '../../lib/emrcontainers/start-job-run'; + +let stack: Stack; +let clusterId: string; +let defaultProps: EmrContainersStartJobRunProps; + +beforeEach(() => { + stack = new Stack(); + clusterId = 'clusterId'; + defaultProps = { + virtualCluster: VirtualClusterInput.fromTaskInput(sfn.TaskInput.fromText(clusterId)), + releaseLabel: ReleaseLabel.EMR_6_2_0, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'), + sparkSubmitParameters: '--conf spark.executor.instances=2', + }, + }, + }; +}); + +describe('Invoke EMR Containers Start Job Run with ', () => { + test('Request/Response integration pattern', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::emr-containers:startJobRun', + ], + ], + }, + }); + }); + + test('.sync integration pattern', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', defaultProps); + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::emr-containers:startJobRun.sync', + ], + ], + }, + }); + }); + + test('virtual cluster id from payload', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + virtualCluster: VirtualClusterInput.fromTaskInput(sfn.TaskInput.fromJsonPathAt('$.ClusterId')), + executionRole: iam.Role.fromRoleArn(stack, 'Job Execution Role', 'arn:aws:iam::xxxxxxxxxxxx:role/JobExecutionRole'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + 'VirtualClusterId.$': '$.ClusterId', + 'ExecutionRoleArn': 'arn:aws:iam::xxxxxxxxxxxx:role/JobExecutionRole', + }, + }); + }); + + test('Tags', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + tags: { + key: 'value', + }, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + Tags: { + key: 'value', + }, + }, + }); + }); + + + test('Application Configuration', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + applicationConfig: [{ + classification: Classification.SPARK_DEFAULTS, + properties: { + 'spark.executor.instances': '1', + 'spark.executor.memory': '512M', + }, + }], + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + ConfigurationOverrides: { + ApplicationConfiguration: [{ + Classification: Classification.SPARK_DEFAULTS.classificationStatement, + Properties: { + 'spark.executor.instances': '1', + 'spark.executor.memory': '512M', + }, + }], + }, + }, + }); + }); + + test('Application Configuration with nested app config and no properties', () => { + const properties: { [key: string]: string } = { HADOOP_DATANODE_HEAPSIZE: '2048', HADOOP_NAMENODE_OPTS: '-XX:GCTimeRatio=19' }; + const struct = { classification: new Classification('export'), properties: properties }; + const appConfigNested: ApplicationConfiguration[] = [struct]; + + const mainConfig = { classification: new Classification('hadoop-env'), nestedConfig: appConfigNested }; + const appConfig: ApplicationConfiguration[] = [mainConfig]; + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + applicationConfig: appConfig, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + ConfigurationOverrides: { + ApplicationConfiguration: [{ + Classification: 'hadoop-env', + Configurations: [{ + Classification: 'export', + Properties: { + HADOOP_DATANODE_HEAPSIZE: '2048', + HADOOP_NAMENODE_OPTS: '-XX:GCTimeRatio=19', + }, + }], + }], + }, + }, + }); + }); + + + test('Job Execution Role', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + executionRole: iam.Role.fromRoleArn(stack, 'Job Execution Role', 'arn:aws:iam::xxxxxxxxxxxx:role/JobExecutionRole'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + ExecutionRoleArn: 'arn:aws:iam::xxxxxxxxxxxx:role/JobExecutionRole', + }, + }); + + // THEN + Template.fromStack(stack).resourceCountIs('AWS::CloudFormation::CustomResource', 0); + }); + + test('Virtual Cluster Input from virtualClusterId', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + virtualCluster: VirtualClusterInput.fromVirtualClusterId(clusterId), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + VirtualClusterId: clusterId, + }, + }); + }); + + describe('Invoke EMR Containers Start Job Run with Monitoring ', () => { + test('generated automatically', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + monitoring: { + logging: true, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + 's3:DeleteObject*', + 's3:PutObject*', + 's3:Abort*', + ], + Effect: 'Allow', + Resource: [ + { + 'Fn::GetAtt': [ + 'EMRContainersStartJobRunMonitoringBucket8BB3FC54', + 'Arn', + ], + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'EMRContainersStartJobRunMonitoringBucket8BB3FC54', + 'Arn', + ], + }, + '/*', + ], + ], + }, + ], + }, + { + Action: [ + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'EMRContainersStartJobRunMonitoringLogGroup882D450C', + 'Arn', + ], + }, + }, + { + Action: 'logs:DescribeLogStreams', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'EMRContainersStartJobRunMonitoringLogGroup882D450C', + 'Arn', + ], + }, + }, + { + Action: 'logs:DescribeLogGroups', + Effect: 'Allow', + Resource: 'arn:aws:logs:*:*:*', + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'EMRContainersStartJobRunJobExecutionRoleDefaultPolicyCDBDF13E', + Roles: [ + { + Ref: 'EMRContainersStartJobRunJobExecutionRole40B8DD81', + }, + ], + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + ConfigurationOverrides: { + MonitoringConfiguration: { + CloudWatchMonitoringConfiguration: { + LogGroupName: { + Ref: 'EMRContainersStartJobRunMonitoringLogGroup882D450C', + }, + }, + PersistentAppUI: 'ENABLED', + S3MonitoringConfiguration: { + LogUri: { + 'Fn::Join': [ + '', + [ + 's3://', + { + Ref: 'EMRContainersStartJobRunMonitoringBucket8BB3FC54', + }, + ], + ], + }, + }, + }, + }, + }, + }); + }); + + test('provided from user', () => { + // WHEN + const logGroup = logs.LogGroup.fromLogGroupName(stack, 'Monitoring Group', 'providedloggroup'); + const s3Bucket = s3.Bucket.fromBucketName(stack, 'Monitoring Bucket', 'providedbucket');; + const prefixName = 'prefix'; + + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + monitoring: { + logBucket: s3Bucket, + logGroup: logGroup, + logStreamNamePrefix: prefixName, + logging: false, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + 's3:DeleteObject*', + 's3:PutObject*', + 's3:Abort*', + ], + Effect: 'Allow', + Resource: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::providedbucket', + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::providedbucket/*', + ], + ], + }, + ], + }, + { + Action: [ + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':log-group:providedloggroup:*', + ], + ], + }, + }, + { + Action: 'logs:DescribeLogStreams', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':logs:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':log-group:providedloggroup:*', + ], + ], + }, + }, + { + Action: 'logs:DescribeLogGroups', + Effect: 'Allow', + Resource: 'arn:aws:logs:*:*:*', + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'EMRContainersStartJobRunJobExecutionRoleDefaultPolicyCDBDF13E', + Roles: [ + { + Ref: 'EMRContainersStartJobRunJobExecutionRole40B8DD81', + }, + ], + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + ConfigurationOverrides: { + MonitoringConfiguration: { + CloudWatchMonitoringConfiguration: { + LogGroupName: logGroup.logGroupName, + LogStreamNamePrefix: prefixName, + }, + S3MonitoringConfiguration: { + LogUri: 's3://' + s3Bucket.bucketName, + }, + }, + }, + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'EMRContainersStartJobRunJobExecutionRole40B8DD81', + 'Arn', + ], + }, + }, + }); + }); + + test('PersistentAppUI to be disabled when set to false', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', { + ...defaultProps, + monitoring: { + persistentAppUI: false, + }, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toMatchObject({ + Parameters: { + ConfigurationOverrides: { + MonitoringConfiguration: { + PersistentAppUI: 'DISABLED', + }, + }, + }, + }); + }); + }); + + describe('Task throws if ', () => { + test('Application Configuration array is larger than 100', () => { + // WHEN + const struct = { classification: Classification.SPARK }; + const appConfig: ApplicationConfiguration[] = new Array(101).fill(struct); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Task', { + ...defaultProps, + applicationConfig: appConfig, + }); + }).toThrow(`Application configuration array must have 100 or fewer entries. Received ${appConfig.length}`); + }); + + test('Application Configuration nested configuration array is larger than 100', () => { + // WHEN + const struct = { classification: Classification.SPARK }; + let appConfig: ApplicationConfiguration[] = new Array(101).fill(struct); + + const nestedConfigStruct = { classification: Classification.SPARK, nestedConfig: appConfig }; + appConfig[0] = nestedConfigStruct; + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Task', { + ...defaultProps, + applicationConfig: appConfig, + }); + }).toThrow(`Application configuration array must have 100 or fewer entries. Received ${appConfig.length}`); + }); + + test('Application Configuration properties is larger than 100 entries', () => { + // WHEN + const properties: { [key: string]: string } = {}; + for (let index = 0; index <= 100; index++) { + properties[index.toString()] = 'value'; + } + const appConfig: ApplicationConfiguration = { classification: Classification.SPARK, properties: properties }; + + expect(() => { + new EmrContainersStartJobRun(stack, 'Task', { + ...defaultProps, + applicationConfig: [appConfig], + }); + }).toThrow(`Application configuration properties must have 100 or fewer entries. Received ${Object.keys(properties).length}`); + }); + + test('Application Configuration properties is undefined and nested configuration array is undefined', () => { + // WHEN + const struct = { classification: Classification.SPARK }; + let appConfig: ApplicationConfiguration[] = new Array(1).fill(struct); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Task', { + ...defaultProps, + applicationConfig: appConfig, + }); + }).toThrow('Application configuration must have either properties or nested app configurations defined.'); + }); + + test('Entry Point is not between 1 to 256 characters in length', () => { + // WHEN + const entryPointString = 'x'.repeat(257); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Start Job Run Task', { + ...defaultProps, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText(entryPointString), + }, + }, + }); + }).toThrow(`Entry point must be between 1 and 256 characters in length. Received ${entryPointString.length}.`); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Task', { + ...defaultProps, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText(''), + }, + }, + }); + }).toThrow('Entry point must be between 1 and 256 characters in length. Received 0.'); + }); + + test('Entry Point Arguments is not an string array that is between 1 and 10280 entries in length', () => { + // WHEN + const entryPointArgs = sfn.TaskInput.fromObject(new Array(10281).fill('x', 10281)); + const entryPointArgsNone = sfn.TaskInput.fromObject([]); + const entryPointNumbers = sfn.TaskInput.fromObject(new Array(1).fill(1)); + const entryPointJson = sfn.TaskInput.fromText('x'); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'String array error Task', { + ...defaultProps, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('job-location'), + entryPointArguments: entryPointNumbers, + }, + }, + }); + }).toThrow('Entry point arguments must be a string array or encoded JSON path but received object'); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'JSON Path error Task', { + ...defaultProps, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('job-location'), + entryPointArguments: entryPointJson, + }, + }, + }); + }).toThrow('Entry point arguments must be a string array or encoded JSON path, but received a non JSON path string'); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Greater than 256 Task', { + ...defaultProps, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('job-location'), + entryPointArguments: entryPointArgs, + }, + }, + }); + }).toThrow(`Entry point arguments must be a string array between 1 and 10280 in length. Received ${entryPointArgs.value.length}.`); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Less than 1 Task', { + ...defaultProps, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('job-location'), + entryPointArguments: entryPointArgsNone, + }, + }, + }); + }).toThrow(`Entry point arguments must be a string array between 1 and 10280 in length. Received ${entryPointArgsNone.value.length}.`); + }); + + test('Spark Submit Parameters is NOT between 1 characters and 102400 characters in length', () => { + // WHEN + const sparkSubmitParam = 'x'.repeat(102401); + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Spark Submit Parameter Task', { + ...defaultProps, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('job-location'), + sparkSubmitParameters: sparkSubmitParam, + }, + }, + }); + }).toThrow(`Spark submit parameters must be between 1 and 102400 characters in length. Received ${sparkSubmitParam.length}.`); + }); + + test('an execution role is undefined and the virtual cluster ID is not a concrete value', () => { + // WHEN + const jsonPath = '$.ClusterId'; + + // THEN + expect(() => { + new EmrContainersStartJobRun(stack, 'Task', { + ...defaultProps, + virtualCluster: VirtualClusterInput.fromTaskInput(sfn.TaskInput.fromJsonPathAt(jsonPath)), + }); + }).toThrow('Execution role cannot be undefined when the virtual cluster ID is not a concrete value. Provide an execution role with the correct trust policy'); + }); + }); + + test('Permitted role actions and resources with Start Job Run for SYNC integration pattern', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'EMR Containers Start Job Run', defaultProps); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: 'emr-containers:StartJobRun', + Condition: { + StringEquals: { + 'emr-containers:ExecutionRoleArn': { + 'Fn::GetAtt': [ + 'EMRContainersStartJobRunJobExecutionRole40B8DD81', + 'Arn', + ], + }, + }, + }, + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':emr-containers:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + `:/virtualclusters/${clusterId}`, + ], + ], + }, + }, + { + Action: [ + 'emr-containers:DescribeJobRun', + 'emr-containers:CancelJobRun', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':emr-containers:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + `:/virtualclusters/${clusterId}/jobruns/*`, + ], + ], + }, + }], + }, + }); + }); + + test('Permitted role actions and resources with Start Job Run from payload', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'Task', { + ...defaultProps, + virtualCluster: VirtualClusterInput.fromTaskInput(sfn.TaskInput.fromJsonPathAt('$.ClusterId')), + executionRole: iam.Role.fromRoleArn(stack, 'Job Role', 'arn:aws:iam::xxxxxxxxxxxx:role/JobExecutionRole'), + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: 'emr-containers:StartJobRun', + Condition: { + StringEquals: { + 'emr-containers:ExecutionRoleArn': 'arn:aws:iam::xxxxxxxxxxxx:role/JobExecutionRole', + }, + }, + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':emr-containers:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':/virtualclusters/*', + ], + ], + }, + }, + { + Action: [ + 'emr-containers:DescribeJobRun', + 'emr-containers:CancelJobRun', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':emr-containers:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':/virtualclusters/*', + ], + ], + }, + }], + }, + }); + }); + + test('Permitted role actions for Start Job Run with REQUEST/RESPONSE integration pattern', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'Task', { + ...defaultProps, + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + }); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: 'emr-containers:StartJobRun', + Condition: { + StringEquals: { + 'emr-containers:ExecutionRoleArn': { + 'Fn::GetAtt': [ + 'TaskJobExecutionRole5D5BBA5A', + 'Arn', + ], + }, + }, + }, + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':emr-containers:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + `:/virtualclusters/${clusterId}`, + ], + ], + }, + }], + }, + }); + }); + + test('Custom resource is created with EMR Containers Describe Virtual Cluster invocation and has correct IAM policy permissions', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'Task', defaultProps); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('Custom::AWS', { + ServiceToken: { + 'Fn::GetAtt': [ + 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', + 'Arn', + ], + }, + Create: '{\"service\":\"EMRcontainers\",\"action\":\"describeVirtualCluster\",\"parameters\":{\"id\":\"clusterId\"},\"outputPaths\":[\"virtualCluster.containerProvider.info.eksInfo.namespace\",\"virtualCluster.containerProvider.id\"],\"physicalResourceId\":{\"id\":\"id\"}}', + InstallLatestAwsSdk: true, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Action: 'emr-containers:DescribeVirtualCluster', + Effect: 'Allow', + Resource: '*', + }], + }, + }); + }); + + test('Custom resource is created that has correct EKS namespace, environment, AWSCLI layer, and IAM policy permissions', () => { + // WHEN + const task = new EmrContainersStartJobRun(stack, 'Task', defaultProps); + + new sfn.StateMachine(stack, 'SM', { + definition: task, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'eks:DescribeCluster', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':eks:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':cluster/', + { + 'Fn::GetAtt': [ + 'TaskGetEksClusterInfo2F156985', + 'virtualCluster.containerProvider.id', + ], + }, + ], + ], + }, + }, + { + Action: [ + 'iam:GetRole', + 'iam:UpdateAssumeRolePolicy', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'TaskJobExecutionRole5D5BBA5A', + 'Arn', + ], + }, + }, + ], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Handler: 'index.handler', + Layers: [ + { + Ref: 'TaskawsclilayerB1A11740', + }, + ], + MemorySize: 256, + Runtime: 'python3.6', + Timeout: 30, + }); + }); +}); + +test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration pattern', () => { + expect(() => { + new EmrContainersStartJobRun(stack, 'Task', { + virtualCluster: VirtualClusterInput.fromTaskInput(sfn.TaskInput.fromText(clusterId)), + releaseLabel: ReleaseLabel.EMR_6_2_0, + jobDriver: { + sparkSubmitJobDriver: { + entryPoint: sfn.TaskInput.fromText('job-location'), + }, + }, + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + }); + }).toThrow(/Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE,RUN_JOB. Received: WAIT_FOR_TASK_TOKEN/); +}); \ No newline at end of file From ec4187c26d68df970d72d0e766d7d27b42e8b784 Mon Sep 17 00:00:00 2001 From: Tatsuya Yamamoto Date: Thu, 25 Nov 2021 07:05:33 +0900 Subject: [PATCH 11/82] feat(iot): add Action to capture CloudWatch metrics (#17503) I'm trying to implement aws-iot L2 Constructs. This PR is one of steps after following PR: - https://github.com/aws/aws-cdk/pull/16681#issuecomment-942233029 ---- *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-iot-actions/README.md | 25 ++++ .../lib/cloudwatch-put-metric-action.ts | 77 ++++++++++ .../@aws-cdk/aws-iot-actions/lib/index.ts | 1 + .../@aws-cdk/aws-iot-actions/package.json | 2 + .../cloudwatch-put-metric-action.test.ts | 134 ++++++++++++++++++ .../integ.cloudwatch-logs-action.ts | 1 - ...cloudwatch-put-metric-action.expected.json | 68 +++++++++ .../integ.cloudwatch-put-metric-action.ts | 26 ++++ .../integ.firehose-stream-action.ts | 1 - .../lambda/integ.lambda-function-action.ts | 1 - .../test/s3/integ.s3-put-object-action.ts | 1 - 11 files changed, 333 insertions(+), 4 deletions(-) create mode 100644 packages/@aws-cdk/aws-iot-actions/lib/cloudwatch-put-metric-action.ts create mode 100644 packages/@aws-cdk/aws-iot-actions/test/cloudwatch/cloudwatch-put-metric-action.test.ts create mode 100644 packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-put-metric-action.expected.json create mode 100644 packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-put-metric-action.ts diff --git a/packages/@aws-cdk/aws-iot-actions/README.md b/packages/@aws-cdk/aws-iot-actions/README.md index e02f67cee0d45..bf2955757abe8 100644 --- a/packages/@aws-cdk/aws-iot-actions/README.md +++ b/packages/@aws-cdk/aws-iot-actions/README.md @@ -24,6 +24,7 @@ Currently supported are: - Invoke a Lambda function - Put objects to a S3 bucket - Put logs to CloudWatch Logs +- Capture CloudWatch metrics - Put records to Kinesis Data Firehose stream ## Invoke a Lambda function @@ -123,6 +124,30 @@ new iot.TopicRule(this, 'TopicRule', { }); ``` +## Capture CloudWatch metrics + +The code snippet below creates an AWS IoT Rule that capture CloudWatch metrics +when it is triggered. + +```ts +import * as iot from '@aws-cdk/aws-iot'; +import * as actions from '@aws-cdk/aws-iot-actions'; + +const topicRule = new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323( + "SELECT topic(2) as device_id, namespace, unit, value, timestamp FROM 'device/+/data'", + ), + actions: [ + new actions.CloudWatchPutMetricAction({ + metricName: '${topic(2)}', + metricNamespace: '${namespace}', + metricUnit: '${unit}', + metricValue: '${value}', + metricTimestamp: '${timestamp}', + }), + ], +}); +``` ## Put records to Kinesis Data Firehose stream diff --git a/packages/@aws-cdk/aws-iot-actions/lib/cloudwatch-put-metric-action.ts b/packages/@aws-cdk/aws-iot-actions/lib/cloudwatch-put-metric-action.ts new file mode 100644 index 0000000000000..90d7658e4a493 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/lib/cloudwatch-put-metric-action.ts @@ -0,0 +1,77 @@ +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import * as iot from '@aws-cdk/aws-iot'; +import { CommonActionProps } from './common-action-props'; +import { singletonActionRole } from './private/role'; + +/** + * Configuration properties of an action for CloudWatch metric. + */ +export interface CloudWatchPutMetricActionProps extends CommonActionProps { + /** + * The CloudWatch metric name. + * + * Supports substitution templates. + * @see https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html + */ + readonly metricName: string; + + /** + * The CloudWatch metric namespace name. + * + * Supports substitution templates. + * @see https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html + */ + readonly metricNamespace: string; + + /** + * A string that contains the timestamp, expressed in seconds in Unix epoch time. + * + * Supports substitution templates. + * @see https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html + * + * @default - none -- Defaults to the current Unix epoch time. + */ + readonly metricTimestamp?: string; + + /** + * The metric unit supported by CloudWatch. + * + * Supports substitution templates. + * @see https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html + */ + readonly metricUnit: string; + + /** + * A string that contains the CloudWatch metric value. + * + * Supports substitution templates. + * @see https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html + */ + readonly metricValue: string; +} + +/** + * The action to capture an Amazon CloudWatch metric. + */ +export class CloudWatchPutMetricAction implements iot.IAction { + constructor(private readonly props: CloudWatchPutMetricActionProps) { + } + + bind(rule: iot.ITopicRule): iot.ActionConfig { + const role = this.props.role ?? singletonActionRole(rule); + cloudwatch.Metric.grantPutMetricData(role); + + return { + configuration: { + cloudwatchMetric: { + metricName: this.props.metricName, + metricNamespace: this.props.metricNamespace, + metricTimestamp: this.props.metricTimestamp, + metricUnit: this.props.metricUnit, + metricValue: this.props.metricValue, + roleArn: role.roleArn, + }, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-iot-actions/lib/index.ts b/packages/@aws-cdk/aws-iot-actions/lib/index.ts index ce74a2ff2b685..4ad9c1d2a1fb6 100644 --- a/packages/@aws-cdk/aws-iot-actions/lib/index.ts +++ b/packages/@aws-cdk/aws-iot-actions/lib/index.ts @@ -1,4 +1,5 @@ export * from './cloudwatch-logs-action'; +export * from './cloudwatch-put-metric-action'; export * from './common-action-props'; export * from './firehose-stream-action'; export * from './lambda-function-action'; diff --git a/packages/@aws-cdk/aws-iot-actions/package.json b/packages/@aws-cdk/aws-iot-actions/package.json index 8deede8b080c3..39b486cdcc285 100644 --- a/packages/@aws-cdk/aws-iot-actions/package.json +++ b/packages/@aws-cdk/aws-iot-actions/package.json @@ -80,6 +80,7 @@ "jest": "^27.3.1" }, "dependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-iot": "0.0.0", "@aws-cdk/aws-kinesisfirehose": "0.0.0", @@ -92,6 +93,7 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-iot": "0.0.0", "@aws-cdk/aws-kinesisfirehose": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/cloudwatch-put-metric-action.test.ts b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/cloudwatch-put-metric-action.test.ts new file mode 100644 index 0000000000000..ed6b23bb90bde --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/cloudwatch-put-metric-action.test.ts @@ -0,0 +1,134 @@ +import { Template, Match } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; +import * as iot from '@aws-cdk/aws-iot'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +test('Default cloudwatch metric action', () => { + // GIVEN + const stack = new cdk.Stack(); + const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, namespace, unit, value, timestamp FROM 'device/+/data'"), + }); + + // WHEN + topicRule.addAction( + new actions.CloudWatchPutMetricAction({ + metricName: '${topic(2)}', + metricNamespace: '${namespace}', + metricUnit: '${unit}', + metricValue: '${value}', + }), + ); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + { + CloudwatchMetric: { + MetricName: '${topic(2)}', + MetricNamespace: '${namespace}', + MetricUnit: '${unit}', + MetricValue: '${value}', + RoleArn: { + 'Fn::GetAtt': ['MyTopicRuleTopicRuleActionRoleCE2D05DA', 'Arn'], + }, + }, + }, + ], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'iot.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'cloudwatch:PutMetricData', + Effect: 'Allow', + Resource: '*', + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyTopicRuleTopicRuleActionRoleDefaultPolicy54A701F7', + Roles: [{ Ref: 'MyTopicRuleTopicRuleActionRoleCE2D05DA' }], + }); +}); + +test('can set timestamp', () => { + // GIVEN + const stack = new cdk.Stack(); + const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, namespace, unit, value, timestamp FROM 'device/+/data'"), + }); + + // WHEN + topicRule.addAction( + new actions.CloudWatchPutMetricAction({ + metricName: '${topic(2)}', + metricNamespace: '${namespace}', + metricUnit: '${unit}', + metricValue: '${value}', + metricTimestamp: '${timestamp()}', + }), + ); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + Match.objectLike({ CloudwatchMetric: { MetricTimestamp: '${timestamp()}' } }), + ], + }, + }); +}); + +test('can set role', () => { + // GIVEN + const stack = new cdk.Stack(); + const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, namespace, unit, value, timestamp FROM 'device/+/data'"), + }); + const role = iam.Role.fromRoleArn(stack, 'MyRole', 'arn:aws:iam::123456789012:role/ForTest'); + + // WHEN + topicRule.addAction( + new actions.CloudWatchPutMetricAction({ + metricName: '${topic(2)}', + metricNamespace: '${namespace}', + metricUnit: '${unit}', + metricValue: '${value}', + role, + }), + ); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + Match.objectLike({ CloudwatchMetric: { RoleArn: 'arn:aws:iam::123456789012:role/ForTest' } }), + ], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyName: 'MyRolePolicy64AB00A5', + Roles: ['ForTest'], + }); +}); diff --git a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-logs-action.ts b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-logs-action.ts index 802f485b77e37..ce8b3a8111c5d 100644 --- a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-logs-action.ts +++ b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-logs-action.ts @@ -1,4 +1,3 @@ -/// !cdk-integ pragma:ignore-assets import * as iot from '@aws-cdk/aws-iot'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-put-metric-action.expected.json b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-put-metric-action.expected.json new file mode 100644 index 0000000000000..c3ab0305174d4 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-put-metric-action.expected.json @@ -0,0 +1,68 @@ +{ + "Resources": { + "TopicRule40A4EA44": { + "Type": "AWS::IoT::TopicRule", + "Properties": { + "TopicRulePayload": { + "Actions": [ + { + "CloudwatchMetric": { + "MetricName": "${topic(2)}", + "MetricNamespace": "${namespace}", + "MetricTimestamp": "${timestamp}", + "MetricUnit": "${unit}", + "MetricValue": "${value}", + "RoleArn": { + "Fn::GetAtt": [ + "TopicRuleTopicRuleActionRole246C4F77", + "Arn" + ] + } + } + } + ], + "AwsIotSqlVersion": "2016-03-23", + "Sql": "SELECT topic(2) as device_id, namespace, unit, value, timestamp FROM 'device/+/data'" + } + } + }, + "TopicRuleTopicRuleActionRole246C4F77": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "iot.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "cloudwatch:PutMetricData", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687", + "Roles": [ + { + "Ref": "TopicRuleTopicRuleActionRole246C4F77" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-put-metric-action.ts b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-put-metric-action.ts new file mode 100644 index 0000000000000..5a70d0bca3652 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-put-metric-action.ts @@ -0,0 +1,26 @@ +import * as iot from '@aws-cdk/aws-iot'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +const app = new cdk.App(); + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const topicRule = new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, namespace, unit, value, timestamp FROM 'device/+/data'"), + }); + + topicRule.addAction(new actions.CloudWatchPutMetricAction({ + metricName: '${topic(2)}', + metricNamespace: '${namespace}', + metricUnit: '${unit}', + metricValue: '${value}', + metricTimestamp: '${timestamp}', + })); + } +} + +new TestStack(app, 'test-stack'); +app.synth(); diff --git a/packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-stream-action.ts b/packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-stream-action.ts index 9287f1294b4dd..2c6c93cf0460f 100644 --- a/packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-stream-action.ts +++ b/packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-stream-action.ts @@ -1,4 +1,3 @@ -/// !cdk-integ pragma:ignore-assets import * as iot from '@aws-cdk/aws-iot'; import * as firehose from '@aws-cdk/aws-kinesisfirehose'; import * as destinations from '@aws-cdk/aws-kinesisfirehose-destinations'; diff --git a/packages/@aws-cdk/aws-iot-actions/test/lambda/integ.lambda-function-action.ts b/packages/@aws-cdk/aws-iot-actions/test/lambda/integ.lambda-function-action.ts index 58a7773afec03..b6052c80aeabf 100644 --- a/packages/@aws-cdk/aws-iot-actions/test/lambda/integ.lambda-function-action.ts +++ b/packages/@aws-cdk/aws-iot-actions/test/lambda/integ.lambda-function-action.ts @@ -1,4 +1,3 @@ -/// !cdk-integ pragma:ignore-assets import * as iot from '@aws-cdk/aws-iot'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-iot-actions/test/s3/integ.s3-put-object-action.ts b/packages/@aws-cdk/aws-iot-actions/test/s3/integ.s3-put-object-action.ts index 9e100e0254eaf..eb9773fa395cd 100644 --- a/packages/@aws-cdk/aws-iot-actions/test/s3/integ.s3-put-object-action.ts +++ b/packages/@aws-cdk/aws-iot-actions/test/s3/integ.s3-put-object-action.ts @@ -1,4 +1,3 @@ -/// !cdk-integ pragma:ignore-assets import * as iot from '@aws-cdk/aws-iot'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; From 4982aca6f95ca864a285ed9955a9618a20ca0415 Mon Sep 17 00:00:00 2001 From: markussiebert Date: Thu, 25 Nov 2021 00:43:03 +0100 Subject: [PATCH 12/82] feat(docdb): implement audit and profiler logs (#17570) closes #17478 *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-docdb/README.md | 16 +++++ packages/@aws-cdk/aws-docdb/lib/cluster.ts | 29 +++++++++ .../@aws-cdk/aws-docdb/test/cluster.test.ts | 64 +++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/packages/@aws-cdk/aws-docdb/README.md b/packages/@aws-cdk/aws-docdb/README.md index 808fe85208c45..650d37ffffc5f 100644 --- a/packages/@aws-cdk/aws-docdb/README.md +++ b/packages/@aws-cdk/aws-docdb/README.md @@ -116,3 +116,19 @@ cluster.addRotationMultiUser('MyUser', { // Add rotation using the multi user sc The rotation will start as soon as this user exists. See also [@aws-cdk/aws-secretsmanager](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-secretsmanager/README.md) for credentials rotation of existing clusters. + +## Audit and profiler Logs + +Sending audit or profiler needs to be configured in two places: + +1. Check / create the needed options in your ParameterGroup for [audit](https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html#event-auditing-enabling-auditing) and +[profiler](https://docs.aws.amazon.com/documentdb/latest/developerguide/profiling.html#profiling.enable-profiling) logs. +2. Enable the corresponding option(s) when creating the `DatabaseCluster`: + +```ts +const cluster = new DatabaseCluster(this, 'Database', { + ..., + exportProfilerLogsToCloudWatch: true, // Enable sending profiler logs + exportAuditLogsToCloudWatch: true, // Enable sending audit logs +}); +``` diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts index 6a744d089320c..fe208c068c213 100644 --- a/packages/@aws-cdk/aws-docdb/lib/cluster.ts +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -146,6 +146,24 @@ export interface DatabaseClusterProps { * @default - false */ readonly deletionProtection?: boolean; + + /** + * Whether the profiler logs should be exported to CloudWatch. + * Note that you also have to configure the profiler log export in the Cluster's Parameter Group. + * + * @see https://docs.aws.amazon.com/documentdb/latest/developerguide/profiling.html#profiling.enable-profiling + * @default false + */ + readonly exportProfilerLogsToCloudWatch?: boolean; + + /** + * Whether the audit logs should be exported to CloudWatch. + * Note that you also have to configure the audit log export in the Cluster's Parameter Group. + * + * @see https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html#event-auditing-enabling-auditing + * @default false + */ + readonly exportAuditLogsToCloudWatch?: boolean; } /** @@ -346,6 +364,15 @@ export class DatabaseCluster extends DatabaseClusterBase { } this.securityGroupId = securityGroup.securityGroupId; + // Create the CloudwatchLogsConfiguratoin + const enableCloudwatchLogsExports: string[] = []; + if (props.exportAuditLogsToCloudWatch) { + enableCloudwatchLogsExports.push('audit'); + } + if (props.exportProfilerLogsToCloudWatch) { + enableCloudwatchLogsExports.push('profiler'); + } + // Create the secret manager secret if no password is specified let secret: DatabaseSecret | undefined; if (!props.masterUser.password) { @@ -383,6 +410,8 @@ export class DatabaseCluster extends DatabaseClusterBase { backupRetentionPeriod: props.backup?.retention?.toDays(), preferredBackupWindow: props.backup?.preferredWindow, preferredMaintenanceWindow: props.preferredMaintenanceWindow, + // EnableCloudwatchLogsExports + enableCloudwatchLogsExports: enableCloudwatchLogsExports.length > 0 ? enableCloudwatchLogsExports : undefined, // Encryption kmsKeyId: props.kmsKey?.keyArn, storageEncrypted, diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index 819825f6df094..f8bfdc65adda1 100644 --- a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -588,6 +588,70 @@ describe('DatabaseCluster', () => { })); }); + test('can configure CloudWatchLogs for audit', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + exportAuditLogsToCloudWatch: true, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + EnableCloudwatchLogsExports: ['audit'], + })); + }); + + test('can configure CloudWatchLogs for profiler', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + exportProfilerLogsToCloudWatch: true, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + EnableCloudwatchLogsExports: ['profiler'], + })); + }); + + test('can configure CloudWatchLogs for all logs', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + exportAuditLogsToCloudWatch: true, + exportProfilerLogsToCloudWatch: true, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + EnableCloudwatchLogsExports: ['audit', 'profiler'], + })); + }); + test('single user rotation', () => { // GIVEN const stack = testStack(); From 2d19e1535586d2b006d43da787ffbb0fad8b4978 Mon Sep 17 00:00:00 2001 From: arcrank Date: Wed, 24 Nov 2021 19:25:35 -0500 Subject: [PATCH 13/82] feat(servicecatalog): Add TagOptions to a CloudformationProduct (#17672) Users can now associate TagOptions to a cloudformation product through an association call or upon instantiation. TagOptions added to a portfolio are made available for any products within it, but you can also have separate, product level tag options. We only create unique TagOption constructs in the template but we can have the same Tag Option associated with both a portfolio and a product in that portfolio, the logic that resolves this is handled by service catalog. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* Co-authored-by: Dillon Ponzo --- .../@aws-cdk/aws-servicecatalog/README.md | 15 +++- .../aws-servicecatalog/lib/portfolio.ts | 4 +- .../lib/private/association-manager.ts | 23 ++--- .../aws-servicecatalog/lib/product.ts | 25 +++++- .../test/integ.portfolio.expected.json | 33 +++++++ .../test/integ.portfolio.ts | 1 + .../test/integ.product.expected.json | 57 ++++++++++++ .../aws-servicecatalog/test/integ.product.ts | 9 +- .../aws-servicecatalog/test/product.test.ts | 89 +++++++++++++++++++ 9 files changed, 237 insertions(+), 19 deletions(-) diff --git a/packages/@aws-cdk/aws-servicecatalog/README.md b/packages/@aws-cdk/aws-servicecatalog/README.md index bbc82e13e2d7b..436fe376f9624 100644 --- a/packages/@aws-cdk/aws-servicecatalog/README.md +++ b/packages/@aws-cdk/aws-servicecatalog/README.md @@ -202,15 +202,22 @@ portfolio.addProduct(product); TagOptions allow administrators to easily manage tags on provisioned products by creating a selection of tags for end users to choose from. For example, an end user can choose an `ec2` for the instance type size. -TagOptions are created by specifying a key with a selection of values. +TagOptions are created by specifying a key with a selection of values and can be associated with both portfolios and products. +When launching a product, both the TagOptions associated with the product and the containing portfolio are made available. + At the moment, TagOptions can only be disabled in the console. -```ts fixture=basic-portfolio -const tagOptions = new servicecatalog.TagOptions({ +```ts fixture=portfolio-product +const tagOptionsForPortfolio = new servicecatalog.TagOptions({ + costCenter: ['Data Insights', 'Marketing'], +}); +portfolio.associateTagOptions(tagOptionsForPortfolio); + +const tagOptionsForProduct = new servicecatalog.TagOptions({ ec2InstanceType: ['A1', 'M4'], ec2InstanceSize: ['medium', 'large'], }); -portfolio.associateTagOptions(tagOptions); +product.associateTagOptions(tagOptionsForProduct); ``` ## Constraints diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/portfolio.ts b/packages/@aws-cdk/aws-servicecatalog/lib/portfolio.ts index 36d267d022519..cfe92db543a8e 100644 --- a/packages/@aws-cdk/aws-servicecatalog/lib/portfolio.ts +++ b/packages/@aws-cdk/aws-servicecatalog/lib/portfolio.ts @@ -186,7 +186,7 @@ abstract class PortfolioBase extends cdk.Resource implements IPortfolio { } public associateTagOptions(tagOptions: TagOptions) { - AssociationManager.associateTagOptions(this, tagOptions); + AssociationManager.associateTagOptions(this, this.portfolioId, tagOptions); } public constrainTagUpdates(product: IProduct, options: TagUpdateConstraintOptions = {}): void { @@ -275,7 +275,7 @@ export interface PortfolioProps { readonly description?: string; /** - * TagOptions associated directly on portfolio + * TagOptions associated directly to a portfolio. * * @default - No tagOptions provided */ diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/private/association-manager.ts b/packages/@aws-cdk/aws-servicecatalog/lib/private/association-manager.ts index b92fb2483ad54..e1e4ee8de38da 100644 --- a/packages/@aws-cdk/aws-servicecatalog/lib/private/association-manager.ts +++ b/packages/@aws-cdk/aws-servicecatalog/lib/private/association-manager.ts @@ -139,27 +139,28 @@ export class AssociationManager { } } - public static associateTagOptions(portfolio: IPortfolio, tagOptions: TagOptions): void { - const portfolioStack = cdk.Stack.of(portfolio); + + public static associateTagOptions(resource: cdk.IResource, resourceId: string, tagOptions: TagOptions): void { + const resourceStack = cdk.Stack.of(resource); for (const [key, tagOptionsList] of Object.entries(tagOptions.tagOptionsMap)) { - InputValidator.validateLength(portfolio.node.addr, 'TagOption key', 1, 128, key); + InputValidator.validateLength(resource.node.addr, 'TagOption key', 1, 128, key); tagOptionsList.forEach((value: string) => { - InputValidator.validateLength(portfolio.node.addr, 'TagOption value', 1, 256, value); - const tagOptionKey = hashValues(key, value, portfolioStack.node.addr); + InputValidator.validateLength(resource.node.addr, 'TagOption value', 1, 256, value); + const tagOptionKey = hashValues(key, value, resourceStack.node.addr); const tagOptionConstructId = `TagOption${tagOptionKey}`; - let cfnTagOption = portfolioStack.node.tryFindChild(tagOptionConstructId) as CfnTagOption; + let cfnTagOption = resourceStack.node.tryFindChild(tagOptionConstructId) as CfnTagOption; if (!cfnTagOption) { - cfnTagOption = new CfnTagOption(portfolioStack, tagOptionConstructId, { + cfnTagOption = new CfnTagOption(resourceStack, tagOptionConstructId, { key: key, value: value, active: true, }); } - const tagAssocationKey = hashValues(key, value, portfolio.node.addr); + const tagAssocationKey = hashValues(key, value, resource.node.addr); const tagAssocationConstructId = `TagOptionAssociation${tagAssocationKey}`; - if (!portfolio.node.tryFindChild(tagAssocationConstructId)) { - new CfnTagOptionAssociation(portfolio as unknown as cdk.Resource, tagAssocationConstructId, { - resourceId: portfolio.portfolioId, + if (!resource.node.tryFindChild(tagAssocationConstructId)) { + new CfnTagOptionAssociation(resource as cdk.Resource, tagAssocationConstructId, { + resourceId: resourceId, tagOptionId: cfnTagOption.ref, }); } diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/product.ts b/packages/@aws-cdk/aws-servicecatalog/lib/product.ts index 466e1fa726e55..29a47fc6932a9 100644 --- a/packages/@aws-cdk/aws-servicecatalog/lib/product.ts +++ b/packages/@aws-cdk/aws-servicecatalog/lib/product.ts @@ -1,7 +1,9 @@ import { ArnFormat, IResource, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { TagOptions } from '.'; import { CloudFormationTemplate } from './cloudformation-template'; import { MessageLanguage } from './common'; +import { AssociationManager } from './private/association-manager'; import { InputValidator } from './private/validation'; import { CfnCloudFormationProduct } from './servicecatalog.generated'; @@ -20,11 +22,22 @@ export interface IProduct extends IResource { * @attribute */ readonly productId: string; + + /** + * Associate Tag Options. + * A TagOption is a key-value pair managed in AWS Service Catalog. + * It is not an AWS tag, but serves as a template for creating an AWS tag based on the TagOption. + */ + associateTagOptions(tagOptions: TagOptions): void; } abstract class ProductBase extends Resource implements IProduct { public abstract readonly productArn: string; public abstract readonly productId: string; + + public associateTagOptions(tagOptions: TagOptions) { + AssociationManager.associateTagOptions(this, this.productId, tagOptions); + } } /** @@ -118,6 +131,13 @@ export interface CloudFormationProductProps { * @default - No support URL provided */ readonly supportUrl?: string; + + /** + * TagOptions associated directly to a product. + * + * @default - No tagOptions provided + */ + readonly tagOptions?: TagOptions } /** @@ -170,13 +190,16 @@ export class CloudFormationProduct extends Product { supportUrl: props.supportUrl, }); + this.productId = product.ref; this.productArn = Stack.of(this).formatArn({ service: 'catalog', resource: 'product', resourceName: product.ref, }); - this.productId = product.ref; + if (props.tagOptions !== undefined) { + this.associateTagOptions(props.tagOptions); + } } private renderProvisioningArtifacts( diff --git a/packages/@aws-cdk/aws-servicecatalog/test/integ.portfolio.expected.json b/packages/@aws-cdk/aws-servicecatalog/test/integ.portfolio.expected.json index 5407c293f09b5..c298f292d039d 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/integ.portfolio.expected.json +++ b/packages/@aws-cdk/aws-servicecatalog/test/integ.portfolio.expected.json @@ -256,6 +256,39 @@ ] } }, + "TestProductTagOptionAssociation667d45e6d8a1F30303D6": { + "Type": "AWS::ServiceCatalog::TagOptionAssociation", + "Properties": { + "ResourceId": { + "Ref": "TestProduct7606930B" + }, + "TagOptionId": { + "Ref": "TagOptionc0d88a3c4b8b" + } + } + }, + "TestProductTagOptionAssociationec68fcd0154fF6DAD979": { + "Type": "AWS::ServiceCatalog::TagOptionAssociation", + "Properties": { + "ResourceId": { + "Ref": "TestProduct7606930B" + }, + "TagOptionId": { + "Ref": "TagOption9b16df08f83d" + } + } + }, + "TestProductTagOptionAssociation259ba31b62cc63D068F9": { + "Type": "AWS::ServiceCatalog::TagOptionAssociation", + "Properties": { + "ResourceId": { + "Ref": "TestProduct7606930B" + }, + "TagOptionId": { + "Ref": "TagOptiondf34c1c83580" + } + } + }, "Topic198E71B3E": { "Type": "AWS::SNS::Topic" }, diff --git a/packages/@aws-cdk/aws-servicecatalog/test/integ.portfolio.ts b/packages/@aws-cdk/aws-servicecatalog/test/integ.portfolio.ts index a96c11a45ba3f..669016f35be2a 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/integ.portfolio.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/integ.portfolio.ts @@ -40,6 +40,7 @@ const product = new servicecatalog.CloudFormationProduct(stack, 'TestProduct', { 'https://awsdocs.s3.amazonaws.com/servicecatalog/development-environment.template'), }, ], + tagOptions: tagOptions, }); portfolio.addProduct(product); diff --git a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json index f54d640e1d0ca..fb51ec2ad0df4 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json +++ b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.expected.json @@ -218,6 +218,63 @@ } ] } + }, + "TestProductTagOptionAssociation0d813eebb333DA3E2F21": { + "Type": "AWS::ServiceCatalog::TagOptionAssociation", + "Properties": { + "ResourceId": { + "Ref": "TestProduct7606930B" + }, + "TagOptionId": { + "Ref": "TagOptionab501c9aef99" + } + } + }, + "TestProductTagOptionAssociation5d93a5c977b4B664DD87": { + "Type": "AWS::ServiceCatalog::TagOptionAssociation", + "Properties": { + "ResourceId": { + "Ref": "TestProduct7606930B" + }, + "TagOptionId": { + "Ref": "TagOptiona453ac93ee6f" + } + } + }, + "TestProductTagOptionAssociationcfaf40b186a3E5FDECDC": { + "Type": "AWS::ServiceCatalog::TagOptionAssociation", + "Properties": { + "ResourceId": { + "Ref": "TestProduct7606930B" + }, + "TagOptionId": { + "Ref": "TagOptiona006431604cb" + } + } + }, + "TagOptionab501c9aef99": { + "Type": "AWS::ServiceCatalog::TagOption", + "Properties": { + "Key": "key1", + "Value": "value1", + "Active": true + } + }, + "TagOptiona453ac93ee6f": { + "Type": "AWS::ServiceCatalog::TagOption", + "Properties": { + "Key": "key1", + "Value": "value2", + "Active": true + } + }, + "TagOptiona006431604cb": { + "Type": "AWS::ServiceCatalog::TagOption", + "Properties": { + "Key": "key2", + "Value": "value1", + "Active": true + } } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts index 7a88c98a466d1..e1e08105ee3ce 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/integ.product.ts @@ -14,7 +14,7 @@ class TestProductStack extends servicecatalog.ProductStack { } } -new servicecatalog.CloudFormationProduct(stack, 'TestProduct', { +const product = new servicecatalog.CloudFormationProduct(stack, 'TestProduct', { productName: 'testProduct', owner: 'testOwner', productVersions: [ @@ -38,4 +38,11 @@ new servicecatalog.CloudFormationProduct(stack, 'TestProduct', { ], }); +const tagOptions = new servicecatalog.TagOptions({ + key1: ['value1', 'value2'], + key2: ['value1'], +}); + +product.associateTagOptions(tagOptions); + app.synth(); diff --git a/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts b/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts index f399a79dcdb83..0afc91ce86153 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/product.test.ts @@ -271,5 +271,94 @@ describe('Product', () => { productVersions: [], }); }).toThrowError(/Invalid product versions for resource Default\/MyProduct/); + }), + + describe('adding and associating TagOptions to a product', () => { + let product: servicecatalog.IProduct; + + beforeEach(() => { + product = new servicecatalog.CloudFormationProduct(stack, 'MyProduct', { + productName: 'testProduct', + owner: 'testOwner', + productVersions: [ + { + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromUrl('https://awsdocs.s3.amazonaws.com/servicecatalog/development-environment.template'), + }, + ], + }); + }), + + test('add tag options to product', () => { + const tagOptions = new servicecatalog.TagOptions({ + key1: ['value1', 'value2'], + key2: ['value1'], + }); + + product.associateTagOptions(tagOptions); + + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalog::TagOption', 3); //Generates a resource for each unique key-value pair + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalog::TagOptionAssociation', 3); + }), + + test('add tag options as input to product in props', () => { + const tagOptions = new servicecatalog.TagOptions({ + key1: ['value1', 'value2'], + key2: ['value1'], + }); + + new servicecatalog.CloudFormationProduct(stack, 'MyProductWithTagOptions', { + productName: 'testProduct', + owner: 'testOwner', + productVersions: [ + { + cloudFormationTemplate: servicecatalog.CloudFormationTemplate.fromUrl('https://awsdocs.s3.amazonaws.com/servicecatalog/development-environment.template'), + }, + ], + tagOptions: tagOptions, + }); + + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalog::TagOption', 3); //Generates a resource for each unique key-value pair + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalog::TagOptionAssociation', 3); + }), + + test('adding identical tag options to product is idempotent', () => { + const tagOptions1 = new servicecatalog.TagOptions({ + key1: ['value1', 'value2'], + key2: ['value1'], + }); + + const tagOptions2 = new servicecatalog.TagOptions({ + key1: ['value1', 'value2'], + }); + + product.associateTagOptions(tagOptions1); + product.associateTagOptions(tagOptions2); // If not idempotent this would fail + + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalog::TagOption', 3); //Generates a resource for each unique key-value pair + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalog::TagOptionAssociation', 3); + }), + + test('adding duplicate tag options to portfolio and product creates unique tag options and enumerated associations', () => { + const tagOptions1 = new servicecatalog.TagOptions({ + key1: ['value1', 'value2'], + key2: ['value1'], + }); + + const tagOptions2 = new servicecatalog.TagOptions({ + key1: ['value1', 'value2'], + key2: ['value2'], + }); + + const portfolio = new servicecatalog.Portfolio(stack, 'MyPortfolio', { + displayName: 'testPortfolio', + providerName: 'testProvider', + }); + + portfolio.associateTagOptions(tagOptions1); + product.associateTagOptions(tagOptions2); // If not idempotent this would fail + + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalog::TagOption', 4); //Generates a resource for each unique key-value pair + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalog::TagOptionAssociation', 6); + }); }); }); From 1fe2215dc40eb58f1babc2c3fbca501a5e89b09f Mon Sep 17 00:00:00 2001 From: markussiebert Date: Thu, 25 Nov 2021 02:08:11 +0100 Subject: [PATCH 14/82] fix(docdb): secret rotation ignores excluded characters in password (#17609) We need to pass whatever `excludeCharacters` were passed to the generated Secret to the application responsible for the rotation. Fixes #17347 Fixes #17575 ------ *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-docdb/README.md | 2 +- packages/@aws-cdk/aws-docdb/lib/cluster.ts | 2 ++ packages/@aws-cdk/aws-docdb/lib/database-secret.ts | 13 ++++++++++++- packages/@aws-cdk/aws-docdb/test/cluster.test.ts | 2 ++ .../test/integ.cluster-rotation.lit.expected.json | 1 + 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-docdb/README.md b/packages/@aws-cdk/aws-docdb/README.md index 650d37ffffc5f..2ee2a9791c7d0 100644 --- a/packages/@aws-cdk/aws-docdb/README.md +++ b/packages/@aws-cdk/aws-docdb/README.md @@ -21,7 +21,7 @@ your instances will be launched privately or publicly: const cluster = new DatabaseCluster(this, 'Database', { masterUser: { username: 'myuser' // NOTE: 'admin' is reserved by DocumentDB - excludeCharacters: '\"@/:', // optional, defaults to the set "\"@/" + excludeCharacters: '\"@/:', // optional, defaults to the set "\"@/" and is also used for eventually created rotations secretName: '/myapp/mydocdb/masteruser', // optional, if you prefer to specify the secret name }, instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE), diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts index fe208c068c213..52ce8ff5e3a64 100644 --- a/packages/@aws-cdk/aws-docdb/lib/cluster.ts +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -491,6 +491,7 @@ export class DatabaseCluster extends DatabaseClusterBase { secret: this.secret, automaticallyAfter, application: DatabaseCluster.SINGLE_USER_ROTATION_APPLICATION, + excludeCharacters: (this.node.tryFindChild('Secret') as DatabaseSecret)._excludedCharacters, vpc: this.vpc, vpcSubnets: this.vpcSubnets, target: this, @@ -508,6 +509,7 @@ export class DatabaseCluster extends DatabaseClusterBase { secret: options.secret, masterSecret: this.secret, automaticallyAfter: options.automaticallyAfter, + excludeCharacters: (this.node.tryFindChild('Secret') as DatabaseSecret)._excludedCharacters, application: DatabaseCluster.MULTI_USER_ROTATION_APPLICATION, vpc: this.vpc, vpcSubnets: this.vpcSubnets, diff --git a/packages/@aws-cdk/aws-docdb/lib/database-secret.ts b/packages/@aws-cdk/aws-docdb/lib/database-secret.ts index 8f1bca671da6d..97b1f7bff1df0 100644 --- a/packages/@aws-cdk/aws-docdb/lib/database-secret.ts +++ b/packages/@aws-cdk/aws-docdb/lib/database-secret.ts @@ -48,7 +48,16 @@ export interface DatabaseSecretProps { * @resource AWS::SecretsManager::Secret */ export class DatabaseSecret extends Secret { + + /** + * the excluded characters for this Secret + * @internal + */ + public readonly _excludedCharacters: string; + constructor(scope: Construct, id: string, props: DatabaseSecretProps) { + const excludedCharacters = props.excludeCharacters ?? '"@/'; + super(scope, id, { secretName: props.secretName, description: `Generated by the CDK for stack: ${Aws.STACK_NAME}`, @@ -68,8 +77,10 @@ export class DatabaseSecret extends Secret { masterarn: props.masterSecret?.secretArn, }), generateStringKey: 'password', - excludeCharacters: props.excludeCharacters ?? '"@/', + excludeCharacters: excludedCharacters, }, }); + + this._excludedCharacters = excludedCharacters; } } diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index f8bfdc65adda1..d68a91f0b80c6 100644 --- a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -684,6 +684,7 @@ describe('DatabaseCluster', () => { ], }, functionName: 'DatabaseRotationSingleUser458A45BE', + excludeCharacters: '\"@/', vpcSubnetIds: { 'Fn::Join': [ '', @@ -796,6 +797,7 @@ describe('DatabaseCluster', () => { ], }, functionName: 'DatabaseRotation0D47EBD2', + excludeCharacters: '\"@/', vpcSubnetIds: { 'Fn::Join': [ '', diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json index c063376359496..a2c3c5d8138a4 100644 --- a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json @@ -785,6 +785,7 @@ ] }, "functionName": "awscdkdocdbclusterrotationDatabaseRotationSingleUser7DAE65BE", + "excludeCharacters": "\"@/", "vpcSubnetIds": { "Fn::Join": [ "", From 39fe11bc1b0d12920111331dca560150006a0733 Mon Sep 17 00:00:00 2001 From: Jan W Date: Thu, 25 Nov 2021 02:50:09 +0100 Subject: [PATCH 15/82] fix(codepipeline): cannot trigger on all tags anymore in EcrSourceAction (#17270) The EcrSourceAction could previously be used to trigger on changes to all tags of an image. As part of the fix aws#13818, the imageTag was defaulted to latest if not provided. Therefore it was no longer possible to call the underlying onCloudTrailImagePushed function with an undefined imageTag to watch changes on all tags. Reintroduce triggering on all tags by passing an empty string as the imageTag. Fixes aws#13818 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/ecr/source-action.ts | 5 +- .../test/ecr/ecr-source-action.test.ts | 73 +++++++++++++++++++ .../integ.pipeline-ecr-source.expected.json | 2 +- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts index eb40c994ccd98..01c878ca9e139 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts @@ -36,6 +36,7 @@ export interface EcrSourceVariables { export interface EcrSourceActionProps extends codepipeline.CommonAwsActionProps { /** * The image tag that will be checked for changes. + * Provide an empty string to trigger on changes to any tag. * * @default 'latest' */ @@ -95,7 +96,7 @@ export class EcrSourceAction extends Action { this.props.repository.onCloudTrailImagePushed(Names.nodeUniqueId(stage.pipeline.node) + 'SourceEventRule', { target: new targets.CodePipeline(stage.pipeline), - imageTag: this.props.imageTag ?? 'latest', + imageTag: this.props.imageTag === '' ? undefined : (this.props.imageTag ?? 'latest'), }); // the Action Role also needs to write to the Pipeline's bucket @@ -104,7 +105,7 @@ export class EcrSourceAction extends Action { return { configuration: { RepositoryName: this.props.repository.repositoryName, - ImageTag: this.props.imageTag, + ImageTag: this.props.imageTag ? this.props.imageTag : undefined, // `''` is falsy in JS/TS }, }; } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts index b51a566d4ef14..99160cdd4193a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts @@ -1,4 +1,5 @@ import '@aws-cdk/assert-internal/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as ecr from '@aws-cdk/aws-ecr'; @@ -60,6 +61,78 @@ describe('ecr source action', () => { }); + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + 'EventPattern': { + 'detail': { + 'requestParameters': { + 'imageTag': ['latest'], + }, + }, + }, + }); + }); + + test('watches all tags when imageTag provided as empty string', () => { + const stack = new Stack(); + + const sourceOutput = new codepipeline.Artifact(); + const ecrSourceAction = new cpactions.EcrSourceAction({ + actionName: 'Source', + output: sourceOutput, + repository: ecr.Repository.fromRepositoryName(stack, 'Repo', 'repo'), + imageTag: '', + }); + + new codepipeline.Pipeline(stack, 'Pipeline', { + stages: [ + { + stageName: 'Source', + actions: [ecrSourceAction], + }, + { + stageName: 'Build', + actions: [ + new cpactions.CodeBuildAction({ + actionName: 'Build', + project: new codebuild.PipelineProject(stack, 'MyProject'), + input: sourceOutput, + environmentVariables: { + ImageDigest: { value: ecrSourceAction.variables.imageDigest }, + }, + }), + ], + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.ecr', + ], + 'detail': { + 'requestParameters': { + 'imageTag': ABSENT, + }, + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { + 'Name': 'Source', + 'Actions': [ + { + 'Name': 'Source', + 'Configuration': { + 'ImageTag': ABSENT, + }, + }, + ], + }, + ], + }); }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json index c200ab454d71a..53c605d58da68 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json @@ -415,4 +415,4 @@ } } } -} \ No newline at end of file +} From 37596e6be4cf05432dcba3838955484e512beca6 Mon Sep 17 00:00:00 2001 From: diegotry <33488603+diegotry@users.noreply.github.com> Date: Thu, 25 Nov 2021 02:09:59 -0800 Subject: [PATCH 16/82] fix(assert): support multiline strings with `stringLike()` (#17692) Updates the `RegExp` constructor to support multiline. Resolves https://github.com/aws/aws-cdk/issues/17691 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/assert-internal/README.md | 2 +- .../lib/assertions/have-resource-matchers.ts | 4 +-- .../test/have-resource.test.ts | 36 ++++++++++++++++++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/assert-internal/README.md b/packages/@aws-cdk/assert-internal/README.md index ae72469dc59e2..a74f9304f60d6 100644 --- a/packages/@aws-cdk/assert-internal/README.md +++ b/packages/@aws-cdk/assert-internal/README.md @@ -103,7 +103,7 @@ The following matchers exist: back to exact value matching. - `arrayWith(E, [F, ...])` - value must be an array containing the given elements (or matchers) in any order. - `stringLike(S)` - value must be a string matching `S`. `S` may contain `*` as wildcard to match any number - of characters. + of characters. Multiline strings are supported. - `anything()` - matches any value. - `notMatching(M)` - any value that does NOT match the given matcher (or exact value) given. - `encodedJson(M)` - value must be a string which, when decoded as JSON, matches the given matcher or diff --git a/packages/@aws-cdk/assert-internal/lib/assertions/have-resource-matchers.ts b/packages/@aws-cdk/assert-internal/lib/assertions/have-resource-matchers.ts index deb64b769ff16..d82b59feffea0 100644 --- a/packages/@aws-cdk/assert-internal/lib/assertions/have-resource-matchers.ts +++ b/packages/@aws-cdk/assert-internal/lib/assertions/have-resource-matchers.ts @@ -239,11 +239,11 @@ function isCallable(x: any): x is ((...args: any[]) => any) { } /** - * Do a glob-like pattern match (which only supports *s) + * Do a glob-like pattern match (which only supports *s). Supports multiline strings. */ export function stringLike(pattern: string): PropertyMatcher { // Replace * with .* in the string, escape the rest and brace with ^...$ - const regex = new RegExp(`^${pattern.split('*').map(escapeRegex).join('.*')}$`); + const regex = new RegExp(`^${pattern.split('*').map(escapeRegex).join('.*')}$`, 'm'); return annotateMatcher({ $stringContaining: pattern }, (value: any, failure: InspectionFailure) => { if (typeof value !== 'string') { diff --git a/packages/@aws-cdk/assert-internal/test/have-resource.test.ts b/packages/@aws-cdk/assert-internal/test/have-resource.test.ts index 324e221114df0..c43433e8ca14f 100644 --- a/packages/@aws-cdk/assert-internal/test/have-resource.test.ts +++ b/packages/@aws-cdk/assert-internal/test/have-resource.test.ts @@ -1,4 +1,14 @@ -import { ABSENT, arrayWith, exactValue, expect as cdkExpect, haveResource, haveResourceLike, Capture, anything } from '../lib/index'; +import { + ABSENT, + arrayWith, + exactValue, + expect as cdkExpect, + haveResource, + haveResourceLike, + Capture, + anything, + stringLike, +} from '../lib/index'; import { mkResource, mkStack } from './cloud-artifact'; test('support resource with no properties', () => { @@ -156,6 +166,30 @@ describe('property absence', () => { }).toThrowError(/Array did not contain expected element/); }); + test('can use matcher to test stringLike on single-line strings', () => { + const synthStack = mkResource({ + Content: 'something required something', + }); + + expect(() => { + cdkExpect(synthStack).to(haveResource('Some::Resource', { + Content: stringLike('*required*'), + })); + }).not.toThrowError(); + }); + + test('can use matcher to test stringLike on multi-line strings', () => { + const synthStack = mkResource({ + Content: 'something\nrequired\nsomething', + }); + + expect(() => { + cdkExpect(synthStack).to(haveResource('Some::Resource', { + Content: stringLike('*required*'), + })); + }).not.toThrowError(); + }); + test('arrayContaining must match all elements in any order', () => { const synthStack = mkResource({ List: ['a', 'b'], From cb3154789da52b94e4688d645adba87ef2ebf39f Mon Sep 17 00:00:00 2001 From: saqibdhuka <39248128+saqibdhuka@users.noreply.github.com> Date: Thu, 25 Nov 2021 07:20:35 -0800 Subject: [PATCH 17/82] feat(apigateway): step functions integration (#16827) - Added StepFunctionsRestApi and StepFunctionsIntegration implementation closes #15081. ---- *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-apigateway/README.md | 116 +++++ packages/@aws-cdk/aws-apigateway/lib/index.ts | 1 + .../aws-apigateway/lib/integrations/index.ts | 2 + .../lib/integrations/request-context.ts | 161 +++++++ .../lib/integrations/stepfunctions.ts | 288 +++++++++++++ .../lib/integrations/stepfunctions.vtl | 63 +++ .../@aws-cdk/aws-apigateway/lib/restapi.ts | 1 + .../aws-apigateway/lib/stepfunctions-api.ts | 153 +++++++ packages/@aws-cdk/aws-apigateway/package.json | 2 + .../aws-apigateway/rosetta/default.ts-fixture | 1 + .../rosetta/stepfunctions.ts-fixture | 17 + .../integ.stepfunctions-api.expected.json | 289 +++++++++++++ .../test/integ.stepfunctions-api.ts | 52 +++ .../test/integrations/stepfunctions.test.ts | 407 ++++++++++++++++++ .../test/stepfunctions-api.test.ts | 197 +++++++++ .../aws-stepfunctions/lib/state-machine.ts | 20 + .../test/state-machine-resources.test.ts | 30 ++ 17 files changed, 1800 insertions(+) create mode 100644 packages/@aws-cdk/aws-apigateway/lib/integrations/request-context.ts create mode 100644 packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.ts create mode 100644 packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.vtl create mode 100644 packages/@aws-cdk/aws-apigateway/lib/stepfunctions-api.ts create mode 100644 packages/@aws-cdk/aws-apigateway/rosetta/stepfunctions.ts-fixture create mode 100644 packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.expected.json create mode 100644 packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.ts create mode 100644 packages/@aws-cdk/aws-apigateway/test/integrations/stepfunctions.test.ts create mode 100644 packages/@aws-cdk/aws-apigateway/test/stepfunctions-api.test.ts diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index 4789a8cc62410..83e9d04cd31c6 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -22,6 +22,7 @@ running on AWS Lambda, or any web application. - [Defining APIs](#defining-apis) - [Breaking up Methods and Resources across Stacks](#breaking-up-methods-and-resources-across-stacks) - [AWS Lambda-backed APIs](#aws-lambda-backed-apis) +- [AWS StepFunctions backed APIs](#aws-stepfunctions-backed-APIs) - [Integration Targets](#integration-targets) - [Usage Plan & API Keys](#usage-plan--api-keys) - [Working with models](#working-with-models) @@ -106,6 +107,121 @@ item.addMethod('GET'); // GET /items/{item} item.addMethod('DELETE', new apigateway.HttpIntegration('http://amazon.com')); ``` +## AWS StepFunctions backed APIs + +You can use Amazon API Gateway with AWS Step Functions as the backend integration, specifically Synchronous Express Workflows. + +The `StepFunctionsRestApi` only supports integration with Synchronous Express state machine. The `StepFunctionsRestApi` construct makes this easy by setting up input, output and error mapping. + +The construct sets up an API endpoint and maps the `ANY` HTTP method and any calls to the API endpoint starts an express workflow execution for the underlying state machine. + +Invoking the endpoint with any HTTP method (`GET`, `POST`, `PUT`, `DELETE`, ...) in the example below will send the request to the state machine as a new execution. On success, an HTTP code `200` is returned with the execution output as the Response Body. + +If the execution fails, an HTTP `500` response is returned with the `error` and `cause` from the execution output as the Response Body. If the request is invalid (ex. bad execution input) HTTP code `400` is returned. + +The response from the invocation contains only the `output` field from the +[StartSyncExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartSyncExecution.html#API_StartSyncExecution_ResponseSyntax) API. +In case of failures, the fields `error` and `cause` are returned as part of the response. +Other metadata such as billing details, AWS account ID and resource ARNs are not returned in the API response. + +By default, a `prod` stage is provisioned. + +In order to reduce the payload size sent to AWS Step Functions, `headers` are not forwarded to the Step Functions execution input. It is possible to choose whether `headers`, `requestContext`, `path` and `querystring` are included or not. By default, `headers` are excluded in all requests. + +More details about AWS Step Functions payload limit can be found at https://docs.aws.amazon.com/step-functions/latest/dg/limits-overview.html#service-limits-task-executions. + +The following code defines a REST API that routes all requests to the specified AWS StepFunctions state machine: + +```ts +const stateMachineDefinition = new stepfunctions.Pass(this, 'PassState'); + +const stateMachine: stepfunctions.IStateMachine = new stepfunctions.StateMachine(this, 'StateMachine', { + definition: stateMachineDefinition, + stateMachineType: stepfunctions.StateMachineType.EXPRESS, +}); + +new apigateway.StepFunctionsRestApi(this, 'StepFunctionsRestApi', { + deploy: true, + stateMachine: stateMachine, +}); +``` + +When the REST API endpoint configuration above is invoked using POST, as follows - + +```bash +curl -X POST -d '{ "customerId": 1 }' https://example.com/ +``` + +AWS Step Functions will receive the request body in its input as follows: + +```json +{ + "body": { + "customerId": 1 + }, + "path": "/", + "querystring": {} +} +``` + +When the endpoint is invoked at path '/users/5' using the HTTP GET method as below: + +```bash +curl -X GET https://example.com/users/5?foo=bar +``` + +AWS Step Functions will receive the following execution input: + +```json +{ + "body": {}, + "path": { + "users": "5" + }, + "querystring": { + "foo": "bar" + } +} +``` + +Additional information around the request such as the request context and headers can be included as part of the input +forwarded to the state machine. The following example enables headers to be included in the input but not query string. + +```ts fixture=stepfunctions +new apigateway.StepFunctionsRestApi(this, 'StepFunctionsRestApi', { + stateMachine: machine, + headers: true, + path: false, + querystring: false, + requestContext: { + caller: true, + user: true, + }, +}); +``` + +In such a case, when the endpoint is invoked as below: + +```bash +curl -X GET https://example.com/ +``` + +AWS Step Functions will receive the following execution input: + +```json +{ + "headers": { + "Accept": "...", + "CloudFront-Forwarded-Proto": "...", + }, + "requestContext": { + "accountId": "...", + "apiKey": "...", + }, + "body": {} +} +``` + ### Breaking up Methods and Resources across Stacks It is fairly common for REST APIs with a large number of Resources and Methods to hit the [CloudFormation diff --git a/packages/@aws-cdk/aws-apigateway/lib/index.ts b/packages/@aws-cdk/aws-apigateway/lib/index.ts index 4c288b27f4160..58b8150e2ebf9 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/index.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/index.ts @@ -21,6 +21,7 @@ export * from './authorizers'; export * from './access-log'; export * from './api-definition'; export * from './gateway-response'; +export * from './stepfunctions-api'; // AWS::ApiGateway CloudFormation Resources: export * from './apigateway.generated'; diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/index.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/index.ts index 1369c366d655f..9ebc36bf92a58 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/index.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/index.ts @@ -2,3 +2,5 @@ export * from './aws'; export * from './lambda'; export * from './http'; export * from './mock'; +export * from './stepfunctions'; +export * from './request-context'; diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/request-context.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/request-context.ts new file mode 100644 index 0000000000000..12847584f5958 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/request-context.ts @@ -0,0 +1,161 @@ +/** + * Configure what must be included in the `requestContext` + * + * More details can be found at mapping templates documentation. + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html + */ +export interface RequestContext { + /** + * Represents the information of $context.identity.accountId + * + * Whether the AWS account of the API owner should be included in the request context + * @default false + */ + readonly accountId?: boolean; + + /** + * Represents the information of $context.apiId + * + * Whether the identifier API Gateway assigns to your API should be included in the request context. + * @default false + */ + readonly apiId?: boolean; + + /** + * Represents the information of $context.identity.apiKey + * + * Whether the API key associated with the request should be included in request context. + * @default false + */ + readonly apiKey?: boolean; + + /** + * Represents the information of $context.authorizer.principalId + * + * Whether the principal user identifier associated with the token sent by the client and returned + * from an API Gateway Lambda authorizer should be included in the request context. + * @default false + */ + readonly authorizerPrincipalId?: boolean; + + /** + * Represents the information of $context.identity.caller + * + * Whether the principal identifier of the caller that signed the request should be included in the request context. + * Supported for resources that use IAM authorization. + * @default false + */ + readonly caller?: boolean; + + /** + * Represents the information of $context.identity.cognitoAuthenticationProvider + * + * Whether the list of the Amazon Cognito authentication providers used by the caller making the request should be included in the request context. + * Available only if the request was signed with Amazon Cognito credentials. + * @default false + */ + readonly cognitoAuthenticationProvider?: boolean; + + /** + * Represents the information of $context.identity.cognitoAuthenticationType + * + * Whether the Amazon Cognito authentication type of the caller making the request should be included in the request context. + * Available only if the request was signed with Amazon Cognito credentials. + * Possible values include authenticated for authenticated identities and unauthenticated for unauthenticated identities. + * @default false + */ + readonly cognitoAuthenticationType?: boolean; + + /** + * Represents the information of $context.identity.cognitoIdentityId + * + * Whether the Amazon Cognito identity ID of the caller making the request should be included in the request context. + * Available only if the request was signed with Amazon Cognito credentials. + * @default false + */ + readonly cognitoIdentityId?: boolean; + + /** + * Represents the information of $context.identity.cognitoIdentityPoolId + * + * Whether the Amazon Cognito identity pool ID of the caller making the request should be included in the request context. + * Available only if the request was signed with Amazon Cognito credentials. + * @default false + */ + readonly cognitoIdentityPoolId?: boolean; + + /** + * Represents the information of $context.httpMethod + * + * Whether the HTTP method used should be included in the request context. + * Valid values include: DELETE, GET, HEAD, OPTIONS, PATCH, POST, and PUT. + * @default false + */ + readonly httpMethod?: boolean; + + /** + * Represents the information of $context.stage + * + * Whether the deployment stage of the API request should be included in the request context. + * @default false + */ + readonly stage?: boolean; + + /** + * Represents the information of $context.identity.sourceIp + * + * Whether the source IP address of the immediate TCP connection making the request + * to API Gateway endpoint should be included in the request context. + * @default false + */ + readonly sourceIp?: boolean; + + /** + * Represents the information of $context.identity.user + * + * Whether the principal identifier of the user that will be authorized should be included in the request context. + * Supported for resources that use IAM authorization. + * @default false + */ + readonly user?: boolean; + + /** + * Represents the information of $context.identity.userAgent + * + * Whether the User-Agent header of the API caller should be included in the request context. + * @default false + */ + readonly userAgent?: boolean; + + /** + * Represents the information of $context.identity.userArn + * + * Whether the Amazon Resource Name (ARN) of the effective user identified after authentication should be included in the request context. + * @default false + */ + readonly userArn?: boolean; + + /** + * Represents the information of $context.requestId + * + * Whether the ID for the request should be included in the request context. + * @default false + */ + readonly requestId?: boolean; + + /** + * Represents the information of $context.resourceId + * + * Whether the identifier that API Gateway assigns to your resource should be included in the request context. + * @default false + */ + readonly resourceId?: boolean; + + /** + * Represents the information of $context.resourcePath + * + * Whether the path to the resource should be included in the request context. + * @default false + */ + readonly resourcePath?: boolean; +} diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.ts new file mode 100644 index 0000000000000..339e7b2949198 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.ts @@ -0,0 +1,288 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Token } from '@aws-cdk/core'; +import { RequestContext } from '.'; +import { IntegrationConfig, IntegrationOptions, PassthroughBehavior } from '../integration'; +import { Method } from '../method'; +import { AwsIntegration } from './aws'; +/** + * Options when configuring Step Functions synchronous integration with Rest API + */ +export interface StepFunctionsExecutionIntegrationOptions extends IntegrationOptions { + + /** + * Which details of the incoming request must be passed onto the underlying state machine, + * such as, account id, user identity, request id, etc. The execution input will include a new key `requestContext`: + * + * { + * "body": {}, + * "requestContext": { + * "key": "value" + * } + * } + * + * @default - all parameters within request context will be set as false + */ + readonly requestContext?: RequestContext; + + /** + * Check if querystring is to be included inside the execution input. The execution input will include a new key `queryString`: + * + * { + * "body": {}, + * "querystring": { + * "key": "value" + * } + * } + * + * @default true + */ + readonly querystring?: boolean; + + /** + * Check if path is to be included inside the execution input. The execution input will include a new key `path`: + * + * { + * "body": {}, + * "path": { + * "resourceName": "resourceValue" + * } + * } + * + * @default true + */ + readonly path?: boolean; + + /** + * Check if header is to be included inside the execution input. The execution input will include a new key `headers`: + * + * { + * "body": {}, + * "headers": { + * "header1": "value", + * "header2": "value" + * } + * } + * @default false + */ + readonly headers?: boolean; +} + +/** + * Options to integrate with various StepFunction API + */ +export class StepFunctionsIntegration { + /** + * Integrates a Synchronous Express State Machine from AWS Step Functions to an API Gateway method. + * + * @example + * + * const stateMachine = new stepfunctions.StateMachine(this, 'MyStateMachine', { + * definition: stepfunctions.Chain.start(new stepfunctions.Pass(this, 'Pass')), + * }); + * + * const api = new apigateway.RestApi(this, 'Api', { + * restApiName: 'MyApi', + * }); + * api.root.addMethod('GET', apigateway.StepFunctionsIntegration.startExecution(stateMachine)); + */ + public static startExecution(stateMachine: sfn.IStateMachine, options?: StepFunctionsExecutionIntegrationOptions): AwsIntegration { + return new StepFunctionsExecutionIntegration(stateMachine, options); + } +} + +class StepFunctionsExecutionIntegration extends AwsIntegration { + private readonly stateMachine: sfn.IStateMachine; + constructor(stateMachine: sfn.IStateMachine, options: StepFunctionsExecutionIntegrationOptions = {}) { + super({ + service: 'states', + action: 'StartSyncExecution', + options: { + credentialsRole: options.credentialsRole, + integrationResponses: integrationResponse(), + passthroughBehavior: PassthroughBehavior.NEVER, + requestTemplates: requestTemplates(stateMachine, options), + ...options, + }, + }); + + this.stateMachine = stateMachine; + } + + public bind(method: Method): IntegrationConfig { + const bindResult = super.bind(method); + const principal = new iam.ServicePrincipal('apigateway.amazonaws.com'); + + this.stateMachine.grantExecution(principal, 'states:StartSyncExecution'); + + let stateMachineName; + + if (this.stateMachine instanceof sfn.StateMachine) { + const stateMachineType = (this.stateMachine as sfn.StateMachine).stateMachineType; + if (stateMachineType !== sfn.StateMachineType.EXPRESS) { + throw new Error('State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType'); + } + + //if not imported, extract the name from the CFN layer to reach the + //literal value if it is given (rather than a token) + stateMachineName = (this.stateMachine.node.defaultChild as sfn.CfnStateMachine).stateMachineName; + } else { + //imported state machine + stateMachineName = `StateMachine-${this.stateMachine.stack.node.addr}`; + } + + let deploymentToken; + + if (stateMachineName !== undefined && !Token.isUnresolved(stateMachineName)) { + deploymentToken = JSON.stringify({ stateMachineName }); + } + return { + ...bindResult, + deploymentToken, + }; + } +} + +/** + * Defines the integration response that passes the result on success, + * or the error on failure, from the synchronous execution to the caller. + * + * @returns integrationResponse mapping + */ +function integrationResponse() { + const errorResponse = [ + { + /** + * Specifies the regular expression (regex) pattern used to choose + * an integration response based on the response from the back end. + * In this case it will match all '4XX' HTTP Errors + */ + selectionPattern: '4\\d{2}', + statusCode: '400', + responseTemplates: { + 'application/json': `{ + "error": "Bad request!" + }`, + }, + }, + { + /** + * Match all '5XX' HTTP Errors + */ + selectionPattern: '5\\d{2}', + statusCode: '500', + responseTemplates: { + 'application/json': '"error": $input.path(\'$.error\')', + }, + }, + ]; + + const integResponse = [ + { + statusCode: '200', + responseTemplates: { + /* eslint-disable */ + 'application/json': [ + '#set($inputRoot = $input.path(\'$\'))', + '#if($input.path(\'$.status\').toString().equals("FAILED"))', + '#set($context.responseOverride.status = 500)', + '{', + '"error": "$input.path(\'$.error\')"', + '"cause": "$input.path(\'$.cause\')"', + '}', + '#else', + '$input.path(\'$.output\')', + '#end', + /* eslint-enable */ + ].join('\n'), + }, + }, + ...errorResponse, + ]; + + return integResponse; +} + +/** + * Defines the request template that will be used for the integration + * @param stateMachine + * @param options + * @returns requestTemplate + */ +function requestTemplates(stateMachine: sfn.IStateMachine, options: StepFunctionsExecutionIntegrationOptions) { + const templateStr = templateString(stateMachine, options); + + const requestTemplate: { [contentType:string] : string } = + { + 'application/json': templateStr, + }; + + return requestTemplate; +} + +/** + * Reads the VTL template and returns the template string to be used + * for the request template. + * + * @param stateMachine + * @param includeRequestContext + * @param options + * @reutrns templateString + */ +function templateString( + stateMachine: sfn.IStateMachine, + options: StepFunctionsExecutionIntegrationOptions): string { + let templateStr: string; + + let requestContextStr = ''; + + const includeHeader = options.headers?? false; + const includeQueryString = options.querystring?? true; + const includePath = options.path?? true; + + if (options.requestContext && Object.keys(options.requestContext).length > 0) { + requestContextStr = requestContext(options.requestContext); + } + + templateStr = fs.readFileSync(path.join(__dirname, 'stepfunctions.vtl'), { encoding: 'utf-8' }); + templateStr = templateStr.replace('%STATEMACHINE%', stateMachine.stateMachineArn); + templateStr = templateStr.replace('%INCLUDE_HEADERS%', String(includeHeader)); + templateStr = templateStr.replace('%INCLUDE_QUERYSTRING%', String(includeQueryString)); + templateStr = templateStr.replace('%INCLUDE_PATH%', String(includePath)); + templateStr = templateStr.replace('%REQUESTCONTEXT%', requestContextStr); + + return templateStr; +} + +function requestContext(requestContextObj: RequestContext | undefined): string { + const context = { + accountId: requestContextObj?.accountId? '$context.identity.accountId': undefined, + apiId: requestContextObj?.apiId? '$context.apiId': undefined, + apiKey: requestContextObj?.apiKey? '$context.identity.apiKey': undefined, + authorizerPrincipalId: requestContextObj?.authorizerPrincipalId? '$context.authorizer.principalId': undefined, + caller: requestContextObj?.caller? '$context.identity.caller': undefined, + cognitoAuthenticationProvider: requestContextObj?.cognitoAuthenticationProvider? '$context.identity.cognitoAuthenticationProvider': undefined, + cognitoAuthenticationType: requestContextObj?.cognitoAuthenticationType? '$context.identity.cognitoAuthenticationType': undefined, + cognitoIdentityId: requestContextObj?.cognitoIdentityId? '$context.identity.cognitoIdentityId': undefined, + cognitoIdentityPoolId: requestContextObj?.cognitoIdentityPoolId? '$context.identity.cognitoIdentityPoolId': undefined, + httpMethod: requestContextObj?.httpMethod? '$context.httpMethod': undefined, + stage: requestContextObj?.stage? '$context.stage': undefined, + sourceIp: requestContextObj?.sourceIp? '$context.identity.sourceIp': undefined, + user: requestContextObj?.user? '$context.identity.user': undefined, + userAgent: requestContextObj?.userAgent? '$context.identity.userAgent': undefined, + userArn: requestContextObj?.userArn? '$context.identity.userArn': undefined, + requestId: requestContextObj?.requestId? '$context.requestId': undefined, + resourceId: requestContextObj?.resourceId? '$context.resourceId': undefined, + resourcePath: requestContextObj?.resourcePath? '$context.resourcePath': undefined, + }; + + const contextAsString = JSON.stringify(context); + + // The VTL Template conflicts with double-quotes (") for strings. + // Before sending to the template, we replace double-quotes (") with @@ and replace it back inside the .vtl file + const doublequotes = '"'; + const replaceWith = '@@'; + return contextAsString.split(doublequotes).join(replaceWith); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.vtl b/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.vtl new file mode 100644 index 0000000000000..df4eda7c279d5 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/stepfunctions.vtl @@ -0,0 +1,63 @@ +## Velocity Template used for API Gateway request mapping template +## +## This template forwards the request body, header, path, and querystring +## to the execution input of the state machine. +## +## "@@" is used here as a placeholder for '"' to avoid using escape characters. + +#set($inputString = '') +#set($includeHeaders = %INCLUDE_HEADERS%) +#set($includeQueryString = %INCLUDE_QUERYSTRING%) +#set($includePath = %INCLUDE_PATH%) +#set($allParams = $input.params()) +{ + "stateMachineArn": "%STATEMACHINE%", + + #set($inputString = "$inputString,@@body@@: $input.body") + + #if ($includeHeaders) + #set($inputString = "$inputString, @@header@@:{") + #foreach($paramName in $allParams.header.keySet()) + #set($inputString = "$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@") + #if($foreach.hasNext) + #set($inputString = "$inputString,") + #end + #end + #set($inputString = "$inputString }") + + #end + + #if ($includeQueryString) + #set($inputString = "$inputString, @@querystring@@:{") + #foreach($paramName in $allParams.querystring.keySet()) + #set($inputString = "$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@") + #if($foreach.hasNext) + #set($inputString = "$inputString,") + #end + #end + #set($inputString = "$inputString }") + #end + + #if ($includePath) + #set($inputString = "$inputString, @@path@@:{") + #foreach($paramName in $allParams.path.keySet()) + #set($inputString = "$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@") + #if($foreach.hasNext) + #set($inputString = "$inputString,") + #end + #end + #set($inputString = "$inputString }") + #end + + #set($requestContext = "%REQUESTCONTEXT%") + ## Check if the request context should be included as part of the execution input + #if($requestContext && !$requestContext.empty) + #set($inputString = "$inputString,") + #set($inputString = "$inputString @@requestContext@@: $requestContext") + #end + + #set($inputString = "$inputString}") + #set($inputString = $inputString.replaceAll("@@",'"')) + #set($len = $inputString.length() - 1) + "input": "{$util.escapeJavaScript($inputString.substring(1,$len))}" +} diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index 0ed981690af3c..4d278eef9a500 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -312,6 +312,7 @@ export abstract class RestApiBase extends Resource implements IRestApi { /** * A human friendly name for this Rest API. Note that this is different from `restApiId`. + * @attribute */ public readonly restApiName: string; diff --git a/packages/@aws-cdk/aws-apigateway/lib/stepfunctions-api.ts b/packages/@aws-cdk/aws-apigateway/lib/stepfunctions-api.ts new file mode 100644 index 0000000000000..69addc0619383 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/lib/stepfunctions-api.ts @@ -0,0 +1,153 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Construct } from 'constructs'; +import { RestApi, RestApiProps } from '.'; +import { RequestContext } from './integrations'; +import { StepFunctionsIntegration } from './integrations/stepfunctions'; +import { Model } from './model'; + +/** + * Properties for StepFunctionsRestApi + * + */ +export interface StepFunctionsRestApiProps extends RestApiProps { +/** + * The default State Machine that handles all requests from this API. + * + * This stateMachine will be used as a the default integration for all methods in + * this API, unless specified otherwise in `addMethod`. + */ + readonly stateMachine: sfn.IStateMachine; + + /** + * Which details of the incoming request must be passed onto the underlying state machine, + * such as, account id, user identity, request id, etc. The execution input will include a new key `requestContext`: + * + * { + * "body": {}, + * "requestContext": { + * "key": "value" + * } + * } + * + * @default - all parameters within request context will be set as false + */ + readonly requestContext?: RequestContext; + + /** + * Check if querystring is to be included inside the execution input. The execution input will include a new key `queryString`: + * + * { + * "body": {}, + * "querystring": { + * "key": "value" + * } + * } + * + * @default true + */ + readonly querystring?: boolean; + + /** + * Check if path is to be included inside the execution input. The execution input will include a new key `path`: + * + * { + * "body": {}, + * "path": { + * "resourceName": "resourceValue" + * } + * } + * + * @default true + */ + readonly path?: boolean; + + /** + * Check if header is to be included inside the execution input. The execution input will include a new key `headers`: + * + * { + * "body": {}, + * "headers": { + * "header1": "value", + * "header2": "value" + * } + * } + * @default false + */ + readonly headers?: boolean; +} + +/** + * Defines an API Gateway REST API with a Synchrounous Express State Machine as a proxy integration. + */ +export class StepFunctionsRestApi extends RestApi { + constructor(scope: Construct, id: string, props: StepFunctionsRestApiProps) { + if (props.defaultIntegration) { + throw new Error('Cannot specify "defaultIntegration" since Step Functions integration is automatically defined'); + } + + if ((props.stateMachine.node.defaultChild as sfn.CfnStateMachine).stateMachineType !== sfn.StateMachineType.EXPRESS) { + throw new Error('State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType'); + } + + const stepfunctionsIntegration = StepFunctionsIntegration.startExecution(props.stateMachine, { + credentialsRole: role(scope, props), + requestContext: props.requestContext, + path: props.path?? true, + querystring: props.querystring?? true, + headers: props.headers, + }); + + super(scope, id, props); + + this.root.addMethod('ANY', stepfunctionsIntegration, { + methodResponses: methodResponse(), + }); + } +} + +/** + * Defines the IAM Role for API Gateway with required permissions + * to invoke a synchronous execution for the provided state machine + * + * @param scope + * @param props + * @returns Role - IAM Role + */ +function role(scope: Construct, props: StepFunctionsRestApiProps): iam.Role { + const roleName: string = 'StartSyncExecutionRole'; + const apiRole = new iam.Role(scope, roleName, { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + }); + + props.stateMachine.grantStartSyncExecution(apiRole); + + return apiRole; +} + +/** + * Defines the method response modelfor each HTTP code response + * @returns methodResponse + */ +function methodResponse() { + return [ + { + statusCode: '200', + responseModels: { + 'application/json': Model.EMPTY_MODEL, + }, + }, + { + statusCode: '400', + responseModels: { + 'application/json': Model.ERROR_MODEL, + }, + }, + { + statusCode: '500', + responseModels: { + 'application/json': Model.ERROR_MODEL, + }, + }, + ]; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 8324c62c0b143..1c6e564c1496b 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -97,6 +97,7 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" @@ -113,6 +114,7 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" diff --git a/packages/@aws-cdk/aws-apigateway/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-apigateway/rosetta/default.ts-fixture index ae79983790fe4..bd7747f2a7a26 100644 --- a/packages/@aws-cdk/aws-apigateway/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/aws-apigateway/rosetta/default.ts-fixture @@ -8,6 +8,7 @@ import iam = require('@aws-cdk/aws-iam'); import s3 = require('@aws-cdk/aws-s3'); import ec2 = require('@aws-cdk/aws-ec2'); import logs = require('@aws-cdk/aws-logs'); +import stepfunctions = require('@aws-cdk/aws-stepfunctions'); class Fixture extends Stack { constructor(scope: Construct, id: string) { diff --git a/packages/@aws-cdk/aws-apigateway/rosetta/stepfunctions.ts-fixture b/packages/@aws-cdk/aws-apigateway/rosetta/stepfunctions.ts-fixture new file mode 100644 index 0000000000000..eb7728585bcde --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/rosetta/stepfunctions.ts-fixture @@ -0,0 +1,17 @@ +import { Construct } from 'constructs'; +import { Stack } from '@aws-cdk/core'; +import apigateway = require('@aws-cdk/aws-apigateway'); +import stepfunctions = require('@aws-cdk/aws-stepfunctions'); + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const machine: stepfunctions.IStateMachine = new stepfunctions.StateMachine(this, 'StateMachine', { + definition: new stepfunctions.Pass(this, 'PassState'), + stateMachineType: stepfunctions.StateMachineType.EXPRESS, + }); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.expected.json new file mode 100644 index 0000000000000..81e4a643c14e4 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.expected.json @@ -0,0 +1,289 @@ +{ + "Resources": { + "StateMachineRoleB840431D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, + "DefinitionString": "{\"StartAt\":\"PassTask\",\"States\":{\"PassTask\":{\"Type\":\"Pass\",\"Result\":\"Hello\",\"End\":true}}}", + "StateMachineType": "EXPRESS" + }, + "DependsOn": [ + "StateMachineRoleB840431D" + ] + }, + "StartSyncExecutionRoleDE73CB90": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StartSyncExecutionRoleDefaultPolicy5A5803F8": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartSyncExecution", + "Effect": "Allow", + "Resource": { + "Ref": "StateMachine2E01A3A5" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StartSyncExecutionRoleDefaultPolicy5A5803F8", + "Roles": [ + { + "Ref": "StartSyncExecutionRoleDE73CB90" + } + ] + } + }, + "StepFunctionsRestApiC6E3E883": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "StepFunctionsRestApi" + } + }, + "StepFunctionsRestApiCloudWatchRoleB06ACDB9": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + } + }, + "StepFunctionsRestApiAccountBD0CCC0E": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "StepFunctionsRestApiCloudWatchRoleB06ACDB9", + "Arn" + ] + } + }, + "DependsOn": [ + "StepFunctionsRestApiC6E3E883" + ] + }, + "StepFunctionsRestApiANY7699CA92": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "ANY", + "ResourceId": { + "Fn::GetAtt": [ + "StepFunctionsRestApiC6E3E883", + "RootResourceId" + ] + }, + "RestApiId": { + "Ref": "StepFunctionsRestApiC6E3E883" + }, + "AuthorizationType": "NONE", + "Integration": { + "Credentials": { + "Fn::GetAtt": [ + "StartSyncExecutionRoleDE73CB90", + "Arn" + ] + }, + "IntegrationHttpMethod": "POST", + "IntegrationResponses": [ + { + "ResponseTemplates": { + "application/json": "#set($inputRoot = $input.path('$'))\n#if($input.path('$.status').toString().equals(\"FAILED\"))\n#set($context.responseOverride.status = 500)\n{\n\"error\": \"$input.path('$.error')\"\n\"cause\": \"$input.path('$.cause')\"\n}\n#else\n$input.path('$.output')\n#end" + }, + "StatusCode": "200" + }, + { + "ResponseTemplates": { + "application/json": "{\n \"error\": \"Bad request!\"\n }" + }, + "SelectionPattern": "4\\d{2}", + "StatusCode": "400" + }, + { + "ResponseTemplates": { + "application/json": "\"error\": $input.path('$.error')" + }, + "SelectionPattern": "5\\d{2}", + "StatusCode": "500" + } + ], + "PassthroughBehavior": "NEVER", + "RequestTemplates": { + "application/json": { + "Fn::Join": [ + "", + [ + "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = true)\n#set($includeQueryString = false)\n#set($includePath = false)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", + { + "Ref": "StateMachine2E01A3A5" + }, + "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #set($requestContext = \"{@@accountId@@:@@$context.identity.accountId@@,@@userArn@@:@@$context.identity.userArn@@}\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n" + ] + ] + } + }, + "Type": "AWS", + "Uri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":states:action/StartSyncExecution" + ] + ] + } + }, + "MethodResponses": [ + { + "ResponseModels": { + "application/json": "Empty" + }, + "StatusCode": "200" + }, + { + "ResponseModels": { + "application/json": "Error" + }, + "StatusCode": "400" + }, + { + "ResponseModels": { + "application/json": "Error" + }, + "StatusCode": "500" + } + ] + } + }, + "deployment33381975b5dafda9a97138f301ea25da405640e8": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "StepFunctionsRestApiC6E3E883" + } + }, + "DependsOn": [ + "StepFunctionsRestApiANY7699CA92" + ] + }, + "stage0661E4AC": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "StepFunctionsRestApiC6E3E883" + }, + "DeploymentId": { + "Ref": "deployment33381975b5dafda9a97138f301ea25da405640e8" + }, + "StageName": "prod" + } + } + }, + "Outputs": { + "ApiEndpoint": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "StepFunctionsRestApiC6E3E883" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "stage0661E4AC" + }, + "/" + ] + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.ts b/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.ts new file mode 100644 index 0000000000000..baa43fb1e97e3 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/integ.stepfunctions-api.ts @@ -0,0 +1,52 @@ +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as apigw from '../lib'; + +/** + * Stack verification steps: + * * `curl -X POST 'https://.execute-api..amazonaws.com/prod' \ + * * -d '{"key":"Hello"}' -H 'Content-Type: application/json'` + * The above should return a "Hello" response + */ + +class StepFunctionsRestApiDeploymentStack extends cdk.Stack { + constructor(scope: Construct) { + super(scope, 'StepFunctionsRestApiDeploymentStack'); + + const passTask = new sfn.Pass(this, 'PassTask', { + result: { value: 'Hello' }, + }); + + const stateMachine = new sfn.StateMachine(this, 'StateMachine', { + definition: passTask, + stateMachineType: sfn.StateMachineType.EXPRESS, + }); + + const api = new apigw.StepFunctionsRestApi(this, 'StepFunctionsRestApi', { + deploy: false, + stateMachine: stateMachine, + headers: true, + path: false, + querystring: false, + requestContext: { + accountId: true, + userArn: true, + }, + }); + + api.deploymentStage = new apigw.Stage(this, 'stage', { + deployment: new apigw.Deployment(this, 'deployment', { + api, + }), + }); + + new cdk.CfnOutput(this, 'ApiEndpoint', { + value: api.url, + }); + } +} + +const app = new cdk.App(); +new StepFunctionsRestApiDeploymentStack(app); +app.synth(); diff --git a/packages/@aws-cdk/aws-apigateway/test/integrations/stepfunctions.test.ts b/packages/@aws-cdk/aws-apigateway/test/integrations/stepfunctions.test.ts new file mode 100644 index 0000000000000..c803fa974f7f6 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/integrations/stepfunctions.test.ts @@ -0,0 +1,407 @@ +import '@aws-cdk/assert-internal/jest'; +import { stringLike, anything } from '@aws-cdk/assert-internal'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { StateMachine, StateMachineType } from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as apigw from '../../lib'; + +describe('StepFunctionsIntegration', () => { + describe('startExecution', () => { + test('minimal setup', () => { + //GIVEN + const { stack, api, stateMachine } = givenSetup(); + + //WHEN + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine); + api.root.addMethod('GET', integ); + + //THEN + expect(stack).toHaveResource('AWS::ApiGateway::Method', { + ResourceId: { + 'Fn::GetAtt': [ + 'myrestapiBAC2BF45', + 'RootResourceId', + ], + }, + RestApiId: { + Ref: 'myrestapiBAC2BF45', + }, + AuthorizationType: 'NONE', + Integration: { + IntegrationHttpMethod: 'POST', + IntegrationResponses: getIntegrationResponse(), + Type: 'AWS', + Uri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':states:action/StartSyncExecution', + ], + ], + }, + PassthroughBehavior: 'NEVER', + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = false)\n#set($includeQueryString = true)\n#set($includePath = true)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", + { + Ref: 'StateMachine2E01A3A5', + }, + "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #set($requestContext = \"\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n", + ], + ], + }, + }, + }, + }); + }); + + test('headers are NOT included by default', () => { + //GIVEN + const { stack, api, stateMachine } = givenSetup(); + + //WHEN + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine); + api.root.addMethod('GET', integ); + + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + stringLike('*includeHeaders = false*'), + { Ref: 'StateMachine2E01A3A5' }, + anything(), + ], + ], + }, + }, + }, + }); + }); + + test('headers are included when specified by the integration', () => { + //GIVEN + const { stack, api, stateMachine } = givenSetup(); + + //WHEN + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine, { + headers: true, + }); + api.root.addMethod('GET', integ); + + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + stringLike('*#set($includeHeaders = true)*'), + { Ref: 'StateMachine2E01A3A5' }, + anything(), + ], + ], + }, + }, + }, + }); + }); + + test('querystring and path are included by default', () => { + //GIVEN + const { stack, api, stateMachine } = givenSetup(); + + //WHEN + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine); + api.root.addMethod('GET', integ); + + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + stringLike('*#set($includeQueryString = true)*'), + { Ref: 'StateMachine2E01A3A5' }, + anything(), + ], + ], + }, + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + stringLike('*#set($includePath = true)*'), + { Ref: 'StateMachine2E01A3A5' }, + anything(), + ], + ], + }, + }, + }, + }); + }); + + test('querystring and path are false when specified by the integration', () => { + //GIVEN + const { stack, api, stateMachine } = givenSetup(); + + //WHEN + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine, { + querystring: false, + path: false, + }); + api.root.addMethod('GET', integ); + + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + stringLike('*#set($includeQueryString = false)*'), + { Ref: 'StateMachine2E01A3A5' }, + anything(), + ], + ], + }, + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + stringLike('*#set($includePath = false)*'), + { Ref: 'StateMachine2E01A3A5' }, + anything(), + ], + ], + }, + }, + }, + }); + }); + + test('request context is NOT included by default', () => { + //GIVEN + const { stack, api, stateMachine } = givenSetup(); + + //WHEN + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine, {}); + api.root.addMethod('GET', integ); + + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + anything(), + { Ref: 'StateMachine2E01A3A5' }, + stringLike('*#set($requestContext = \"\")*'), + ], + ], + }, + }, + }, + }); + }); + + test('request context is included when specified by the integration', () => { + //GIVEN + const { stack, api, stateMachine } = givenSetup(); + + //WHEN + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine, { + requestContext: { + accountId: true, + }, + }); + api.root.addMethod('GET', integ); + + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + anything(), + { Ref: 'StateMachine2E01A3A5' }, + stringLike('*#set($requestContext = \"{@@accountId@@:@@$context.identity.accountId@@}\"*'), + ], + ], + }, + }, + }, + }); + }); + + test('works for imported RestApi', () => { + const stack = new cdk.Stack(); + const api = apigw.RestApi.fromRestApiAttributes(stack, 'RestApi', { + restApiId: 'imported-rest-api-id', + rootResourceId: 'imported-root-resource-id', + }); + + const passTask = new sfn.Pass(stack, 'passTask', { + inputPath: '$.somekey', + }); + + const stateMachine: sfn.IStateMachine = new StateMachine(stack, 'StateMachine', { + definition: passTask, + stateMachineType: sfn.StateMachineType.EXPRESS, + }); + + api.root.addMethod('ANY', apigw.StepFunctionsIntegration.startExecution(stateMachine)); + + expect(stack).toHaveResource('AWS::ApiGateway::Method', { + ResourceId: 'imported-root-resource-id', + RestApiId: 'imported-rest-api-id', + }); + }); + + test('fingerprint is not computed when stateMachineName is not specified', () => { + // GIVEN + const stack = new cdk.Stack(); + const restapi = new apigw.RestApi(stack, 'RestApi'); + const method = restapi.root.addMethod('ANY'); + + const passTask = new sfn.Pass(stack, 'passTask', { + inputPath: '$.somekey', + }); + + const stateMachine: sfn.IStateMachine = new StateMachine(stack, 'StateMachine', { + definition: passTask, + stateMachineType: sfn.StateMachineType.EXPRESS, + }); + + const integ = apigw.StepFunctionsIntegration.startExecution(stateMachine); + + // WHEN + const bindResult = integ.bind(method); + + // THEN + expect(bindResult?.deploymentToken).toBeUndefined(); + }); + + test('bind works for integration with imported State Machine', () => { + // GIVEN + const stack = new cdk.Stack(); + const restapi = new apigw.RestApi(stack, 'RestApi'); + const method = restapi.root.addMethod('ANY'); + const stateMachine: sfn.IStateMachine = StateMachine.fromStateMachineArn(stack, 'MyStateMachine', 'arn:aws:states:region:account:stateMachine:MyStateMachine'); + const integration = apigw.StepFunctionsIntegration.startExecution(stateMachine, {}); + + // WHEN + const bindResult = integration.bind(method); + + // the deployment token should be defined since the function name + // should be a literal string. + expect(bindResult?.deploymentToken).toEqual('{"stateMachineName":"StateMachine-c8adc83b19e793491b1c6ea0fd8b46cd9f32e592fc"}'); + }); + + test('fails integration if State Machine is not of type EXPRESS', () => { + //GIVEN + const stack = new cdk.Stack(); + const restapi = new apigw.RestApi(stack, 'RestApi'); + const method = restapi.root.addMethod('ANY'); + const stateMachine: sfn.StateMachine = new StateMachine(stack, 'StateMachine', { + definition: new sfn.Pass(stack, 'passTask'), + stateMachineType: StateMachineType.STANDARD, + }); + const integration = apigw.StepFunctionsIntegration.startExecution(stateMachine); + + //WHEN + THEN + expect(() => integration.bind(method)) + .toThrow(/State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType/); + }); + }); +}); + +function givenSetup() { + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'my-rest-api'); + const passTask = new sfn.Pass(stack, 'passTask', { + inputPath: '$.somekey', + }); + + const stateMachine: sfn.IStateMachine = new StateMachine(stack, 'StateMachine', { + definition: passTask, + stateMachineType: sfn.StateMachineType.EXPRESS, + }); + + return { stack, api, stateMachine }; +} + +function getIntegrationResponse() { + const errorResponse = [ + { + SelectionPattern: '4\\d{2}', + StatusCode: '400', + ResponseTemplates: { + 'application/json': `{ + "error": "Bad request!" + }`, + }, + }, + { + SelectionPattern: '5\\d{2}', + StatusCode: '500', + ResponseTemplates: { + 'application/json': '"error": $input.path(\'$.error\')', + }, + }, + ]; + + const integResponse = [ + { + StatusCode: '200', + ResponseTemplates: { + 'application/json': [ + '#set($inputRoot = $input.path(\'$\'))', + '#if($input.path(\'$.status\').toString().equals("FAILED"))', + '#set($context.responseOverride.status = 500)', + '{', + '"error": "$input.path(\'$.error\')"', + '"cause": "$input.path(\'$.cause\')"', + '}', + '#else', + '$input.path(\'$.output\')', + '#end', + ].join('\n'), + }, + }, + ...errorResponse, + ]; + + return integResponse; +} diff --git a/packages/@aws-cdk/aws-apigateway/test/stepfunctions-api.test.ts b/packages/@aws-cdk/aws-apigateway/test/stepfunctions-api.test.ts new file mode 100644 index 0000000000000..30a1769b8965b --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/test/stepfunctions-api.test.ts @@ -0,0 +1,197 @@ +import '@aws-cdk/assert-internal/jest'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { StateMachine } from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as apigw from '../lib'; + +describe('Step Functions api', () => { + test('StepFunctionsRestApi defines correct REST API resources', () => { + //GIVEN + const { stack, stateMachine } = givenSetup(); + + //WHEN + const api = whenCondition(stack, stateMachine); + + expect(() => { + api.root.addResource('not allowed'); + }).toThrow(); + + //THEN + expect(stack).toHaveResource('AWS::ApiGateway::Method', { + HttpMethod: 'ANY', + MethodResponses: getMethodResponse(), + AuthorizationType: 'NONE', + RestApiId: { + Ref: 'StepFunctionsRestApiC6E3E883', + }, + ResourceId: { + 'Fn::GetAtt': [ + 'StepFunctionsRestApiC6E3E883', + 'RootResourceId', + ], + }, + Integration: { + Credentials: { + 'Fn::GetAtt': [ + 'StartSyncExecutionRoleDE73CB90', + 'Arn', + ], + }, + IntegrationHttpMethod: 'POST', + IntegrationResponses: getIntegrationResponse(), + RequestTemplates: { + 'application/json': { + 'Fn::Join': [ + '', + [ + "## Velocity Template used for API Gateway request mapping template\n##\n## This template forwards the request body, header, path, and querystring\n## to the execution input of the state machine.\n##\n## \"@@\" is used here as a placeholder for '\"' to avoid using escape characters.\n\n#set($inputString = '')\n#set($includeHeaders = false)\n#set($includeQueryString = true)\n#set($includePath = true)\n#set($allParams = $input.params())\n{\n \"stateMachineArn\": \"", + { + Ref: 'StateMachine2E01A3A5', + }, + "\",\n\n #set($inputString = \"$inputString,@@body@@: $input.body\")\n\n #if ($includeHeaders)\n #set($inputString = \"$inputString, @@header@@:{\")\n #foreach($paramName in $allParams.header.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n \n #end\n\n #if ($includeQueryString)\n #set($inputString = \"$inputString, @@querystring@@:{\")\n #foreach($paramName in $allParams.querystring.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n\n #if ($includePath)\n #set($inputString = \"$inputString, @@path@@:{\")\n #foreach($paramName in $allParams.path.keySet())\n #set($inputString = \"$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@\")\n #if($foreach.hasNext)\n #set($inputString = \"$inputString,\")\n #end\n #end\n #set($inputString = \"$inputString }\")\n #end\n \n #set($requestContext = \"\")\n ## Check if the request context should be included as part of the execution input\n #if($requestContext && !$requestContext.empty)\n #set($inputString = \"$inputString,\")\n #set($inputString = \"$inputString @@requestContext@@: $requestContext\")\n #end\n\n #set($inputString = \"$inputString}\")\n #set($inputString = $inputString.replaceAll(\"@@\",'\"'))\n #set($len = $inputString.length() - 1)\n \"input\": \"{$util.escapeJavaScript($inputString.substring(1,$len))}\"\n}\n", + ], + ], + }, + }, + Type: 'AWS', + Uri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':states:action/StartSyncExecution', + ], + ], + }, + PassthroughBehavior: 'NEVER', + }, + }); + }); + + test('fails if options.defaultIntegration is set', () => { + //GIVEN + const { stack, stateMachine } = givenSetup(); + + const httpURL: string = 'https://foo/bar'; + + //WHEN & THEN + expect(() => new apigw.StepFunctionsRestApi(stack, 'StepFunctionsRestApi', { + stateMachine: stateMachine, + defaultIntegration: new apigw.HttpIntegration(httpURL), + })).toThrow(/Cannot specify \"defaultIntegration\" since Step Functions integration is automatically defined/); + + }); + + test('fails if State Machine is not of type EXPRESS', () => { + //GIVEN + const stack = new cdk.Stack(); + + const passTask = new sfn.Pass(stack, 'passTask', { + inputPath: '$.somekey', + }); + + const stateMachine: sfn.IStateMachine = new StateMachine(stack, 'StateMachine', { + definition: passTask, + stateMachineType: sfn.StateMachineType.STANDARD, + }); + + //WHEN & THEN + expect(() => new apigw.StepFunctionsRestApi(stack, 'StepFunctionsRestApi', { + stateMachine: stateMachine, + })).toThrow(/State Machine must be of type "EXPRESS". Please use StateMachineType.EXPRESS as the stateMachineType/); + }); +}); + +function givenSetup() { + const stack = new cdk.Stack(); + + const passTask = new sfn.Pass(stack, 'passTask', { + inputPath: '$.somekey', + }); + + const stateMachine: sfn.IStateMachine = new StateMachine(stack, 'StateMachine', { + definition: passTask, + stateMachineType: sfn.StateMachineType.EXPRESS, + }); + + return { stack, stateMachine }; +} + +function whenCondition(stack:cdk.Stack, stateMachine: sfn.IStateMachine) { + const api = new apigw.StepFunctionsRestApi(stack, 'StepFunctionsRestApi', { stateMachine: stateMachine }); + return api; +} + +function getMethodResponse() { + return [ + { + StatusCode: '200', + ResponseModels: { + 'application/json': 'Empty', + }, + }, + { + StatusCode: '400', + ResponseModels: { + 'application/json': 'Error', + }, + }, + { + StatusCode: '500', + ResponseModels: { + 'application/json': 'Error', + }, + }, + ]; +} + +function getIntegrationResponse() { + const errorResponse = [ + { + SelectionPattern: '4\\d{2}', + StatusCode: '400', + ResponseTemplates: { + 'application/json': `{ + "error": "Bad request!" + }`, + }, + }, + { + SelectionPattern: '5\\d{2}', + StatusCode: '500', + ResponseTemplates: { + 'application/json': '"error": $input.path(\'$.error\')', + }, + }, + ]; + + const integResponse = [ + { + StatusCode: '200', + ResponseTemplates: { + 'application/json': [ + '#set($inputRoot = $input.path(\'$\'))', + '#if($input.path(\'$.status\').toString().equals("FAILED"))', + '#set($context.responseOverride.status = 500)', + '{', + '"error": "$input.path(\'$.error\')"', + '"cause": "$input.path(\'$.cause\')"', + '}', + '#else', + '$input.path(\'$.output\')', + '#end', + ].join('\n'), + }, + }, + ...errorResponse, + ]; + + return integResponse; +} diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts index a75a5f1843992..30eb7dd7c550b 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts @@ -164,6 +164,18 @@ abstract class StateMachineBase extends Resource implements IStateMachine { }); } + /** + * Grant the given identity permissions to start a synchronous execution of + * this state machine. + */ + public grantStartSyncExecution(identity: iam.IGrantable): iam.Grant { + return iam.Grant.addToPrincipal({ + grantee: identity, + actions: ['states:StartSyncExecution'], + resourceArns: [this.stateMachineArn], + }); + } + /** * Grant the given identity permissions to read results from state * machine. @@ -505,6 +517,14 @@ export interface IStateMachine extends IResource, iam.IGrantable { */ grantStartExecution(identity: iam.IGrantable): iam.Grant; + /** + * Grant the given identity permissions to start a synchronous execution of + * this state machine. + * + * @param identity The principal + */ + grantStartSyncExecution(identity: iam.IGrantable): iam.Grant; + /** * Grant the given identity read permissions for this state machine * diff --git a/packages/@aws-cdk/aws-stepfunctions/test/state-machine-resources.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/state-machine-resources.test.ts index 78448372842b9..e80201f5d4adf 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/state-machine-resources.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/state-machine-resources.test.ts @@ -196,6 +196,36 @@ describe('State Machine Resources', () => { }), + test('Created state machine can grant start sync execution to a role', () => { + // GIVEN + const stack = new cdk.Stack(); + const task = new FakeTask(stack, 'Task'); + const stateMachine = new stepfunctions.StateMachine(stack, 'StateMachine', { + definition: task, + stateMachineType: stepfunctions.StateMachineType.EXPRESS, + }); + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + + // WHEN + stateMachine.grantStartSyncExecution(role); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: Match.arrayWith([Match.objectLike({ + Action: 'states:StartSyncExecution', + Effect: 'Allow', + Resource: { + Ref: 'StateMachine2E01A3A5', + }, + })]), + }, + }); + + }), + test('Created state machine can grant read access to a role', () => { // GIVEN const stack = new cdk.Stack(); From b03b4dcba158f85b4bd84c90e61f24557317a61e Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 25 Nov 2021 17:40:53 +0100 Subject: [PATCH 18/82] docs: add links to CloudFormation documentation to READMEs (#17696) Currently, the documentation of our CFN-only libraries leaves a lot to be desired, which is confusing users. Update the READMEs to make it very clear that we don't have anything for them, and point them to the right location for getting documentation. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/alexa-ask/README.md | 17 ++++- .../@aws-cdk/aws-accessanalyzer/README.md | 13 +++- packages/@aws-cdk/aws-amazonmq/README.md | 15 +++- packages/@aws-cdk/aws-appconfig/README.md | 13 +++- packages/@aws-cdk/aws-appflow/README.md | 15 +++- .../@aws-cdk/aws-appintegrations/README.md | 15 +++- .../aws-applicationinsights/README.md | 15 +++- packages/@aws-cdk/aws-appstream/README.md | 15 +++- packages/@aws-cdk/aws-aps/README.md | 15 +++- packages/@aws-cdk/aws-athena/README.md | 15 ++++ packages/@aws-cdk/aws-auditmanager/README.md | 15 +++- .../@aws-cdk/aws-autoscalingplans/README.md | 15 ++++ packages/@aws-cdk/aws-budgets/README.md | 15 ++++ packages/@aws-cdk/aws-cassandra/README.md | 13 +++- packages/@aws-cdk/aws-ce/README.md | 13 +++- packages/@aws-cdk/aws-codeartifact/README.md | 15 +++- .../@aws-cdk/aws-codegurureviewer/README.md | 15 +++- .../aws-codestarconnections/README.md | 13 +++- packages/@aws-cdk/aws-connect/README.md | 15 +++- packages/@aws-cdk/aws-cur/README.md | 15 +++- .../@aws-cdk/aws-customerprofiles/README.md | 15 +++- packages/@aws-cdk/aws-databrew/README.md | 15 +++- packages/@aws-cdk/aws-datapipeline/README.md | 15 ++++ packages/@aws-cdk/aws-datasync/README.md | 15 +++- packages/@aws-cdk/aws-dax/README.md | 15 ++++ packages/@aws-cdk/aws-detective/README.md | 13 +++- packages/@aws-cdk/aws-devopsguru/README.md | 15 +++- .../@aws-cdk/aws-directoryservice/README.md | 15 ++++ packages/@aws-cdk/aws-dlm/README.md | 15 +++- packages/@aws-cdk/aws-dms/README.md | 15 ++++ packages/@aws-cdk/aws-elasticache/README.md | 15 ++++ .../@aws-cdk/aws-elasticbeanstalk/README.md | 15 ++++ packages/@aws-cdk/aws-emr/README.md | 15 ++++ packages/@aws-cdk/aws-emrcontainers/README.md | 15 +++- packages/@aws-cdk/aws-eventschemas/README.md | 13 +++- packages/@aws-cdk/aws-finspace/README.md | 15 +++- packages/@aws-cdk/aws-fis/README.md | 15 +++- packages/@aws-cdk/aws-fms/README.md | 13 +++- packages/@aws-cdk/aws-frauddetector/README.md | 15 +++- packages/@aws-cdk/aws-gamelift/README.md | 15 ++++ packages/@aws-cdk/aws-greengrass/README.md | 13 +++- packages/@aws-cdk/aws-greengrassv2/README.md | 15 +++- packages/@aws-cdk/aws-groundstation/README.md | 15 +++- packages/@aws-cdk/aws-guardduty/README.md | 15 ++++ packages/@aws-cdk/aws-healthlake/README.md | 15 +++- packages/@aws-cdk/aws-imagebuilder/README.md | 15 +++- packages/@aws-cdk/aws-inspector/README.md | 15 ++++ packages/@aws-cdk/aws-iot1click/README.md | 15 +++- packages/@aws-cdk/aws-iotanalytics/README.md | 15 +++- .../aws-iotcoredeviceadvisor/README.md | 15 +++- packages/@aws-cdk/aws-iotevents/README.md | 13 +++- packages/@aws-cdk/aws-iotfleethub/README.md | 15 +++- packages/@aws-cdk/aws-iotsitewise/README.md | 15 +++- .../@aws-cdk/aws-iotthingsgraph/README.md | 13 +++- packages/@aws-cdk/aws-iotwireless/README.md | 15 +++- packages/@aws-cdk/aws-kendra/README.md | 15 +++- .../@aws-cdk/aws-kinesisanalytics/README.md | 16 +++-- .../package.json | 2 +- packages/@aws-cdk/aws-lakeformation/README.md | 13 +++- .../@aws-cdk/aws-licensemanager/README.md | 15 +++- packages/@aws-cdk/aws-lightsail/README.md | 15 +++- packages/@aws-cdk/aws-location/README.md | 15 +++- .../@aws-cdk/aws-lookoutequipment/README.md | 15 +++- .../@aws-cdk/aws-lookoutmetrics/README.md | 15 +++- packages/@aws-cdk/aws-lookoutvision/README.md | 15 +++- packages/@aws-cdk/aws-macie/README.md | 15 +++- .../@aws-cdk/aws-managedblockchain/README.md | 13 +++- packages/@aws-cdk/aws-mediaconnect/README.md | 15 +++- packages/@aws-cdk/aws-mediaconvert/README.md | 13 +++- packages/@aws-cdk/aws-medialive/README.md | 13 +++- packages/@aws-cdk/aws-mediapackage/README.md | 15 +++- packages/@aws-cdk/aws-mediastore/README.md | 13 +++- packages/@aws-cdk/aws-memorydb/README.md | 15 +++- packages/@aws-cdk/aws-mwaa/README.md | 15 +++- .../@aws-cdk/aws-networkfirewall/README.md | 15 +++- .../@aws-cdk/aws-networkmanager/README.md | 13 +++- packages/@aws-cdk/aws-nimblestudio/README.md | 15 +++- packages/@aws-cdk/aws-opsworks/README.md | 15 ++++ packages/@aws-cdk/aws-opsworkscm/README.md | 13 +++- packages/@aws-cdk/aws-panorama/README.md | 15 +++- packages/@aws-cdk/aws-pinpoint/README.md | 13 +++- packages/@aws-cdk/aws-pinpointemail/README.md | 13 +++- packages/@aws-cdk/aws-qldb/README.md | 13 +++- packages/@aws-cdk/aws-quicksight/README.md | 15 +++- packages/@aws-cdk/aws-ram/README.md | 13 +++- packages/@aws-cdk/aws-rekognition/README.md | 15 +++- .../@aws-cdk/aws-resourcegroups/README.md | 13 +++- packages/@aws-cdk/aws-robomaker/README.md | 13 +++- .../aws-route53recoverycontrol/README.md | 15 +++- .../aws-route53recoveryreadiness/README.md | 15 +++- .../@aws-cdk/aws-s3objectlambda/README.md | 15 +++- packages/@aws-cdk/aws-s3outposts/README.md | 15 +++- packages/@aws-cdk/aws-sagemaker/README.md | 15 +++- packages/@aws-cdk/aws-sam/README.md | 19 ++--- packages/@aws-cdk/aws-sdb/README.md | 15 ++++ packages/@aws-cdk/aws-securityhub/README.md | 11 +++ packages/@aws-cdk/aws-ssmcontacts/README.md | 13 +++- packages/@aws-cdk/aws-ssmincidents/README.md | 13 +++- packages/@aws-cdk/aws-sso/README.md | 13 +++- packages/@aws-cdk/aws-timestream/README.md | 13 +++- packages/@aws-cdk/aws-transfer/README.md | 13 +++- packages/@aws-cdk/aws-waf/README.md | 15 ++++ packages/@aws-cdk/aws-wafregional/README.md | 15 ++++ packages/@aws-cdk/aws-wafv2/README.md | 31 +++----- packages/@aws-cdk/aws-wisdom/README.md | 13 +++- packages/@aws-cdk/aws-workspaces/README.md | 15 ++++ packages/@aws-cdk/aws-xray/README.md | 13 +++- .../build-tools/create-missing-libraries.ts | 4 +- .../@aws-cdk/cfnspec/lib/library-creation.ts | 29 ++------ packages/@aws-cdk/cfnspec/package.json | 2 +- tools/@aws-cdk/pkglint/lib/index.ts | 1 + tools/@aws-cdk/pkglint/lib/readme-contents.ts | 70 +++++++++++++++++++ tools/@aws-cdk/pkglint/lib/rules.ts | 30 ++++++++ tools/@aws-cdk/ubergen/bin/ubergen.ts | 1 + 114 files changed, 1496 insertions(+), 190 deletions(-) create mode 100644 tools/@aws-cdk/pkglint/lib/readme-contents.ts diff --git a/packages/@aws-cdk/alexa-ask/README.md b/packages/@aws-cdk/alexa-ask/README.md index 766afeef6d3cd..79d4c4729cec3 100644 --- a/packages/@aws-cdk/alexa-ask/README.md +++ b/packages/@aws-cdk/alexa-ask/README.md @@ -13,6 +13,19 @@ -```ts -import * as alexaAsk from '@aws-cdk/alexa-ask'; +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as alexa_ask from '@aws-cdk/alexa-ask'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for Alexa::ASK](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Alexa_ASK.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-accessanalyzer/README.md b/packages/@aws-cdk/aws-accessanalyzer/README.md index c17d07f97b27d..3f7c1c8a5190b 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/README.md +++ b/packages/@aws-cdk/aws-accessanalyzer/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as accessanalyzer from '@aws-cdk/aws-accessanalyzer'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::AccessAnalyzer](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_AccessAnalyzer.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-amazonmq/README.md b/packages/@aws-cdk/aws-amazonmq/README.md index db1446c38060c..84f7f7b1a62b6 100644 --- a/packages/@aws-cdk/aws-amazonmq/README.md +++ b/packages/@aws-cdk/aws-amazonmq/README.md @@ -13,6 +13,19 @@ -```ts +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture import * as amazonmq from '@aws-cdk/aws-amazonmq'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::AmazonMQ](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_AmazonMQ.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-appconfig/README.md b/packages/@aws-cdk/aws-appconfig/README.md index 946842bae0410..411401ccf1e1a 100644 --- a/packages/@aws-cdk/aws-appconfig/README.md +++ b/packages/@aws-cdk/aws-appconfig/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as appconfig from '@aws-cdk/aws-appconfig'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::AppConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_AppConfig.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-appflow/README.md b/packages/@aws-cdk/aws-appflow/README.md index 6c9ad8badf2ac..321608f9739a6 100644 --- a/packages/@aws-cdk/aws-appflow/README.md +++ b/packages/@aws-cdk/aws-appflow/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import appflow = require('@aws-cdk/aws-appflow'); +```ts nofixture +import * as appflow from '@aws-cdk/aws-appflow'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::AppFlow](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_AppFlow.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-appintegrations/README.md b/packages/@aws-cdk/aws-appintegrations/README.md index 67455ee5e4fe6..e5f2097ef7376 100644 --- a/packages/@aws-cdk/aws-appintegrations/README.md +++ b/packages/@aws-cdk/aws-appintegrations/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import appintegrations = require('@aws-cdk/aws-appintegrations'); +```ts nofixture +import * as appintegrations from '@aws-cdk/aws-appintegrations'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::AppIntegrations](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_AppIntegrations.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-applicationinsights/README.md b/packages/@aws-cdk/aws-applicationinsights/README.md index 24c74eacaf545..fec0418e64892 100644 --- a/packages/@aws-cdk/aws-applicationinsights/README.md +++ b/packages/@aws-cdk/aws-applicationinsights/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import applicationinsights = require('@aws-cdk/aws-applicationinsights'); +```ts nofixture +import * as applicationinsights from '@aws-cdk/aws-applicationinsights'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::ApplicationInsights](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_ApplicationInsights.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-appstream/README.md b/packages/@aws-cdk/aws-appstream/README.md index 34f0ffafdb52f..e99a4163fb0b6 100644 --- a/packages/@aws-cdk/aws-appstream/README.md +++ b/packages/@aws-cdk/aws-appstream/README.md @@ -13,6 +13,19 @@ -```ts +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture import * as appstream from '@aws-cdk/aws-appstream'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::AppStream](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_AppStream.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-aps/README.md b/packages/@aws-cdk/aws-aps/README.md index 013603efa8143..b4ebc35bfc1b5 100644 --- a/packages/@aws-cdk/aws-aps/README.md +++ b/packages/@aws-cdk/aws-aps/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import aps = require('@aws-cdk/aws-aps'); +```ts nofixture +import * as aps from '@aws-cdk/aws-aps'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::APS](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_APS.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-athena/README.md b/packages/@aws-cdk/aws-athena/README.md index 60b234d13f16a..f357e89a2d3a1 100644 --- a/packages/@aws-cdk/aws-athena/README.md +++ b/packages/@aws-cdk/aws-athena/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as athena from '@aws-cdk/aws-athena'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Athena](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Athena.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-auditmanager/README.md b/packages/@aws-cdk/aws-auditmanager/README.md index ee34051ab78e3..34da423fc808e 100644 --- a/packages/@aws-cdk/aws-auditmanager/README.md +++ b/packages/@aws-cdk/aws-auditmanager/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import auditmanager = require('@aws-cdk/aws-auditmanager'); +```ts nofixture +import * as auditmanager from '@aws-cdk/aws-auditmanager'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::AuditManager](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_AuditManager.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-autoscalingplans/README.md b/packages/@aws-cdk/aws-autoscalingplans/README.md index 72bc8e028968f..3de46432bfa2b 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/README.md +++ b/packages/@aws-cdk/aws-autoscalingplans/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as autoscalingplans from '@aws-cdk/aws-autoscalingplans'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::AutoScalingPlans](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_AutoScalingPlans.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-budgets/README.md b/packages/@aws-cdk/aws-budgets/README.md index 90c1e8567a673..67d7c551301ab 100644 --- a/packages/@aws-cdk/aws-budgets/README.md +++ b/packages/@aws-cdk/aws-budgets/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as budgets from '@aws-cdk/aws-budgets'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Budgets](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Budgets.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-cassandra/README.md b/packages/@aws-cdk/aws-cassandra/README.md index 50e34cd63ba9d..8aa0b943ef49e 100644 --- a/packages/@aws-cdk/aws-cassandra/README.md +++ b/packages/@aws-cdk/aws-cassandra/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as cassandra from '@aws-cdk/aws-cassandra'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Cassandra](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Cassandra.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-ce/README.md b/packages/@aws-cdk/aws-ce/README.md index c5723bd9714db..26e60e13d15e7 100644 --- a/packages/@aws-cdk/aws-ce/README.md +++ b/packages/@aws-cdk/aws-ce/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as ce from '@aws-cdk/aws-ce'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::CE](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CE.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-codeartifact/README.md b/packages/@aws-cdk/aws-codeartifact/README.md index 3e65e5cb8dbaf..d3626398e947a 100644 --- a/packages/@aws-cdk/aws-codeartifact/README.md +++ b/packages/@aws-cdk/aws-codeartifact/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import codeartifact = require('@aws-cdk/aws-codeartifact'); +```ts nofixture +import * as codeartifact from '@aws-cdk/aws-codeartifact'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::CodeArtifact](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CodeArtifact.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-codegurureviewer/README.md b/packages/@aws-cdk/aws-codegurureviewer/README.md index d0bfe0650fe69..7dfeac01b431d 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/README.md +++ b/packages/@aws-cdk/aws-codegurureviewer/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import codegurureviewer = require('@aws-cdk/aws-codegurureviewer'); +```ts nofixture +import * as codegurureviewer from '@aws-cdk/aws-codegurureviewer'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::CodeGuruReviewer](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CodeGuruReviewer.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-codestarconnections/README.md b/packages/@aws-cdk/aws-codestarconnections/README.md index 5f6e7e73fc163..88f80abf6eafd 100644 --- a/packages/@aws-cdk/aws-codestarconnections/README.md +++ b/packages/@aws-cdk/aws-codestarconnections/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as codestarconnections from '@aws-cdk/aws-codestarconnections'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::CodeStarConnections](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CodeStarConnections.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-connect/README.md b/packages/@aws-cdk/aws-connect/README.md index b1ce493585b71..848fd8c1e5dec 100644 --- a/packages/@aws-cdk/aws-connect/README.md +++ b/packages/@aws-cdk/aws-connect/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import connect = require('@aws-cdk/aws-connect'); +```ts nofixture +import * as connect from '@aws-cdk/aws-connect'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Connect](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Connect.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-cur/README.md b/packages/@aws-cdk/aws-cur/README.md index b889cab0377cc..9d1bfbba9cd76 100644 --- a/packages/@aws-cdk/aws-cur/README.md +++ b/packages/@aws-cdk/aws-cur/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import cur = require('@aws-cdk/aws-cur'); +```ts nofixture +import * as cur from '@aws-cdk/aws-cur'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::CUR](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CUR.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-customerprofiles/README.md b/packages/@aws-cdk/aws-customerprofiles/README.md index fb215d6b27201..f5b6226a1ea29 100644 --- a/packages/@aws-cdk/aws-customerprofiles/README.md +++ b/packages/@aws-cdk/aws-customerprofiles/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import customerprofiles = require('@aws-cdk/aws-customerprofiles'); +```ts nofixture +import * as customerprofiles from '@aws-cdk/aws-customerprofiles'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::CustomerProfiles](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CustomerProfiles.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-databrew/README.md b/packages/@aws-cdk/aws-databrew/README.md index 66ed60292f316..d9070a6421593 100644 --- a/packages/@aws-cdk/aws-databrew/README.md +++ b/packages/@aws-cdk/aws-databrew/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import databrew = require('@aws-cdk/aws-databrew'); +```ts nofixture +import * as databrew from '@aws-cdk/aws-databrew'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::DataBrew](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DataBrew.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-datapipeline/README.md b/packages/@aws-cdk/aws-datapipeline/README.md index 6f0564d8a12aa..163b635d6f6c5 100644 --- a/packages/@aws-cdk/aws-datapipeline/README.md +++ b/packages/@aws-cdk/aws-datapipeline/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as datapipeline from '@aws-cdk/aws-datapipeline'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::DataPipeline](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DataPipeline.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-datasync/README.md b/packages/@aws-cdk/aws-datasync/README.md index ab865b0be83a8..7913e038caf5c 100644 --- a/packages/@aws-cdk/aws-datasync/README.md +++ b/packages/@aws-cdk/aws-datasync/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import datasync = require('@aws-cdk/aws-datasync'); +```ts nofixture +import * as datasync from '@aws-cdk/aws-datasync'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::DataSync](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DataSync.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-dax/README.md b/packages/@aws-cdk/aws-dax/README.md index 5b0287374de26..52c213e63ba08 100644 --- a/packages/@aws-cdk/aws-dax/README.md +++ b/packages/@aws-cdk/aws-dax/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as dax from '@aws-cdk/aws-dax'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::DAX](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DAX.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-detective/README.md b/packages/@aws-cdk/aws-detective/README.md index af4fca54d905d..6dd1d44a66354 100644 --- a/packages/@aws-cdk/aws-detective/README.md +++ b/packages/@aws-cdk/aws-detective/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as detective from '@aws-cdk/aws-detective'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Detective](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Detective.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-devopsguru/README.md b/packages/@aws-cdk/aws-devopsguru/README.md index 39e6d778d82c4..3f2ae2ef7b436 100644 --- a/packages/@aws-cdk/aws-devopsguru/README.md +++ b/packages/@aws-cdk/aws-devopsguru/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import devopsguru = require('@aws-cdk/aws-devopsguru'); +```ts nofixture +import * as devopsguru from '@aws-cdk/aws-devopsguru'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::DevOpsGuru](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DevOpsGuru.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-directoryservice/README.md b/packages/@aws-cdk/aws-directoryservice/README.md index 5e7a656ebb37d..7aa8cc2a2fa11 100644 --- a/packages/@aws-cdk/aws-directoryservice/README.md +++ b/packages/@aws-cdk/aws-directoryservice/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as directoryservice from '@aws-cdk/aws-directoryservice'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::DirectoryService](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DirectoryService.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-dlm/README.md b/packages/@aws-cdk/aws-dlm/README.md index c6172c8f0f683..918f56cc83c02 100644 --- a/packages/@aws-cdk/aws-dlm/README.md +++ b/packages/@aws-cdk/aws-dlm/README.md @@ -13,6 +13,19 @@ -```ts +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture import * as dlm from '@aws-cdk/aws-dlm'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::DLM](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DLM.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-dms/README.md b/packages/@aws-cdk/aws-dms/README.md index 3df28c7cf517b..582ae8166d98d 100644 --- a/packages/@aws-cdk/aws-dms/README.md +++ b/packages/@aws-cdk/aws-dms/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as dms from '@aws-cdk/aws-dms'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::DMS](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DMS.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-elasticache/README.md b/packages/@aws-cdk/aws-elasticache/README.md index 486be94c97bdb..2f2c8bd419b97 100644 --- a/packages/@aws-cdk/aws-elasticache/README.md +++ b/packages/@aws-cdk/aws-elasticache/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as elasticache from '@aws-cdk/aws-elasticache'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::ElastiCache](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_ElastiCache.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/README.md b/packages/@aws-cdk/aws-elasticbeanstalk/README.md index e8e2b25ec2c49..60b9fac0aef3c 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/README.md +++ b/packages/@aws-cdk/aws-elasticbeanstalk/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as elasticbeanstalk from '@aws-cdk/aws-elasticbeanstalk'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::ElasticBeanstalk](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_ElasticBeanstalk.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-emr/README.md b/packages/@aws-cdk/aws-emr/README.md index 3cf2fe80fd10d..b69d03ec2b9af 100644 --- a/packages/@aws-cdk/aws-emr/README.md +++ b/packages/@aws-cdk/aws-emr/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as emr from '@aws-cdk/aws-emr'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::EMR](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_EMR.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-emrcontainers/README.md b/packages/@aws-cdk/aws-emrcontainers/README.md index b948468a7150d..0de36910ada12 100644 --- a/packages/@aws-cdk/aws-emrcontainers/README.md +++ b/packages/@aws-cdk/aws-emrcontainers/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import emrcontainers = require('@aws-cdk/aws-emrcontainers'); +```ts nofixture +import * as emrcontainers from '@aws-cdk/aws-emrcontainers'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::EMRContainers](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_EMRContainers.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-eventschemas/README.md b/packages/@aws-cdk/aws-eventschemas/README.md index 84b02b1657fa4..bb35952a8a59e 100644 --- a/packages/@aws-cdk/aws-eventschemas/README.md +++ b/packages/@aws-cdk/aws-eventschemas/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as eventschemas from '@aws-cdk/aws-eventschemas'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::EventSchemas](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_EventSchemas.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-finspace/README.md b/packages/@aws-cdk/aws-finspace/README.md index 686a32758ad3e..62b4da5de2d79 100644 --- a/packages/@aws-cdk/aws-finspace/README.md +++ b/packages/@aws-cdk/aws-finspace/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import finspace = require('@aws-cdk/aws-finspace'); +```ts nofixture +import * as finspace from '@aws-cdk/aws-finspace'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::FinSpace](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_FinSpace.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-fis/README.md b/packages/@aws-cdk/aws-fis/README.md index 6331d99791be2..b4f4ad1df3352 100644 --- a/packages/@aws-cdk/aws-fis/README.md +++ b/packages/@aws-cdk/aws-fis/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import fis = require('@aws-cdk/aws-fis'); +```ts nofixture +import * as fis from '@aws-cdk/aws-fis'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::FIS](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_FIS.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-fms/README.md b/packages/@aws-cdk/aws-fms/README.md index a96ed41040664..a44f270c776fe 100644 --- a/packages/@aws-cdk/aws-fms/README.md +++ b/packages/@aws-cdk/aws-fms/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as fms from '@aws-cdk/aws-fms'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::FMS](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_FMS.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-frauddetector/README.md b/packages/@aws-cdk/aws-frauddetector/README.md index 2805d63c38fb7..27a94afc164d2 100644 --- a/packages/@aws-cdk/aws-frauddetector/README.md +++ b/packages/@aws-cdk/aws-frauddetector/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import frauddetector = require('@aws-cdk/aws-frauddetector'); +```ts nofixture +import * as frauddetector from '@aws-cdk/aws-frauddetector'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::FraudDetector](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_FraudDetector.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-gamelift/README.md b/packages/@aws-cdk/aws-gamelift/README.md index 2c912d4a2f830..57c3e217d1be1 100644 --- a/packages/@aws-cdk/aws-gamelift/README.md +++ b/packages/@aws-cdk/aws-gamelift/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as gamelift from '@aws-cdk/aws-gamelift'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::GameLift](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GameLift.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-greengrass/README.md b/packages/@aws-cdk/aws-greengrass/README.md index ca6177fcab834..8eccf4e0edb58 100644 --- a/packages/@aws-cdk/aws-greengrass/README.md +++ b/packages/@aws-cdk/aws-greengrass/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as greengrass from '@aws-cdk/aws-greengrass'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Greengrass](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Greengrass.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-greengrassv2/README.md b/packages/@aws-cdk/aws-greengrassv2/README.md index 52debb8e8c7d0..cfaecb27eda60 100644 --- a/packages/@aws-cdk/aws-greengrassv2/README.md +++ b/packages/@aws-cdk/aws-greengrassv2/README.md @@ -1,4 +1,4 @@ -# AWS IoT GreengrassV2 Construct Library +# AWS::GreengrassV2 Construct Library --- @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as greengrass from '@aws-cdk/aws-greengrassv2'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::GreengrassV2](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GreengrassV2.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-groundstation/README.md b/packages/@aws-cdk/aws-groundstation/README.md index 85fdbd3aa4247..241061fd81bea 100644 --- a/packages/@aws-cdk/aws-groundstation/README.md +++ b/packages/@aws-cdk/aws-groundstation/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import groundstation = require('@aws-cdk/aws-groundstation'); +```ts nofixture +import * as groundstation from '@aws-cdk/aws-groundstation'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::GroundStation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GroundStation.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-guardduty/README.md b/packages/@aws-cdk/aws-guardduty/README.md index aa7ad63e9bef0..b9b8d25fdde20 100644 --- a/packages/@aws-cdk/aws-guardduty/README.md +++ b/packages/@aws-cdk/aws-guardduty/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as guardduty from '@aws-cdk/aws-guardduty'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::GuardDuty](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GuardDuty.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-healthlake/README.md b/packages/@aws-cdk/aws-healthlake/README.md index 81c90c8d4d295..199873760972b 100644 --- a/packages/@aws-cdk/aws-healthlake/README.md +++ b/packages/@aws-cdk/aws-healthlake/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import healthlake = require('@aws-cdk/aws-healthlake'); +```ts nofixture +import * as healthlake from '@aws-cdk/aws-healthlake'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::HealthLake](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_HealthLake.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-imagebuilder/README.md b/packages/@aws-cdk/aws-imagebuilder/README.md index 0d2596a505862..1026cadece32b 100644 --- a/packages/@aws-cdk/aws-imagebuilder/README.md +++ b/packages/@aws-cdk/aws-imagebuilder/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import imagebuilder = require('@aws-cdk/aws-imagebuilder'); +```ts nofixture +import * as imagebuilder from '@aws-cdk/aws-imagebuilder'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::ImageBuilder](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_ImageBuilder.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-inspector/README.md b/packages/@aws-cdk/aws-inspector/README.md index 52406518d3f50..373c6ad55bddd 100644 --- a/packages/@aws-cdk/aws-inspector/README.md +++ b/packages/@aws-cdk/aws-inspector/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as inspector from '@aws-cdk/aws-inspector'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Inspector](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Inspector.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-iot1click/README.md b/packages/@aws-cdk/aws-iot1click/README.md index 91c7751093fe1..1c4332c0640e3 100644 --- a/packages/@aws-cdk/aws-iot1click/README.md +++ b/packages/@aws-cdk/aws-iot1click/README.md @@ -13,6 +13,19 @@ -```ts +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture import * as iot1click from '@aws-cdk/aws-iot1click'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoT1Click](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoT1Click.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-iotanalytics/README.md b/packages/@aws-cdk/aws-iotanalytics/README.md index f618a736f9c63..1c3dc8af11d85 100644 --- a/packages/@aws-cdk/aws-iotanalytics/README.md +++ b/packages/@aws-cdk/aws-iotanalytics/README.md @@ -13,6 +13,19 @@ -```ts +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture import * as iotanalytics from '@aws-cdk/aws-iotanalytics'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoTAnalytics](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoTAnalytics.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/README.md b/packages/@aws-cdk/aws-iotcoredeviceadvisor/README.md index abd988512eeb5..4f8ba30b13b17 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/README.md +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import iotcoredeviceadvisor = require('@aws-cdk/aws-iotcoredeviceadvisor'); +```ts nofixture +import * as iotcoredeviceadvisor from '@aws-cdk/aws-iotcoredeviceadvisor'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoTCoreDeviceAdvisor](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoTCoreDeviceAdvisor.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index e750952ae5550..e9a17af332776 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as iotevents from '@aws-cdk/aws-iotevents'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoTEvents](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoTEvents.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-iotfleethub/README.md b/packages/@aws-cdk/aws-iotfleethub/README.md index 8a07a0f02d3ee..b9b1e82194765 100644 --- a/packages/@aws-cdk/aws-iotfleethub/README.md +++ b/packages/@aws-cdk/aws-iotfleethub/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import iotfleethub = require('@aws-cdk/aws-iotfleethub'); +```ts nofixture +import * as iotfleethub from '@aws-cdk/aws-iotfleethub'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoTFleetHub](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoTFleetHub.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-iotsitewise/README.md b/packages/@aws-cdk/aws-iotsitewise/README.md index a793ab3aa3f8e..aa7e84d7d9e50 100644 --- a/packages/@aws-cdk/aws-iotsitewise/README.md +++ b/packages/@aws-cdk/aws-iotsitewise/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import iotsitewise = require('@aws-cdk/aws-iotsitewise'); +```ts nofixture +import * as iotsitewise from '@aws-cdk/aws-iotsitewise'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoTSiteWise](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoTSiteWise.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-iotthingsgraph/README.md b/packages/@aws-cdk/aws-iotthingsgraph/README.md index a8f6689bbd794..6d0dbfe0253f3 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/README.md +++ b/packages/@aws-cdk/aws-iotthingsgraph/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as iotthingsgraph from '@aws-cdk/aws-iotthingsgraph'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoTThingsGraph](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoTThingsGraph.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-iotwireless/README.md b/packages/@aws-cdk/aws-iotwireless/README.md index c6afd2e256718..878cd2ffa2940 100644 --- a/packages/@aws-cdk/aws-iotwireless/README.md +++ b/packages/@aws-cdk/aws-iotwireless/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import iotwireless = require('@aws-cdk/aws-iotwireless'); +```ts nofixture +import * as iotwireless from '@aws-cdk/aws-iotwireless'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoTWireless](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoTWireless.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-kendra/README.md b/packages/@aws-cdk/aws-kendra/README.md index 32663d6737fe4..208b0242f1e09 100644 --- a/packages/@aws-cdk/aws-kendra/README.md +++ b/packages/@aws-cdk/aws-kendra/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import kendra = require('@aws-cdk/aws-kendra'); +```ts nofixture +import * as kendra from '@aws-cdk/aws-kendra'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Kendra](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Kendra.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-kinesisanalytics/README.md b/packages/@aws-cdk/aws-kinesisanalytics/README.md index 33dfe482719b0..a1c715aded3df 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/README.md +++ b/packages/@aws-cdk/aws-kinesisanalytics/README.md @@ -15,9 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -## Kinesis Analytics Flink +```ts nofixture +import * as kinesisanalytics from '@aws-cdk/aws-kinesisanalytics'; +``` -The `aws-kinesisanalytics-flink` package provides constructs for building Flink applications. + - * [Github](https://github.com/aws/aws-cdk/tree/master/packages/%40aws-cdk/aws-kinesisanalytics-flink) - * [CDK Docs](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-kinesisanalytics-flink.html) +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::KinesisAnalytics](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_KinesisAnalytics.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json index f847c08041608..3e7838382b52e 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json @@ -32,7 +32,7 @@ "metadata": { "jsii": { "rosetta": { - "strict": true + "strict": true } } } diff --git a/packages/@aws-cdk/aws-lakeformation/README.md b/packages/@aws-cdk/aws-lakeformation/README.md index d2e2e6c205e98..914ecee373c41 100644 --- a/packages/@aws-cdk/aws-lakeformation/README.md +++ b/packages/@aws-cdk/aws-lakeformation/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as lakeformation from '@aws-cdk/aws-lakeformation'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::LakeFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_LakeFormation.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-licensemanager/README.md b/packages/@aws-cdk/aws-licensemanager/README.md index 87c7870bde979..2911ba0c01ece 100644 --- a/packages/@aws-cdk/aws-licensemanager/README.md +++ b/packages/@aws-cdk/aws-licensemanager/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import licensemanager = require('@aws-cdk/aws-licensemanager'); +```ts nofixture +import * as licensemanager from '@aws-cdk/aws-licensemanager'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::LicenseManager](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_LicenseManager.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-lightsail/README.md b/packages/@aws-cdk/aws-lightsail/README.md index 09d952a84e6c7..431c94b25b00f 100644 --- a/packages/@aws-cdk/aws-lightsail/README.md +++ b/packages/@aws-cdk/aws-lightsail/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import lightsail = require('@aws-cdk/aws-lightsail'); +```ts nofixture +import * as lightsail from '@aws-cdk/aws-lightsail'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Lightsail](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Lightsail.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-location/README.md b/packages/@aws-cdk/aws-location/README.md index de1c9d9a20e6a..8887053fc5cc1 100644 --- a/packages/@aws-cdk/aws-location/README.md +++ b/packages/@aws-cdk/aws-location/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import location = require('@aws-cdk/aws-location'); +```ts nofixture +import * as location from '@aws-cdk/aws-location'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Location](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Location.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-lookoutequipment/README.md b/packages/@aws-cdk/aws-lookoutequipment/README.md index 9985449bd1ea8..11a5f5225bd79 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/README.md +++ b/packages/@aws-cdk/aws-lookoutequipment/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import lookoutequipment = require('@aws-cdk/aws-lookoutequipment'); +```ts nofixture +import * as lookoutequipment from '@aws-cdk/aws-lookoutequipment'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::LookoutEquipment](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_LookoutEquipment.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-lookoutmetrics/README.md b/packages/@aws-cdk/aws-lookoutmetrics/README.md index 0c10b9250d502..406cb7379eb80 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/README.md +++ b/packages/@aws-cdk/aws-lookoutmetrics/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import lookoutmetrics = require('@aws-cdk/aws-lookoutmetrics'); +```ts nofixture +import * as lookoutmetrics from '@aws-cdk/aws-lookoutmetrics'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::LookoutMetrics](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_LookoutMetrics.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-lookoutvision/README.md b/packages/@aws-cdk/aws-lookoutvision/README.md index b0082462251d2..364df07a50f72 100644 --- a/packages/@aws-cdk/aws-lookoutvision/README.md +++ b/packages/@aws-cdk/aws-lookoutvision/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import lookoutvision = require('@aws-cdk/aws-lookoutvision'); +```ts nofixture +import * as lookoutvision from '@aws-cdk/aws-lookoutvision'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::LookoutVision](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_LookoutVision.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-macie/README.md b/packages/@aws-cdk/aws-macie/README.md index d4154b38a9d9b..4d9a630859492 100644 --- a/packages/@aws-cdk/aws-macie/README.md +++ b/packages/@aws-cdk/aws-macie/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import macie = require('@aws-cdk/aws-macie'); +```ts nofixture +import * as macie from '@aws-cdk/aws-macie'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Macie](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Macie.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-managedblockchain/README.md b/packages/@aws-cdk/aws-managedblockchain/README.md index bc8534fd8bf22..7c0fc6ef6a49c 100644 --- a/packages/@aws-cdk/aws-managedblockchain/README.md +++ b/packages/@aws-cdk/aws-managedblockchain/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as managedblockchain from '@aws-cdk/aws-managedblockchain'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::ManagedBlockchain](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_ManagedBlockchain.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-mediaconnect/README.md b/packages/@aws-cdk/aws-mediaconnect/README.md index 46776462c67ff..f519fc73997bf 100644 --- a/packages/@aws-cdk/aws-mediaconnect/README.md +++ b/packages/@aws-cdk/aws-mediaconnect/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import mediaconnect = require('@aws-cdk/aws-mediaconnect'); +```ts nofixture +import * as mediaconnect from '@aws-cdk/aws-mediaconnect'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::MediaConnect](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_MediaConnect.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-mediaconvert/README.md b/packages/@aws-cdk/aws-mediaconvert/README.md index c58e480114a6d..ffbdfd8f1d8fc 100644 --- a/packages/@aws-cdk/aws-mediaconvert/README.md +++ b/packages/@aws-cdk/aws-mediaconvert/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as mediaconvert from '@aws-cdk/aws-mediaconvert'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::MediaConvert](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_MediaConvert.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-medialive/README.md b/packages/@aws-cdk/aws-medialive/README.md index 6a13191e2a7bc..017be8f531511 100644 --- a/packages/@aws-cdk/aws-medialive/README.md +++ b/packages/@aws-cdk/aws-medialive/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as medialive from '@aws-cdk/aws-medialive'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::MediaLive](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_MediaLive.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-mediapackage/README.md b/packages/@aws-cdk/aws-mediapackage/README.md index f49ba1fb5fd87..ab57a4cd781d4 100644 --- a/packages/@aws-cdk/aws-mediapackage/README.md +++ b/packages/@aws-cdk/aws-mediapackage/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import mediapackage = require('@aws-cdk/aws-mediapackage'); +```ts nofixture +import * as mediapackage from '@aws-cdk/aws-mediapackage'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::MediaPackage](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_MediaPackage.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-mediastore/README.md b/packages/@aws-cdk/aws-mediastore/README.md index f420f2299d899..b16b96761d8e5 100644 --- a/packages/@aws-cdk/aws-mediastore/README.md +++ b/packages/@aws-cdk/aws-mediastore/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as mediastore from '@aws-cdk/aws-mediastore'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::MediaStore](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_MediaStore.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-memorydb/README.md b/packages/@aws-cdk/aws-memorydb/README.md index e2b1d4faa518a..cd692a452354c 100644 --- a/packages/@aws-cdk/aws-memorydb/README.md +++ b/packages/@aws-cdk/aws-memorydb/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import memorydb = require('@aws-cdk/aws-memorydb'); +```ts nofixture +import * as memorydb from '@aws-cdk/aws-memorydb'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::MemoryDB](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_MemoryDB.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-mwaa/README.md b/packages/@aws-cdk/aws-mwaa/README.md index 836c3a4bab55a..3ba085345e222 100644 --- a/packages/@aws-cdk/aws-mwaa/README.md +++ b/packages/@aws-cdk/aws-mwaa/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import mwaa = require('@aws-cdk/aws-mwaa'); +```ts nofixture +import * as mwaa from '@aws-cdk/aws-mwaa'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::MWAA](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_MWAA.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-networkfirewall/README.md b/packages/@aws-cdk/aws-networkfirewall/README.md index 9b6dc5712e4de..878400e334ea4 100644 --- a/packages/@aws-cdk/aws-networkfirewall/README.md +++ b/packages/@aws-cdk/aws-networkfirewall/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import networkfirewall = require('@aws-cdk/aws-networkfirewall'); +```ts nofixture +import * as networkfirewall from '@aws-cdk/aws-networkfirewall'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::NetworkFirewall](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_NetworkFirewall.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-networkmanager/README.md b/packages/@aws-cdk/aws-networkmanager/README.md index 0cee3e1290f04..4b8331034f291 100644 --- a/packages/@aws-cdk/aws-networkmanager/README.md +++ b/packages/@aws-cdk/aws-networkmanager/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as networkmanager from '@aws-cdk/aws-networkmanager'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::NetworkManager](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_NetworkManager.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-nimblestudio/README.md b/packages/@aws-cdk/aws-nimblestudio/README.md index ff5936d0e9147..69076a91d12b0 100644 --- a/packages/@aws-cdk/aws-nimblestudio/README.md +++ b/packages/@aws-cdk/aws-nimblestudio/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import nimblestudio = require('@aws-cdk/aws-nimblestudio'); +```ts nofixture +import * as nimblestudio from '@aws-cdk/aws-nimblestudio'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::NimbleStudio](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_NimbleStudio.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-opsworks/README.md b/packages/@aws-cdk/aws-opsworks/README.md index f5cc663c1b4d9..26d5a88fb5e6e 100644 --- a/packages/@aws-cdk/aws-opsworks/README.md +++ b/packages/@aws-cdk/aws-opsworks/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as opsworks from '@aws-cdk/aws-opsworks'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::OpsWorks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_OpsWorks.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-opsworkscm/README.md b/packages/@aws-cdk/aws-opsworkscm/README.md index 84a537a7012ad..99bb78686ebdd 100644 --- a/packages/@aws-cdk/aws-opsworkscm/README.md +++ b/packages/@aws-cdk/aws-opsworkscm/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as opsworkscm from '@aws-cdk/aws-opsworkscm'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::OpsWorksCM](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_OpsWorksCM.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-panorama/README.md b/packages/@aws-cdk/aws-panorama/README.md index 334264b4ea581..76e4ca1a2523a 100644 --- a/packages/@aws-cdk/aws-panorama/README.md +++ b/packages/@aws-cdk/aws-panorama/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import aws-panorama = require('@aws-cdk/aws-panorama'); +```ts nofixture +import * as panorama from '@aws-cdk/aws-panorama'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Panorama](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Panorama.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-pinpoint/README.md b/packages/@aws-cdk/aws-pinpoint/README.md index 3f2622e8063ca..14ce1809d073c 100644 --- a/packages/@aws-cdk/aws-pinpoint/README.md +++ b/packages/@aws-cdk/aws-pinpoint/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as pinpoint from '@aws-cdk/aws-pinpoint'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Pinpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Pinpoint.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-pinpointemail/README.md b/packages/@aws-cdk/aws-pinpointemail/README.md index c2a0bf252be8f..867e411fed53a 100644 --- a/packages/@aws-cdk/aws-pinpointemail/README.md +++ b/packages/@aws-cdk/aws-pinpointemail/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as pinpointemail from '@aws-cdk/aws-pinpointemail'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::PinpointEmail](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_PinpointEmail.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-qldb/README.md b/packages/@aws-cdk/aws-qldb/README.md index 3df572f4dfcae..460cd50767b11 100644 --- a/packages/@aws-cdk/aws-qldb/README.md +++ b/packages/@aws-cdk/aws-qldb/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as qldb from '@aws-cdk/aws-qldb'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::QLDB](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_QLDB.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-quicksight/README.md b/packages/@aws-cdk/aws-quicksight/README.md index 04afa0f01ffee..4182e2c173731 100644 --- a/packages/@aws-cdk/aws-quicksight/README.md +++ b/packages/@aws-cdk/aws-quicksight/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import quicksight = require('@aws-cdk/aws-quicksight'); +```ts nofixture +import * as quicksight from '@aws-cdk/aws-quicksight'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::QuickSight](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_QuickSight.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-ram/README.md b/packages/@aws-cdk/aws-ram/README.md index a2099d1f65a47..7426a8dc8b7bb 100644 --- a/packages/@aws-cdk/aws-ram/README.md +++ b/packages/@aws-cdk/aws-ram/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as ram from '@aws-cdk/aws-ram'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::RAM](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_RAM.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-rekognition/README.md b/packages/@aws-cdk/aws-rekognition/README.md index 9e158afddf5de..3f9947118b839 100644 --- a/packages/@aws-cdk/aws-rekognition/README.md +++ b/packages/@aws-cdk/aws-rekognition/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import aws-rekognition = require('@aws-cdk/aws-rekognition'); +```ts nofixture +import * as rekognition from '@aws-cdk/aws-rekognition'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Rekognition](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Rekognition.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-resourcegroups/README.md b/packages/@aws-cdk/aws-resourcegroups/README.md index b24c366c8a3ca..919f48a56c299 100644 --- a/packages/@aws-cdk/aws-resourcegroups/README.md +++ b/packages/@aws-cdk/aws-resourcegroups/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as resourcegroups from '@aws-cdk/aws-resourcegroups'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::ResourceGroups](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_ResourceGroups.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-robomaker/README.md b/packages/@aws-cdk/aws-robomaker/README.md index 4951007e3c051..33283e79fab9a 100644 --- a/packages/@aws-cdk/aws-robomaker/README.md +++ b/packages/@aws-cdk/aws-robomaker/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as robomaker from '@aws-cdk/aws-robomaker'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::RoboMaker](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_RoboMaker.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/README.md b/packages/@aws-cdk/aws-route53recoverycontrol/README.md index 9a4113847129c..69738a72e8d60 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/README.md +++ b/packages/@aws-cdk/aws-route53recoverycontrol/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import route53recoverycontrol = require('@aws-cdk/aws-route53recoverycontrol'); +```ts nofixture +import * as route53recoverycontrol from '@aws-cdk/aws-route53recoverycontrol'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Route53RecoveryControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Route53RecoveryControl.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/README.md b/packages/@aws-cdk/aws-route53recoveryreadiness/README.md index fd92f9a6d4954..5cb1c6ecfbc77 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/README.md +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import route53recoveryreadiness = require('@aws-cdk/aws-route53recoveryreadiness'); +```ts nofixture +import * as route53recoveryreadiness from '@aws-cdk/aws-route53recoveryreadiness'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Route53RecoveryReadiness](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Route53RecoveryReadiness.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-s3objectlambda/README.md b/packages/@aws-cdk/aws-s3objectlambda/README.md index ebb6f1b79c7e6..60a5c42835925 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/README.md +++ b/packages/@aws-cdk/aws-s3objectlambda/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import s3objectlambda = require('@aws-cdk/aws-s3objectlambda'); +```ts nofixture +import * as s3objectlambda from '@aws-cdk/aws-s3objectlambda'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::S3ObjectLambda](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_S3ObjectLambda.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-s3outposts/README.md b/packages/@aws-cdk/aws-s3outposts/README.md index 08fc4b75a732a..143c7f381975f 100644 --- a/packages/@aws-cdk/aws-s3outposts/README.md +++ b/packages/@aws-cdk/aws-s3outposts/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import s3outposts = require('@aws-cdk/aws-s3outposts'); +```ts nofixture +import * as s3outposts from '@aws-cdk/aws-s3outposts'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::S3Outposts](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_S3Outposts.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-sagemaker/README.md b/packages/@aws-cdk/aws-sagemaker/README.md index b3e6c5c20fbe3..7de51f88c1f5b 100644 --- a/packages/@aws-cdk/aws-sagemaker/README.md +++ b/packages/@aws-cdk/aws-sagemaker/README.md @@ -13,6 +13,19 @@ -```ts +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture import * as sagemaker from '@aws-cdk/aws-sagemaker'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::SageMaker](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_SageMaker.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-sam/README.md b/packages/@aws-cdk/aws-sam/README.md index caf5119f08c7e..f3ea169c97b4b 100644 --- a/packages/@aws-cdk/aws-sam/README.md +++ b/packages/@aws-cdk/aws-sam/README.md @@ -13,18 +13,19 @@ -This module includes low-level constructs that synthesize into `AWS::Serverless` resources. +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts -import * as sam from '@aws-cdk/aws-sam'; +```ts nofixture +import * as serverless from '@aws-cdk/aws-sam'; ``` -## Related + -The following AWS CDK modules include constructs that can be used to work with Amazon API Gateway and AWS Lambda: +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. -* [aws-lambda](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-lambda-readme.html): define AWS Lambda functions -* [aws-lambda-event-sources](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-lambda-event-sources-readme.html): classes that allow using various AWS services as event sources for AWS Lambda functions -* [aws-apigateway](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-apigateway-readme.html): define APIs through Amazon API Gateway -* [aws-codedeploy](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-codedeploy-readme.html#lambda-applications): define AWS Lambda deployment with traffic shifting support +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Serverless](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Serverless.html). +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-sdb/README.md b/packages/@aws-cdk/aws-sdb/README.md index 228ed6b04074a..c5c6cf1a337a3 100644 --- a/packages/@aws-cdk/aws-sdb/README.md +++ b/packages/@aws-cdk/aws-sdb/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as sdb from '@aws-cdk/aws-sdb'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::SDB](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_SDB.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-securityhub/README.md b/packages/@aws-cdk/aws-securityhub/README.md index c4b1bebcf6e6c..8a339cd42601b 100644 --- a/packages/@aws-cdk/aws-securityhub/README.md +++ b/packages/@aws-cdk/aws-securityhub/README.md @@ -18,3 +18,14 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw ```ts nofixture import * as securityhub from '@aws-cdk/aws-securityhub'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::SecurityHub](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_SecurityHub.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-ssmcontacts/README.md b/packages/@aws-cdk/aws-ssmcontacts/README.md index cab7c329a4bab..1764c3f1510c4 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/README.md +++ b/packages/@aws-cdk/aws-ssmcontacts/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as ssmcontacts from '@aws-cdk/aws-ssmcontacts'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::SSMContacts](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_SSMContacts.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-ssmincidents/README.md b/packages/@aws-cdk/aws-ssmincidents/README.md index 411c652fc7d8c..e13234645e076 100644 --- a/packages/@aws-cdk/aws-ssmincidents/README.md +++ b/packages/@aws-cdk/aws-ssmincidents/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as ssmincidents from '@aws-cdk/aws-ssmincidents'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::SSMIncidents](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_SSMIncidents.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-sso/README.md b/packages/@aws-cdk/aws-sso/README.md index d1f2b8988da89..951aeeb0cb308 100644 --- a/packages/@aws-cdk/aws-sso/README.md +++ b/packages/@aws-cdk/aws-sso/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as sso from '@aws-cdk/aws-sso'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::SSO](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_SSO.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-timestream/README.md b/packages/@aws-cdk/aws-timestream/README.md index c5b4cb3de1e85..e4fe5d80033c2 100644 --- a/packages/@aws-cdk/aws-timestream/README.md +++ b/packages/@aws-cdk/aws-timestream/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as timestream from '@aws-cdk/aws-timestream'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Timestream](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Timestream.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-transfer/README.md b/packages/@aws-cdk/aws-transfer/README.md index 0420a5e279d0b..984d4c4170413 100644 --- a/packages/@aws-cdk/aws-transfer/README.md +++ b/packages/@aws-cdk/aws-transfer/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as transfer from '@aws-cdk/aws-transfer'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Transfer](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Transfer.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-waf/README.md b/packages/@aws-cdk/aws-waf/README.md index c0622ec0b0479..4ca7fd0241968 100644 --- a/packages/@aws-cdk/aws-waf/README.md +++ b/packages/@aws-cdk/aws-waf/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as waf from '@aws-cdk/aws-waf'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::WAF](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_WAF.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-wafregional/README.md b/packages/@aws-cdk/aws-wafregional/README.md index e2194b636bdc0..cdc3e9f8d90c1 100644 --- a/packages/@aws-cdk/aws-wafregional/README.md +++ b/packages/@aws-cdk/aws-wafregional/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as wafregional from '@aws-cdk/aws-wafregional'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::WAFRegional](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_WAFRegional.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-wafv2/README.md b/packages/@aws-cdk/aws-wafv2/README.md index eb0003b605449..9405ace0f26a3 100644 --- a/packages/@aws-cdk/aws-wafv2/README.md +++ b/packages/@aws-cdk/aws-wafv2/README.md @@ -15,26 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as wafv2 from '@aws-cdk/aws-wafv2'; ``` -## Examples - -Create a simple WebACL resource. - -```csharp -var WebACL = new CfnWebACL(this, "WebACL", new CfnWebACLProps{ - Name = "MyWebACL", - Scope = "REGIONAL", - DefaultAction = new CfnWebACL.DefaultActionProperty { - Allow = new CfnWebACL.AllowActionProperty{} - }, - VisibilityConfig = new CfnWebACL.VisibilityConfigProperty { - SampledRequestsEnabled = true, - CloudWatchMetricsEnabled = true, - MetricName = "WebACL", - }, - Rules = new CfnWebACL.RuleProperty[] {} - }); -``` + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::WAFv2](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_WAFv2.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-wisdom/README.md b/packages/@aws-cdk/aws-wisdom/README.md index 218dae4f51735..59db42987d99f 100644 --- a/packages/@aws-cdk/aws-wisdom/README.md +++ b/packages/@aws-cdk/aws-wisdom/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as wisdom from '@aws-cdk/aws-wisdom'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::Wisdom](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Wisdom.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-workspaces/README.md b/packages/@aws-cdk/aws-workspaces/README.md index f8fbe73f105b1..72a67c8270544 100644 --- a/packages/@aws-cdk/aws-workspaces/README.md +++ b/packages/@aws-cdk/aws-workspaces/README.md @@ -14,3 +14,18 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as workspaces from '@aws-cdk/aws-workspaces'; +``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::WorkSpaces](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_WorkSpaces.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/aws-xray/README.md b/packages/@aws-cdk/aws-xray/README.md index c543893c88228..846ca02c1ae1c 100644 --- a/packages/@aws-cdk/aws-xray/README.md +++ b/packages/@aws-cdk/aws-xray/README.md @@ -15,6 +15,17 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. -```ts +```ts nofixture import * as xray from '@aws-cdk/aws-xray'; ``` + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::XRay](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_XRay.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) + + diff --git a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts index ec6f0cd589bf7..b6fa4a44c6f7f 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -79,10 +79,12 @@ async function main() { console.log(`generating module for ${module.packageName}...`); + const description = `${namespace} Construct Library`; + await write('package.json', { name: module.packageName, version, - description: `The CDK Construct Library for ${namespace}`, + description, main: 'lib/index.js', types: 'lib/index.d.ts', jsii: { diff --git a/packages/@aws-cdk/cfnspec/lib/library-creation.ts b/packages/@aws-cdk/cfnspec/lib/library-creation.ts index 0d36def9ba8e6..4471a1bf6dc75 100644 --- a/packages/@aws-cdk/cfnspec/lib/library-creation.ts +++ b/packages/@aws-cdk/cfnspec/lib/library-creation.ts @@ -1,3 +1,4 @@ +import * as pkglint from '@aws-cdk/pkglint'; import * as fs from 'fs-extra'; export interface ModuleDefinition { @@ -54,30 +55,12 @@ export function createModuleDefinitionFromCfnNamespace(namespace: string): Modul }; } + export async function createLibraryReadme(namespace: string, readmePath: string) { const module = createModuleDefinitionFromCfnNamespace(namespace); - await fs.writeFile(readmePath, [ - `# ${namespace} Construct Library`, - '', - '', - '---', - '', - '![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)', - '', - '> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use.', - '>', - '> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib', - '', - '---', - '', - '', - '', - 'This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.', - '', - '```ts nofixture', - `import * as ${module.moduleName.toLocaleLowerCase().replace(/[^a-z0-9_]/g, '_')} from '${module.packageName}';`, - '```', - '', - ].join('\n'), 'utf8'); + await fs.writeFile(readmePath, pkglint.cfnOnlyReadmeContents({ + cfnNamespace: namespace, + packageName: module.packageName, + })); } diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index 828529273ae87..fa705c6fbe312 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -30,7 +30,6 @@ "types": "lib/index.d.ts", "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", - "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/jest": "^27.0.3", "@types/md5": "^2.3.1", @@ -40,6 +39,7 @@ "sort-json": "^2.0.0" }, "dependencies": { + "@aws-cdk/pkglint": "0.0.0", "fs-extra": "^9.1.0", "md5": "^2.3.0" }, diff --git a/tools/@aws-cdk/pkglint/lib/index.ts b/tools/@aws-cdk/pkglint/lib/index.ts index beaf49d75d3fa..e63f0c6bf1b52 100644 --- a/tools/@aws-cdk/pkglint/lib/index.ts +++ b/tools/@aws-cdk/pkglint/lib/index.ts @@ -1,2 +1,3 @@ export * from './packagejson'; export * from './rules'; +export * from './readme-contents'; diff --git a/tools/@aws-cdk/pkglint/lib/readme-contents.ts b/tools/@aws-cdk/pkglint/lib/readme-contents.ts new file mode 100644 index 0000000000000..6e8492566c359 --- /dev/null +++ b/tools/@aws-cdk/pkglint/lib/readme-contents.ts @@ -0,0 +1,70 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +const AWS_SERVICE_NAMES = require('./aws-service-official-names.json'); // eslint-disable-line @typescript-eslint/no-require-imports + +export interface LibraryReadmeOptions { + /** + * CloudFormation namespace for this CFN-only module + */ + readonly cfnNamespace: string; + + /** + * The name under which we publish this NPM package + */ + readonly packageName: string; +} + +/** + * Define what the contents of the module README should look like. + * + * It lives in pkglint because these all need it: + * + * - pkglint, in order to be able to rewrite READMEs to their desired content + * - cfnspec, in order to generate new library directories on-the-fly when new modules + * appear in the CloudFormation specification + * - ubergen, to rewrite the README of an experimental package back to its 'cfn-only' state + * + * And 'pkglint' is the only package that is shared in the dependency tree between all + * of them. + */ +export function cfnOnlyReadmeContents(options: LibraryReadmeOptions) { + const title = `${AWS_SERVICE_NAMES[options.cfnNamespace] ?? options.cfnNamespace} Construct Library`; + + const cfnLink = `https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/${options.cfnNamespace.replace('::', '_')}.html`; + + const moduleName = options.cfnNamespace.replace('::', '-').replace(/V\d+$/, '').toLocaleLowerCase(); + const importName = moduleName.replace(/[^a-z0-9_]/g, '_').replace(/^aws_/, ''); + + return [ + `# ${title}`, + '', + '', + '---', + '', + '![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)', + '', + '> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use.', + '>', + '> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib', + '', + '---', + '', + '', + '', + 'This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.', + '', + '```ts nofixture', + `import * as ${importName} from '${options.packageName}';`, + '```', + '', + '', + '', + 'There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. ', + 'However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly.', + '', + `For more information on the resources and properties available for this service, see the [CloudFormation documentation for ${options.cfnNamespace}](${cfnLink}).`, + '', + '(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.)', + '', + '', + ].join('\n') + '\n'; // File must end in newline otherwise linter will complain +} diff --git a/tools/@aws-cdk/pkglint/lib/rules.ts b/tools/@aws-cdk/pkglint/lib/rules.ts index dab684878d98f..b65c9af096e24 100644 --- a/tools/@aws-cdk/pkglint/lib/rules.ts +++ b/tools/@aws-cdk/pkglint/lib/rules.ts @@ -5,6 +5,7 @@ import * as glob from 'glob'; import * as semver from 'semver'; import { LICENSE, NOTICE } from './licensing'; import { PackageJson, ValidationRule } from './packagejson'; +import { cfnOnlyReadmeContents } from './readme-contents'; import { deepGet, deepSet, expectDevDependency, expectJSON, @@ -239,6 +240,27 @@ export class ReadmeFile extends ValidationRule { const scope: string = typeof scopes === 'string' ? scopes : scopes[0]; const serviceName = AWS_SERVICE_NAMES[scope]; + // If this is a 'cfn-only' package, we fix the README to specific file contents, and + // don't do any other checks. + if (pkg.json.maturity === 'cfn-only') { + fileShouldBe(this.name, pkg, 'README.md', cfnOnlyReadmeContents({ + cfnNamespace: scope, + packageName: pkg.packageName, + })); + return; + } + + // Otherwise, the cfn-specific disclaimer in it MUST NOT exist. + const disclaimerRegex = beginEndRegex('CFNONLY DISCLAIMER'); + const currentReadme = readIfExists(readmeFile); + if (currentReadme && disclaimerRegex.test(currentReadme)) { + pkg.report({ + ruleName: this.name, + message: 'README must not include CFNONLY DISCLAIMER section', + fix: () => fs.writeFileSync(readmeFile, currentReadme.replace(disclaimerRegex, '')), + }); + } + const headline = serviceName && `${serviceName} Construct Library`; if (!fs.existsSync(readmeFile)) { @@ -1843,3 +1865,11 @@ function isIncludedInMonolith(pkg: PackageJson): boolean { } return true; } + +function beginEndRegex(label: string) { + return new RegExp(`(<\!--BEGIN ${label}-->)([\s\S]+)(<\!--END ${label}-->)`, 'm'); +} + +function readIfExists(filename: string): string | undefined { + return fs.existsSync(filename) ? fs.readFileSync(filename, { encoding: 'utf8' }) : undefined; +} \ No newline at end of file diff --git a/tools/@aws-cdk/ubergen/bin/ubergen.ts b/tools/@aws-cdk/ubergen/bin/ubergen.ts index ed8f342c972c4..d3b4889ece4df 100644 --- a/tools/@aws-cdk/ubergen/bin/ubergen.ts +++ b/tools/@aws-cdk/ubergen/bin/ubergen.ts @@ -42,6 +42,7 @@ interface LibraryReference { } interface PackageJson { + readonly description?: string; readonly bundleDependencies?: readonly string[]; readonly bundledDependencies?: readonly string[]; readonly dependencies?: { readonly [name: string]: string }; From 9d436a0c68e34ce8fd695efddbd2ed2b57cf8b69 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Thu, 25 Nov 2021 17:25:40 +0000 Subject: [PATCH 19/82] chore(assertions): snippets avoid using intermediate variable assignment (#17714) Previously, the rosetta translations could not determine the type of objects being passed into methods when they are untyped. Some were being interpreted as 'props' type while they should just be regarding as `Record` or `any`. To compensate for this, the README in this module assigned them to variables, so the translator did a better job at knowing this. This has now been fixed in rosetta. Move back to using this inline, since the usage is just nicer. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/assertions/README.md | 93 ++++++++++---------------- 1 file changed, 36 insertions(+), 57 deletions(-) diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index 559bb3cea3c0f..158397d1e4af1 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -37,7 +37,7 @@ The simplest assertion would be to assert that the template matches a given template. ```ts -const expected = { +template.templateMatches({ Resources: { BarLogicalId: { Type: 'Foo::Bar', @@ -46,9 +46,7 @@ const expected = { }, }, }, -}; - -template.templateMatches(expected); +}); ``` By default, the `templateMatches()` API will use the an 'object-like' comparison, @@ -84,23 +82,21 @@ The following code asserts that the `Properties` section of a resource of type `Foo::Bar` contains the specified properties - ```ts -const expected = { +template.hasResourceProperties('Foo::Bar', { Foo: 'Bar', Baz: 5, Qux: [ 'Waldo', 'Fred' ], -}; -template.hasResourceProperties('Foo::Bar', expected); +}); ``` Alternatively, if you would like to assert the entire resource definition, you can use the `hasResource()` API. ```ts -const expected = { +template.hasResource('Foo::Bar', { Properties: { Foo: 'Bar' }, DependsOn: [ 'Waldo', 'Fred' ], -}; -template.hasResource('Foo::Bar', expected); +}); ``` Beyond assertions, the module provides APIs to retrieve matching resources. @@ -128,21 +124,17 @@ template.hasOutput('Foo', expected); If you want to match against all Outputs in the template, use `*` as the `logicalId`. ```ts -const expected = { +template.hasOutput('*', { Value: 'Bar', Export: { Name: 'ExportBaz' }, -}; -template.hasOutput('*', expected); +}); ``` `findOutputs()` will return a set of outputs that match the `logicalId` and `props`, and you can use the `'*'` special case as well. ```ts -const expected = { - Value: 'Fred', -}; -const result = template.findOutputs('*', expected); +const result = template.findOutputs('*', { Value: 'Fred' }); expect(result.Foo).toEqual({ Value: 'Fred', Description: 'FooFred' }); expect(result.Bar).toEqual({ Value: 'Fred', Description: 'BarFred' }); ``` @@ -182,20 +174,18 @@ level, the list of keys in the target is a subset of the provided pattern. // } // The following will NOT throw an assertion error -const expected = { +template.hasResourceProperties('Foo::Bar', { Fred: Match.objectLike({ Wobble: 'Flob', }), -}; -template.hasResourceProperties('Foo::Bar', expected); +}); // The following will throw an assertion error -const unexpected = { +template.hasResourceProperties('Foo::Bar', { Fred: Match.objectLike({ Brew: 'Coffee', }), -} -template.hasResourceProperties('Foo::Bar', unexpected); +}); ``` The `Match.objectEquals()` API can be used to assert a target as a deep exact @@ -223,20 +213,18 @@ or outside of any matchers. // } // The following will NOT throw an assertion error -const expected = { +template.hasResourceProperties('Foo::Bar', { Fred: Match.objectLike({ Bob: Match.absent(), }), -}; -template.hasResourceProperties('Foo::Bar', expected); +}); // The following will throw an assertion error -const unexpected = { +template.hasResourceProperties('Foo::Bar', { Fred: Match.objectLike({ Wobble: Match.absent(), }), -}; -template.hasResourceProperties('Foo::Bar', unexpected); +}); ``` The `Match.anyValue()` matcher can be used to specify that a specific value should be found @@ -261,20 +249,18 @@ This matcher can be combined with any of the other matchers. // } // The following will NOT throw an assertion error -const expected = { +template.hasResourceProperties('Foo::Bar', { Fred: { - Wobble: [Match.anyValue(), "Flip"], + Wobble: [ Match.anyValue(), "Flip" ], }, -}; -template.hasResourceProperties('Foo::Bar', expected); +}); // The following will throw an assertion error -const unexpected = { +template.hasResourceProperties('Foo::Bar', { Fred: { Wimble: Match.anyValue(), }, -}; -template.hasResourceProperties('Foo::Bar', unexpected); +}); ``` ### Array Matchers @@ -297,16 +283,14 @@ This API will perform subset match on the target. // } // The following will NOT throw an assertion error -const expected = { +template.hasResourceProperties('Foo::Bar', { Fred: Match.arrayWith(['Flob']), -}; -template.hasResourceProperties('Foo::Bar', expected); +}); // The following will throw an assertion error -const unexpected = Match.objectLike({ +template.hasResourceProperties('Foo::Bar', Match.objectLike({ Fred: Match.arrayWith(['Wobble']), -}); -template.hasResourceProperties('Foo::Bar', unexpected); +})); ``` *Note:* The list of items in the pattern array should be in order as they appear in the @@ -334,16 +318,14 @@ not match the pattern specified. // } // The following will NOT throw an assertion error -const expected = { +template.hasResourceProperties('Foo::Bar', { Fred: Match.not(['Flob']), -}; -template.hasResourceProperties('Foo::Bar', expected); +}); // The following will throw an assertion error -const unexpected = Match.objectLike({ +template.hasResourceProperties('Foo::Bar', Match.objectLike({ Fred: Match.not(['Flob', 'Cat']), -}); -template.hasResourceProperties('Foo::Bar', unexpected); +})); ``` ### Serialized JSON @@ -370,20 +352,18 @@ The `Match.serializedJson()` matcher allows deep matching within a stringified J // } // The following will NOT throw an assertion error -const expected = { +template.hasResourceProperties('Foo::Bar', { Baz: Match.serializedJson({ Fred: Match.arrayWith(["Waldo"]), }), -}; -template.hasResourceProperties('Foo::Bar', expected); +}); // The following will throw an assertion error -const unexpected = { +template.hasResourceProperties('Foo::Bar', { Baz: Match.serializedJson({ Fred: ["Waldo", "Johnny"], }), -}; -template.hasResourceProperties('Foo::Bar', unexpected); +}); ``` [Pipeline BuildSpec]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-buildspec @@ -411,11 +391,10 @@ matching resource. const fredCapture = new Capture(); const waldoCapture = new Capture(); -const expected = { +template.hasResourceProperties('Foo::Bar', { Fred: fredCapture, Waldo: ["Qix", waldoCapture], -} -template.hasResourceProperties('Foo::Bar', expected); +}); fredCapture.asArray(); // returns ["Flob", "Cat"] waldoCapture.asString(); // returns "Qux" From b8a4a9a9d28c65aff419beb5d7ac14fa4a0a473e Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Thu, 25 Nov 2021 18:14:00 +0000 Subject: [PATCH 20/82] chore(apigatewayv2): remove dependency of "http" from "common" (#17715) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-apigatewayv2/lib/common/api-mapping.ts | 17 ++++++----------- .../test/common/api-mapping.test.ts | 4 ++-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/common/api-mapping.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/common/api-mapping.ts index a4031ddf783e2..e8d48599f6e73 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/common/api-mapping.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/common/api-mapping.ts @@ -1,7 +1,6 @@ import { IResource, Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnApiMapping, CfnApiMappingProps } from '../apigatewayv2.generated'; -import { HttpApi } from '../http/api'; import { IApi } from './api'; import { IDomainName } from './domain-name'; import { IStage } from './stage'; @@ -90,17 +89,13 @@ export class ApiMapping extends Resource implements IApiMapping { constructor(scope: Construct, id: string, props: ApiMappingProps) { super(scope, id); - let stage = props.stage; + // defaultStage is present in IHttpStage. + // However, importing "http" or "websocket" must import "common", but creating dependencies + // the other way will cause potential cycles. + // So casting to 'any' + let stage = props.stage ?? (props.api as any).defaultStage; if (!stage) { - if (props.api instanceof HttpApi) { - if (props.api.defaultStage) { - stage = props.api.defaultStage; - } else { - throw new Error('stage is required if default stage is not available'); - } - } else { - throw new Error('stage is required for WebSocket API'); - } + throw new Error('stage property must be specified'); } if (props.apiMappingKey === '') { diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/common/api-mapping.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/common/api-mapping.test.ts index 855ad32dda137..c057d4a578050 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/common/api-mapping.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/common/api-mapping.test.ts @@ -120,7 +120,7 @@ describe('ApiMapping', () => { api, domainName: dn, }); - }).toThrow(/stage is required if default stage is not available/); + }).toThrow(/stage property must be specified/); }); test('stage validation - throws if stage not provided for WebSocketApi', () => { @@ -138,6 +138,6 @@ describe('ApiMapping', () => { api, domainName: dn, }); - }).toThrow(/stage is required for WebSocket API/); + }).toThrow(/stage property must be specified/); }); }); From 53620e92cfc72ab342c9c804c3868481c8a576c2 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 25 Nov 2021 20:31:45 +0100 Subject: [PATCH 21/82] chore(aws-cdk-lib): prevent deep imports (#17707) Sometimes, IDEs like VSCode will autocomplete deep imports into the CDK library. For example, they may generate the following: ```ts import { Bucket } from 'aws-cdk-lib/aws-s3/lib/bucket'; ``` Whereas the correct import should have been: ```ts import { Bucket } from 'aws-cdk-lib/aws-s3'; ``` If we allow people to write the former, they will be broken every time we change the internal file layout of our module (or conversely, we will not be allowed to change the file layout at all). Use the `package.json` `"exports"` mechanism to advertise the select paths that users are allowed to import from, and disallow the rest. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/pipelines/package.json | 7 + packages/aws-cdk-lib/package.json | 215 ++++++++++++++++- .../scripts/verify-imports-shielded.ts | 57 +++++ packages/decdk/lib/util.ts | 11 +- packages/monocdk/package.json | 222 ++++++++++++++++++ tools/@aws-cdk/ubergen/bin/ubergen.ts | 45 ++++ 6 files changed, 546 insertions(+), 11 deletions(-) create mode 100644 packages/aws-cdk-lib/scripts/verify-imports-shielded.ts diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index 417acf6d16b3a..350b0668c0fdd 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -26,6 +26,13 @@ "build+extract": "yarn build && yarn rosetta:extract", "build+test+extract": "yarn build+test && yarn rosetta:extract" }, + "exports": { + ".": "./lib/index.js", + "./package.json": "./package.json", + "./.jsii": "./.jsii", + "./.warnings.jsii.js": "./.warnings.jsii.js", + "./lib/helpers-internal": "./lib/helpers-internal/index.js" + }, "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com", diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index b33c257a2030c..baaca0e17ba02 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -38,7 +38,8 @@ }, "stripDeprecated": true, "post": [ - "node ./scripts/verify-imports-resolve-same.js" + "node ./scripts/verify-imports-resolve-same.js", + "node ./scripts/verify-imports-shielded.js" ] }, "cdk-package": { @@ -361,5 +362,217 @@ "ubergen": { "exclude": true, "excludeExperimentalModules": true + }, + "exports": { + ".": "./index.js", + "./alexa-ask": "./alexa-ask/index.js", + "./assertions": "./assertions/index.js", + "./assets": "./assets/index.js", + "./aws-accessanalyzer": "./aws-accessanalyzer/index.js", + "./aws-acmpca": "./aws-acmpca/index.js", + "./aws-amazonmq": "./aws-amazonmq/index.js", + "./aws-amplify": "./aws-amplify/index.js", + "./aws-apigateway": "./aws-apigateway/index.js", + "./aws-apigatewayv2": "./aws-apigatewayv2/index.js", + "./aws-appconfig": "./aws-appconfig/index.js", + "./aws-appflow": "./aws-appflow/index.js", + "./aws-appintegrations": "./aws-appintegrations/index.js", + "./aws-applicationautoscaling": "./aws-applicationautoscaling/index.js", + "./aws-applicationinsights": "./aws-applicationinsights/index.js", + "./aws-appmesh": "./aws-appmesh/index.js", + "./aws-apprunner": "./aws-apprunner/index.js", + "./aws-appstream": "./aws-appstream/index.js", + "./aws-appsync": "./aws-appsync/index.js", + "./aws-aps": "./aws-aps/index.js", + "./aws-athena": "./aws-athena/index.js", + "./aws-auditmanager": "./aws-auditmanager/index.js", + "./aws-autoscaling": "./aws-autoscaling/index.js", + "./aws-autoscaling-common": "./aws-autoscaling-common/index.js", + "./aws-autoscaling-hooktargets": "./aws-autoscaling-hooktargets/index.js", + "./aws-autoscalingplans": "./aws-autoscalingplans/index.js", + "./aws-backup": "./aws-backup/index.js", + "./aws-batch": "./aws-batch/index.js", + "./aws-budgets": "./aws-budgets/index.js", + "./aws-cassandra": "./aws-cassandra/index.js", + "./aws-ce": "./aws-ce/index.js", + "./aws-certificatemanager": "./aws-certificatemanager/index.js", + "./aws-chatbot": "./aws-chatbot/index.js", + "./aws-cloud9": "./aws-cloud9/index.js", + "./aws-cloudformation": "./aws-cloudformation/index.js", + "./aws-cloudfront": "./aws-cloudfront/index.js", + "./aws-cloudfront-origins": "./aws-cloudfront-origins/index.js", + "./aws-cloudtrail": "./aws-cloudtrail/index.js", + "./aws-cloudwatch": "./aws-cloudwatch/index.js", + "./aws-cloudwatch-actions": "./aws-cloudwatch-actions/index.js", + "./aws-codeartifact": "./aws-codeartifact/index.js", + "./aws-codebuild": "./aws-codebuild/index.js", + "./aws-codecommit": "./aws-codecommit/index.js", + "./aws-codedeploy": "./aws-codedeploy/index.js", + "./aws-codeguruprofiler": "./aws-codeguruprofiler/index.js", + "./aws-codegurureviewer": "./aws-codegurureviewer/index.js", + "./aws-codepipeline": "./aws-codepipeline/index.js", + "./aws-codepipeline-actions": "./aws-codepipeline-actions/index.js", + "./aws-codestar": "./aws-codestar/index.js", + "./aws-codestarconnections": "./aws-codestarconnections/index.js", + "./aws-codestarnotifications": "./aws-codestarnotifications/index.js", + "./aws-cognito": "./aws-cognito/index.js", + "./aws-config": "./aws-config/index.js", + "./aws-connect": "./aws-connect/index.js", + "./aws-cur": "./aws-cur/index.js", + "./aws-customerprofiles": "./aws-customerprofiles/index.js", + "./aws-databrew": "./aws-databrew/index.js", + "./aws-datapipeline": "./aws-datapipeline/index.js", + "./aws-datasync": "./aws-datasync/index.js", + "./aws-dax": "./aws-dax/index.js", + "./aws-detective": "./aws-detective/index.js", + "./aws-devopsguru": "./aws-devopsguru/index.js", + "./aws-directoryservice": "./aws-directoryservice/index.js", + "./aws-dlm": "./aws-dlm/index.js", + "./aws-dms": "./aws-dms/index.js", + "./aws-docdb": "./aws-docdb/index.js", + "./aws-dynamodb": "./aws-dynamodb/index.js", + "./aws-ec2": "./aws-ec2/index.js", + "./aws-ecr": "./aws-ecr/index.js", + "./aws-ecr-assets": "./aws-ecr-assets/index.js", + "./aws-ecs": "./aws-ecs/index.js", + "./aws-ecs-patterns": "./aws-ecs-patterns/index.js", + "./aws-efs": "./aws-efs/index.js", + "./aws-eks": "./aws-eks/index.js", + "./aws-elasticache": "./aws-elasticache/index.js", + "./aws-elasticbeanstalk": "./aws-elasticbeanstalk/index.js", + "./aws-elasticloadbalancing": "./aws-elasticloadbalancing/index.js", + "./aws-elasticloadbalancingv2": "./aws-elasticloadbalancingv2/index.js", + "./aws-elasticloadbalancingv2-actions": "./aws-elasticloadbalancingv2-actions/index.js", + "./aws-elasticloadbalancingv2-targets": "./aws-elasticloadbalancingv2-targets/index.js", + "./aws-elasticsearch": "./aws-elasticsearch/index.js", + "./aws-emr": "./aws-emr/index.js", + "./aws-emrcontainers": "./aws-emrcontainers/index.js", + "./aws-events": "./aws-events/index.js", + "./aws-events-targets": "./aws-events-targets/index.js", + "./aws-eventschemas": "./aws-eventschemas/index.js", + "./aws-finspace": "./aws-finspace/index.js", + "./aws-fis": "./aws-fis/index.js", + "./aws-fms": "./aws-fms/index.js", + "./aws-frauddetector": "./aws-frauddetector/index.js", + "./aws-fsx": "./aws-fsx/index.js", + "./aws-gamelift": "./aws-gamelift/index.js", + "./aws-globalaccelerator": "./aws-globalaccelerator/index.js", + "./aws-globalaccelerator-endpoints": "./aws-globalaccelerator-endpoints/index.js", + "./aws-glue": "./aws-glue/index.js", + "./aws-greengrass": "./aws-greengrass/index.js", + "./aws-greengrassv2": "./aws-greengrassv2/index.js", + "./aws-groundstation": "./aws-groundstation/index.js", + "./aws-guardduty": "./aws-guardduty/index.js", + "./aws-healthlake": "./aws-healthlake/index.js", + "./aws-iam": "./aws-iam/index.js", + "./aws-imagebuilder": "./aws-imagebuilder/index.js", + "./aws-inspector": "./aws-inspector/index.js", + "./aws-iot": "./aws-iot/index.js", + "./aws-iot1click": "./aws-iot1click/index.js", + "./aws-iotanalytics": "./aws-iotanalytics/index.js", + "./aws-iotcoredeviceadvisor": "./aws-iotcoredeviceadvisor/index.js", + "./aws-iotevents": "./aws-iotevents/index.js", + "./aws-iotfleethub": "./aws-iotfleethub/index.js", + "./aws-iotsitewise": "./aws-iotsitewise/index.js", + "./aws-iotthingsgraph": "./aws-iotthingsgraph/index.js", + "./aws-iotwireless": "./aws-iotwireless/index.js", + "./aws-ivs": "./aws-ivs/index.js", + "./aws-kendra": "./aws-kendra/index.js", + "./aws-kinesis": "./aws-kinesis/index.js", + "./aws-kinesisanalytics": "./aws-kinesisanalytics/index.js", + "./aws-kinesisfirehose": "./aws-kinesisfirehose/index.js", + "./aws-kms": "./aws-kms/index.js", + "./aws-lakeformation": "./aws-lakeformation/index.js", + "./aws-lambda": "./aws-lambda/index.js", + "./aws-lambda-destinations": "./aws-lambda-destinations/index.js", + "./aws-lambda-event-sources": "./aws-lambda-event-sources/index.js", + "./aws-lambda-nodejs": "./aws-lambda-nodejs/index.js", + "./aws-licensemanager": "./aws-licensemanager/index.js", + "./aws-lightsail": "./aws-lightsail/index.js", + "./aws-location": "./aws-location/index.js", + "./aws-logs": "./aws-logs/index.js", + "./aws-logs-destinations": "./aws-logs-destinations/index.js", + "./aws-lookoutequipment": "./aws-lookoutequipment/index.js", + "./aws-lookoutmetrics": "./aws-lookoutmetrics/index.js", + "./aws-lookoutvision": "./aws-lookoutvision/index.js", + "./aws-macie": "./aws-macie/index.js", + "./aws-managedblockchain": "./aws-managedblockchain/index.js", + "./aws-mediaconnect": "./aws-mediaconnect/index.js", + "./aws-mediaconvert": "./aws-mediaconvert/index.js", + "./aws-medialive": "./aws-medialive/index.js", + "./aws-mediapackage": "./aws-mediapackage/index.js", + "./aws-mediastore": "./aws-mediastore/index.js", + "./aws-memorydb": "./aws-memorydb/index.js", + "./aws-msk": "./aws-msk/index.js", + "./aws-mwaa": "./aws-mwaa/index.js", + "./aws-neptune": "./aws-neptune/index.js", + "./aws-networkfirewall": "./aws-networkfirewall/index.js", + "./aws-networkmanager": "./aws-networkmanager/index.js", + "./aws-nimblestudio": "./aws-nimblestudio/index.js", + "./aws-opensearchservice": "./aws-opensearchservice/index.js", + "./aws-opsworks": "./aws-opsworks/index.js", + "./aws-opsworkscm": "./aws-opsworkscm/index.js", + "./aws-panorama": "./aws-panorama/index.js", + "./aws-pinpoint": "./aws-pinpoint/index.js", + "./aws-pinpointemail": "./aws-pinpointemail/index.js", + "./aws-qldb": "./aws-qldb/index.js", + "./aws-quicksight": "./aws-quicksight/index.js", + "./aws-ram": "./aws-ram/index.js", + "./aws-rds": "./aws-rds/index.js", + "./aws-redshift": "./aws-redshift/index.js", + "./aws-rekognition": "./aws-rekognition/index.js", + "./aws-resourcegroups": "./aws-resourcegroups/index.js", + "./aws-robomaker": "./aws-robomaker/index.js", + "./aws-route53": "./aws-route53/index.js", + "./aws-route53-patterns": "./aws-route53-patterns/index.js", + "./aws-route53-targets": "./aws-route53-targets/index.js", + "./aws-route53recoverycontrol": "./aws-route53recoverycontrol/index.js", + "./aws-route53recoveryreadiness": "./aws-route53recoveryreadiness/index.js", + "./aws-route53resolver": "./aws-route53resolver/index.js", + "./aws-s3": "./aws-s3/index.js", + "./aws-s3-assets": "./aws-s3-assets/index.js", + "./aws-s3-deployment": "./aws-s3-deployment/index.js", + "./aws-s3-notifications": "./aws-s3-notifications/index.js", + "./aws-s3objectlambda": "./aws-s3objectlambda/index.js", + "./aws-s3outposts": "./aws-s3outposts/index.js", + "./aws-sagemaker": "./aws-sagemaker/index.js", + "./aws-sam": "./aws-sam/index.js", + "./aws-sdb": "./aws-sdb/index.js", + "./aws-secretsmanager": "./aws-secretsmanager/index.js", + "./aws-securityhub": "./aws-securityhub/index.js", + "./aws-servicecatalog": "./aws-servicecatalog/index.js", + "./aws-servicecatalogappregistry": "./aws-servicecatalogappregistry/index.js", + "./aws-servicediscovery": "./aws-servicediscovery/index.js", + "./aws-ses": "./aws-ses/index.js", + "./aws-ses-actions": "./aws-ses-actions/index.js", + "./aws-signer": "./aws-signer/index.js", + "./aws-sns": "./aws-sns/index.js", + "./aws-sns-subscriptions": "./aws-sns-subscriptions/index.js", + "./aws-sqs": "./aws-sqs/index.js", + "./aws-ssm": "./aws-ssm/index.js", + "./aws-ssmcontacts": "./aws-ssmcontacts/index.js", + "./aws-ssmincidents": "./aws-ssmincidents/index.js", + "./aws-sso": "./aws-sso/index.js", + "./aws-stepfunctions": "./aws-stepfunctions/index.js", + "./aws-stepfunctions-tasks": "./aws-stepfunctions-tasks/index.js", + "./aws-synthetics": "./aws-synthetics/index.js", + "./aws-timestream": "./aws-timestream/index.js", + "./aws-transfer": "./aws-transfer/index.js", + "./aws-waf": "./aws-waf/index.js", + "./aws-wafregional": "./aws-wafregional/index.js", + "./aws-wafv2": "./aws-wafv2/index.js", + "./aws-wisdom": "./aws-wisdom/index.js", + "./aws-workspaces": "./aws-workspaces/index.js", + "./aws-xray": "./aws-xray/index.js", + "./cloud-assembly-schema": "./cloud-assembly-schema/index.js", + "./cloudformation-include": "./cloudformation-include/index.js", + "./custom-resources": "./custom-resources/index.js", + "./cx-api": "./cx-api/index.js", + "./lambda-layer-awscli": "./lambda-layer-awscli/index.js", + "./lambda-layer-kubectl": "./lambda-layer-kubectl/index.js", + "./lambda-layer-node-proxy-agent": "./lambda-layer-node-proxy-agent/index.js", + "./pipelines": "./pipelines/index.js", + "./pipelines/lib/helpers-internal": "./pipelines/lib/helpers-internal/index.js", + "./region-info": "./region-info/index.js" } } diff --git a/packages/aws-cdk-lib/scripts/verify-imports-shielded.ts b/packages/aws-cdk-lib/scripts/verify-imports-shielded.ts new file mode 100644 index 0000000000000..50ad38704e726 --- /dev/null +++ b/packages/aws-cdk-lib/scripts/verify-imports-shielded.ts @@ -0,0 +1,57 @@ +/** + * Check that the imports from 'aws-cdk-lib' we expect to work, work, and those we have shielded off don't work. + */ +import * as os from 'os'; +import * as path from 'path'; +import * as fs from 'fs-extra'; + +async function main() { + // First make a tempdir and symlink `aws-cdk-lib` into it so we can refer to it + // as if it was an installed module. + await withTemporaryDirectory(async (tmpDir) => { + await fs.mkdirp(path.join(tmpDir, 'node_modules')); + await fs.symlink(path.resolve(__dirname, '..'), path.join(tmpDir, 'node_modules', 'aws-cdk-lib')); + + assertImportSucceeds('aws-cdk-lib'); + assertImportFails('aws-cdk-lib/LICENSE', 'ERR_PACKAGE_PATH_NOT_EXPORTED'); + assertImportFails('aws-cdk-lib/aws-s3/lib/bucket', 'ERR_PACKAGE_PATH_NOT_EXPORTED'); + assertImportSucceeds('aws-cdk-lib/aws-s3'); + + function assertImportSucceeds(name: string) { + require.resolve(name, { paths: [tmpDir] }); + } + + function assertImportFails(name: string, code: string) { + try { + require.resolve(name, { paths: [tmpDir] }); + + // eslint-disable-next-line no-console + console.error(`Import of '${name}' should have produced an error, but didn't.`); + process.exitCode = 1; + } catch (e) { + if ((e as any).code !== code) { + // eslint-disable-next-line no-console + console.error(`Import of '${name}' should have produced error ${code}, but got ${(e as any).code}.`); + process.exitCode = 1; + } + } + } + }); +} + + +export async function withTemporaryDirectory(callback: (dir: string) => Promise): Promise { + const tmpdir = await fs.mkdtemp(path.join(os.tmpdir(), path.basename(__filename))); + try { + return await callback(tmpdir); + } finally { + await fs.remove(tmpdir); + } +} + + +main().catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + process.exitCode = 1; +}); diff --git a/packages/decdk/lib/util.ts b/packages/decdk/lib/util.ts index f0dde14d5755b..4378ba01c8223 100644 --- a/packages/decdk/lib/util.ts +++ b/packages/decdk/lib/util.ts @@ -14,16 +14,7 @@ export async function readTemplate(templateFile: string) { export async function loadTypeSystem(validate = true) { const typeSystem = new jsiiReflect.TypeSystem(); - const packageJson = require('../package.json'); - - for (const depName of Object.keys(packageJson.dependencies || {})) { - const jsiiModuleDir = path.dirname(require.resolve(`${depName}/package.json`)); - if (!fs.existsSync(path.resolve(jsiiModuleDir, '.jsii'))) { - continue; - } - await typeSystem.load(jsiiModuleDir, { validate }); - } - + await typeSystem.loadNpmDependencies(path.resolve(__dirname, '..'), { validate }); return typeSystem; } diff --git a/packages/monocdk/package.json b/packages/monocdk/package.json index ea10f3a7ec3c3..6fb1ad42f3283 100644 --- a/packages/monocdk/package.json +++ b/packages/monocdk/package.json @@ -357,5 +357,227 @@ }, "publishConfig": { "tag": "latest" + }, + "exports": { + ".": "./index.js", + "./alexa-ask": "./alexa-ask/index.js", + "./app-delivery": "./app-delivery/index.js", + "./assertions": "./assertions/index.js", + "./assets": "./assets/index.js", + "./aws-accessanalyzer": "./aws-accessanalyzer/index.js", + "./aws-acmpca": "./aws-acmpca/index.js", + "./aws-amazonmq": "./aws-amazonmq/index.js", + "./aws-amplify": "./aws-amplify/index.js", + "./aws-apigateway": "./aws-apigateway/index.js", + "./aws-apigatewayv2": "./aws-apigatewayv2/index.js", + "./aws-apigatewayv2-authorizers": "./aws-apigatewayv2-authorizers/index.js", + "./aws-apigatewayv2-integrations": "./aws-apigatewayv2-integrations/index.js", + "./aws-appconfig": "./aws-appconfig/index.js", + "./aws-appflow": "./aws-appflow/index.js", + "./aws-appintegrations": "./aws-appintegrations/index.js", + "./aws-applicationautoscaling": "./aws-applicationautoscaling/index.js", + "./aws-applicationinsights": "./aws-applicationinsights/index.js", + "./aws-appmesh": "./aws-appmesh/index.js", + "./aws-apprunner": "./aws-apprunner/index.js", + "./aws-appstream": "./aws-appstream/index.js", + "./aws-appsync": "./aws-appsync/index.js", + "./aws-aps": "./aws-aps/index.js", + "./aws-athena": "./aws-athena/index.js", + "./aws-auditmanager": "./aws-auditmanager/index.js", + "./aws-autoscaling": "./aws-autoscaling/index.js", + "./aws-autoscaling-common": "./aws-autoscaling-common/index.js", + "./aws-autoscaling-hooktargets": "./aws-autoscaling-hooktargets/index.js", + "./aws-autoscalingplans": "./aws-autoscalingplans/index.js", + "./aws-backup": "./aws-backup/index.js", + "./aws-batch": "./aws-batch/index.js", + "./aws-budgets": "./aws-budgets/index.js", + "./aws-cassandra": "./aws-cassandra/index.js", + "./aws-ce": "./aws-ce/index.js", + "./aws-certificatemanager": "./aws-certificatemanager/index.js", + "./aws-chatbot": "./aws-chatbot/index.js", + "./aws-cloud9": "./aws-cloud9/index.js", + "./aws-cloudformation": "./aws-cloudformation/index.js", + "./aws-cloudfront": "./aws-cloudfront/index.js", + "./aws-cloudfront-origins": "./aws-cloudfront-origins/index.js", + "./aws-cloudtrail": "./aws-cloudtrail/index.js", + "./aws-cloudwatch": "./aws-cloudwatch/index.js", + "./aws-cloudwatch-actions": "./aws-cloudwatch-actions/index.js", + "./aws-codeartifact": "./aws-codeartifact/index.js", + "./aws-codebuild": "./aws-codebuild/index.js", + "./aws-codecommit": "./aws-codecommit/index.js", + "./aws-codedeploy": "./aws-codedeploy/index.js", + "./aws-codeguruprofiler": "./aws-codeguruprofiler/index.js", + "./aws-codegurureviewer": "./aws-codegurureviewer/index.js", + "./aws-codepipeline": "./aws-codepipeline/index.js", + "./aws-codepipeline-actions": "./aws-codepipeline-actions/index.js", + "./aws-codestar": "./aws-codestar/index.js", + "./aws-codestarconnections": "./aws-codestarconnections/index.js", + "./aws-codestarnotifications": "./aws-codestarnotifications/index.js", + "./aws-cognito": "./aws-cognito/index.js", + "./aws-config": "./aws-config/index.js", + "./aws-connect": "./aws-connect/index.js", + "./aws-cur": "./aws-cur/index.js", + "./aws-customerprofiles": "./aws-customerprofiles/index.js", + "./aws-databrew": "./aws-databrew/index.js", + "./aws-datapipeline": "./aws-datapipeline/index.js", + "./aws-datasync": "./aws-datasync/index.js", + "./aws-dax": "./aws-dax/index.js", + "./aws-detective": "./aws-detective/index.js", + "./aws-devopsguru": "./aws-devopsguru/index.js", + "./aws-directoryservice": "./aws-directoryservice/index.js", + "./aws-dlm": "./aws-dlm/index.js", + "./aws-dms": "./aws-dms/index.js", + "./aws-docdb": "./aws-docdb/index.js", + "./aws-dynamodb": "./aws-dynamodb/index.js", + "./aws-ec2": "./aws-ec2/index.js", + "./aws-ecr": "./aws-ecr/index.js", + "./aws-ecr-assets": "./aws-ecr-assets/index.js", + "./aws-ecs": "./aws-ecs/index.js", + "./aws-ecs-patterns": "./aws-ecs-patterns/index.js", + "./aws-efs": "./aws-efs/index.js", + "./aws-eks": "./aws-eks/index.js", + "./aws-eks-legacy": "./aws-eks-legacy/index.js", + "./aws-elasticache": "./aws-elasticache/index.js", + "./aws-elasticbeanstalk": "./aws-elasticbeanstalk/index.js", + "./aws-elasticloadbalancing": "./aws-elasticloadbalancing/index.js", + "./aws-elasticloadbalancingv2": "./aws-elasticloadbalancingv2/index.js", + "./aws-elasticloadbalancingv2-actions": "./aws-elasticloadbalancingv2-actions/index.js", + "./aws-elasticloadbalancingv2-targets": "./aws-elasticloadbalancingv2-targets/index.js", + "./aws-elasticsearch": "./aws-elasticsearch/index.js", + "./aws-emr": "./aws-emr/index.js", + "./aws-emrcontainers": "./aws-emrcontainers/index.js", + "./aws-events": "./aws-events/index.js", + "./aws-events-targets": "./aws-events-targets/index.js", + "./aws-eventschemas": "./aws-eventschemas/index.js", + "./aws-finspace": "./aws-finspace/index.js", + "./aws-fis": "./aws-fis/index.js", + "./aws-fms": "./aws-fms/index.js", + "./aws-frauddetector": "./aws-frauddetector/index.js", + "./aws-fsx": "./aws-fsx/index.js", + "./aws-gamelift": "./aws-gamelift/index.js", + "./aws-globalaccelerator": "./aws-globalaccelerator/index.js", + "./aws-globalaccelerator-endpoints": "./aws-globalaccelerator-endpoints/index.js", + "./aws-glue": "./aws-glue/index.js", + "./aws-greengrass": "./aws-greengrass/index.js", + "./aws-greengrassv2": "./aws-greengrassv2/index.js", + "./aws-groundstation": "./aws-groundstation/index.js", + "./aws-guardduty": "./aws-guardduty/index.js", + "./aws-healthlake": "./aws-healthlake/index.js", + "./aws-iam": "./aws-iam/index.js", + "./aws-imagebuilder": "./aws-imagebuilder/index.js", + "./aws-inspector": "./aws-inspector/index.js", + "./aws-iot": "./aws-iot/index.js", + "./aws-iot-actions": "./aws-iot-actions/index.js", + "./aws-iot1click": "./aws-iot1click/index.js", + "./aws-iotanalytics": "./aws-iotanalytics/index.js", + "./aws-iotcoredeviceadvisor": "./aws-iotcoredeviceadvisor/index.js", + "./aws-iotevents": "./aws-iotevents/index.js", + "./aws-iotfleethub": "./aws-iotfleethub/index.js", + "./aws-iotsitewise": "./aws-iotsitewise/index.js", + "./aws-iotthingsgraph": "./aws-iotthingsgraph/index.js", + "./aws-iotwireless": "./aws-iotwireless/index.js", + "./aws-ivs": "./aws-ivs/index.js", + "./aws-kendra": "./aws-kendra/index.js", + "./aws-kinesis": "./aws-kinesis/index.js", + "./aws-kinesisanalytics": "./aws-kinesisanalytics/index.js", + "./aws-kinesisanalytics-flink": "./aws-kinesisanalytics-flink/index.js", + "./aws-kinesisfirehose": "./aws-kinesisfirehose/index.js", + "./aws-kinesisfirehose-destinations": "./aws-kinesisfirehose-destinations/index.js", + "./aws-kms": "./aws-kms/index.js", + "./aws-lakeformation": "./aws-lakeformation/index.js", + "./aws-lambda": "./aws-lambda/index.js", + "./aws-lambda-destinations": "./aws-lambda-destinations/index.js", + "./aws-lambda-event-sources": "./aws-lambda-event-sources/index.js", + "./aws-lambda-go": "./aws-lambda-go/index.js", + "./aws-lambda-nodejs": "./aws-lambda-nodejs/index.js", + "./aws-lambda-python": "./aws-lambda-python/index.js", + "./aws-licensemanager": "./aws-licensemanager/index.js", + "./aws-lightsail": "./aws-lightsail/index.js", + "./aws-location": "./aws-location/index.js", + "./aws-logs": "./aws-logs/index.js", + "./aws-logs-destinations": "./aws-logs-destinations/index.js", + "./aws-lookoutequipment": "./aws-lookoutequipment/index.js", + "./aws-lookoutmetrics": "./aws-lookoutmetrics/index.js", + "./aws-lookoutvision": "./aws-lookoutvision/index.js", + "./aws-macie": "./aws-macie/index.js", + "./aws-managedblockchain": "./aws-managedblockchain/index.js", + "./aws-mediaconnect": "./aws-mediaconnect/index.js", + "./aws-mediaconvert": "./aws-mediaconvert/index.js", + "./aws-medialive": "./aws-medialive/index.js", + "./aws-mediapackage": "./aws-mediapackage/index.js", + "./aws-mediastore": "./aws-mediastore/index.js", + "./aws-memorydb": "./aws-memorydb/index.js", + "./aws-msk": "./aws-msk/index.js", + "./aws-mwaa": "./aws-mwaa/index.js", + "./aws-neptune": "./aws-neptune/index.js", + "./aws-networkfirewall": "./aws-networkfirewall/index.js", + "./aws-networkmanager": "./aws-networkmanager/index.js", + "./aws-nimblestudio": "./aws-nimblestudio/index.js", + "./aws-opensearchservice": "./aws-opensearchservice/index.js", + "./aws-opsworks": "./aws-opsworks/index.js", + "./aws-opsworkscm": "./aws-opsworkscm/index.js", + "./aws-panorama": "./aws-panorama/index.js", + "./aws-pinpoint": "./aws-pinpoint/index.js", + "./aws-pinpointemail": "./aws-pinpointemail/index.js", + "./aws-qldb": "./aws-qldb/index.js", + "./aws-quicksight": "./aws-quicksight/index.js", + "./aws-ram": "./aws-ram/index.js", + "./aws-rds": "./aws-rds/index.js", + "./aws-redshift": "./aws-redshift/index.js", + "./aws-rekognition": "./aws-rekognition/index.js", + "./aws-resourcegroups": "./aws-resourcegroups/index.js", + "./aws-robomaker": "./aws-robomaker/index.js", + "./aws-route53": "./aws-route53/index.js", + "./aws-route53-patterns": "./aws-route53-patterns/index.js", + "./aws-route53-targets": "./aws-route53-targets/index.js", + "./aws-route53recoverycontrol": "./aws-route53recoverycontrol/index.js", + "./aws-route53recoveryreadiness": "./aws-route53recoveryreadiness/index.js", + "./aws-route53resolver": "./aws-route53resolver/index.js", + "./aws-s3": "./aws-s3/index.js", + "./aws-s3-assets": "./aws-s3-assets/index.js", + "./aws-s3-deployment": "./aws-s3-deployment/index.js", + "./aws-s3-notifications": "./aws-s3-notifications/index.js", + "./aws-s3objectlambda": "./aws-s3objectlambda/index.js", + "./aws-s3outposts": "./aws-s3outposts/index.js", + "./aws-sagemaker": "./aws-sagemaker/index.js", + "./aws-sam": "./aws-sam/index.js", + "./aws-sdb": "./aws-sdb/index.js", + "./aws-secretsmanager": "./aws-secretsmanager/index.js", + "./aws-securityhub": "./aws-securityhub/index.js", + "./aws-servicecatalog": "./aws-servicecatalog/index.js", + "./aws-servicecatalogappregistry": "./aws-servicecatalogappregistry/index.js", + "./aws-servicediscovery": "./aws-servicediscovery/index.js", + "./aws-ses": "./aws-ses/index.js", + "./aws-ses-actions": "./aws-ses-actions/index.js", + "./aws-signer": "./aws-signer/index.js", + "./aws-sns": "./aws-sns/index.js", + "./aws-sns-subscriptions": "./aws-sns-subscriptions/index.js", + "./aws-sqs": "./aws-sqs/index.js", + "./aws-ssm": "./aws-ssm/index.js", + "./aws-ssmcontacts": "./aws-ssmcontacts/index.js", + "./aws-ssmincidents": "./aws-ssmincidents/index.js", + "./aws-sso": "./aws-sso/index.js", + "./aws-stepfunctions": "./aws-stepfunctions/index.js", + "./aws-stepfunctions-tasks": "./aws-stepfunctions-tasks/index.js", + "./aws-synthetics": "./aws-synthetics/index.js", + "./aws-timestream": "./aws-timestream/index.js", + "./aws-transfer": "./aws-transfer/index.js", + "./aws-waf": "./aws-waf/index.js", + "./aws-wafregional": "./aws-wafregional/index.js", + "./aws-wafv2": "./aws-wafv2/index.js", + "./aws-wisdom": "./aws-wisdom/index.js", + "./aws-workspaces": "./aws-workspaces/index.js", + "./aws-xray": "./aws-xray/index.js", + "./cloud-assembly-schema": "./cloud-assembly-schema/index.js", + "./cloudformation-include": "./cloudformation-include/index.js", + "./custom-resources": "./custom-resources/index.js", + "./cx-api": "./cx-api/index.js", + "./lambda-layer-awscli": "./lambda-layer-awscli/index.js", + "./lambda-layer-kubectl": "./lambda-layer-kubectl/index.js", + "./lambda-layer-node-proxy-agent": "./lambda-layer-node-proxy-agent/index.js", + "./pipelines": "./pipelines/index.js", + "./pipelines/lib/helpers-internal": "./pipelines/lib/helpers-internal/index.js", + "./region-info": "./region-info/index.js", + "./yaml-cfn": "./yaml-cfn/index.js" } } diff --git a/tools/@aws-cdk/ubergen/bin/ubergen.ts b/tools/@aws-cdk/ubergen/bin/ubergen.ts index d3b4889ece4df..ea08678bd1a43 100644 --- a/tools/@aws-cdk/ubergen/bin/ubergen.ts +++ b/tools/@aws-cdk/ubergen/bin/ubergen.ts @@ -25,6 +25,9 @@ async function main() { await verifyDependencies(uberPackageJson, libraries); await prepareSourceFiles(libraries, uberPackageJson); await combineRosettaFixtures(libraries, uberPackageJson); + + // Rewrite package.json (exports will have changed) + await fs.writeJson(UBER_PACKAGE_JSON_PATH, uberPackageJson, { spaces: 2 }); } main().then( @@ -42,6 +45,7 @@ interface LibraryReference { } interface PackageJson { + readonly main?: string; readonly description?: string; readonly bundleDependencies?: readonly string[]; readonly bundledDependencies?: readonly string[]; @@ -76,6 +80,7 @@ interface PackageJson { readonly deprecatedPackages?: readonly string[]; readonly excludeExperimentalModules?: boolean; }; + exports?: Record; } /** @@ -236,6 +241,20 @@ async function prepareSourceFiles(libraries: readonly LibraryReference[], packag await fs.remove(LIB_ROOT); } + // Control 'exports' field of the 'package.json'. This will control what kind of 'import' statements are + // allowed for this package: we only want to allow the exact import statements that we want to support. + packageJson.exports = { + '.': './index.js', + + // We need to expose 'package.json' and '.jsii' because 'jsii' and 'jsii-reflect' load them using + // require(). (-_-). Can be removed after https://github.com/aws/jsii/pull/3205 gets merged. + './package.json': './package.json', + './.jsii': './.jsii', + + // This is necessary to support jsii cross-module warnings + './.warnings.jsii.js': './.warnings.jsii.js', + }; + const indexStatements = new Array(); for (const library of libraries) { const libDir = path.join(LIB_ROOT, library.shortName); @@ -248,6 +267,7 @@ async function prepareSourceFiles(libraries: readonly LibraryReference[], packag indexStatements.push(`export * from './${library.shortName}';`); } else { indexStatements.push(`export * as ${library.shortName.replace(/-/g, '_')} from './${library.shortName}';`); + copySubmoduleExports(packageJson.exports, library, library.shortName); } } @@ -256,6 +276,24 @@ async function prepareSourceFiles(libraries: readonly LibraryReference[], packag console.log('\t🍺 Success!'); } +/** + * Copy the sublibrary's exports into the 'exports' of the main library. + * + * Replace the original 'main' export with an export of the new '/index.ts` file we've written + * in 'transformPackage'. + */ +function copySubmoduleExports(targetExports: Record, library: LibraryReference, subdirectory: string) { + const visibleName = library.shortName; + + for (const [relPath, relSource] of Object.entries(library.packageJson.exports ?? {})) { + targetExports[`./${unixPath(path.join(visibleName, relPath))}`] = `./${unixPath(path.join(subdirectory, relSource))}`; + } + + // If there was an export for '.' in the original submodule, this assignment will overwrite it, + // which is exactly what we want. + targetExports[`./${unixPath(visibleName)}`] = `./${unixPath(subdirectory)}/index.js`; +} + async function combineRosettaFixtures(libraries: readonly LibraryReference[], uberPackageJson: PackageJson) { console.log('📝 Combining Rosetta fixtures...'); @@ -501,3 +539,10 @@ function sortObject(obj: Record): Record { return result; } + +/** + * Turn potential backslashes into forward slashes + */ +function unixPath(x: string) { + return x.replace(/\\/g, '/'); +} \ No newline at end of file From 88a5204a295874e3cffcc041469d8fffbd32b57d Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Fri, 26 Nov 2021 02:44:17 -0700 Subject: [PATCH 22/82] feat(ec2): add mac1 instance (#17677) `mac1` instances got released last year: https://aws.amazon.com/about-aws/whats-new/2021/10/amazon-ec2-mac-instances-additional-regions/ Docs have already been updated a while ago: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-instancetype Note: Whenever `mac2` comes out (probably on M1, or most likely on M1Pro/M1Max) we'll have to update `InstanceArchitecture` enum [here](https://github.com/aws/aws-cdk/blob/ddf2881ee24cbf3083463a6e772a5c91acc229aa/packages/%40aws-cdk/aws-ec2/lib/instance-types.ts#L573). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/instance-types.ts | 13 +++++++++++-- packages/@aws-cdk/aws-ec2/test/instance.test.ts | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index 5fafb03327873..018291783ef94 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -574,7 +574,17 @@ export enum InstanceClass { /** * Inferentia Chips based instances for machine learning inference applications, 1st generation */ - INF1 = 'inf1' + INF1 = 'inf1', + + /** + * Macintosh instances built on Apple Mac mini computers, 1st generation with Intel procesors + */ + MACINTOSH1_INTEL = 'mac1', + + /** + * Macintosh instances built on Apple Mac mini computers, 1st generation with Intel procesors + */ + MAC1 = 'mac1', } /** @@ -695,7 +705,6 @@ export enum InstanceSize { * Instance size METAL (metal) */ METAL = 'metal', - } /** diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index 21f7277200a99..632a1f7b7e10f 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -483,4 +483,4 @@ test('cause replacement from s3 asset in userdata', () => { [`InstanceTwoDC29A7A7${hash}`]: expect.objectContaining({ Type: 'AWS::EC2::Instance', Properties: expect.anything() }), }), })); -}); \ No newline at end of file +}); From 7e0c9a341e2bc2837d5c5d671339fe968714d9ce Mon Sep 17 00:00:00 2001 From: AWS CDK Automation <43080478+aws-cdk-automation@users.noreply.github.com> Date: Fri, 26 Nov 2021 15:59:33 +0530 Subject: [PATCH 23/82] feat(cfnspec): cloudformation spec v49.0.0 (#17727) Co-authored-by: AWS CDK Team Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- packages/monocdk/package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/monocdk/package.json b/packages/monocdk/package.json index 6fb1ad42f3283..c194f59d3d9c9 100644 --- a/packages/monocdk/package.json +++ b/packages/monocdk/package.json @@ -360,6 +360,9 @@ }, "exports": { ".": "./index.js", + "./package.json": "./package.json", + "./.jsii": "./.jsii", + "./.warnings.jsii.js": "./.warnings.jsii.js", "./alexa-ask": "./alexa-ask/index.js", "./app-delivery": "./app-delivery/index.js", "./assertions": "./assertions/index.js", @@ -576,6 +579,9 @@ "./lambda-layer-kubectl": "./lambda-layer-kubectl/index.js", "./lambda-layer-node-proxy-agent": "./lambda-layer-node-proxy-agent/index.js", "./pipelines": "./pipelines/index.js", + "./pipelines/package.json": "./pipelines/package.json", + "./pipelines/.jsii": "./pipelines/.jsii", + "./pipelines/.warnings.jsii.js": "./pipelines/.warnings.jsii.js", "./pipelines/lib/helpers-internal": "./pipelines/lib/helpers-internal/index.js", "./region-info": "./region-info/index.js", "./yaml-cfn": "./yaml-cfn/index.js" From 8191f1f1d4072feeba74844a31c942909cee7d83 Mon Sep 17 00:00:00 2001 From: Arlind Nocaj Date: Fri, 26 Nov 2021 12:26:03 +0100 Subject: [PATCH 24/82] fix(cli): S3 asset uploads are rejected by commonly referenced encryption SCP (introduces bootstrap stack v9) (#17668) Many organizations around the world have started to use a specific Service Control Policy (SCP) from this blog post: https://aws.amazon.com/blogs/security/how-to-prevent-uploads-of-unencrypted-objects-to-amazon-s3/ in order to make sure all S3 bucket uploads are encrypted. CDK configures the `DefaultEncryptionConfiguration` on the bucket so that objects are always encrypted by default, but this specific SCP can only check that individual upload actions include the "enable encryption" option. That means that even though the end result would still be satisfied (objects are encrypted in S3), the SCP would nevertheless reject the CDK upload. We would rather people use AWS Config to make sure all buckets have `DefaultEncryptionConfiguration` set, so that this SCP is not necessary... but there is no arguing with deployed reality. Change the CDK upload code path to first read out the default encryption configuration from the bucket, only to then mirror those exact same settings in the `PutObject` call so that the SCP can see that they are present. This requires adding a new permission to the `cdk-assets` role, namely `s3:GetEncryptionConfiguration`, so requires a new bootstrap stack version: version 9. If you want this new behavior because your organization applies this specific SCP, you must upgrade to bootstrap stack version 9. If you do not care about this new behavior you don't have to do anything: if the call to `getEncryptionConfiguration` fails, the CDK will fall back to the old behavior (not specifying any header). Fixes #11265. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/api/bootstrap/bootstrap-template.yaml | 3 +- .../cdk-assets/lib/private/handlers/files.ts | 130 ++++++++++++++++-- packages/cdk-assets/lib/publishing.ts | 13 +- packages/cdk-assets/test/files.test.ts | 97 ++++++++++++- packages/cdk-assets/test/mock-aws.ts | 1 + 5 files changed, 223 insertions(+), 21 deletions(-) diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml index 36182c083fa55..ce3cf9fbe3c18 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml @@ -304,6 +304,7 @@ Resources: - Action: - s3:GetObject* - s3:GetBucket* + - s3:GetEncryptionConfiguration - s3:List* - s3:DeleteObject* - s3:PutObject* @@ -490,7 +491,7 @@ Resources: Type: String Name: Fn::Sub: '/cdk-bootstrap/${Qualifier}/version' - Value: '8' + Value: '9' Outputs: BucketName: Description: The name of the S3 bucket owned by the CDK toolkit stack diff --git a/packages/cdk-assets/lib/private/handlers/files.ts b/packages/cdk-assets/lib/private/handlers/files.ts index dc4f0a8768a6a..0350edb27c39d 100644 --- a/packages/cdk-assets/lib/private/handlers/files.ts +++ b/packages/cdk-assets/lib/private/handlers/files.ts @@ -23,14 +23,15 @@ export class FileAssetHandler implements IAssetHandler { public async publish(): Promise { const destination = await replaceAwsPlaceholders(this.asset.destination, this.host.aws); const s3Url = `s3://${destination.bucketName}/${destination.objectKey}`; - const s3 = await this.host.aws.s3Client(destination); this.host.emitMessage(EventType.CHECK, `Check ${s3Url}`); + const bucketInfo = BucketInformation.for(this.host); + // A thunk for describing the current account. Used when we need to format an error // message, not in the success case. const account = async () => (await this.host.aws.discoverCurrentAccount())?.accountId; - switch (await bucketOwnership(s3, destination.bucketName)) { + switch (await bucketInfo.bucketOwnership(s3, destination.bucketName)) { case BucketOwnership.MINE: break; case BucketOwnership.DOES_NOT_EXIST: @@ -44,17 +45,42 @@ export class FileAssetHandler implements IAssetHandler { return; } + // Identify the the bucket encryption type to set the header on upload + // required for SCP rules denying uploads without encryption header + let paramsEncryption: {[index: string]:any}= {}; + const encryption2 = await bucketInfo.bucketEncryption(s3, destination.bucketName); + switch (encryption2) { + case BucketEncryption.NO_ENCRYPTION: + break; + case BucketEncryption.SSEAlgorithm_AES256: + paramsEncryption = { ServerSideEncryption: 'AES256' }; + break; + case BucketEncryption.SSEAlgorithm_aws_kms: + paramsEncryption = { ServerSideEncryption: 'aws:kms' }; + break; + case BucketEncryption.DOES_NOT_EXIST: + this.host.emitMessage(EventType.DEBUG, `No bucket named '${destination.bucketName}'. Is account ${await account()} bootstrapped?`); + break; + case BucketEncryption.ACCES_DENIED: + this.host.emitMessage(EventType.DEBUG, `ACCES_DENIED for getting encryption of bucket '${destination.bucketName}'. Either wrong account ${await account()} or s3:GetEncryptionConfiguration not set for cdk role. Try "cdk bootstrap" again.`); + break; + } + if (this.host.aborted) { return; } const publishFile = this.asset.source.executable ? await this.externalPackageFile(this.asset.source.executable) : await this.packageFile(this.asset.source); this.host.emitMessage(EventType.UPLOAD, `Upload ${s3Url}`); - await s3.upload({ + + const params = Object.assign({}, { Bucket: destination.bucketName, Key: destination.objectKey, Body: createReadStream(publishFile.packagedPath), ContentType: publishFile.contentType, - }).promise(); + }, + paramsEncryption); + + await s3.upload(params).promise(); } private async packageFile(source: FileSource): Promise { @@ -100,15 +126,12 @@ enum BucketOwnership { SOMEONE_ELSES_OR_NO_ACCESS } -async function bucketOwnership(s3: AWS.S3, bucket: string): Promise { - try { - await s3.getBucketLocation({ Bucket: bucket }).promise(); - return BucketOwnership.MINE; - } catch (e) { - if (e.code === 'NoSuchBucket') { return BucketOwnership.DOES_NOT_EXIST; } - if (['AccessDenied', 'AllAccessDisabled'].includes(e.code)) { return BucketOwnership.SOMEONE_ELSES_OR_NO_ACCESS; } - throw e; - } +enum BucketEncryption { + NO_ENCRYPTION, + SSEAlgorithm_AES256, + SSEAlgorithm_aws_kms, + ACCES_DENIED, + DOES_NOT_EXIST } async function objectExists(s3: AWS.S3, bucket: string, key: string) { @@ -144,3 +167,84 @@ interface PackagedFileAsset { */ readonly contentType?: string; } + + +/** + * Cache for bucket information, so we don't have to keep doing the same calls again and again + * + * We scope the lifetime of the cache to the lifetime of the host, so that we don't have to do + * anything special for tests and yet the cache will live for the entire lifetime of the asset + * upload session when used by the CLI. + */ +class BucketInformation { + public static for(host: IHandlerHost) { + const existing = BucketInformation.caches.get(host); + if (existing) { return existing; } + + const fresh = new BucketInformation(); + BucketInformation.caches.set(host, fresh); + return fresh; + } + + private static readonly caches = new WeakMap(); + + private readonly ownerships = new Map(); + private readonly encryptions = new Map(); + + private constructor() { + } + + public async bucketOwnership(s3: AWS.S3, bucket: string): Promise { + return cached(this.ownerships, bucket, () => this._bucketOwnership(s3, bucket)); + } + + public async bucketEncryption(s3: AWS.S3, bucket: string): Promise { + return cached(this.encryptions, bucket, () => this._bucketEncryption(s3, bucket)); + } + + private async _bucketOwnership(s3: AWS.S3, bucket: string): Promise { + try { + await s3.getBucketLocation({ Bucket: bucket }).promise(); + return BucketOwnership.MINE; + } catch (e) { + if (e.code === 'NoSuchBucket') { return BucketOwnership.DOES_NOT_EXIST; } + if (['AccessDenied', 'AllAccessDisabled'].includes(e.code)) { return BucketOwnership.SOMEONE_ELSES_OR_NO_ACCESS; } + throw e; + } + } + + private async _bucketEncryption(s3: AWS.S3, bucket: string): Promise { + try { + const encryption = await s3.getBucketEncryption({ Bucket: bucket }).promise(); + const l = encryption?.ServerSideEncryptionConfiguration?.Rules?.length ?? 0; + if (l > 0) { + let ssealgo = encryption?.ServerSideEncryptionConfiguration?.Rules[0]?.ApplyServerSideEncryptionByDefault?.SSEAlgorithm; + if (ssealgo === 'AES256') return BucketEncryption.SSEAlgorithm_AES256; + if (ssealgo === 'aws:kms') return BucketEncryption.SSEAlgorithm_aws_kms; + } + return BucketEncryption.NO_ENCRYPTION; + } catch (e) { + if (e.code === 'NoSuchBucket') { + return BucketEncryption.DOES_NOT_EXIST; + } + if (e.code === 'ServerSideEncryptionConfigurationNotFoundError') { + return BucketEncryption.NO_ENCRYPTION; + } + + if (['AccessDenied', 'AllAccessDisabled'].includes(e.code)) { + return BucketEncryption.ACCES_DENIED; + } + return BucketEncryption.NO_ENCRYPTION; + } + } +} + +async function cached(cache: Map, key: A, factory: (x: A) => Promise): Promise { + if (cache.has(key)) { + return cache.get(key)!; + } + + const fresh = await factory(key); + cache.set(key, fresh); + return fresh; +} \ No newline at end of file diff --git a/packages/cdk-assets/lib/publishing.ts b/packages/cdk-assets/lib/publishing.ts index 528daee539986..4cb77508d020f 100644 --- a/packages/cdk-assets/lib/publishing.ts +++ b/packages/cdk-assets/lib/publishing.ts @@ -1,5 +1,6 @@ import { AssetManifest, IManifestEntry } from './asset-manifest'; import { IAws } from './aws'; +import { IHandlerHost } from './private/asset-handler'; import { makeAssetHandler } from './private/handlers'; import { EventType, IPublishProgress, IPublishProgressListener } from './progress'; @@ -67,6 +68,12 @@ export class AssetPublishing implements IPublishProgress { public async publish(): Promise { const self = this; + const handlerHost: IHandlerHost = { + aws: this.options.aws, + get aborted() { return self.aborted; }, + emitMessage(t, m) { self.progressEvent(t, m); }, + }; + for (const asset of this.assets) { if (this.aborted) { break; } this.currentAsset = asset; @@ -74,11 +81,7 @@ export class AssetPublishing implements IPublishProgress { try { if (this.progressEvent(EventType.START, `Publishing ${asset.id}`)) { break; } - const handler = makeAssetHandler(this.manifest, asset, { - aws: this.options.aws, - get aborted() { return self.aborted; }, - emitMessage(t, m) { self.progressEvent(t, m); }, - }); + const handler = makeAssetHandler(this.manifest, asset, handlerHost); await handler.publish(); if (this.aborted) { diff --git a/packages/cdk-assets/test/files.test.ts b/packages/cdk-assets/test/files.test.ts index 36e6d3f66b6a4..a2cbb592263dc 100644 --- a/packages/cdk-assets/test/files.test.ts +++ b/packages/cdk-assets/test/files.test.ts @@ -3,7 +3,7 @@ jest.mock('child_process'); import { Manifest } from '@aws-cdk/cloud-assembly-schema'; import * as mockfs from 'mock-fs'; import { AssetManifest, AssetPublishing } from '../lib'; -import { mockAws, mockedApiResult, mockUpload } from './mock-aws'; +import { mockAws, mockedApiFailure, mockedApiResult, mockUpload } from './mock-aws'; import { mockSpawn } from './mock-child_process'; const ABS_PATH = '/simple/cdk.out/some_external_file'; @@ -126,7 +126,6 @@ test('Do nothing if file already exists', async () => { const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws }); aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: [{ Key: 'some_key' }] }); - await pub.publish(); expect(aws.mockS3.listObjectsV2).toHaveBeenCalledWith(expect.objectContaining({ @@ -153,6 +152,100 @@ test('upload file if new (list returns other key)', async () => { // We'll just have to assume the contents are correct }); +test('upload with server side encryption AES256 header', async () => { + const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws }); + + aws.mockS3.getBucketEncryption = mockedApiResult({ + ServerSideEncryptionConfiguration: { + Rules: [ + { + ApplyServerSideEncryptionByDefault: { + SSEAlgorithm: 'AES256', + }, + BucketKeyEnabled: false, + }, + ], + }, + }); + aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: [{ Key: 'some_key.but_not_the_one' }] }); + aws.mockS3.upload = mockUpload('FILE_CONTENTS'); + + await pub.publish(); + + expect(aws.mockS3.upload).toHaveBeenCalledWith(expect.objectContaining({ + Bucket: 'some_bucket', + Key: 'some_key', + ContentType: 'application/octet-stream', + ServerSideEncryption: 'AES256', + })); + + // We'll just have to assume the contents are correct +}); + +test('upload with server side encryption aws:kms header', async () => { + const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws }); + + aws.mockS3.getBucketEncryption = mockedApiResult({ + ServerSideEncryptionConfiguration: { + Rules: [ + { + ApplyServerSideEncryptionByDefault: { + SSEAlgorithm: 'aws:kms', + }, + BucketKeyEnabled: false, + }, + ], + }, + }); + + aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: [{ Key: 'some_key.but_not_the_one' }] }); + aws.mockS3.upload = mockUpload('FILE_CONTENTS'); + + await pub.publish(); + + expect(aws.mockS3.upload).toHaveBeenCalledWith(expect.objectContaining({ + Bucket: 'some_bucket', + Key: 'some_key', + ContentType: 'application/octet-stream', + ServerSideEncryption: 'aws:kms', + })); + + // We'll just have to assume the contents are correct +}); + +test('will only read bucketEncryption once even for multiple assets', async () => { + const pub = new AssetPublishing(AssetManifest.fromPath('/types/cdk.out'), { aws }); + + aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: [{ Key: 'some_key.but_not_the_one' }] }); + aws.mockS3.upload = mockUpload('FILE_CONTENTS'); + + await pub.publish(); + + expect(aws.mockS3.upload).toHaveBeenCalledTimes(2); + expect(aws.mockS3.getBucketEncryption).toHaveBeenCalledTimes(1); +}); + +test('no server side encryption header if access denied for bucket encryption', async () => { + const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws }); + + aws.mockS3.getBucketEncryption = mockedApiFailure('AccessDenied', 'Access Denied'); + + aws.mockS3.listObjectsV2 = mockedApiResult({ Contents: [{ Key: 'some_key.but_not_the_one' }] }); + aws.mockS3.upload = mockUpload('FILE_CONTENTS'); + + await pub.publish(); + + expect(aws.mockS3.upload).toHaveBeenCalledWith(expect.not.objectContaining({ + ServerSideEncryption: 'aws:kms', + })); + + expect(aws.mockS3.upload).toHaveBeenCalledWith(expect.not.objectContaining({ + ServerSideEncryption: 'AES256', + })); + + // We'll just have to assume the contents are correct +}); + test('correctly looks up content type', async () => { const pub = new AssetPublishing(AssetManifest.fromPath('/types/cdk.out'), { aws }); diff --git a/packages/cdk-assets/test/mock-aws.ts b/packages/cdk-assets/test/mock-aws.ts index 2d40f7c756a28..fcf2fdffa6447 100644 --- a/packages/cdk-assets/test/mock-aws.ts +++ b/packages/cdk-assets/test/mock-aws.ts @@ -8,6 +8,7 @@ export function mockAws() { // Sane defaults which can be overridden mockS3.getBucketLocation = mockedApiResult({}); + mockS3.getBucketEncryption = mockedApiResult({}); mockEcr.describeRepositories = mockedApiResult({ repositories: [ { From 3b5b97ac1f972f53240798df19af43d85ebf6f13 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Fri, 26 Nov 2021 14:10:28 +0000 Subject: [PATCH 25/82] fix(apigatewayv2): integration class does not render an integration resource (#17729) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Routes on APIGateway V2 can integrate with different backends. This is achieved by creating the CFN resource `AWS::ApiGatewayV2::Integration` that is then referenced in the resource for the Route. Currently, the `IHttpRouteIntegration` (and `IWebSocketRouteIntegration`) interface represents a unique backend that a route can integrate with, using the CDK "bind" pattern. An integration can be bound to any number of routes but should be rendered into a single instance of `AWS::ApiGatewayV2::Integration` resource. To achieve this currently, the `HttpApi` (and `WebSocketApi`) class holds a cache of all integrations defined against its routes. This is the wrong level of caching and causes a number of problems. 1. We rely on the configuration of the `AWS::ApiGateway::Integration` resource to determine if one already exists. This means that two instances of `IHttpRouteIntegration` can result in rendering only one instance of `AWS::ApiGateway::Integration` resource. Users may want to intentionally generate multiple instances of `AWS::ApiGateway::Integration` classes with the same configuration. Taking away this power with CDK "magic" is just confusing. 2. Currently, we allow using the same instance of `IHttpRouteIntegration` (or `IWebSocketRouteIntegration`) to be bound to routes in different `HttpApi`. When bound to the route, the CDK renders an instance of `AWS::ApiGatewayV2::Integration` for each API. This is another "magic" that has the potential for user confusion and bugs. The solution is to KeepItSimple™. Remove the API level caching and simply cache at the level of each integration. This ensures that each instance of `HttpRouteIntegration` (previously `IHttpRouteIntegration`) renders to exactly one instance of `AWS::ApiGatewayV2::Integration`. Disallow using the same instance of `HttpRouteIntegration` across different instances of `HttpApi`. fixes #13213 BREAKING CHANGE: The interface `IHttpRouteIntegration` is replaced by the abstract class `HttpRouteIntegration`. * **apigatewayv2:** The interface `IWebSocketRouteIntegration` is now replaced by the abstract class `WebSocketRouteIntegration`. * **apigatewayv2:** Previously, we allowed the usage of integration classes to be used with routes defined in multiple `HttpApi` instances (or `WebSocketApi` instances). This is now disallowed, and separate instances must be created for each instance of `HttpApi` or `WebSocketApi`. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../test/http/jwt.test.ts | 4 +- .../test/http/lambda.test.ts | 4 +- .../test/http/user-pool.test.ts | 4 +- .../lib/http/http-proxy.ts | 5 +- .../lib/http/lambda.ts | 5 +- .../lib/http/private/integration.ts | 4 +- .../lib/websocket/lambda.ts | 8 ++-- .../aws-apigatewayv2/lib/common/base.ts | 5 -- .../@aws-cdk/aws-apigatewayv2/lib/http/api.ts | 35 +------------- .../aws-apigatewayv2/lib/http/integration.ts | 42 ++++++++++++++-- .../aws-apigatewayv2/lib/http/route.ts | 10 ++-- .../lib/private/integration-cache.ts | 29 ----------- .../aws-apigatewayv2/lib/websocket/api.ts | 25 ---------- .../lib/websocket/integration.ts | 37 ++++++++++++-- .../aws-apigatewayv2/lib/websocket/route.ts | 10 ++-- .../aws-apigatewayv2/test/http/api.test.ts | 4 +- .../aws-apigatewayv2/test/http/route.test.ts | 48 +++++++++---------- .../test/websocket/api.test.ts | 4 +- .../test/websocket/route.test.ts | 44 ++++++++++++++++- 19 files changed, 172 insertions(+), 155 deletions(-) delete mode 100644 packages/@aws-cdk/aws-apigatewayv2/lib/private/integration-cache.ts diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts index f97e3d4c24d74..c65642d8df4d3 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts @@ -1,5 +1,5 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, IHttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, HttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Stack } from '@aws-cdk/core'; import { HttpJwtAuthorizer } from '../../lib'; @@ -59,7 +59,7 @@ describe('HttpJwtAuthorizer', () => { }); }); -class DummyRouteIntegration implements IHttpRouteIntegration { +class DummyRouteIntegration extends HttpRouteIntegration { public bind(_: HttpRouteIntegrationBindOptions) { return { payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts index c9fdf62c17d57..28b007dafd359 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts @@ -1,5 +1,5 @@ import { Match, Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, IHttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, HttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; import { Duration, Stack } from '@aws-cdk/core'; import { HttpLambdaAuthorizer, HttpLambdaResponseType } from '../../lib'; @@ -170,7 +170,7 @@ describe('HttpLambdaAuthorizer', () => { }); }); -class DummyRouteIntegration implements IHttpRouteIntegration { +class DummyRouteIntegration extends HttpRouteIntegration { public bind(_: HttpRouteIntegrationBindOptions) { return { payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts index 127b389b8b0f2..7189c060b877b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts @@ -1,5 +1,5 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, IHttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, HttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { UserPool } from '@aws-cdk/aws-cognito'; import { Stack } from '@aws-cdk/core'; import { HttpUserPoolAuthorizer } from '../../lib'; @@ -112,7 +112,7 @@ describe('HttpUserPoolAuthorizer', () => { }); }); -class DummyRouteIntegration implements IHttpRouteIntegration { +class DummyRouteIntegration extends HttpRouteIntegration { public bind(_: HttpRouteIntegrationBindOptions) { return { payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts index 70873c9582fc8..879912ee881cf 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts @@ -3,7 +3,7 @@ import { HttpRouteIntegrationBindOptions, HttpRouteIntegrationConfig, HttpMethod, - IHttpRouteIntegration, + HttpRouteIntegration, ParameterMapping, PayloadFormatVersion, } from '@aws-cdk/aws-apigatewayv2'; @@ -34,8 +34,9 @@ export interface HttpProxyIntegrationProps { /** * The HTTP Proxy integration resource for HTTP API */ -export class HttpProxyIntegration implements IHttpRouteIntegration { +export class HttpProxyIntegration extends HttpRouteIntegration { constructor(private readonly props: HttpProxyIntegrationProps) { + super(); } public bind(_: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts index 358263f724bda..ff5750da71077 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts @@ -2,7 +2,7 @@ import { HttpIntegrationType, HttpRouteIntegrationBindOptions, HttpRouteIntegrationConfig, - IHttpRouteIntegration, + HttpRouteIntegration, PayloadFormatVersion, ParameterMapping, } from '@aws-cdk/aws-apigatewayv2'; @@ -37,9 +37,10 @@ export interface LambdaProxyIntegrationProps { /** * The Lambda Proxy integration resource for HTTP API */ -export class LambdaProxyIntegration implements IHttpRouteIntegration { +export class LambdaProxyIntegration extends HttpRouteIntegration { constructor(private readonly props: LambdaProxyIntegrationProps) { + super(); } public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/private/integration.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/private/integration.ts index 6d32b22794722..c7e671f59879c 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/private/integration.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/private/integration.ts @@ -3,7 +3,7 @@ import { HttpIntegrationType, HttpRouteIntegrationBindOptions, HttpRouteIntegrationConfig, - IHttpRouteIntegration, + HttpRouteIntegration, PayloadFormatVersion, HttpMethod, IVpcLink, @@ -37,7 +37,7 @@ export interface VpcLinkConfigurationOptions { * * @internal */ -export abstract class HttpPrivateIntegration implements IHttpRouteIntegration { +export abstract class HttpPrivateIntegration extends HttpRouteIntegration { protected httpMethod = HttpMethod.ANY; protected payloadFormatVersion = PayloadFormatVersion.VERSION_1_0; // 1.0 is required and is the only supported format protected integrationType = HttpIntegrationType.HTTP_PROXY; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts index 8dedb470ce6af..8e41b30d65295 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts @@ -1,5 +1,5 @@ import { - IWebSocketRouteIntegration, + WebSocketRouteIntegration, WebSocketIntegrationType, WebSocketRouteIntegrationBindOptions, WebSocketRouteIntegrationConfig, @@ -21,8 +21,10 @@ export interface LambdaWebSocketIntegrationProps { /** * Lambda WebSocket Integration */ -export class LambdaWebSocketIntegration implements IWebSocketRouteIntegration { - constructor(private props: LambdaWebSocketIntegrationProps) {} +export class LambdaWebSocketIntegration extends WebSocketRouteIntegration { + constructor(private props: LambdaWebSocketIntegrationProps) { + super(); + } bind(options: WebSocketRouteIntegrationBindOptions): WebSocketRouteIntegrationConfig { const route = options.route; diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts index 26d9ca64e391a..26342c75b5a0f 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts @@ -1,6 +1,5 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { Resource } from '@aws-cdk/core'; -import { IntegrationCache } from '../private/integration-cache'; import { IApi } from './api'; import { ApiMapping } from './api-mapping'; import { DomainMappingOptions, IStage } from './stage'; @@ -12,10 +11,6 @@ import { DomainMappingOptions, IStage } from './stage'; export abstract class ApiBase extends Resource implements IApi { abstract readonly apiId: string; abstract readonly apiEndpoint: string; - /** - * @internal - */ - protected _integrationCache: IntegrationCache = new IntegrationCache(); public metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric { return new cloudwatch.Metric({ diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index 32dfe0a0c2120..bf24c31dbaeca 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -6,7 +6,7 @@ import { IApi } from '../common/api'; import { ApiBase } from '../common/base'; import { DomainMappingOptions } from '../common/stage'; import { IHttpRouteAuthorizer } from './authorizer'; -import { IHttpRouteIntegration, HttpIntegration, HttpRouteIntegrationConfig } from './integration'; +import { HttpRouteIntegration } from './integration'; import { BatchHttpRouteOptions, HttpMethod, HttpRoute, HttpRouteKey } from './route'; import { IHttpStage, HttpStage, HttpStageOptions } from './stage'; import { VpcLink, VpcLinkProps } from './vpc-link'; @@ -71,12 +71,6 @@ export interface IHttpApi extends IApi { * Add a new VpcLink */ addVpcLink(options: VpcLinkProps): VpcLink - - /** - * Add a http integration - * @internal - */ - _addIntegration(scope: Construct, config: HttpRouteIntegrationConfig): HttpIntegration; } /** @@ -99,7 +93,7 @@ export interface HttpApiProps { * An integration that will be configured on the catch-all route ($default). * @default - none */ - readonly defaultIntegration?: IHttpRouteIntegration; + readonly defaultIntegration?: HttpRouteIntegration; /** * Whether a default stage and deployment should be automatically created. @@ -286,31 +280,6 @@ abstract class HttpApiBase extends ApiBase implements IHttpApi { // note that th return vpcLink; } - - /** - * @internal - */ - public _addIntegration(scope: Construct, config: HttpRouteIntegrationConfig): HttpIntegration { - const { configHash, integration: existingIntegration } = this._integrationCache.getIntegration(scope, config); - if (existingIntegration) { - return existingIntegration as HttpIntegration; - } - - const integration = new HttpIntegration(scope, `HttpIntegration-${configHash}`, { - httpApi: this, - integrationType: config.type, - integrationUri: config.uri, - method: config.method, - connectionId: config.connectionId, - connectionType: config.connectionType, - payloadFormatVersion: config.payloadFormatVersion, - secureServerName: config.secureServerName, - parameterMapping: config.parameterMapping, - }); - this._integrationCache.saveIntegration(scope, config, integration); - - return integration; - } } /** diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts index df0cf84c13da0..6865875af5c80 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts @@ -1,5 +1,6 @@ /* eslint-disable quotes */ -import { Resource } from '@aws-cdk/core'; +import * as crypto from 'crypto'; +import { Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnIntegration } from '../apigatewayv2.generated'; import { IIntegration } from '../common'; @@ -191,11 +192,46 @@ export interface HttpRouteIntegrationBindOptions { /** * The interface that various route integration classes will inherit. */ -export interface IHttpRouteIntegration { +export abstract class HttpRouteIntegration { + private integration?: HttpIntegration; + + /** + * Internal method called when binding this integration to the route. + * @internal + */ + public _bindToRoute(options: HttpRouteIntegrationBindOptions): { readonly integrationId: string } { + if (this.integration && this.integration.httpApi.node.addr !== options.route.httpApi.node.addr) { + throw new Error('A single integration cannot be associated with multiple APIs.'); + } + + if (!this.integration) { + const config = this.bind(options); + + this.integration = new HttpIntegration(options.scope, `HttpIntegration-${hash(config)}`, { + httpApi: options.route.httpApi, + integrationType: config.type, + integrationUri: config.uri, + method: config.method, + connectionId: config.connectionId, + connectionType: config.connectionType, + payloadFormatVersion: config.payloadFormatVersion, + secureServerName: config.secureServerName, + parameterMapping: config.parameterMapping, + }); + + function hash(x: any) { + const stringifiedConfig = JSON.stringify(Stack.of(options.scope).resolve(x)); + const configHash = crypto.createHash('md5').update(stringifiedConfig).digest('hex'); + return configHash; + } + } + return { integrationId: this.integration.integrationId }; + } + /** * Bind this integration to the route. */ - bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig; + public abstract bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig; } /** diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts index ecc54b7f6acd9..7894defce6077 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts @@ -4,7 +4,7 @@ import { CfnRoute, CfnRouteProps } from '../apigatewayv2.generated'; import { IRoute } from '../common'; import { IHttpApi } from './api'; import { IHttpRouteAuthorizer } from './authorizer'; -import { IHttpRouteIntegration } from './integration'; +import { HttpRouteIntegration } from './integration'; /** * Represents a Route for an HTTP API. @@ -88,7 +88,7 @@ export interface BatchHttpRouteOptions { /** * The integration to be configured on this route. */ - readonly integration: IHttpRouteIntegration; + readonly integration: HttpRouteIntegration; } /** @@ -149,13 +149,11 @@ export class HttpRoute extends Resource implements IHttpRoute { this.httpApi = props.httpApi; this.path = props.routeKey.path; - const config = props.integration.bind({ + const config = props.integration._bindToRoute({ route: this, scope: this, }); - const integration = props.httpApi._addIntegration(this, config); - const authBindResult = props.authorizer ? props.authorizer.bind({ route: this, scope: this.httpApi instanceof Construct ? this.httpApi : this, // scope under the API if it's not imported @@ -181,7 +179,7 @@ export class HttpRoute extends Resource implements IHttpRoute { const routeProps: CfnRouteProps = { apiId: props.httpApi.apiId, routeKey: props.routeKey.key, - target: `integrations/${integration.integrationId}`, + target: `integrations/${config.integrationId}`, authorizerId: authBindResult?.authorizerId, authorizationType: authBindResult?.authorizationType ?? 'NONE', // must be explicitly NONE (not undefined) for stack updates to work correctly authorizationScopes, diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/private/integration-cache.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/private/integration-cache.ts deleted file mode 100644 index 2401d28e20d2d..0000000000000 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/private/integration-cache.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as crypto from 'crypto'; -import { Stack } from '@aws-cdk/core'; -import { Construct } from 'constructs'; -import { IIntegration } from '../common/integration'; -import { HttpRouteIntegrationConfig } from '../http'; -import { WebSocketRouteIntegrationConfig } from '../websocket'; - -type IntegrationConfig = HttpRouteIntegrationConfig | WebSocketRouteIntegrationConfig; - -export class IntegrationCache { - private integrations: Record = {}; - - getIntegration(scope: Construct, config: IntegrationConfig) { - const configHash = this.integrationConfigHash(scope, config); - const integration = this.integrations[configHash]; - return { configHash, integration }; - } - - saveIntegration(scope: Construct, config: IntegrationConfig, integration: IIntegration) { - const configHash = this.integrationConfigHash(scope, config); - this.integrations[configHash] = integration; - } - - private integrationConfigHash(scope: Construct, config: IntegrationConfig): string { - const stringifiedConfig = JSON.stringify(Stack.of(scope).resolve(config)); - const configHash = crypto.createHash('md5').update(stringifiedConfig).digest('hex'); - return configHash; - } -} diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts index fdcfbdbce6d30..d78d16842e295 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts @@ -4,18 +4,12 @@ import { Construct } from 'constructs'; import { CfnApi } from '../apigatewayv2.generated'; import { IApi } from '../common/api'; import { ApiBase } from '../common/base'; -import { WebSocketRouteIntegrationConfig, WebSocketIntegration } from './integration'; import { WebSocketRoute, WebSocketRouteOptions } from './route'; /** * Represents a WebSocket API */ export interface IWebSocketApi extends IApi { - /** - * Add a websocket integration - * @internal - */ - _addIntegration(scope: Construct, config: WebSocketRouteIntegrationConfig): WebSocketIntegration } /** @@ -100,25 +94,6 @@ export class WebSocketApi extends ApiBase implements IWebSocketApi { } } - /** - * @internal - */ - public _addIntegration(scope: Construct, config: WebSocketRouteIntegrationConfig): WebSocketIntegration { - const { configHash, integration: existingIntegration } = this._integrationCache.getIntegration(scope, config); - if (existingIntegration) { - return existingIntegration as WebSocketIntegration; - } - - const integration = new WebSocketIntegration(scope, `WebSocketIntegration-${configHash}`, { - webSocketApi: this, - integrationType: config.type, - integrationUri: config.uri, - }); - this._integrationCache.saveIntegration(scope, config, integration); - - return integration; - } - /** * Add a new route */ diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/integration.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/integration.ts index e75bd00b63d95..3c59269b474f6 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/integration.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/integration.ts @@ -1,4 +1,5 @@ -import { Resource } from '@aws-cdk/core'; +import * as crypto from 'crypto'; +import { Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnIntegration } from '../apigatewayv2.generated'; import { IIntegration } from '../common'; @@ -87,11 +88,41 @@ export interface WebSocketRouteIntegrationBindOptions { /** * The interface that various route integration classes will inherit. */ -export interface IWebSocketRouteIntegration { +export abstract class WebSocketRouteIntegration { + private integration?: WebSocketIntegration; + + /** + * Internal method called when binding this integration to the route. + * @internal + */ + public _bindToRoute(options: WebSocketRouteIntegrationBindOptions): { readonly integrationId: string } { + if (this.integration && this.integration.webSocketApi.node.addr !== options.route.webSocketApi.node.addr) { + throw new Error('A single integration cannot be associated with multiple APIs.'); + } + + if (!this.integration) { + const config = this.bind(options); + + this.integration = new WebSocketIntegration(options.scope, `WebSocketIntegration-${hash(config)}`, { + webSocketApi: options.route.webSocketApi, + integrationType: config.type, + integrationUri: config.uri, + }); + + function hash(x: any) { + const stringifiedConfig = JSON.stringify(Stack.of(options.scope).resolve(x)); + const configHash = crypto.createHash('md5').update(stringifiedConfig).digest('hex'); + return configHash; + } + } + + return { integrationId: this.integration.integrationId }; + } + /** * Bind this integration to the route. */ - bind(options: WebSocketRouteIntegrationBindOptions): WebSocketRouteIntegrationConfig; + public abstract bind(options: WebSocketRouteIntegrationBindOptions): WebSocketRouteIntegrationConfig; } /** diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/route.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/route.ts index 0588889a603bc..38316c6449c13 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/route.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/route.ts @@ -3,7 +3,7 @@ import { Construct } from 'constructs'; import { CfnRoute } from '../apigatewayv2.generated'; import { IRoute } from '../common'; import { IWebSocketApi } from './api'; -import { IWebSocketRouteIntegration } from './integration'; +import { WebSocketRouteIntegration } from './integration'; /** * Represents a Route for an WebSocket API. @@ -28,7 +28,7 @@ export interface WebSocketRouteOptions { /** * The integration to be configured on this route. */ - readonly integration: IWebSocketRouteIntegration; + readonly integration: WebSocketRouteIntegration; } @@ -67,17 +67,15 @@ export class WebSocketRoute extends Resource implements IWebSocketRoute { this.webSocketApi = props.webSocketApi; this.routeKey = props.routeKey; - const config = props.integration.bind({ + const config = props.integration._bindToRoute({ route: this, scope: this, }); - const integration = props.webSocketApi._addIntegration(this, config); - const route = new CfnRoute(this, 'Resource', { apiId: props.webSocketApi.apiId, routeKey: props.routeKey, - target: `integrations/${integration.integrationId}`, + target: `integrations/${config.integrationId}`, }); this.routeId = route.ref; } diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts index 200933eefbca9..658b139193612 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts @@ -6,7 +6,7 @@ import { Duration, Stack } from '@aws-cdk/core'; import { CorsHttpMethod, DomainName, HttpApi, HttpAuthorizer, HttpIntegrationType, HttpMethod, HttpRouteAuthorizerBindOptions, HttpRouteAuthorizerConfig, - HttpRouteIntegrationBindOptions, HttpRouteIntegrationConfig, IHttpRouteAuthorizer, IHttpRouteIntegration, HttpNoneAuthorizer, PayloadFormatVersion, + HttpRouteIntegrationBindOptions, HttpRouteIntegrationConfig, IHttpRouteAuthorizer, HttpRouteIntegration, HttpNoneAuthorizer, PayloadFormatVersion, } from '../../lib'; describe('HttpApi', () => { @@ -531,7 +531,7 @@ describe('HttpApi', () => { }); }); -class DummyRouteIntegration implements IHttpRouteIntegration { +class DummyRouteIntegration extends HttpRouteIntegration { public bind(_: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { return { payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts index 75d744b6b5bcc..b5ddae7919a62 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts @@ -2,7 +2,7 @@ import { Template } from '@aws-cdk/assertions'; import { Stack, App } from '@aws-cdk/core'; import { HttpApi, HttpAuthorizer, HttpAuthorizerType, HttpConnectionType, HttpIntegrationType, HttpMethod, HttpRoute, - HttpRouteAuthorizerBindOptions, HttpRouteAuthorizerConfig, HttpRouteIntegrationConfig, HttpRouteKey, IHttpRouteAuthorizer, IHttpRouteIntegration, + HttpRouteAuthorizerBindOptions, HttpRouteAuthorizerConfig, HttpRouteIntegrationConfig, HttpRouteKey, IHttpRouteAuthorizer, HttpRouteIntegration, MappingValue, ParameterMapping, PayloadFormatVersion, @@ -81,42 +81,42 @@ describe('HttpRoute', () => { Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::Integration', 1); }); - test('integration can be used across HttpApis', () => { + test('integration cannot be used across HttpApis', () => { // GIVEN const integration = new DummyIntegration(); // WHEN - const stack1 = new Stack(); - const httpApi1 = new HttpApi(stack1, 'HttpApi1'); + const stack = new Stack(); + const httpApi1 = new HttpApi(stack, 'HttpApi1'); + const httpApi2 = new HttpApi(stack, 'HttpApi2'); - new HttpRoute(stack1, 'HttpRoute1', { + new HttpRoute(stack, 'HttpRoute1', { httpApi: httpApi1, integration, routeKey: HttpRouteKey.with('/books', HttpMethod.GET), }); - new HttpRoute(stack1, 'HttpRoute2', { - httpApi: httpApi1, - integration, - routeKey: HttpRouteKey.with('/books', HttpMethod.POST), - }); - - const stack2 = new Stack(); - const httpApi2 = new HttpApi(stack2, 'HttpApi2'); - new HttpRoute(stack2, 'HttpRoute1', { + expect(() => new HttpRoute(stack, 'HttpRoute2', { httpApi: httpApi2, integration, routeKey: HttpRouteKey.with('/books', HttpMethod.GET), + })).toThrow(/cannot be associated with multiple APIs/); + }); + + test('associating integrations in different APIs creates separate AWS::ApiGatewayV2::Integration', () => { + const stack = new Stack(); + + const api = new HttpApi(stack, 'HttpApi'); + api.addRoutes({ + path: '/books', + integration: new DummyIntegration(), }); - new HttpRoute(stack2, 'HttpRoute2', { - httpApi: httpApi2, - integration, - routeKey: HttpRouteKey.with('/books', HttpMethod.POST), + api.addRoutes({ + path: '/magazines', + integration: new DummyIntegration(), }); - // THEN - Template.fromStack(stack1).resourceCountIs('AWS::ApiGatewayV2::Integration', 1); - Template.fromStack(stack2).resourceCountIs('AWS::ApiGatewayV2::Integration', 1); + Template.fromStack(stack).hasResource('AWS::ApiGatewayV2::Integration', 2); }); test('route defined in a separate stack does not create cycles', () => { @@ -167,7 +167,7 @@ describe('HttpRoute', () => { const stack = new Stack(); const httpApi = new HttpApi(stack, 'HttpApi'); - class PrivateIntegration implements IHttpRouteIntegration { + class PrivateIntegration extends HttpRouteIntegration { public bind(): HttpRouteIntegrationConfig { return { method: HttpMethod.ANY, @@ -212,7 +212,7 @@ describe('HttpRoute', () => { const stack = new Stack(); const httpApi = new HttpApi(stack, 'HttpApi'); - class PrivateIntegration implements IHttpRouteIntegration { + class PrivateIntegration extends HttpRouteIntegration { public bind(): HttpRouteIntegrationConfig { return { method: HttpMethod.ANY, @@ -310,7 +310,7 @@ describe('HttpRoute', () => { }); }); -class DummyIntegration implements IHttpRouteIntegration { +class DummyIntegration extends HttpRouteIntegration { public bind(): HttpRouteIntegrationConfig { return { type: HttpIntegrationType.HTTP_PROXY, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts index 24337a3f7c3f2..0a5e7c05b706d 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts @@ -2,7 +2,7 @@ import { Match, Template } from '@aws-cdk/assertions'; import { User } from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; import { - IWebSocketRouteIntegration, WebSocketApi, WebSocketIntegrationType, + WebSocketRouteIntegration, WebSocketApi, WebSocketIntegrationType, WebSocketRouteIntegrationBindOptions, WebSocketRouteIntegrationConfig, } from '../../lib'; @@ -126,7 +126,7 @@ describe('WebSocketApi', () => { }); }); -class DummyIntegration implements IWebSocketRouteIntegration { +class DummyIntegration extends WebSocketRouteIntegration { bind(_options: WebSocketRouteIntegrationBindOptions): WebSocketRouteIntegrationConfig { return { type: WebSocketIntegrationType.AWS_PROXY, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts index 07eadc5300a85..512006fb8a2a4 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts @@ -1,7 +1,7 @@ import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; import { - IWebSocketRouteIntegration, WebSocketApi, WebSocketIntegrationType, + WebSocketRouteIntegration, WebSocketApi, WebSocketIntegrationType, WebSocketRoute, WebSocketRouteIntegrationBindOptions, WebSocketRouteIntegrationConfig, } from '../../lib'; @@ -41,10 +41,50 @@ describe('WebSocketRoute', () => { IntegrationUri: 'some-uri', }); }); + + test('integration cannot be used across WebSocketApis', () => { + // GIVEN + const integration = new DummyIntegration(); + + // WHEN + const stack = new Stack(); + const webSocketApi1 = new WebSocketApi(stack, 'WebSocketApi1'); + const webSocketApi2 = new WebSocketApi(stack, 'WebSocketApi2'); + + new WebSocketRoute(stack, 'WebSocketRoute1', { + webSocketApi: webSocketApi1, + integration, + routeKey: 'route', + }); + + expect(() => new WebSocketRoute(stack, 'WebSocketRoute2', { + webSocketApi: webSocketApi2, + integration, + routeKey: 'route', + })).toThrow(/cannot be associated with multiple APIs/); + }); + + test('associating integrations in different APIs creates separate AWS::ApiGatewayV2::Integration', () => { + const stack = new Stack(); + + const api = new WebSocketApi(stack, 'WebSocketApi'); + new WebSocketRoute(stack, 'WebSocketRoute1', { + webSocketApi: api, + integration: new DummyIntegration(), + routeKey: '/books', + }); + new WebSocketRoute(stack, 'WebSocketRoute2', { + webSocketApi: api, + integration: new DummyIntegration(), + routeKey: '/magazines', + }); + + Template.fromStack(stack).hasResource('AWS::ApiGatewayV2::Integration', 2); + }); }); -class DummyIntegration implements IWebSocketRouteIntegration { +class DummyIntegration extends WebSocketRouteIntegration { bind(_options: WebSocketRouteIntegrationBindOptions): WebSocketRouteIntegrationConfig { return { type: WebSocketIntegrationType.AWS_PROXY, From 87fd60f047e9f1994459de874b54e901d1871e6e Mon Sep 17 00:00:00 2001 From: Ben Briggs Date: Fri, 26 Nov 2021 15:08:35 +0000 Subject: [PATCH 26/82] feat(lambda): function construct exposes configured timeout (#17594) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supersedes https://github.com/aws/aws-cdk/pull/17000. I didn't realise that the "allow edits by maintainers" was not supported under organisation accounts, so I've forked under my account instead. Otherwise, these changes are the same as the linked PR. Thanks! 👍 ---- *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-lambda/README.md | 32 ++++++++++++++++++ packages/@aws-cdk/aws-lambda/lib/function.ts | 7 ++++ .../@aws-cdk/aws-lambda/test/function.test.ts | 33 +++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index bb42d0811994d..13a5b81dd35e0 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -119,6 +119,38 @@ myRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName("service-role myRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaVPCAccessExecutionRole")); // only required if your function lives in a VPC ``` +## Function Timeout + +AWS Lambda functions have a default timeout of 3 seconds, but this can be increased +up to 15 minutes. The timeout is available as a property of `Function` so that +you can reference it elsewhere in your stack. For instance, you could use it to create +a CloudWatch alarm to report when your function timed out: + +```ts +import * as cdk from '@aws-cdk/core'; +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; + +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + timeout: cdk.Duration.minutes(5), +}); + +if (fn.timeout) { + new cloudwatch.Alarm(this, `MyAlarm`, { + metric: fn.metricDuration().with({ + statistic: 'Maximum', + }), + evaluationPeriods: 1, + datapointsToAlarm: 1, + threshold: fn.timeout.toMilliseconds(), + treatMissingData: cloudwatch.TreatMissingData.IGNORE, + alarmName: 'My Lambda Timeout', + }); +} +``` + ## Resource-based Policies AWS Lambda supports resource-based policies for controlling access to Lambda diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index c3936287a0990..564e45d5a9460 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -577,6 +577,12 @@ export class Function extends FunctionBase { * The architecture of this Lambda Function (this is an optional attribute and defaults to X86_64). */ public readonly architecture?: Architecture; + + /** + * The timeout configured for this lambda. + */ + public readonly timeout?: Duration; + public readonly permissionsNode = this.node; @@ -725,6 +731,7 @@ export class Function extends FunctionBase { }); this.runtime = props.runtime; + this.timeout = props.timeout; this.architecture = props.architecture; diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index 965f41aed66f7..bd25c33b7a109 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -1842,6 +1842,39 @@ describe('function', () => { }); }); + describe('lambda.Function timeout', () => { + test('should be a cdk.Duration when defined', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const { timeout } = new lambda.Function(stack, 'MyFunction', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + timeout: cdk.Duration.minutes(2), + }); + + // THEN + expect(timeout).toEqual(cdk.Duration.minutes(2)); + }); + + test('should be optional', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const { timeout } = new lambda.Function(stack, 'MyFunction', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + }); + + // THEN + expect(timeout).not.toBeDefined(); + }); + }); + describe('currentVersion', () => { // see test.function-hash.ts for more coverage for this test('logical id of version is based on the function hash', () => { From f17f29e94265eb450d8f11bdbdbe719f3e511ea2 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Fri, 26 Nov 2021 16:51:28 +0100 Subject: [PATCH 27/82] fix(codepipeline): cross-env pipeline cannot be created in `Stage` (#17730) Because a cross-environment pipeline cannot be created in `Stage`, it cannot be deployed using CDK Pipelines. The error is: ``` Error: You cannot add a dependency from 'AAA' (in Stage 'BBB') to 'CCC' (in the App): dependency cannot cross stage boundaries ``` Root cause is that the `Pipeline` construct creates a support stack in the `App` scope, which is outside its containing `Stage`, and hence the dependency crosses stage boundaries. Fixes #17643. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-codepipeline/lib/pipeline.ts | 28 +++++++++++++------ .../aws-codepipeline/test/cross-env.test.ts | 20 +++++++++---- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 1dc98ccca51d4..0866d3436bb03 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -4,8 +4,18 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; import { - App, ArnFormat, BootstraplessSynthesizer, DefaultStackSynthesizer, - IStackSynthesizer, Lazy, Names, PhysicalName, RemovalPolicy, Resource, Stack, Token, + ArnFormat, + BootstraplessSynthesizer, + DefaultStackSynthesizer, + IStackSynthesizer, + Lazy, + Names, + PhysicalName, + RemovalPolicy, + Resource, + Stack, + Stage as CdkStage, + Token, } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { ActionCategory, IAction, IPipeline, IStage, PipelineNotificationEvents, PipelineNotifyOnOptions } from './action'; @@ -620,7 +630,7 @@ export class Pipeline extends PipelineBase { throw new Error("You need to specify an explicit account when using CodePipeline's cross-region support"); } - const app = this.requireApp(); + const app = this.supportScope(); const supportStackId = `cross-region-stack-${pipelineAccount}:${actionRegion}`; let supportStack = app.node.tryFindChild(supportStackId) as CrossRegionSupportStack; if (!supportStack) { @@ -816,7 +826,7 @@ export class Pipeline extends PipelineBase { let targetAccountStack: Stack | undefined = this._crossAccountSupport[targetAccount]; if (!targetAccountStack) { const stackId = `cross-account-support-stack-${targetAccount}`; - const app = this.requireApp(); + const app = this.supportScope(); targetAccountStack = app.node.tryFindChild(stackId) as Stack; if (!targetAccountStack) { const actionRegion = action.actionProperties.resource @@ -1026,12 +1036,12 @@ export class Pipeline extends PipelineBase { return region; } - private requireApp(): App { - const app = this.node.root; - if (!app || !App.isApp(app)) { - throw new Error('Pipeline stack which uses cross-environment actions must be part of a CDK app'); + private supportScope(): CdkStage { + const scope = CdkStage.of(this); + if (!scope) { + throw new Error('Pipeline stack which uses cross-environment actions must be part of a CDK App or Stage'); } - return app; + return scope; } } diff --git a/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts b/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts index f22c80e82cba1..337a110a35b0f 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/cross-env.test.ts @@ -1,13 +1,20 @@ import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; -import { Stack, App } from '@aws-cdk/core'; +import { Stack, App, Stage as CdkStage } from '@aws-cdk/core'; +import { Construct } from 'constructs'; import * as codepipeline from '../lib'; import { FakeBuildAction } from './fake-build-action'; import { FakeSourceAction } from './fake-source-action'; -describe.each(['legacy', 'modern'])('with %s synthesis', (synthesisStyle: string) => { +describe.each([ + ['legacy', false], + ['legacy', true], + ['modern', false], + ['modern', true], +])('with %s synthesis, in Stage=%p', (synthesisStyle: string, inStage: boolean) => { let app: App; + let stackScope: Construct; let stack: Stack; let sourceArtifact: codepipeline.Artifact; let initialStages: codepipeline.StageProps[]; @@ -18,7 +25,9 @@ describe.each(['legacy', 'modern'])('with %s synthesis', (synthesisStyle: string ...synthesisStyle === 'modern' ? { '@aws-cdk/core:newStyleStackSynthesis': true } : undefined, }, }); - stack = new Stack(app, 'PipelineStack', { env: { account: '2222', region: 'us-east-1' } }); + stackScope = inStage ? new CdkStage(app, 'MyStage') : app; + + stack = new Stack(stackScope, 'PipelineStack', { env: { account: '2222', region: 'us-east-1' } }); sourceArtifact = new codepipeline.Artifact(); initialStages = [ { @@ -114,7 +123,8 @@ describe.each(['legacy', 'modern'])('with %s synthesis', (synthesisStyle: string })); // THEN - const asm = app.synth(); + let asm = app.synth(); + asm = inStage ? asm.getNestedAssembly('assembly-MyStage') : asm; const supportStack = asm.getStackByName(`${stack.stackName}-support-eu-west-1`); // THEN @@ -123,7 +133,7 @@ describe.each(['legacy', 'modern'])('with %s synthesis', (synthesisStyle: string }); test('when twiddling another stack', () => { - const stack2 = new Stack(app, 'Stack2', { env: { account: '2222', region: 'eu-west-1' } }); + const stack2 = new Stack(stackScope, 'Stack2', { env: { account: '2222', region: 'eu-west-1' } }); // WHEN stage.addAction(new FakeBuildAction({ From efaaaf54191252c33727819b741280706bbe917b Mon Sep 17 00:00:00 2001 From: Cory Hall <43035978+corymhall@users.noreply.github.com> Date: Fri, 26 Nov 2021 11:34:27 -0500 Subject: [PATCH 28/82] chore(cognito): docs showed incorrect default value for preventUserExistenceErrors (#17667) The docs for preventUserExistenceErrors showed a default of `true` when the default has always been `false`. Update the docs to reflect the actual default. Also remove references to "new stacks" since the functionality is the same between new and existing stacks. fixes #17044 ---- *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-cognito/README.md | 2 +- packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index 906480586b769..57a442512d9f6 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -582,7 +582,7 @@ pool.addClient('app-client', { An app client can be configured to prevent user existence errors. This instructs the Cognito authentication API to return generic authentication failure responses instead of an UserNotFoundException. By default, the flag -is not set, which means different things for existing and new stacks. See the +is not set, which means the CloudFormation default (false) will be used. See the [documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-managing-errors.html) for the full details on the behavior of this flag. diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts index 99ddaac75e595..549b0c60ef5f5 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts @@ -243,7 +243,7 @@ export interface UserPoolClientOptions { * user does not exist in the user pool (false), or whether it returns * another type of error that doesn't reveal the user's absence. * @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-managing-errors.html - * @default true for new stacks + * @default false */ readonly preventUserExistenceErrors?: boolean; From df7b9b41bd99534abb8a6becccc23320a3b6cb41 Mon Sep 17 00:00:00 2001 From: Unnati Parekh <80710604+upparekh@users.noreply.github.com> Date: Fri, 26 Nov 2021 12:04:15 -0800 Subject: [PATCH 29/82] feat(ecs-service-extensions): Auto scaling for Queue Extension (#17430) ---- This PR adds target tracking auto scaling policy for the the SQS Queues provided to and created by the `QueueExtension` (in the `useService()` hook). The auto scaling is based on `backlogPerTask` custom metric which is emitted by an AWS Lambda Function. The PR also contains this Lambda Function and its tests. *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../ecs-service-extensions/README.md | 35 +- .../lib/extensions/index.ts | 2 +- .../lib/extensions/queue.ts | 212 --------- .../lib/extensions/queue/index.ts | 1 + .../lib/extensions/queue/lambda/index.py | 15 + .../queue/lambda/queue_backlog_calculator.py | 71 +++ .../lib/extensions/queue/queue.ts | 418 ++++++++++++++++++ .../ecs-service-extensions/package.json | 2 + .../test/integ.assign-public-ip.expected.json | 18 +- ...teg.custom-service-extension.expected.json | 18 +- .../integ.multiple-environments.expected.json | 36 +- .../integ.publish-subscribe.expected.json | 348 ++++++++++++++- .../test/integ.publish-subscribe.ts | 15 +- .../test/queue-handler/Dockerfile | 9 + .../test/queue-handler/test.sh | 19 + .../test/queue-handler/test_index.py | 149 +++++++ .../test/queue.lambda.test.ts | 8 + .../ecs-service-extensions/test/queue.test.ts | 334 +++++++++++++- 18 files changed, 1456 insertions(+), 254 deletions(-) delete mode 100644 packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue.ts create mode 100644 packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/index.ts create mode 100644 packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/lambda/index.py create mode 100644 packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/lambda/queue_backlog_calculator.py create mode 100644 packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/queue.ts create mode 100644 packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/Dockerfile create mode 100755 packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/test.sh create mode 100644 packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/test_index.py create mode 100644 packages/@aws-cdk-containers/ecs-service-extensions/test/queue.lambda.test.ts diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/README.md b/packages/@aws-cdk-containers/ecs-service-extensions/README.md index b80f1539f4447..115c8785ddbc1 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/README.md +++ b/packages/@aws-cdk-containers/ecs-service-extensions/README.md @@ -392,11 +392,42 @@ For setting up a topic-specific queue subscription, you can provide a custom que ```ts nameDescription.add(new QueueExtension({ - queue: myEventsQueue, + eventsQueue: myEventsQueue, subscriptions: [new TopicSubscription({ topic: new sns.Topic(stack, 'my-topic'), // `myTopicQueue` will subscribe to the `my-topic` instead of `eventsQueue` - queue: myTopicQueue, + topicSubscriptionQueue: { + queue: myTopicQueue, + }, + }], +})); +``` + +### Configuring auto scaling based on SQS Queues + +You can scale your service up or down to maintain an acceptable queue latency by tracking the backlog per task. It configures a target tracking scaling policy with target value (acceptable backlog per task) calculated by dividing the `acceptableLatency` by `messageProcessingTime`. For example, if the maximum acceptable latency for a message to be processed after its arrival in the SQS Queue is 10 mins and the average processing time for a task is 250 milliseconds per message, then `acceptableBacklogPerTask = 10 * 60 / 0.25 = 2400`. Therefore, each queue can hold up to 2400 messages before the service starts to scale up. For this, a target tracking policy will be attached to the scaling target for your service with target value `2400`. For more information, please refer: https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-using-sqs-queue.html . + +You can configure auto scaling based on SQS Queue for your service as follows: + +```ts +nameDescription.add(new QueueExtension({ + eventsQueue: myEventsQueue, + // Need to specify `scaleOnLatency` to configure auto scaling based on SQS Queue + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(10), + messageProcessingTime: cdk.Duration.millis(250), + }, + subscriptions: [new TopicSubscription({ + topic: new sns.Topic(stack, 'my-topic'), + // `myTopicQueue` will subscribe to the `my-topic` instead of `eventsQueue` + topicSubscriptionQueue: { + queue: myTopicQueue, + // Optionally provide `scaleOnLatency` for configuring separate autoscaling for `myTopicQueue` + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(10), + messageProcessingTime: cdk.Duration.millis(250), + } + }, }], })); ``` diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/index.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/index.ts index 2191def8aaa15..2a7a55bb348ec 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/index.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/index.ts @@ -6,5 +6,5 @@ export * from './cloudwatch-agent'; export * from './scale-on-cpu-utilization'; export * from './xray'; export * from './assign-public-ip'; -export * from './queue'; +export * from './queue/queue'; export * from './injecter'; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue.ts deleted file mode 100644 index d43b587d6326e..0000000000000 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue.ts +++ /dev/null @@ -1,212 +0,0 @@ -import * as ecs from '@aws-cdk/aws-ecs'; -import * as sns from '@aws-cdk/aws-sns'; -import * as subscription from '@aws-cdk/aws-sns-subscriptions'; -import * as sqs from '@aws-cdk/aws-sqs'; -import * as cdk from '@aws-cdk/core'; -import { Service } from '../service'; -import { Container } from './container'; -import { ContainerMutatingHook, ServiceExtension } from './extension-interfaces'; - -// Keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - -/** - * An interface that will be implemented by all the resources that can be subscribed to. - */ -export interface ISubscribable { - /** - * All classes implementing this interface must also implement the `subscribe()` method - */ - subscribe(extension: QueueExtension): sqs.IQueue; -} - -/** - * The settings for the Queue extension. - */ -export interface QueueExtensionProps { - /** - * The list of subscriptions for this service. - * - * @default none - */ - readonly subscriptions?: ISubscribable[]; - - /** - * The user-provided default queue for this service. - * - * @default If the `eventsQueue` is not provided, a default SQS Queue is created for the service. - */ - readonly eventsQueue?: sqs.IQueue; -} - -/** - * The topic-specific settings for creating the queue subscriptions. - */ -export interface TopicSubscriptionProps { - /** - * The SNS Topic to subscribe to. - */ - readonly topic: sns.ITopic; - - /** - * The user-provided queue to subscribe to the given topic. - * If the `queue` is not provided, the default `eventsQueue` will subscribe to the given topic. - * - * @default none - */ - readonly queue?: sqs.IQueue; -} - -/** - * The `TopicSubscription` class represents an SNS Topic resource that can be subscribed to by the service queues. - */ -export class TopicSubscription implements ISubscribable { - public readonly topic: sns.ITopic; - - public readonly queue?: sqs.IQueue; - - constructor(props: TopicSubscriptionProps) { - this.topic = props.topic; - this.queue = props.queue; - } - - /** - * This method sets up SNS Topic subscriptions for the SQS queue provided by the user. If a `queue` is not provided, - * the default `eventsQueue` subscribes to the given topic. - * - * @param extension `QueueExtension` added to the service - * @returns the queue subscribed to the given topic - */ - public subscribe(extension: QueueExtension) : sqs.IQueue { - let queue = extension.eventsQueue; - if (this.queue) { - queue = this.queue; - } - this.topic.addSubscription(new subscription.SqsSubscription(queue)); - return queue; - } -} - -/** - * Settings for the hook which mutates the application container - * to add the events queue URI to its environment. - */ -interface ContainerMutatingProps { - /** - * The events queue name and URI to be added to the container environment. - */ - readonly environment: { [key: string]: string }; -} - -/** - * This hook modifies the application container's environment to - * add the queue URL for the events queue of the service. - */ -class QueueExtensionMutatingHook extends ContainerMutatingHook { - private environment: { [key: string]: string }; - - constructor(props: ContainerMutatingProps) { - super(); - this.environment = props.environment; - } - - public mutateContainerDefinition(props: ecs.ContainerDefinitionOptions): ecs.ContainerDefinitionOptions { - return { - ...props, - - environment: { ...(props.environment || {}), ...this.environment }, - } as ecs.ContainerDefinitionOptions; - } -} - -/** - * This extension creates a default `eventsQueue` for the service (if not provided) and accepts a list of objects of - * type `ISubscribable` that the `eventsQueue` subscribes to. It creates the subscriptions and sets up permissions - * for the service to consume messages from the SQS Queues. - * - * The default queue for this service can be accessed using the getter `.eventsQueue`. - */ -export class QueueExtension extends ServiceExtension { - private _eventsQueue!: sqs.IQueue; - - private subscriptionQueues = new Set(); - - private environment: { [key: string]: string } = {}; - - private props?: QueueExtensionProps; - - constructor(props?: QueueExtensionProps) { - super('queue'); - - this.props = props; - } - - /** - * This hook creates (if required) and sets the default queue `eventsQueue`. It also sets up the subscriptions for - * the provided `ISubscribable` objects. - * - * @param service The parent service which this extension has been added to - * @param scope The scope that this extension should create resources in - */ - public prehook(service: Service, scope: Construct) { - this.parentService = service; - this.scope = scope; - - let eventsQueue = this.props?.eventsQueue; - if (!eventsQueue) { - const deadLetterQueue = new sqs.Queue(this.scope, 'EventsDeadLetterQueue', { - retentionPeriod: cdk.Duration.days(14), - }); - - eventsQueue = new sqs.Queue(this.scope, 'EventsQueue', { - deadLetterQueue: { - queue: deadLetterQueue, - maxReceiveCount: 3, - }, - }); - } - this._eventsQueue = eventsQueue; - - this.environment[`${this.parentService.id.toUpperCase()}_QUEUE_URI`] = this._eventsQueue.queueUrl; - - if (this.props?.subscriptions) { - for (const subs of this.props.subscriptions) { - const subsQueue = subs.subscribe(this); - this.subscriptionQueues.add(subsQueue); - } - } - } - - /** - * Add hooks to the main application extension so that it is modified to - * add the events queue URL to the container environment. - */ - public addHooks() { - const container = this.parentService.serviceDescription.get('service-container') as Container; - - if (!container) { - throw new Error('Queue Extension requires an application extension'); - } - - container.addContainerMutatingHook(new QueueExtensionMutatingHook({ - environment: this.environment, - })); - } - - /** - * After the task definition has been created, this hook grants SQS permissions to the task role. - * - * @param taskDefinition The created task definition - */ - public useTaskDefinition(taskDefinition: ecs.TaskDefinition) { - this._eventsQueue.grantConsumeMessages(taskDefinition.taskRole); - for (const queue of this.subscriptionQueues) { - queue.grantConsumeMessages(taskDefinition.taskRole); - } - } - - public get eventsQueue() : sqs.IQueue { - return this._eventsQueue; - } -} \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/index.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/index.ts new file mode 100644 index 0000000000000..1abfa1e06c359 --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/index.ts @@ -0,0 +1 @@ +export * from './queue'; \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/lambda/index.py b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/lambda/index.py new file mode 100644 index 0000000000000..d24454171e478 --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/lambda/index.py @@ -0,0 +1,15 @@ +import os +import boto3 +from queue_backlog_calculator import QueueHandler + +def queue_handler(event, context): + """ + Handler for the lambda trigger + """ + + ecs = boto3.client('ecs') + sqs = boto3.client('sqs') + + queue_handler = QueueHandler(ecs_client=ecs, sqs_client=sqs, environ=os.environ) + + return queue_handler.emit() diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/lambda/queue_backlog_calculator.py b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/lambda/queue_backlog_calculator.py new file mode 100644 index 0000000000000..5f14d74a76bd2 --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/lambda/queue_backlog_calculator.py @@ -0,0 +1,71 @@ +from math import ceil +import time +import json + +class QueueHandler: + def __init__(self, ecs_client, sqs_client, environ): + self.ecs = ecs_client + self.sqs = sqs_client + self.cluster_name = environ['CLUSTER_NAME'] + self.service_name = environ['SERVICE_NAME'] + self.namespace = environ['NAMESPACE'] + self.queue_names = environ['QUEUE_NAMES'].split(',') + + def emit(self): + try: + running_count = self.get_running_task_count() + backlogs = [self.get_queue_backlog(queue_name, running_count) for queue_name in self.queue_names] + self.timestamp = int(time.time() * 1000) + for backlog in backlogs: + self.emit_backlog_per_task_metric(backlog['queueName'], backlog['backlogPerTask']) + except Exception as e: + Exception('Exception: {}'.format(e)) + + """ + Write the backlogPerTask metric to the stdout according to the Cloudwatch embedded metric format. + """ + def emit_backlog_per_task_metric(self, queue_name, backlog_per_task): + print(json.dumps({ + "_aws": { + "Timestamp": self.timestamp, + "CloudWatchMetrics": [{ + "Namespace": self.namespace, + "Dimensions": [["QueueName"]], + "Metrics": [{"Name":"BacklogPerTask", "Unit": "Count"}] + }], + }, + "QueueName": queue_name, + "BacklogPerTask": backlog_per_task, + })) + + """ + Get the number of tasks in the 'RUNNING' state for the service 'service_name'. + """ + def get_running_task_count(self): + service_desc = self.ecs.describe_services( + cluster=self.cluster_name, + services=[self.service_name], + ) + if len(service_desc['services']) == 0: + raise Exception('There are no services with name {} in cluster: {}'.format(self.service_name, self.cluster_name)) + return service_desc['services'][0].get('runningCount', 0) + + """ + This method calculates and returns the backlogPerTask metric for the given queue. + """ + def get_queue_backlog(self, queue_name, count): + queue_url = self.sqs.get_queue_url(QueueName=queue_name) + running_count = 1 if count == 0 else count + + def get_backlog_per_task(): + queue_attributes = self.sqs.get_queue_attributes( + QueueUrl=queue_url['QueueUrl'], + AttributeNames=['ApproximateNumberOfMessages'] + ) + num_of_msgs = int(queue_attributes['Attributes'].get('ApproximateNumberOfMessages', 0)) + return ceil(num_of_msgs/running_count) + + return { + 'queueName': queue_name, + 'backlogPerTask': get_backlog_per_task() + } \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/queue.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/queue.ts new file mode 100644 index 0000000000000..bda38fb81c355 --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/queue.ts @@ -0,0 +1,418 @@ +import * as path from 'path'; +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as events from '@aws-cdk/aws-events'; +import * as events_targets from '@aws-cdk/aws-events-targets'; +import * as iam from '@aws-cdk/aws-iam'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as logs from '@aws-cdk/aws-logs'; +import * as sns from '@aws-cdk/aws-sns'; +import * as subscription from '@aws-cdk/aws-sns-subscriptions'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as cdk from '@aws-cdk/core'; +import { Service } from '../../service'; +import { Container } from '../container'; +import { ContainerMutatingHook, ServiceExtension } from '../extension-interfaces'; + +// Keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/** + * An interface that will be implemented by all the resources that can be subscribed to. + */ +export interface ISubscribable { + /** + * The `SubscriptionQueue` object for the `ISubscribable` object. + * + * @default none + */ + readonly subscriptionQueue?: SubscriptionQueue; + + /** + * All classes implementing this interface must also implement the `subscribe()` method + */ + subscribe(extension: QueueExtension): sqs.IQueue; +} + +/** + * The settings for the Queue extension. + */ +export interface QueueExtensionProps { + /** + * The list of subscriptions for this service. + * + * @default none + */ + readonly subscriptions?: ISubscribable[]; + + /** + * The user-provided default queue for this service. + * If the `eventsQueue` is not provided, a default SQS Queue is created for the service. + * + * @default none + */ + readonly eventsQueue?: sqs.IQueue; + + /** + * The user-provided queue delay fields to configure auto scaling for the default queue. + * + * @default none + */ + readonly scaleOnLatency?: QueueAutoScalingOptions; +} + +/** + * The topic-specific settings for creating the queue subscriptions. + */ +export interface TopicSubscriptionProps { + /** + * The SNS Topic to subscribe to. + */ + readonly topic: sns.ITopic; + + /** + * The user-provided queue to subscribe to the given topic. + * + * @default none + * @deprecated use `topicSubscriptionQueue` + */ + readonly queue?: sqs.IQueue; + + /** + * The object representing topic-specific queue and corresponding queue delay fields to configure auto scaling. + * If not provided, the default `eventsQueue` will subscribe to the given topic. + * + * @default none + */ + readonly topicSubscriptionQueue?: SubscriptionQueue; +} + +/** + * `SubscriptionQueue` represents the subscription queue object which includes the topic-specific queue and its + * corresponding auto scaling fields. + */ +interface SubscriptionQueue { + /** + * The user-provided queue to subscribe to the given topic. + */ + readonly queue: sqs.IQueue; + + /** + * The user-provided queue delay fields to configure auto scaling for the topic-specific queue. + * + * @default none + */ + readonly scaleOnLatency?: QueueAutoScalingOptions; +} + +/** + * Options for configuring SQS Queue auto scaling. + */ +interface QueueAutoScalingOptions { + /** + * Average amount of time for processing a single message in the queue. + */ + readonly messageProcessingTime: cdk.Duration; + + /** + * Acceptable amount of time a message can sit in the queue (including the time required to process it). + */ + readonly acceptableLatency: cdk.Duration; +} + +/** + * The `TopicSubscription` class represents an SNS Topic resource that can be subscribed to by the service queues. + */ +export class TopicSubscription implements ISubscribable { + public readonly topic: sns.ITopic; + + /** + * The queue that subscribes to the given topic. + * + * @default none + * @deprecated use `subscriptionQueue` + */ + public readonly queue?: sqs.IQueue; + + /** + * The subscription queue object for this subscription. + * + * @default none + */ + public readonly subscriptionQueue?: SubscriptionQueue; + + constructor(props: TopicSubscriptionProps) { + this.topic = props.topic; + + if (props.topicSubscriptionQueue && props.queue) { + throw Error('Either provide the `subscriptionQueue` or the `queue` (deprecated) for the topic subscription, but not both.'); + } + this.subscriptionQueue = props.topicSubscriptionQueue; + this.queue = props.queue ?? props.topicSubscriptionQueue?.queue; + } + + /** + * This method sets up SNS Topic subscriptions for the SQS queue provided by the user. If a `queue` is not provided, + * the default `eventsQueue` subscribes to the given topic. + * + * @param extension `QueueExtension` added to the service + * @returns the queue subscribed to the given topic + */ + public subscribe(extension: QueueExtension) : sqs.IQueue { + const queue = this.subscriptionQueue?.queue ?? this.queue ?? extension.eventsQueue; + this.topic.addSubscription(new subscription.SqsSubscription(queue)); + return queue; + } +} + +/** + * Settings for the hook which mutates the application container + * to add the events queue URI to its environment. + */ +interface ContainerMutatingProps { + /** + * The events queue name and URI to be added to the container environment. + */ + readonly environment: { [key: string]: string }; +} + +/** + * This hook modifies the application container's environment to + * add the queue URL for the events queue of the service. + */ +class QueueExtensionMutatingHook extends ContainerMutatingHook { + private environment: { [key: string]: string }; + + constructor(props: ContainerMutatingProps) { + super(); + this.environment = props.environment; + } + + public mutateContainerDefinition(props: ecs.ContainerDefinitionOptions): ecs.ContainerDefinitionOptions { + return { + ...props, + + environment: { ...(props.environment || {}), ...this.environment }, + } as ecs.ContainerDefinitionOptions; + } +} + +/** + * This extension creates a default `eventsQueue` for the service (if not provided) and accepts a list of objects of + * type `ISubscribable` that the `eventsQueue` subscribes to. It creates the subscriptions and sets up permissions + * for the service to consume messages from the SQS Queues. + * + * It also configures a target tracking scaling policy for the service to maintain an acceptable queue latency by tracking + * the backlog per task. For more information, please refer: https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-using-sqs-queue.html . + * + * The default queue for this service can be accessed using the getter `.eventsQueue`. + */ +export class QueueExtension extends ServiceExtension { + private _eventsQueue!: sqs.IQueue; + + private _autoscalingOptions?: QueueAutoScalingOptions; + + private subscriptionQueues = new Set(); + + private environment: { [key: string]: string } = {}; + + private props?: QueueExtensionProps; + + /** + * The log group created by the extension where the AWS Lambda function logs are stored. + */ + public logGroup?: logs.ILogGroup; + + constructor(props?: QueueExtensionProps) { + super('queue'); + + this.props = props; + } + + /** + * This hook creates (if required) and sets the default queue `eventsQueue`. It also sets up the subscriptions for + * the provided `ISubscribable` objects. + * + * @param service The parent service which this extension has been added to + * @param scope The scope that this extension should create resources in + */ + public prehook(service: Service, scope: Construct) { + this.parentService = service; + this.scope = scope; + + let eventsQueue = this.props?.eventsQueue; + if (!eventsQueue) { + const deadLetterQueue = new sqs.Queue(this.scope, 'EventsDeadLetterQueue', { + retentionPeriod: cdk.Duration.days(14), + }); + + eventsQueue = new sqs.Queue(this.scope, 'EventsQueue', { + deadLetterQueue: { + queue: deadLetterQueue, + maxReceiveCount: 3, + }, + }); + } + this._eventsQueue = eventsQueue; + this._autoscalingOptions = this.props?.scaleOnLatency; + + this.environment[`${this.parentService.id.toUpperCase()}_QUEUE_URI`] = this._eventsQueue.queueUrl; + + if (this.props?.subscriptions) { + for (const subs of this.props.subscriptions) { + const subsQueue = subs.subscribe(this); + if (subsQueue !== this._eventsQueue) { + if (subs.subscriptionQueue?.scaleOnLatency && !this._autoscalingOptions) { + throw Error(`Autoscaling for a topic-specific queue cannot be configured as autoscaling based on SQS Queues hasn’t been set up for the service '${this.parentService.id}'. If you want to enable autoscaling for this service, please also specify 'scaleOnLatency' in the 'QueueExtension'.`); + } + const subscriptionQueue = subs.subscriptionQueue ?? { + queue: subsQueue, + } as SubscriptionQueue; + this.subscriptionQueues.add(subscriptionQueue); + } + } + } + } + + /** + * Add hooks to the main application extension so that it is modified to + * add the events queue URL to the container environment. + */ + public addHooks() { + const container = this.parentService.serviceDescription.get('service-container') as Container; + + if (!container) { + throw new Error('Queue Extension requires an application extension'); + } + + container.addContainerMutatingHook(new QueueExtensionMutatingHook({ + environment: this.environment, + })); + } + + /** + * After the task definition has been created, this hook grants SQS permissions to the task role. + * + * @param taskDefinition The created task definition + */ + public useTaskDefinition(taskDefinition: ecs.TaskDefinition) { + this._eventsQueue.grantConsumeMessages(taskDefinition.taskRole); + for (const subsQueue of this.subscriptionQueues) { + subsQueue.queue.grantConsumeMessages(taskDefinition.taskRole); + } + } + + /** + * When this hook is implemented by extension, it allows the extension + * to use the service which has been created. It is used to add target tracking + * scaling policies for the SQS Queues of the service. It also creates an AWS Lambda + * Function for calculating the backlog per task metric. + * + * @param service - The generated service. + */ + public useService(service: ecs.Ec2Service | ecs.FargateService) { + if (!this._autoscalingOptions) { + return; + } + if (!this.parentService.scalableTaskCount) { + throw Error(`Auto scaling target for the service '${this.parentService.id}' hasn't been configured. Please use Service construct to configure 'minTaskCount' and 'maxTaskCount'.`); + } + + this.addQueueScalingPolicy(this._eventsQueue, this._autoscalingOptions); + for (const subsQueue of this.subscriptionQueues) { + const autoscalingOpts = subsQueue.scaleOnLatency ?? this._autoscalingOptions; + this.addQueueScalingPolicy(subsQueue.queue, autoscalingOpts!); + } + this.parentService.enableAutoScalingPolicy(); + + this.createLambdaFunction(service); + } + + /** + * This method adds a target tracking policy based on the backlog per task custom metric + * to the auto scaling target configured for this service. + * + * @param queue The queue for which backlog per task metric is being configured + * @param queueDelay The auto scaling options for the queue + */ + private addQueueScalingPolicy(queue: sqs.IQueue, queueDelay: QueueAutoScalingOptions) { + const messageProcessingTime = queueDelay.messageProcessingTime.toSeconds(); + const acceptableLatency = queueDelay.acceptableLatency.toSeconds(); + if (messageProcessingTime > acceptableLatency) { + throw Error(`Message processing time (${messageProcessingTime}s) for the queue cannot be greater acceptable queue latency (${acceptableLatency}s).`); + } + const acceptableBacklog = acceptableLatency/messageProcessingTime; + + this.parentService.scalableTaskCount?.scaleToTrackCustomMetric(`${queue.node.id}-autoscaling-policy`, { + metric: new cloudwatch.Metric({ + namespace: `${this.parentService.environment.id}-${this.parentService.id}`, + metricName: 'BacklogPerTask', + dimensionsMap: { QueueName: queue.queueName }, + unit: cloudwatch.Unit.COUNT, + }), + targetValue: acceptableBacklog, + }); + } + + /** + * This method is used to create the AWS Lambda Function for calculating backlog + * per task metric and a Cloudwatch event trigger for this function. + * + * @param service - The generated service. + */ + private createLambdaFunction(service: ecs.Ec2Service | ecs.FargateService) { + const queueNames = [this._eventsQueue.queueName]; + this.subscriptionQueues.forEach(subs => queueNames.push(subs.queue.queueName)); + + const backLogPerTaskCalculator = new lambda.Function(this.scope, 'BackLogPerTaskCalculatorFunction', { + runtime: lambda.Runtime.PYTHON_3_9, + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda')), + handler: 'index.queue_handler', + environment: { + CLUSTER_NAME: this.parentService.cluster.clusterName, + SERVICE_NAME: service.serviceName, + NAMESPACE: `${this.parentService.environment.id}-${this.parentService.id}`, + QUEUE_NAMES: queueNames.join(','), + }, + initialPolicy: [new iam.PolicyStatement({ + actions: ['ecs:DescribeServices'], + resources: [`${service.serviceArn}`], + conditions: { + ArnEquals: { + 'ecs:cluster': this.parentService.cluster.clusterArn, + }, + }, + })], + }); + + const queueArns = [this._eventsQueue.queueArn]; + this.subscriptionQueues.forEach(subs => queueArns.push(subs.queue.queueArn)); + backLogPerTaskCalculator.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: [ + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ], + resources: queueArns, + })); + + new events.Rule(this.scope, 'BacklogPerTaskScheduledRule', { + schedule: events.Schedule.rate(cdk.Duration.seconds(60)), + targets: [new events_targets.LambdaFunction(backLogPerTaskCalculator)], + }); + + this.logGroup = new logs.LogGroup(this.scope, `${this.parentService.id}-BackLogPerTaskCalculatorLogs`, { + logGroupName: `/aws/lambda/${backLogPerTaskCalculator.functionName}`, + removalPolicy: cdk.RemovalPolicy.DESTROY, + retention: logs.RetentionDays.THREE_DAYS, + }); + } + + public get eventsQueue() : sqs.IQueue { + return this._eventsQueue; + } + + public get autoscalingOptions() : QueueAutoScalingOptions | undefined { + return this._autoscalingOptions; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/package.json b/packages/@aws-cdk-containers/ecs-service-extensions/package.json index 3677b75e224d2..629e208b042b1 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/package.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/package.json @@ -50,6 +50,7 @@ "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", @@ -77,6 +78,7 @@ "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-appmesh": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json index 1c061588d688d..faee3f71397ab 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json @@ -1190,7 +1190,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3Bucket4C71F166" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E" }, "S3Key": { "Fn::Join": [ @@ -1203,7 +1203,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -1216,7 +1216,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4" + "Ref": "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632" } ] } @@ -1266,17 +1266,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3Bucket4C71F166": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3BucketF482197E": { "Type": "String", - "Description": "S3 bucket for asset \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" + "Description": "S3 bucket for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dS3VersionKey0124EFC4": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2S3VersionKey38B69632": { "Type": "String", - "Description": "S3 key for asset version \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" + "Description": "S3 key for asset version \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" }, - "AssetParameters1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2dArtifactHash6350D824": { + "AssetParameters6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2ArtifactHash4BE92B79": { "Type": "String", - "Description": "Artifact hash for asset \"1c4eb88f5a8270f387281dcff6e3493840634113c4d57044f4aff74e3ef94c2d\"" + "Description": "Artifact hash for asset \"6ee0a36dd10d630708c265bcf7616c64030040c1bbc383b34150db74b744cad2\"" } }, "Outputs": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.custom-service-extension.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.custom-service-extension.expected.json index eca0061871041..5fbaf177162df 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.custom-service-extension.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.custom-service-extension.expected.json @@ -95,15 +95,15 @@ "productionenvironmentvpcPublicSubnet1NATGateway6075E4CA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "productionenvironmentvpcPublicSubnet1Subnet8D92C089" + }, "AllocationId": { "Fn::GetAtt": [ "productionenvironmentvpcPublicSubnet1EIP54BA88DB", "AllocationId" ] }, - "SubnetId": { - "Ref": "productionenvironmentvpcPublicSubnet1Subnet8D92C089" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "productionenvironmentvpcPublicSubnet2NATGatewayE1850FCC": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "productionenvironmentvpcPublicSubnet2Subnet298E6C31" + }, "AllocationId": { "Fn::GetAtt": [ "productionenvironmentvpcPublicSubnet2EIP14CA46AA", "AllocationId" ] }, - "SubnetId": { - "Ref": "productionenvironmentvpcPublicSubnet2Subnet298E6C31" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "productionenvironmentvpcPublicSubnet3NATGateway94604057": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "productionenvironmentvpcPublicSubnet3SubnetC7B5665D" + }, "AllocationId": { "Fn::GetAtt": [ "productionenvironmentvpcPublicSubnet3EIP53405AED", "AllocationId" ] }, - "SubnetId": { - "Ref": "productionenvironmentvpcPublicSubnet3SubnetC7B5665D" - }, "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json index d5f00cb5708c7..91ce21c4a2c5f 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.multiple-environments.expected.json @@ -95,15 +95,15 @@ "productionenvironmentvpcPublicSubnet1NATGateway6075E4CA": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "productionenvironmentvpcPublicSubnet1Subnet8D92C089" + }, "AllocationId": { "Fn::GetAtt": [ "productionenvironmentvpcPublicSubnet1EIP54BA88DB", "AllocationId" ] }, - "SubnetId": { - "Ref": "productionenvironmentvpcPublicSubnet1Subnet8D92C089" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "productionenvironmentvpcPublicSubnet2NATGatewayE1850FCC": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "productionenvironmentvpcPublicSubnet2Subnet298E6C31" + }, "AllocationId": { "Fn::GetAtt": [ "productionenvironmentvpcPublicSubnet2EIP14CA46AA", "AllocationId" ] }, - "SubnetId": { - "Ref": "productionenvironmentvpcPublicSubnet2Subnet298E6C31" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "productionenvironmentvpcPublicSubnet3NATGateway94604057": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "productionenvironmentvpcPublicSubnet3SubnetC7B5665D" + }, "AllocationId": { "Fn::GetAtt": [ "productionenvironmentvpcPublicSubnet3EIP53405AED", "AllocationId" ] }, - "SubnetId": { - "Ref": "productionenvironmentvpcPublicSubnet3SubnetC7B5665D" - }, "Tags": [ { "Key": "Name", @@ -621,15 +621,15 @@ "developmentenvironmentvpcPublicSubnet1NATGateway6B01CC4E": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "developmentenvironmentvpcPublicSubnet1Subnet0D18046B" + }, "AllocationId": { "Fn::GetAtt": [ "developmentenvironmentvpcPublicSubnet1EIPE8B9F4D4", "AllocationId" ] }, - "SubnetId": { - "Ref": "developmentenvironmentvpcPublicSubnet1Subnet0D18046B" - }, "Tags": [ { "Key": "Name", @@ -718,15 +718,15 @@ "developmentenvironmentvpcPublicSubnet2NATGateway15A9C252": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "developmentenvironmentvpcPublicSubnet2SubnetC2026CD3" + }, "AllocationId": { "Fn::GetAtt": [ "developmentenvironmentvpcPublicSubnet2EIP560C2BBA", "AllocationId" ] }, - "SubnetId": { - "Ref": "developmentenvironmentvpcPublicSubnet2SubnetC2026CD3" - }, "Tags": [ { "Key": "Name", @@ -815,15 +815,15 @@ "developmentenvironmentvpcPublicSubnet3NATGatewayAD65DE0B": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "developmentenvironmentvpcPublicSubnet3Subnet00B8A77C" + }, "AllocationId": { "Fn::GetAtt": [ "developmentenvironmentvpcPublicSubnet3EIPE2E366D3", "AllocationId" ] }, - "SubnetId": { - "Ref": "developmentenvironmentvpcPublicSubnet3Subnet00B8A77C" - }, "Tags": [ { "Key": "Name", diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json index 4fa8a31db3ba9..465a7ce4b3374 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.expected.json @@ -944,7 +944,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 100 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "LaunchType": "FARGATE", "NetworkConfiguration": { @@ -991,6 +990,353 @@ "Ref": "productionenvironmentvpcAEB47DF7" } } + }, + "WorkerserviceTaskCountTarget6636D808": { + "Type": "AWS::ApplicationAutoScaling::ScalableTarget", + "Properties": { + "MaxCapacity": 10, + "MinCapacity": 1, + "ResourceId": { + "Fn::Join": [ + "", + [ + "service/", + { + "Ref": "productionenvironmentclusterC6599D2D" + }, + "/", + { + "Fn::GetAtt": [ + "WorkerserviceService68C5A5C3", + "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" + } + }, + "WorkerserviceTaskCountTargetEventsQueueautoscalingpolicyD12B62ED": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecsintegWorkerserviceTaskCountTargetEventsQueueautoscalingpolicyDBD40B57", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "WorkerserviceTaskCountTarget6636D808" + }, + "TargetTrackingScalingPolicyConfiguration": { + "CustomizedMetricSpecification": { + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "EventsQueueB96EB0D2", + "QueueName" + ] + } + } + ], + "MetricName": "BacklogPerTask", + "Namespace": "production-Worker", + "Statistic": "Average", + "Unit": "Count" + }, + "TargetValue": 15 + } + } + }, + "WorkerserviceTaskCountTargetsignupqueueautoscalingpolicyB7321DB7": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awsecsintegWorkerserviceTaskCountTargetsignupqueueautoscalingpolicyDF93FC37", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "WorkerserviceTaskCountTarget6636D808" + }, + "TargetTrackingScalingPolicyConfiguration": { + "CustomizedMetricSpecification": { + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "signupqueue33AFF2E6", + "QueueName" + ] + } + } + ], + "MetricName": "BacklogPerTask", + "Namespace": "production-Worker", + "Statistic": "Average", + "Unit": "Count" + }, + "TargetValue": 30 + } + } + }, + "BackLogPerTaskCalculatorFunctionServiceRoleEFA723A4": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "BackLogPerTaskCalculatorFunctionServiceRoleDefaultPolicyB6B10266": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ecs:DescribeServices", + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "productionenvironmentclusterC6599D2D", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": { + "Ref": "WorkerserviceService68C5A5C3" + } + }, + { + "Action": [ + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "EventsQueueB96EB0D2", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "signupqueue33AFF2E6", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "BackLogPerTaskCalculatorFunctionServiceRoleDefaultPolicyB6B10266", + "Roles": [ + { + "Ref": "BackLogPerTaskCalculatorFunctionServiceRoleEFA723A4" + } + ] + } + }, + "BackLogPerTaskCalculatorFunction95AA21D5": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3Bucket151170D5" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3VersionKey3D692C3D" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3VersionKey3D692C3D" + } + ] + } + ] + } + ] + ] + } + }, + "Role": { + "Fn::GetAtt": [ + "BackLogPerTaskCalculatorFunctionServiceRoleEFA723A4", + "Arn" + ] + }, + "Environment": { + "Variables": { + "CLUSTER_NAME": { + "Ref": "productionenvironmentclusterC6599D2D" + }, + "SERVICE_NAME": { + "Fn::GetAtt": [ + "WorkerserviceService68C5A5C3", + "Name" + ] + }, + "NAMESPACE": "production-Worker", + "QUEUE_NAMES": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "EventsQueueB96EB0D2", + "QueueName" + ] + }, + ",", + { + "Fn::GetAtt": [ + "signupqueue33AFF2E6", + "QueueName" + ] + } + ] + ] + } + } + }, + "Handler": "index.queue_handler", + "Runtime": "python3.9" + }, + "DependsOn": [ + "BackLogPerTaskCalculatorFunctionServiceRoleDefaultPolicyB6B10266", + "BackLogPerTaskCalculatorFunctionServiceRoleEFA723A4" + ] + }, + "BacklogPerTaskScheduledRuleB871DD15": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "State": "ENABLED", + "Targets": [ + { + "Arn": { + "Fn::GetAtt": [ + "BackLogPerTaskCalculatorFunction95AA21D5", + "Arn" + ] + }, + "Id": "Target0" + } + ] + } + }, + "BacklogPerTaskScheduledRuleAllowEventRuleawsecsintegBackLogPerTaskCalculatorFunctionEB2B91C7CCD725BB": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "BackLogPerTaskCalculatorFunction95AA21D5", + "Arn" + ] + }, + "Principal": "events.amazonaws.com", + "SourceArn": { + "Fn::GetAtt": [ + "BacklogPerTaskScheduledRuleB871DD15", + "Arn" + ] + } + } + }, + "WorkerBackLogPerTaskCalculatorLogsA4B5AF42": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "", + [ + "/aws/lambda/", + { + "Ref": "BackLogPerTaskCalculatorFunction95AA21D5" + } + ] + ] + }, + "RetentionInDays": 3 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Parameters": { + "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3Bucket151170D5": { + "Type": "String", + "Description": "S3 bucket for asset \"cc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19d\"" + }, + "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dS3VersionKey3D692C3D": { + "Type": "String", + "Description": "S3 key for asset version \"cc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19d\"" + }, + "AssetParameterscc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19dArtifactHash167B1C30": { + "Type": "String", + "Description": "Artifact hash for asset \"cc8d03e1cef62b38b47438d429cdc3828f57a52cffd1a84c4cda032bc21be19d\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.ts index acfdae2437646..9cef50adce4c0 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.publish-subscribe.ts @@ -53,7 +53,13 @@ subServiceDescription.add(new Container({ const topicSubscription1 = new TopicSubscription({ topic: topic1.topic, - queue: new sqs.Queue(stack, 'sign-up-queue'), + topicSubscriptionQueue: { + queue: new sqs.Queue(stack, 'sign-up-queue'), + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(10), + messageProcessingTime: cdk.Duration.seconds(20), + }, + }, }); const topicSubscription2 = new TopicSubscription({ topic: topic2.topic, @@ -61,9 +67,16 @@ const topicSubscription2 = new TopicSubscription({ subServiceDescription.add(new QueueExtension({ subscriptions: [topicSubscription1, topicSubscription2], + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(5), + messageProcessingTime: cdk.Duration.seconds(20), + }, })); new Service(stack, 'Worker', { environment: environment, serviceDescription: subServiceDescription, + autoScaleTaskCount: { + maxTaskCount: 10, + }, }); \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/Dockerfile b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/Dockerfile new file mode 100644 index 0000000000000..8c87ab2f7179d --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/Dockerfile @@ -0,0 +1,9 @@ +FROM public.ecr.aws/lambda/python:latest + +ADD . /opt/lambda +WORKDIR /opt/lambda + +RUN pip3 install boto3 +RUN python3 test_index.py + +ENTRYPOINT [ "/bin/bash" ] \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/test.sh b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/test.sh new file mode 100755 index 0000000000000..17ff0d950b21d --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/test.sh @@ -0,0 +1,19 @@ +#!/bin/bash +#--------------------------------------------------------------------------------------------------- +# executes unit tests +# +# prepares a staging directory with the requirements +set -e +script_dir=$(cd $(dirname $0) && pwd) + +# prepare staging directory +staging=$(mktemp -d) +mkdir -p ${staging} +cd ${staging} + +# copy src and overlay with test +cp ${script_dir}/../../lib/extensions/queue/lambda/queue_backlog_calculator.py $PWD +cp ${script_dir}/test_index.py $PWD +cp ${script_dir}/Dockerfile $PWD + +docker build . \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/test_index.py b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/test_index.py new file mode 100644 index 0000000000000..1ff692292eaa1 --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue-handler/test_index.py @@ -0,0 +1,149 @@ +import json +import io +import unittest +import unittest.mock as mock +import time +from botocore.exceptions import ClientError +from queue_backlog_calculator import QueueHandler + +mock_time = time.time() + +class TestQueueAutoscaling(unittest.TestCase): + maxDiff = None + ''' + Test for unexpected error. + ''' + def test_unexpected_error(self): + ecs_client = mock.Mock() + ecs_client.describe_services.side_effect = ClientError({'Error': {'Code': 'UnexpectedError'}}, 'DescribeServices') + + sqs_client = mock.Mock() + environ = { + 'CLUSTER_NAME': 'TEST_CLUSTER', + 'SERVICE_NAME': 'TEST_SERVICE', + 'NAMESPACE': 'TEST', + 'QUEUE_NAMES': 'queue1' + } + + queue_handler = QueueHandler(ecs_client, sqs_client, environ) + queue_handler.emit() + + self.assertRaisesRegex(Exception, r'UnexpectedError') + + ''' + Test for Exception when the service doesn't exist in cluster. + ''' + @mock.patch('sys.stdout', new_callable=io.StringIO) + def test_no_services_in_cluster(self, _): + ecs_client = mock.Mock() + ecs_client.describe_services.return_value = {'services': []} + + sqs_client = mock.Mock() + environ = { + 'CLUSTER_NAME': 'TEST_CLUSTER', + 'SERVICE_NAME': 'TEST_SERVICE', + 'NAMESPACE': 'TEST', + 'QUEUE_NAMES': 'queue1' + } + + queue_handler = QueueHandler(ecs_client, sqs_client, environ) + queue_handler.emit() + + self.assertRaisesRegex(Exception, r'There are no services with name {} in cluster: {}'.format(environ['SERVICE_NAME'], environ['CLUSTER_NAME'])) + + ''' + Test 'backPerTask' value is equal to 'ApproximateNumberOfMessages' in the queue when no tasks are running. + ''' + @mock.patch('time.time', mock.MagicMock(return_value=mock_time)) + @mock.patch('sys.stdout', new_callable=io.StringIO) + def test_backlog_with_no_running_tasks(self, mock_stdout): + ecs_client = mock.Mock() + ecs_client.describe_services.return_value = {'services': [{'runningCount': 0}]} + + sqs_client = mock.Mock() + sqs_client.get_queue_url.return_value = {'QueueUrl': 'queue1_url'} + sqs_client.get_queue_attributes.return_value = {'Attributes': {'ApproximateNumberOfMessages':100}} + environ = { + 'CLUSTER_NAME': 'TEST_CLUSTER', + 'SERVICE_NAME': 'TEST_SERVICE', + 'NAMESPACE': 'TEST', + 'QUEUE_NAMES': 'queue1' + } + + queue_handler = QueueHandler(ecs_client, sqs_client, environ) + queue_handler.emit() + + metric = json.dumps({ + "_aws": { + "Timestamp": int(mock_time*1000), + "CloudWatchMetrics": [{ + "Namespace": "TEST", + "Dimensions": [["QueueName"]], + "Metrics": [{"Name":"BacklogPerTask", "Unit": "Count"}] + }], + }, + "QueueName": "queue1", + "BacklogPerTask": 100, + }) + self.assertEqual(mock_stdout.getvalue(), metric+'\n') + + ''' + Test 'backPerTask' metric is generated correctly for each queue. + ''' + @mock.patch('time.time', mock.MagicMock(return_value=mock_time)) + @mock.patch('sys.stdout', new_callable=io.StringIO) + def test_metric_generation_per_queue(self, mock_stdout): + ecs_client = mock.Mock() + ecs_client.describe_services.return_value = {'services': [{'runningCount': 2}]} + + val1 = { + 'queue1': {'QueueUrl': 'queue1_url'}, + 'queue2': {'QueueUrl': 'queue2_url'} + } + val2 = { + 'queue1_url': {'Attributes': {'ApproximateNumberOfMessages':101}}, + 'queue2_url': {'Attributes': {'ApproximateNumberOfMessages':200}} + } + + sqs_client = mock.Mock() + sqs_client.get_queue_url.side_effect = [val1['queue1'], val1['queue2']] + sqs_client.get_queue_attributes.side_effect = [val2['queue1_url'], val2['queue2_url']] + environ = { + 'CLUSTER_NAME': 'TEST_CLUSTER', + 'SERVICE_NAME': 'TEST_SERVICE', + 'NAMESPACE': 'TEST', + 'QUEUE_NAMES': 'queue1,queue2' + } + + queue_handler = QueueHandler(ecs_client, sqs_client, environ) + queue_handler.emit() + + metric1 = json.dumps({ + "_aws": { + "Timestamp": int(mock_time*1000), + "CloudWatchMetrics": [{ + "Namespace": "TEST", + "Dimensions": [["QueueName"]], + "Metrics": [{"Name":"BacklogPerTask", "Unit": "Count"}] + }], + }, + "QueueName": "queue1", + "BacklogPerTask": 51, + }) + metric2 = json.dumps({ + "_aws": { + "Timestamp": int(mock_time*1000), + "CloudWatchMetrics": [{ + "Namespace": "TEST", + "Dimensions": [["QueueName"]], + "Metrics": [{"Name":"BacklogPerTask", "Unit": "Count"}] + }], + }, + "QueueName": "queue2", + "BacklogPerTask": 100, + }) + + self.assertEqual(mock_stdout.getvalue(), metric1+'\n'+metric2+'\n') + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/queue.lambda.test.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue.lambda.test.ts new file mode 100644 index 0000000000000..c367e0cbb7715 --- /dev/null +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue.lambda.test.ts @@ -0,0 +1,8 @@ +import { spawnSync } from 'child_process'; +import * as path from 'path'; + +test('queue handler', () => { + const testScript = path.join(__dirname, 'queue-handler', 'test.sh'); + const result = spawnSync(testScript, { stdio: 'inherit' }); + expect(result.status).toBe(0); +}); diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/queue.test.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue.test.ts index 02e883380c217..7aa00581361d9 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/queue.test.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/queue.test.ts @@ -327,7 +327,9 @@ describe('queue', () => { const topicSubscription1 = new TopicSubscription({ topic: new sns.Topic(stack, 'topic1'), - queue: new sqs.Queue(stack, 'myQueue'), + topicSubscriptionQueue: { + queue: new sqs.Queue(stack, 'myQueue'), + }, }); const topicSubscription2 = new TopicSubscription({ topic: new sns.Topic(stack, 'topic2'), @@ -501,7 +503,337 @@ describe('queue', () => { }, ], }); + }); + + test('should error when providing both the subscriptionQueue and queue (deprecated) props for a topic subscription', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + // THEN + expect(() => { + new TopicSubscription({ + topic: new sns.Topic(stack, 'topic1'), + queue: new sqs.Queue(stack, 'delete-queue'), + topicSubscriptionQueue: { + queue: new sqs.Queue(stack, 'sign-up-queue'), + }, + }); + }).toThrow('Either provide the `subscriptionQueue` or the `queue` (deprecated) for the topic subscription, but not both.'); + }); + + test('should be able to add target tracking scaling policy for the Events Queue with no subscriptions', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + serviceDescription.add(new QueueExtension({ + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(5), + messageProcessingTime: cdk.Duration.seconds(20), + }, + })); + + new Service(stack, 'my-service', { + environment, + serviceDescription, + autoScaleTaskCount: { + maxTaskCount: 10, + }, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 10, + MinCapacity: 1, + }); + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + CustomizedMetricSpecification: { + Dimensions: [ + { + Name: 'QueueName', + Value: { + 'Fn::GetAtt': [ + 'EventsQueueB96EB0D2', + 'QueueName', + ], + }, + }, + ], + MetricName: 'BacklogPerTask', + Namespace: 'production-my-service', + Statistic: 'Average', + Unit: 'Count', + }, + TargetValue: 15, + }, + }); + }); + + test('should be able to add target tracking scaling policy for the SQS Queues', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + const topicSubscription1 = new TopicSubscription({ + topic: new sns.Topic(stack, 'topic1'), + topicSubscriptionQueue: { + queue: new sqs.Queue(stack, 'myQueue'), + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(10), + messageProcessingTime: cdk.Duration.seconds(20), + }, + }, + }); + const topicSubscription2 = new TopicSubscription({ + topic: new sns.Topic(stack, 'topic2'), + queue: new sqs.Queue(stack, 'tempQueue'), + }); + serviceDescription.add(new QueueExtension({ + subscriptions: [topicSubscription1, topicSubscription2], + eventsQueue: new sqs.Queue(stack, 'defQueue'), + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(5), + messageProcessingTime: cdk.Duration.seconds(20), + }, + })); + + new Service(stack, 'my-service', { + environment, + serviceDescription, + autoScaleTaskCount: { + maxTaskCount: 10, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 10, + MinCapacity: 1, + }); + + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + CustomizedMetricSpecification: { + Dimensions: [ + { + Name: 'QueueName', + Value: { + 'Fn::GetAtt': [ + 'defQueue1F91A65B', + 'QueueName', + ], + }, + }, + ], + MetricName: 'BacklogPerTask', + Namespace: 'production-my-service', + Statistic: 'Average', + Unit: 'Count', + }, + TargetValue: 15, + }, + }); + + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + CustomizedMetricSpecification: { + Dimensions: [ + { + Name: 'QueueName', + Value: { + 'Fn::GetAtt': [ + 'myQueue4FDFF71C', + 'QueueName', + ], + }, + }, + ], + MetricName: 'BacklogPerTask', + Namespace: 'production-my-service', + Statistic: 'Average', + Unit: 'Count', + }, + TargetValue: 30, + }, + }); + + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + CustomizedMetricSpecification: { + Dimensions: [ + { + Name: 'QueueName', + Value: { + 'Fn::GetAtt': [ + 'tempQueueEF946882', + 'QueueName', + ], + }, + }, + ], + MetricName: 'BacklogPerTask', + Namespace: 'production-my-service', + Statistic: 'Average', + Unit: 'Count', + }, + TargetValue: 15, + }, + }); + }); + + test('should error when adding scaling policy if scaling target has not been configured', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + const topicSubscription1 = new TopicSubscription({ + topic: new sns.Topic(stack, 'topic1'), + }); + + serviceDescription.add(new QueueExtension({ + subscriptions: [topicSubscription1], + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(10), + messageProcessingTime: cdk.Duration.seconds(20), + }, + })); + + // THEN + expect(() => { + new Service(stack, 'my-service', { + environment, + serviceDescription, + }); + }).toThrow(/Auto scaling target for the service 'my-service' hasn't been configured. Please use Service construct to configure 'minTaskCount' and 'maxTaskCount'./); + }); + + test('should error when message processing time for the queue is greater than acceptable latency', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + const topicSubscription1 = new TopicSubscription({ + topic: new sns.Topic(stack, 'topic1'), + topicSubscriptionQueue: { + queue: new sqs.Queue(stack, 'sign-up-queue'), + }, + }); + + serviceDescription.add(new QueueExtension({ + subscriptions: [topicSubscription1], + scaleOnLatency: { + acceptableLatency: cdk.Duration.seconds(10), + messageProcessingTime: cdk.Duration.seconds(20), + }, + })); + + // THEN + expect(() => { + new Service(stack, 'my-service', { + environment, + serviceDescription, + autoScaleTaskCount: { + maxTaskCount: 10, + }, + }); + }).toThrow('Message processing time (20s) for the queue cannot be greater acceptable queue latency (10s).'); + }); + + test('should error when configuring auto scaling only for topic-specific queue', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const environment = new Environment(stack, 'production'); + const serviceDescription = new ServiceDescription(); + + serviceDescription.add(new Container({ + cpu: 256, + memoryMiB: 512, + trafficPort: 80, + image: ecs.ContainerImage.fromRegistry('nathanpeck/name'), + })); + + const topicSubscription1 = new TopicSubscription({ + topic: new sns.Topic(stack, 'topic1'), + topicSubscriptionQueue: { + queue: new sqs.Queue(stack, 'sign-up-queue'), + scaleOnLatency: { + acceptableLatency: cdk.Duration.minutes(10), + messageProcessingTime: cdk.Duration.seconds(20), + }, + }, + }); + + serviceDescription.add(new QueueExtension({ + subscriptions: [topicSubscription1], + })); + + // THEN + expect(() => { + new Service(stack, 'my-service', { + environment, + serviceDescription, + autoScaleTaskCount: { + maxTaskCount: 10, + }, + }); + }).toThrow(/Autoscaling for a topic-specific queue cannot be configured as autoscaling based on SQS Queues hasn’t been set up for the service 'my-service'. If you want to enable autoscaling for this service, please also specify 'scaleOnLatency' in the 'QueueExtension'/); }); }); \ No newline at end of file From 171cbc14166b360b0c2739de44f1b1ef220d55f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 10:47:16 +0000 Subject: [PATCH 30/82] chore(deps): bump actions/cache from 2.1.6 to 2.1.7 (#17745) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/cache](https://github.com/actions/cache) from 2.1.6 to 2.1.7.
Release notes

Sourced from actions/cache's releases.

v2.1.7

Support 10GB cache upload using the latest version 1.0.8 of @actions/cache

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/cache&package-manager=github_actions&previous-version=2.1.6&new-version=2.1.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/yarn-upgrade.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml index ea9f2bee5dd31..0389380b2a404 100644 --- a/.github/workflows/yarn-upgrade.yml +++ b/.github/workflows/yarn-upgrade.yml @@ -27,7 +27,7 @@ jobs: run: echo "::set-output name=dir::$(yarn cache dir)" - name: Restore Yarn cache - uses: actions/cache@v2.1.6 + uses: actions/cache@v2.1.7 with: path: ${{ steps.yarn-cache.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} From 168a98fb213184dfef29ae38b986704b5abeb99e Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Tue, 30 Nov 2021 01:02:57 +0900 Subject: [PATCH 31/82] fix(aws-elasticloadbalancingv2): Set stickiness.enabled unless target type is lambda (#17271) Avoid setting `stickiness.enabled` to `false` when the target group type is lambda as it breaks on deployment. Fixes #17261. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../test/integ.lambda-target.expected.json | 6 ----- .../lib/alb/application-target-group.ts | 4 +++ .../test/alb/target-group.test.ts | 27 +++++++++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.lambda-target.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.lambda-target.expected.json index 75905be0cd5ba..a934646e087ab 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.lambda-target.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.lambda-target.expected.json @@ -404,12 +404,6 @@ "LBListenerTargetsGroup76EF81E8": { "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", "Properties": { - "TargetGroupAttributes": [ - { - "Key": "stickiness.enabled", - "Value": "false" - } - ], "Targets": [ { "Id": { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 487394019ed15..cf34ee5a7857e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -166,6 +166,10 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat const result = target.attachToApplicationTargetGroup(this); this.addLoadBalancerTarget(result); } + + if (this.targetType === TargetType.LAMBDA) { + this.setAttribute('stickiness.enabled', undefined); + } } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index 7eed0a4627011..5f08f98ce7d48 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -20,6 +20,33 @@ describe('tests', () => { }).toThrow(/'vpc' is required for a non-Lambda TargetGroup/); }); + test('Lambda target should not have stickiness.enabled set', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + + new elbv2.ApplicationTargetGroup(stack, 'TG', { + targetType: elbv2.TargetType.LAMBDA, + }); + + const tg = new elbv2.ApplicationTargetGroup(stack, 'TG2'); + tg.addTarget({ + attachToApplicationTargetGroup(_targetGroup: elbv2.IApplicationTargetGroup): elbv2.LoadBalancerTargetProps { + return { + targetType: elbv2.TargetType.LAMBDA, + targetJson: { id: 'arn:aws:lambda:eu-west-1:123456789012:function:myFn' }, + }; + }, + }); + + expect(stack).not.toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + TargetGroupAttributes: [ + { + Key: 'stickiness.enabled', + }, + ], + }); + }); + test('Can add self-registering target to imported TargetGroup', () => { // GIVEN const app = new cdk.App(); From a1685c62071846d41eb47234fbf2c94884453c17 Mon Sep 17 00:00:00 2001 From: Harry Guillermo Date: Mon, 29 Nov 2021 08:48:14 -0800 Subject: [PATCH 32/82] feat(ec2): explicit mapPublicIpOnLaunch configuration for public subnets (#17346) **Issue (Fixes https://github.com/aws/aws-cdk/issues/14194, https://github.com/aws/aws-cdk/issues/16838)** When creating a VPC you can define a SubnetConfiguration but it is not possible to define `mapPublicIpOnLaunch` for public subnets. VPC Example: ``` const vpc = new ec2.Vpc(this, 'vpc-id', { maxAzs: 2, subnetConfiguration: [ { name: 'private-subnet-1', subnetType: ec2.SubnetType.PRIVATE, cidrMask: 24, }, { name: 'public-subnet-1', subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24, }, ] }); ``` Proposal: ``` const vpc = new ec2.Vpc(this, 'vpc-id', { maxAzs: 2, subnetConfiguration: [ { name: 'private-subnet-1', subnetType: ec2.SubnetType.PRIVATE, cidrMask: 24, }, { name: 'public-subnet-1', subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24, mapPublicIpOnLaunch: false, // or true }, ] }); ``` --- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 20 +++++- packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 78 +++++++++++++++++++++- 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 6d1722b3135d8..14eebaaee45c0 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -1013,6 +1013,13 @@ export interface SubnetConfiguration { * @default false */ readonly reserved?: boolean; + + /** + * Controls if a public IP is associated to an instance at launch + * + * @default true in Subnet.Public, false in Subnet.Private or Subnet.Isolated. + */ + readonly mapPublicIpOnLaunch?: boolean; } /** @@ -1452,12 +1459,23 @@ export class Vpc extends VpcBase { return; } + // mapPublicIpOnLaunch true in Subnet.Public, false in Subnet.Private or Subnet.Isolated. + let mapPublicIpOnLaunch = false; + if (subnetConfig.subnetType !== SubnetType.PUBLIC && subnetConfig.mapPublicIpOnLaunch !== undefined) { + throw new Error(`${subnetConfig.subnetType} subnet cannot include mapPublicIpOnLaunch parameter`); + } + if (subnetConfig.subnetType === SubnetType.PUBLIC) { + mapPublicIpOnLaunch = (subnetConfig.mapPublicIpOnLaunch !== undefined) + ? subnetConfig.mapPublicIpOnLaunch + : true; + } + const name = subnetId(subnetConfig.name, index); const subnetProps: SubnetProps = { availabilityZone: zone, vpcId: this.vpcId, cidrBlock: this.networkBuilder.addSubnet(cidrMask), - mapPublicIpOnLaunch: (subnetConfig.subnetType === SubnetType.PUBLIC), + mapPublicIpOnLaunch: mapPublicIpOnLaunch, }; let subnet: Subnet; diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index b7922e877c64b..53942f9199a50 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -434,6 +434,82 @@ describe('vpc', () => { }); + test('with public subnets MapPublicIpOnLaunch is true if parameter mapPublicIpOnLaunch is true', () => { + const stack = getTestStack(); + new Vpc(stack, 'VPC', { + maxAzs: 1, + subnetConfiguration: [ + { + cidrMask: 24, + name: 'ingress', + subnetType: SubnetType.PUBLIC, + mapPublicIpOnLaunch: true, + }, + ], + }); + expect(stack).toCountResources('AWS::EC2::Subnet', 1); + expect(stack).not.toHaveResource('AWS::EC2::NatGateway'); + expect(stack).toHaveResource('AWS::EC2::Subnet', { + MapPublicIpOnLaunch: true, + }); + }); + test('with public subnets MapPublicIpOnLaunch is false if parameter mapPublicIpOnLaunch is false', () => { + const stack = getTestStack(); + new Vpc(stack, 'VPC', { + maxAzs: 1, + subnetConfiguration: [ + { + cidrMask: 24, + name: 'ingress', + subnetType: SubnetType.PUBLIC, + mapPublicIpOnLaunch: false, + }, + ], + }); + expect(stack).toCountResources('AWS::EC2::Subnet', 1); + expect(stack).not.toHaveResource('AWS::EC2::NatGateway'); + expect(stack).toHaveResource('AWS::EC2::Subnet', { + MapPublicIpOnLaunch: false, + }); + }); + test('with private subnets throw exception if parameter mapPublicIpOnLaunch is defined', () => { + const stack = getTestStack(); + expect(() => { + new Vpc(stack, 'VPC', { + maxAzs: 1, + subnetConfiguration: [ + { + name: 'public', + subnetType: SubnetType.PUBLIC, + }, + { + name: 'private', + subnetType: SubnetType.PRIVATE_WITH_NAT, + mapPublicIpOnLaunch: true, + }, + ], + }); + }).toThrow(/subnet cannot include mapPublicIpOnLaunch parameter/); + }); + test('with isolated subnets throw exception if parameter mapPublicIpOnLaunch is defined', () => { + const stack = getTestStack(); + expect(() => { + new Vpc(stack, 'VPC', { + maxAzs: 1, + subnetConfiguration: [ + { + name: 'public', + subnetType: SubnetType.PUBLIC, + }, + { + name: 'private', + subnetType: SubnetType.PRIVATE_ISOLATED, + mapPublicIpOnLaunch: true, + }, + ], + }); + }).toThrow(/subnet cannot include mapPublicIpOnLaunch parameter/); + }); test('maxAZs defaults to 3 if unset', () => { const stack = getTestStack(); new Vpc(stack, 'VPC'); @@ -1817,4 +1893,4 @@ function hasTags(expectedTags: Array<{Key: string, Value: string}>): (props: any throw e; } }; -} \ No newline at end of file +} From 29039e8bd13a4fdb7f84254038b3331c179273fd Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Mon, 29 Nov 2021 17:44:35 +0000 Subject: [PATCH 33/82] chore(apigatewayv2): integration api re-organization (#17752) There are three major changes. `HttpRouteIntegration` (and its sibling `WebSocketRouteIntegration`) creates a CDK construct (`HttpIntegration` and `WebSocketIntegration`) as part of its bind operation. The id to this CDK construct is determined by hashing the results of the bind. Using hashes makes the construct id fragile/sensitive, consequently the CFN resource's logical id fragile. The fragility comes mainly from the question - have we hashed all of the expected properties that should be hashed, and nothing extra? If we have not hashed properties that should be there, or hashed too much, we end up with a hash change, hence resource replacement that is unexpected. This commit changes this approach and asks the user to provide the construct's id. This is more aligned with the current CDK expectation that users provide an id when initializing constructs. We just don't have a good way to validate that our hashing is accurate, so let's not do it at all. This change makes the user provide a unique name within a scope, which is already a standard requirement for CDK constructs. Secondly, the ergonomics of specific integration implementations, such as, `LambdaProxyIntegration`, `HttpAlbIntegration`, etc. is modified so that the integrating primitive is moved out of the 'props', and to the constructor. The API ergonomics of this feels much better than having to always provide a 'props'. Since this package contains constructs around both http api and websocket api, the convention to follow is that all classes specific to the former will be prefixed with `Http` and the latter will be prefixed with `WebSocket`. Bring the integration classes `LambdaProxyIntegration` and `HttpProxyIntegration` in line with this convention. These are renamed to `HttpLambdaIntegration` and `HttpUrlIntegration` respectively. BREAKING CHANGE: The `HttpIntegration` and `WebSocketIntegration` classes require an "id" parameter to be provided during its initialization. * **apigatewayv2-integrations:** The `LambdaWebSocketIntegration` is now renamed to `WebSocketLambdaIntegration`. The new class accepts the handler to the target lambda function directly in its constructor. * **apigatewayv2-integrations:** `HttpProxyIntegration` and `HttpProxyIntegrationProps` are now renamed to `HttpUrlIntegration` and `HttpUrlIntegrationProps` respectively. The new class accepts the target url directly in its constructor. * **apigatewayv2-integrations:** `LambdaProxyIntegration` and `LambdaProxyIntegrationProps` are now renamed to `HttpLambdaIntegration` and `HttpLambdaIntegrationProps` respectively. The new class accepts the lambda function handler directly in its constructor. * **apigatewayv2-integrations:** `HttpAlbIntegration` now accepts the ELB listener directly in its constructor. * **apigatewayv2-integrations:** `HttpNlbIntegration` now accepts the ELB listener directly in its constructor. * **apigatewayv2-integrations:** `HttpServiceDiscoveryIntegration` now accepts the service discovery Service directly in its constructor. * **apigatewayv2-authorizers:** `UserPoolAuthorizerProps` is now renamed to `HttpUserPoolAuthorizerProps`. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-apigatewayv2-authorizers/README.md | 36 +++++------------ .../lib/http/user-pool.ts | 6 +-- .../test/http/integ.lambda.expected.json | 6 +-- .../test/http/integ.lambda.ts | 4 +- .../test/http/integ.user-pool.expected.json | 8 ++-- .../test/http/integ.user-pool.ts | 4 +- .../test/http/integration.ts | 15 +++++++ .../test/http/jwt.test.ts | 13 +----- .../test/http/lambda.test.ts | 13 +----- .../test/http/user-pool.test.ts | 13 +----- .../aws-apigatewayv2-integrations/README.md | 35 +++++----------- .../lib/http/alb.ts | 23 ++++++----- .../lib/http/http-proxy.ts | 20 +++++----- .../lib/http/lambda.ts | 31 ++++++++------ .../lib/http/nlb.ts | 23 ++++++----- .../lib/http/service-discovery.ts | 19 +++++---- .../lib/websocket/lambda.ts | 29 +++++++------- .../test/http/alb.test.ts | 26 +++--------- .../test/http/http-proxy.test.ts | 11 ++--- .../test/http/integ.alb.expected.json | 4 +- .../test/http/integ.alb.ts | 4 +- .../test/http/integ.http-proxy.expected.json | 10 ++--- .../test/http/integ.http-proxy.ts | 10 ++--- .../http/integ.lambda-proxy.expected.json | 6 +-- .../test/http/integ.lambda-proxy.ts | 6 +-- .../test/http/integ.nlb.expected.json | 22 +++++----- .../test/http/integ.nlb.ts | 4 +- .../integ.service-discovery.expected.json | 22 +++++----- .../test/http/integ.service-discovery.ts | 3 +- .../test/http/lambda.test.ts | 16 +++----- .../test/http/nlb.test.ts | 26 +++--------- .../test/http/private/integration.test.ts | 2 +- .../test/http/service-discovery.test.ts | 19 +++------ .../test/websocket/integ.lambda.expected.json | 24 +++++------ .../test/websocket/integ.lambda.ts | 10 ++--- .../test/websocket/lambda.test.ts | 4 +- packages/@aws-cdk/aws-apigatewayv2/README.md | 40 ++++++++----------- .../aws-apigatewayv2/lib/http/integration.ts | 18 ++++----- .../lib/websocket/integration.ts | 17 ++++---- .../aws-apigatewayv2/test/http/api.test.ts | 4 ++ .../aws-apigatewayv2/test/http/route.test.ts | 10 +++-- .../test/websocket/api.test.ts | 4 ++ .../test/websocket/route.test.ts | 6 ++- .../integ.call-http-api.expected.json | 6 +-- .../test/apigateway/integ.call-http-api.ts | 4 +- 45 files changed, 281 insertions(+), 355 deletions(-) create mode 100644 packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integration.ts diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md index 7da981240612e..df0a69a82b11e 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md @@ -71,7 +71,7 @@ The example below showcases default authorization, along with route authorizatio ```ts import { HttpJwtAuthorizer } from '@aws-cdk/aws-apigatewayv2-authorizers'; -import { HttpProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; const authorizer = new HttpJwtAuthorizer({ jwtAudience: ['3131231'], @@ -84,34 +84,26 @@ const api = new apigwv2.HttpApi(this, 'HttpApi', { }); api.addRoutes({ - integration: new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', - }), + integration: new HttpUrlIntegration('BooksIntegration', 'https://get-books-proxy.myproxy.internal'), path: '/books', methods: [apigwv2.HttpMethod.GET], }); api.addRoutes({ - integration: new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', - }), + integration: new HttpUrlIntegration('BooksIdIntegration', 'https://get-books-proxy.myproxy.internal'), path: '/books/{id}', methods: [apigwv2.HttpMethod.GET], }); api.addRoutes({ - integration: new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', - }), + integration: new HttpUrlIntegration('BooksIntegration', 'https://get-books-proxy.myproxy.internal'), path: '/books', methods: [apigwv2.HttpMethod.POST], authorizationScopes: ['write:books'] }); api.addRoutes({ - integration: new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', - }), + integration: new HttpUrlIntegration('LoginIntegration', 'https://get-books-proxy.myproxy.internal'), path: '/login', methods: [apigwv2.HttpMethod.POST], authorizer: new apigwv2.HttpNoneAuthorizer(), @@ -136,7 +128,7 @@ Clients that fail authorization are presented with either 2 responses: ```ts import { HttpJwtAuthorizer } from '@aws-cdk/aws-apigatewayv2-authorizers'; -import { HttpProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; const authorizer = new HttpJwtAuthorizer({ jwtAudience: ['3131231'], @@ -146,9 +138,7 @@ const authorizer = new HttpJwtAuthorizer({ const api = new apigwv2.HttpApi(this, 'HttpApi'); api.addRoutes({ - integration: new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', - }), + integration: new HttpUrlIntegration('BooksIntegration', 'https://get-books-proxy.myproxy.internal'), path: '/books', authorizer, }); @@ -165,7 +155,7 @@ pools as authorizer](https://docs.aws.amazon.com/apigateway/latest/developerguid ```ts import * as cognito from '@aws-cdk/aws-cognito'; import { HttpUserPoolAuthorizer } from '@aws-cdk/aws-apigatewayv2-authorizers'; -import { HttpProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; const userPool = new cognito.UserPool(this, 'UserPool'); const userPoolClient = userPool.addClient('UserPoolClient'); @@ -178,9 +168,7 @@ const authorizer = new HttpUserPoolAuthorizer({ const api = new apigwv2.HttpApi(this, 'HttpApi'); api.addRoutes({ - integration: new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', - }), + integration: new HttpUrlIntegration('BooksIntegration', 'https://get-books-proxy.myproxy.internal'), path: '/books', authorizer, }); @@ -195,7 +183,7 @@ Lambda authorizers depending on their response, fall into either two types - Sim ```ts import { HttpLambdaAuthorizer, HttpLambdaResponseType } from '@aws-cdk/aws-apigatewayv2-authorizers'; -import { HttpProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; // This function handles your auth logic declare const authHandler: lambda.Function; @@ -209,9 +197,7 @@ const authorizer = new HttpLambdaAuthorizer({ const api = new apigwv2.HttpApi(this, 'HttpApi'); api.addRoutes({ - integration: new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', - }), + integration: new HttpUrlIntegration('BooksIntegration', 'https://get-books-proxy.myproxy.internal'), path: '/books', authorizer, }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts index 21cef2e478756..cd4e39ad03fea 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts @@ -3,9 +3,9 @@ import { IUserPool, IUserPoolClient } from '@aws-cdk/aws-cognito'; import { Stack, Token } from '@aws-cdk/core'; /** - * Properties to initialize UserPoolAuthorizer. + * Properties to initialize HttpUserPoolAuthorizer. */ -export interface UserPoolAuthorizerProps { +export interface HttpUserPoolAuthorizerProps { /** * The user pool clients that should be used to authorize requests with the user pool. */ @@ -43,7 +43,7 @@ export interface UserPoolAuthorizerProps { export class HttpUserPoolAuthorizer implements IHttpRouteAuthorizer { private authorizer?: HttpAuthorizer; - constructor(private readonly props: UserPoolAuthorizerProps) { + constructor(private readonly props: HttpUserPoolAuthorizerProps) { } public bind(options: HttpRouteAuthorizerBindOptions): HttpRouteAuthorizerConfig { diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json index 6f0d30c71ad66..29ee6fe741501 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json @@ -17,7 +17,7 @@ "AutoDeploy": true } }, - "MyHttpApiGETAuthorizerIntegMyHttpApiGET16D02385PermissionBB02EBFE": { + "MyHttpApiGETRootIntegrationPermission81613491": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -54,7 +54,7 @@ } } }, - "MyHttpApiGETHttpIntegration6f095b8469365f72e33fa33d9711b140516EBE31": { + "MyHttpApiGETRootIntegration5068C5B0": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -87,7 +87,7 @@ [ "integrations/", { - "Ref": "MyHttpApiGETHttpIntegration6f095b8469365f72e33fa33d9711b140516EBE31" + "Ref": "MyHttpApiGETRootIntegration5068C5B0" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts index 264da5f4bf510..9bc2326da21c9 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { HttpApi, HttpMethod } from '@aws-cdk/aws-apigatewayv2'; -import { LambdaProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; import * as lambda from '@aws-cdk/aws-lambda'; import { App, Stack, CfnOutput } from '@aws-cdk/core'; import { HttpLambdaAuthorizer, HttpLambdaResponseType } from '../../lib'; @@ -40,7 +40,7 @@ const handler = new lambda.Function(stack, 'lambda', { httpApi.addRoutes({ path: '/', methods: [HttpMethod.GET], - integration: new LambdaProxyIntegration({ handler }), + integration: new HttpLambdaIntegration('RootIntegration', handler), authorizer, }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json index c3ddc2fbc6e94..3e8577dfa278c 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json @@ -17,7 +17,7 @@ "AutoDeploy": true } }, - "MyHttpApiGETAuthorizerIntegMyHttpApiGET16D02385PermissionBB02EBFE": { + "MyHttpApiGETRootIntegratinPermissionCEEEB498": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -54,7 +54,7 @@ } } }, - "MyHttpApiGETHttpIntegration6f095b8469365f72e33fa33d9711b140516EBE31": { + "MyHttpApiGETRootIntegratin93150A89": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -87,7 +87,7 @@ [ "integrations/", { - "Ref": "MyHttpApiGETHttpIntegration6f095b8469365f72e33fa33d9711b140516EBE31" + "Ref": "MyHttpApiGETRootIntegratin93150A89" } ] ] @@ -101,10 +101,10 @@ "Ref": "MyHttpApi8AEAAC21" }, "AuthorizerType": "JWT", + "Name": "UserPoolAuthorizer", "IdentitySource": [ "$request.header.Authorization" ], - "Name": "UserPoolAuthorizer", "JwtConfiguration": { "Audience": [ { diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts index 3e607b4474365..6e9ddd8e69b5c 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts @@ -1,7 +1,7 @@ /// !cdk-integ pragma:ignore-assets import * as path from 'path'; import { HttpApi, HttpMethod } from '@aws-cdk/aws-apigatewayv2'; -import { LambdaProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; import * as cognito from '@aws-cdk/aws-cognito'; import * as lambda from '@aws-cdk/aws-lambda'; import { App, Stack } from '@aws-cdk/core'; @@ -37,6 +37,6 @@ const handler = new lambda.Function(stack, 'lambda', { httpApi.addRoutes({ path: '/', methods: [HttpMethod.GET], - integration: new LambdaProxyIntegration({ handler }), + integration: new HttpLambdaIntegration('RootIntegratin', handler), authorizer, }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integration.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integration.ts new file mode 100644 index 0000000000000..bfabca0545ea5 --- /dev/null +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integration.ts @@ -0,0 +1,15 @@ +import { HttpIntegrationType, HttpRouteIntegration, HttpRouteIntegrationBindOptions, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; + +export class DummyRouteIntegration extends HttpRouteIntegration { + constructor() { + super('DummyRouteIntegration'); + } + + public bind(_: HttpRouteIntegrationBindOptions) { + return { + payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, + type: HttpIntegrationType.HTTP_PROXY, + uri: 'some-uri', + }; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts index c65642d8df4d3..1d91a37438cfb 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts @@ -1,7 +1,8 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, HttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi } from '@aws-cdk/aws-apigatewayv2'; import { Stack } from '@aws-cdk/core'; import { HttpJwtAuthorizer } from '../../lib'; +import { DummyRouteIntegration } from './integration'; describe('HttpJwtAuthorizer', () => { test('default', () => { @@ -58,13 +59,3 @@ describe('HttpJwtAuthorizer', () => { Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::Authorizer', 1); }); }); - -class DummyRouteIntegration extends HttpRouteIntegration { - public bind(_: HttpRouteIntegrationBindOptions) { - return { - payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, - type: HttpIntegrationType.HTTP_PROXY, - uri: 'some-uri', - }; - } -} diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts index 28b007dafd359..8ced20b3c1e1e 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts @@ -1,8 +1,9 @@ import { Match, Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, HttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi } from '@aws-cdk/aws-apigatewayv2'; import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; import { Duration, Stack } from '@aws-cdk/core'; import { HttpLambdaAuthorizer, HttpLambdaResponseType } from '../../lib'; +import { DummyRouteIntegration } from './integration'; describe('HttpLambdaAuthorizer', () => { @@ -169,13 +170,3 @@ describe('HttpLambdaAuthorizer', () => { }); }); }); - -class DummyRouteIntegration extends HttpRouteIntegration { - public bind(_: HttpRouteIntegrationBindOptions) { - return { - payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, - type: HttpIntegrationType.HTTP_PROXY, - uri: 'some-uri', - }; - } -} diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts index 7189c060b877b..21bda048b1a4d 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts @@ -1,8 +1,9 @@ import { Template } from '@aws-cdk/assertions'; -import { HttpApi, HttpIntegrationType, HttpRouteIntegrationBindOptions, HttpRouteIntegration, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; +import { HttpApi } from '@aws-cdk/aws-apigatewayv2'; import { UserPool } from '@aws-cdk/aws-cognito'; import { Stack } from '@aws-cdk/core'; import { HttpUserPoolAuthorizer } from '../../lib'; +import { DummyRouteIntegration } from './integration'; describe('HttpUserPoolAuthorizer', () => { test('default', () => { @@ -111,13 +112,3 @@ describe('HttpUserPoolAuthorizer', () => { }); }); }); - -class DummyRouteIntegration extends HttpRouteIntegration { - public bind(_: HttpRouteIntegrationBindOptions) { - return { - payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, - type: HttpIntegrationType.HTTP_PROXY, - uri: 'some-uri', - }; - } -} diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md b/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md index d284be9491e99..07c2d3310cc5b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md @@ -41,12 +41,10 @@ proxy integrations](https://docs.aws.amazon.com/apigateway/latest/developerguide The following code configures a route `GET /books` with a Lambda proxy integration. ```ts -import { LambdaProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; declare const booksDefaultFn: lambda.Function; -const booksIntegration = new LambdaProxyIntegration({ - handler: booksDefaultFn, -}); +const booksIntegration = new HttpLambdaIntegration('BooksIntegration', booksDefaultFn); const httpApi = new apigwv2.HttpApi(this, 'HttpApi'); @@ -68,11 +66,9 @@ The following code configures a route `GET /books` with an HTTP proxy integratio `get-books-proxy.myproxy.internal`. ```ts -import { HttpProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; -const booksIntegration = new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', -}); +const booksIntegration = new HttpUrlIntegration('BooksIntegration', 'https://get-books-proxy.myproxy.internal'); const httpApi = new apigwv2.HttpApi(this, 'HttpApi'); @@ -106,9 +102,7 @@ listener.addTargets('target', { }); const httpEndpoint = new apigwv2.HttpApi(this, 'HttpProxyPrivateApi', { - defaultIntegration: new HttpAlbIntegration({ - listener, - }), + defaultIntegration: new HttpAlbIntegration('DefaultIntegration', listener), }); ``` @@ -129,9 +123,7 @@ listener.addTargets('target', { }); const httpEndpoint = new apigwv2.HttpApi(this, 'HttpProxyPrivateApi', { - defaultIntegration: new HttpNlbIntegration({ - listener, - }), + defaultIntegration: new HttpNlbIntegration('DefaultIntegration', listener), }); ``` @@ -154,9 +146,8 @@ const namespace = new servicediscovery.PrivateDnsNamespace(this, 'Namespace', { const service = namespace.createService('Service'); const httpEndpoint = new apigwv2.HttpApi(this, 'HttpProxyPrivateApi', { - defaultIntegration: new HttpServiceDiscoveryIntegration({ + defaultIntegration: new HttpServiceDiscoveryIntegration('DefaultIntegration', service, { vpcLink, - service, }), }); ``` @@ -179,8 +170,7 @@ listener.addTargets('target', { }); const httpEndpoint = new apigwv2.HttpApi(this, 'HttpProxyPrivateApi', { - defaultIntegration: new HttpAlbIntegration({ - listener, + defaultIntegration: new HttpAlbIntegration('DefaultIntegration', listener, { parameterMapping: new apigwv2.ParameterMapping() .appendHeader('header2', apigwv2.MappingValue.requestHeader('header1')) .removeHeader('header1'), @@ -200,8 +190,7 @@ listener.addTargets('target', { }); const httpEndpoint = new apigwv2.HttpApi(this, 'HttpProxyPrivateApi', { - defaultIntegration: new HttpAlbIntegration({ - listener, + defaultIntegration: new HttpAlbIntegration('DefaultIntegration', listener, { parameterMapping: new apigwv2.ParameterMapping().custom('myKey', 'myValue'), }), }); @@ -222,7 +211,7 @@ The API Gateway service will invoke the lambda function with an event payload of The following code configures a `sendmessage` route with a Lambda integration ```ts -import { LambdaWebSocketIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { WebSocketLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; const webSocketApi = new apigwv2.WebSocketApi(this, 'mywsapi'); new apigwv2.WebSocketStage(this, 'mystage', { @@ -233,8 +222,6 @@ new apigwv2.WebSocketStage(this, 'mystage', { declare const messageHandler: lambda.Function; webSocketApi.addRoute('sendmessage', { - integration: new LambdaWebSocketIntegration({ - handler: messageHandler, - }), + integration: new WebSocketLambdaIntegration('SendMessageIntegration', messageHandler), }); ``` diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/alb.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/alb.ts index e5e6d5c448663..d7795f909f874 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/alb.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/alb.ts @@ -8,24 +8,29 @@ import { HttpPrivateIntegration } from './private/integration'; * Properties to initialize `HttpAlbIntegration`. */ export interface HttpAlbIntegrationProps extends HttpPrivateIntegrationOptions { - /** - * The listener to the application load balancer used for the integration - */ - readonly listener: elbv2.IApplicationListener; } /** * The Application Load Balancer integration resource for HTTP API */ export class HttpAlbIntegration extends HttpPrivateIntegration { - constructor(private readonly props: HttpAlbIntegrationProps) { - super(); + /** + * @param id id of the underlying integration construct + * @param listener the ELB application listener + * @param props properties to configure the integration + */ + constructor( + id: string, + private readonly listener: elbv2.IApplicationListener, + private readonly props: HttpAlbIntegrationProps = {}) { + + super(id); } public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { let vpc: ec2.IVpc | undefined = this.props.vpcLink?.vpc; - if (!vpc && (this.props.listener instanceof elbv2.ApplicationListener)) { - vpc = this.props.listener.loadBalancer.vpc; + if (!vpc && (this.listener instanceof elbv2.ApplicationListener)) { + vpc = this.listener.loadBalancer.vpc; } if (!vpc) { throw new Error('The vpcLink property must be specified when using an imported Application Listener.'); @@ -42,7 +47,7 @@ export class HttpAlbIntegration extends HttpPrivateIntegration { type: this.integrationType, connectionType: this.connectionType, connectionId: vpcLink.vpcLinkId, - uri: this.props.listener.listenerArn, + uri: this.listener.listenerArn, secureServerName: this.props.secureServerName, parameterMapping: this.props.parameterMapping, }; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts index 879912ee881cf..c0b3104653cc2 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/http-proxy.ts @@ -11,12 +11,7 @@ import { /** * Properties to initialize a new `HttpProxyIntegration`. */ -export interface HttpProxyIntegrationProps { - /** - * The full-qualified HTTP URL for the HTTP integration - */ - readonly url: string - +export interface HttpUrlIntegrationProps { /** * The HTTP method that must be used to invoke the underlying HTTP proxy. * @default HttpMethod.ANY @@ -34,9 +29,14 @@ export interface HttpProxyIntegrationProps { /** * The HTTP Proxy integration resource for HTTP API */ -export class HttpProxyIntegration extends HttpRouteIntegration { - constructor(private readonly props: HttpProxyIntegrationProps) { - super(); +export class HttpUrlIntegration extends HttpRouteIntegration { + /** + * @param id id of the underlying integration construct + * @param url the URL to proxy to + * @param props properties to configure the integration + */ + constructor(id: string, private readonly url: string, private readonly props: HttpUrlIntegrationProps = {}) { + super(id); } public bind(_: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { @@ -44,7 +44,7 @@ export class HttpProxyIntegration extends HttpRouteIntegration { method: this.props.method ?? HttpMethod.ANY, payloadFormatVersion: PayloadFormatVersion.VERSION_1_0, // 1.0 is required and is the only supported format type: HttpIntegrationType.HTTP_PROXY, - uri: this.props.url, + uri: this.url, parameterMapping: this.props.parameterMapping, }; } diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts index ff5750da71077..6bdce918195cf 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/lambda.ts @@ -8,17 +8,12 @@ import { } from '@aws-cdk/aws-apigatewayv2'; import { ServicePrincipal } from '@aws-cdk/aws-iam'; import { IFunction } from '@aws-cdk/aws-lambda'; -import { Names, Stack } from '@aws-cdk/core'; +import { Stack } from '@aws-cdk/core'; /** * Lambda Proxy integration properties */ -export interface LambdaProxyIntegrationProps { - /** - * The handler for this integration. - */ - readonly handler: IFunction - +export interface HttpLambdaIntegrationProps { /** * Version of the payload sent to the lambda handler. * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html @@ -37,15 +32,27 @@ export interface LambdaProxyIntegrationProps { /** * The Lambda Proxy integration resource for HTTP API */ -export class LambdaProxyIntegration extends HttpRouteIntegration { +export class HttpLambdaIntegration extends HttpRouteIntegration { + + private readonly _id: string; + + /** + * @param id id of the underlying integration construct + * @param handler the Lambda handler to integrate with + * @param props properties to configure the integration + */ + constructor( + id: string, + private readonly handler: IFunction, + private readonly props: HttpLambdaIntegrationProps = {}) { - constructor(private readonly props: LambdaProxyIntegrationProps) { - super(); + super(id); + this._id = id; } public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { const route = options.route; - this.props.handler.addPermission(`${Names.nodeUniqueId(route.node)}-Permission`, { + this.handler.addPermission(`${this._id}-Permission`, { scope: options.scope, principal: new ServicePrincipal('apigateway.amazonaws.com'), sourceArn: Stack.of(route).formatArn({ @@ -57,7 +64,7 @@ export class LambdaProxyIntegration extends HttpRouteIntegration { return { type: HttpIntegrationType.LAMBDA_PROXY, - uri: this.props.handler.functionArn, + uri: this.handler.functionArn, payloadFormatVersion: this.props.payloadFormatVersion ?? PayloadFormatVersion.VERSION_2_0, parameterMapping: this.props.parameterMapping, }; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/nlb.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/nlb.ts index 7aae0aa002354..a7b7690ef3ed4 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/nlb.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/nlb.ts @@ -8,24 +8,29 @@ import { HttpPrivateIntegration } from './private/integration'; * Properties to initialize `HttpNlbIntegration`. */ export interface HttpNlbIntegrationProps extends HttpPrivateIntegrationOptions { - /** - * The listener to the network load balancer used for the integration - */ - readonly listener: elbv2.INetworkListener; } /** * The Network Load Balancer integration resource for HTTP API */ export class HttpNlbIntegration extends HttpPrivateIntegration { - constructor(private readonly props: HttpNlbIntegrationProps) { - super(); + /** + * @param id id of the underlying integration construct + * @param listener the ELB network listener + * @param props properties to configure the integration + */ + constructor( + id: string, + private readonly listener: elbv2.INetworkListener, + private readonly props: HttpNlbIntegrationProps = {}) { + + super(id); } public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { let vpc: ec2.IVpc | undefined = this.props.vpcLink?.vpc; - if (!vpc && (this.props.listener instanceof elbv2.NetworkListener)) { - vpc = this.props.listener.loadBalancer.vpc; + if (!vpc && (this.listener instanceof elbv2.NetworkListener)) { + vpc = this.listener.loadBalancer.vpc; } if (!vpc) { throw new Error('The vpcLink property must be specified when using an imported Network Listener.'); @@ -42,7 +47,7 @@ export class HttpNlbIntegration extends HttpPrivateIntegration { type: this.integrationType, connectionType: this.connectionType, connectionId: vpcLink.vpcLinkId, - uri: this.props.listener.listenerArn, + uri: this.listener.listenerArn, secureServerName: this.props.secureServerName, parameterMapping: this.props.parameterMapping, }; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/service-discovery.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/service-discovery.ts index 6f3b8eedbea0a..3a3433abdb83b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/service-discovery.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/service-discovery.ts @@ -7,18 +7,23 @@ import { HttpPrivateIntegration } from './private/integration'; * Properties to initialize `HttpServiceDiscoveryIntegration`. */ export interface HttpServiceDiscoveryIntegrationProps extends HttpPrivateIntegrationOptions { - /** - * The discovery service used for the integration - */ - readonly service: servicediscovery.IService; } /** * The Service Discovery integration resource for HTTP API */ export class HttpServiceDiscoveryIntegration extends HttpPrivateIntegration { - constructor(private readonly props: HttpServiceDiscoveryIntegrationProps) { - super(); + /** + * @param id id of the underlying integration construct + * @param service the service discovery resource to integrate with + * @param props properties to configure the integration + */ + constructor( + id: string, + private readonly service: servicediscovery.IService, + private readonly props: HttpServiceDiscoveryIntegrationProps = {}) { + + super(id); } public bind(_: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { @@ -32,7 +37,7 @@ export class HttpServiceDiscoveryIntegration extends HttpPrivateIntegration { type: this.integrationType, connectionType: this.connectionType, connectionId: this.props.vpcLink.vpcLinkId, - uri: this.props.service.serviceArn, + uri: this.service.serviceArn, secureServerName: this.props.secureServerName, parameterMapping: this.props.parameterMapping, }; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts index 8e41b30d65295..a5c61af497f89 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts @@ -6,29 +6,28 @@ import { } from '@aws-cdk/aws-apigatewayv2'; import { ServicePrincipal } from '@aws-cdk/aws-iam'; import { IFunction } from '@aws-cdk/aws-lambda'; -import { Names, Stack } from '@aws-cdk/core'; +import { Stack } from '@aws-cdk/core'; /** - * Lambda WebSocket Integration props + * Lambda WebSocket Integration */ -export interface LambdaWebSocketIntegrationProps { +export class WebSocketLambdaIntegration extends WebSocketRouteIntegration { + + private readonly _id: string; + /** - * The handler for this integration. + * @param id id of the underlying integration construct + * @param handler the Lambda function handler + * @param props properties to configure the integration */ - readonly handler: IFunction -} - -/** - * Lambda WebSocket Integration - */ -export class LambdaWebSocketIntegration extends WebSocketRouteIntegration { - constructor(private props: LambdaWebSocketIntegrationProps) { - super(); + constructor(id: string, private readonly handler: IFunction) { + super(id); + this._id = id; } bind(options: WebSocketRouteIntegrationBindOptions): WebSocketRouteIntegrationConfig { const route = options.route; - this.props.handler.addPermission(`${Names.nodeUniqueId(route.node)}-Permission`, { + this.handler.addPermission(`${this._id}-Permission`, { scope: options.scope, principal: new ServicePrincipal('apigateway.amazonaws.com'), sourceArn: Stack.of(route).formatArn({ @@ -42,7 +41,7 @@ export class LambdaWebSocketIntegration extends WebSocketRouteIntegration { service: 'apigateway', account: 'lambda', resource: 'path/2015-03-31/functions', - resourceName: `${this.props.handler.functionArn}/invocations`, + resourceName: `${this.handler.functionArn}/invocations`, }); return { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts index 3c25e92fe6d21..c73d9c41055da 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/alb.test.ts @@ -18,9 +18,7 @@ describe('HttpAlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpAlbIntegration({ - listener, - }), + integration: new HttpAlbIntegration('Integration', listener), routeKey: HttpRouteKey.with('/pets'), }); @@ -52,10 +50,7 @@ describe('HttpAlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpAlbIntegration({ - vpcLink, - listener, - }), + integration: new HttpAlbIntegration('Integration', listener, { vpcLink }), routeKey: HttpRouteKey.with('/pets'), }); @@ -86,10 +81,7 @@ describe('HttpAlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpAlbIntegration({ - listener, - method: HttpMethod.PATCH, - }), + integration: new HttpAlbIntegration('Integration', listener, { method: HttpMethod.PATCH }), routeKey: HttpRouteKey.with('/pets'), }); @@ -110,9 +102,7 @@ describe('HttpAlbIntegration', () => { expect(() => new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpAlbIntegration({ - listener, - }), + integration: new HttpAlbIntegration('Integration', listener), routeKey: HttpRouteKey.with('/pets'), })).toThrow(/vpcLink property must be specified/); }); @@ -129,10 +119,7 @@ describe('HttpAlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpAlbIntegration({ - listener, - secureServerName: 'name-to-verify', - }), + integration: new HttpAlbIntegration('Integration', listener, { secureServerName: 'name-to-verify' }), routeKey: HttpRouteKey.with('/pets'), }); @@ -156,8 +143,7 @@ describe('HttpAlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpAlbIntegration({ - listener, + integration: new HttpAlbIntegration('Integration', listener, { parameterMapping: new ParameterMapping() .appendHeader('header2', MappingValue.requestHeader('header1')) .removeHeader('header1'), diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts index 0f29ec0915fd9..3792f25d84ae1 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/http-proxy.test.ts @@ -1,7 +1,7 @@ import { Template } from '@aws-cdk/assertions'; import { HttpApi, HttpIntegration, HttpIntegrationType, HttpMethod, HttpRoute, HttpRouteKey, MappingValue, ParameterMapping, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Stack } from '@aws-cdk/core'; -import { HttpProxyIntegration } from '../../lib'; +import { HttpUrlIntegration } from '../../lib'; describe('HttpProxyIntegration', () => { test('default', () => { @@ -9,9 +9,7 @@ describe('HttpProxyIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyRoute', { httpApi: api, - integration: new HttpProxyIntegration({ - url: 'some-target-url', - }), + integration: new HttpUrlIntegration('Integration', 'some-target-url'), routeKey: HttpRouteKey.with('/pets'), }); @@ -28,10 +26,7 @@ describe('HttpProxyIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyRoute', { httpApi: api, - integration: new HttpProxyIntegration({ - url: 'some-target-url', - method: HttpMethod.PATCH, - }), + integration: new HttpUrlIntegration('Integration', 'some-target-url', { method: HttpMethod.PATCH }), routeKey: HttpRouteKey.with('/pets'), }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.expected.json index 65149587fb3ce..273e66ff03ac0 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.expected.json @@ -614,7 +614,7 @@ "ProtocolType": "HTTP" } }, - "HttpProxyPrivateApiDefaultRouteHttpIntegration1a580b19954e4317026ffbce1f7d5ade7A32685B": { + "HttpProxyPrivateApiDefaultRouteDefaultIntegration002C2760": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -646,7 +646,7 @@ [ "integrations/", { - "Ref": "HttpProxyPrivateApiDefaultRouteHttpIntegration1a580b19954e4317026ffbce1f7d5ade7A32685B" + "Ref": "HttpProxyPrivateApiDefaultRouteDefaultIntegration002C2760" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.ts index e077560466851..9ef01807d11d4 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.alb.ts @@ -21,9 +21,7 @@ listener.addTargets('target', { port: 80 }); listener.addAction('dsf', { action: elbv2.ListenerAction.fixedResponse(200) }); const httpEndpoint = new HttpApi(stack, 'HttpProxyPrivateApi', { - defaultIntegration: new HttpAlbIntegration({ - listener, - }), + defaultIntegration: new HttpAlbIntegration('DefaultIntegration', listener), }); new CfnOutput(stack, 'Endpoint', { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.expected.json index 0e53d0a223e42..edb4305fe239b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.expected.json @@ -57,7 +57,7 @@ "ProtocolType": "HTTP" } }, - "LambdaProxyApiDefaultRouteinteghttpproxyLambdaProxyApiDefaultRoute17D52FE1Permission4875FF59": { + "LambdaProxyApiDefaultRouteDefaultIntegrationPermission39F587FC": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -94,7 +94,7 @@ } } }, - "LambdaProxyApiDefaultRouteHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24EE575CBA": { + "LambdaProxyApiDefaultRouteDefaultIntegrationAE9908C8": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -124,7 +124,7 @@ [ "integrations/", { - "Ref": "LambdaProxyApiDefaultRouteHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24EE575CBA" + "Ref": "LambdaProxyApiDefaultRouteDefaultIntegrationAE9908C8" } ] ] @@ -148,7 +148,7 @@ "ProtocolType": "HTTP" } }, - "HttpProxyApiDefaultRouteHttpIntegration8eeecf9ecdb91f31bebf6bd54fb711a41921AB82": { + "HttpProxyApiDefaultRouteDefaultIntegration95D23B0D": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -193,7 +193,7 @@ [ "integrations/", { - "Ref": "HttpProxyApiDefaultRouteHttpIntegration8eeecf9ecdb91f31bebf6bd54fb711a41921AB82" + "Ref": "HttpProxyApiDefaultRouteDefaultIntegration95D23B0D" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.ts index 9fa5803973376..14d0a291e7113 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.http-proxy.ts @@ -1,7 +1,7 @@ import { HttpApi } from '@aws-cdk/aws-apigatewayv2'; import * as lambda from '@aws-cdk/aws-lambda'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; -import { HttpProxyIntegration, LambdaProxyIntegration } from '../../lib'; +import { HttpUrlIntegration, HttpLambdaIntegration } from '../../lib'; /* * Stack verification steps: @@ -16,9 +16,7 @@ const stack = new Stack(app, 'integ-http-proxy'); const lambdaEndpoint = lambdaProxyEndpoint(stack); const httpEndpoint = new HttpApi(stack, 'HttpProxyApi', { - defaultIntegration: new HttpProxyIntegration({ - url: lambdaEndpoint.url!, - }), + defaultIntegration: new HttpUrlIntegration('DefaultIntegration', lambdaEndpoint.url!), }); new CfnOutput(stack, 'Endpoint', { @@ -33,8 +31,6 @@ function lambdaProxyEndpoint(s: Stack): HttpApi { }); return new HttpApi(s, 'LambdaProxyApi', { - defaultIntegration: new LambdaProxyIntegration({ - handler, - }), + defaultIntegration: new HttpLambdaIntegration('DefaultIntegration', handler), }); } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.expected.json index 7963d3534e099..5de2892451602 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.expected.json @@ -57,7 +57,7 @@ "ProtocolType": "HTTP" } }, - "LambdaProxyApiDefaultRouteinteglambdaproxyLambdaProxyApiDefaultRoute59CA2390Permission07F93503": { + "LambdaProxyApiDefaultRouteDefaultIntegrationPermission39F587FC": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -94,7 +94,7 @@ } } }, - "LambdaProxyApiDefaultRouteHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24EE575CBA": { + "LambdaProxyApiDefaultRouteDefaultIntegrationAE9908C8": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -124,7 +124,7 @@ [ "integrations/", { - "Ref": "LambdaProxyApiDefaultRouteHttpIntegration70df0ec52c3e3b6bbc96e64ce3a05f24EE575CBA" + "Ref": "LambdaProxyApiDefaultRouteDefaultIntegrationAE9908C8" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.ts index ed1cabee002e4..5f8457a7d8218 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.lambda-proxy.ts @@ -1,7 +1,7 @@ import { HttpApi } from '@aws-cdk/aws-apigatewayv2'; import * as lambda from '@aws-cdk/aws-lambda'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; -import { LambdaProxyIntegration } from '../../lib'; +import { HttpLambdaIntegration } from '../../lib'; /* * Stack verification steps: @@ -19,9 +19,7 @@ const handler = new lambda.Function(stack, 'AlwaysSuccess', { }); const endpoint = new HttpApi(stack, 'LambdaProxyApi', { - defaultIntegration: new LambdaProxyIntegration({ - handler, - }), + defaultIntegration: new HttpLambdaIntegration('DefaultIntegration', handler), }); new CfnOutput(stack, 'Endpoint', { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.expected.json index 0a3241cdc8139..ad0376a19c058 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -573,7 +573,7 @@ "ProtocolType": "HTTP" } }, - "HttpProxyPrivateApiDefaultRouteHttpIntegration1a580b19954e4317026ffbce1f7d5ade7A32685B": { + "HttpProxyPrivateApiDefaultRouteDefaultIntegration002C2760": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -605,7 +605,7 @@ [ "integrations/", { - "Ref": "HttpProxyPrivateApiDefaultRouteHttpIntegration1a580b19954e4317026ffbce1f7d5ade7A32685B" + "Ref": "HttpProxyPrivateApiDefaultRouteDefaultIntegration002C2760" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.ts index 9b78c3f676e30..6c0a8e64e1f94 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.nlb.ts @@ -14,9 +14,7 @@ const listener = lb.addListener('listener', { port: 80 }); listener.addTargets('target', { port: 80 }); const httpEndpoint = new HttpApi(stack, 'HttpProxyPrivateApi', { - defaultIntegration: new HttpNlbIntegration({ - listener, - }), + defaultIntegration: new HttpNlbIntegration('DefaultIntegration', listener), }); new CfnOutput(stack, 'Endpoint', { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.expected.json index 00e587f8ac85f..56af47d74c0c0 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.expected.json @@ -95,15 +95,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "Tags": [ { "Key": "Name", @@ -192,15 +192,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "Tags": [ { "Key": "Name", @@ -289,15 +289,15 @@ "VPCPublicSubnet3NATGatewayD3048F5C": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet3EIPAD4BC883", "AllocationId" ] }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, "Tags": [ { "Key": "Name", @@ -574,7 +574,7 @@ "ProtocolType": "HTTP" } }, - "HttpProxyPrivateApiDefaultRouteHttpIntegrationa5ec5390ca688d567e9449daf58afc6f6DEAA8A8": { + "HttpProxyPrivateApiDefaultRouteDefaultIntegration002C2760": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -609,7 +609,7 @@ [ "integrations/", { - "Ref": "HttpProxyPrivateApiDefaultRouteHttpIntegrationa5ec5390ca688d567e9449daf58afc6f6DEAA8A8" + "Ref": "HttpProxyPrivateApiDefaultRouteDefaultIntegration002C2760" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.ts index 1ff64ba5955c9..a79acef0d0007 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/integ.service-discovery.ts @@ -17,9 +17,8 @@ const namespace = new servicediscovery.PrivateDnsNamespace(stack, 'Namespace', { const service = namespace.createService('Service'); const httpEndpoint = new HttpApi(stack, 'HttpProxyPrivateApi', { - defaultIntegration: new HttpServiceDiscoveryIntegration({ + defaultIntegration: new HttpServiceDiscoveryIntegration('DefaultIntegration', service, { vpcLink, - service, }), }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts index 85bb624a25d54..5c318e1629842 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/lambda.test.ts @@ -2,7 +2,7 @@ import { Template } from '@aws-cdk/assertions'; import { HttpApi, HttpRoute, HttpRouteKey, MappingValue, ParameterMapping, PayloadFormatVersion } from '@aws-cdk/aws-apigatewayv2'; import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; import { App, Stack } from '@aws-cdk/core'; -import { LambdaProxyIntegration } from '../../lib'; +import { HttpLambdaIntegration } from '../../lib'; describe('LambdaProxyIntegration', () => { test('default', () => { @@ -11,9 +11,7 @@ describe('LambdaProxyIntegration', () => { const fooFn = fooFunction(stack, 'Fn'); new HttpRoute(stack, 'LambdaProxyRoute', { httpApi: api, - integration: new LambdaProxyIntegration({ - handler: fooFn, - }), + integration: new HttpLambdaIntegration('Integration', fooFn), routeKey: HttpRouteKey.with('/pets'), }); @@ -29,8 +27,7 @@ describe('LambdaProxyIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'LambdaProxyRoute', { httpApi: api, - integration: new LambdaProxyIntegration({ - handler: fooFunction(stack, 'Fn'), + integration: new HttpLambdaIntegration('Integration', fooFunction(stack, 'Fn'), { payloadFormatVersion: PayloadFormatVersion.VERSION_1_0, }), routeKey: HttpRouteKey.with('/pets'), @@ -46,8 +43,7 @@ describe('LambdaProxyIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'LambdaProxyRoute', { httpApi: api, - integration: new LambdaProxyIntegration({ - handler: fooFunction(stack, 'Fn'), + integration: new HttpLambdaIntegration('Integration', fooFunction(stack, 'Fn'), { parameterMapping: new ParameterMapping() .appendHeader('header2', MappingValue.requestHeader('header1')) .removeHeader('header1'), @@ -70,9 +66,7 @@ describe('LambdaProxyIntegration', () => { const apigwStack = new Stack(app, 'apigwStack'); new HttpApi(apigwStack, 'httpApi', { - defaultIntegration: new LambdaProxyIntegration({ - handler: fooFn, - }), + defaultIntegration: new HttpLambdaIntegration('Integration', fooFn), }); expect(() => app.synth()).not.toThrow(); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts index e1e18c43f49aa..a5c6eded4b884 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/nlb.test.ts @@ -18,9 +18,7 @@ describe('HttpNlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpNlbIntegration({ - listener, - }), + integration: new HttpNlbIntegration('Integration', listener), routeKey: HttpRouteKey.with('/pets'), }); @@ -52,10 +50,7 @@ describe('HttpNlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpNlbIntegration({ - vpcLink, - listener, - }), + integration: new HttpNlbIntegration('Integration', listener, { vpcLink }), routeKey: HttpRouteKey.with('/pets'), }); @@ -86,10 +81,7 @@ describe('HttpNlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpNlbIntegration({ - listener, - method: HttpMethod.PATCH, - }), + integration: new HttpNlbIntegration('Integration', listener, { method: HttpMethod.PATCH }), routeKey: HttpRouteKey.with('/pets'), }); @@ -107,9 +99,7 @@ describe('HttpNlbIntegration', () => { expect(() => new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpNlbIntegration({ - listener, - }), + integration: new HttpNlbIntegration('Integration', listener), routeKey: HttpRouteKey.with('/pets'), })).toThrow(/vpcLink property must be specified/); }); @@ -126,10 +116,7 @@ describe('HttpNlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpNlbIntegration({ - listener, - secureServerName: 'name-to-verify', - }), + integration: new HttpNlbIntegration('Integration', listener, { secureServerName: 'name-to-verify' }), routeKey: HttpRouteKey.with('/pets'), }); @@ -153,8 +140,7 @@ describe('HttpNlbIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpNlbIntegration({ - listener, + integration: new HttpNlbIntegration('Integration', listener, { parameterMapping: new ParameterMapping() .appendHeader('header2', MappingValue.requestHeader('header1')) .removeHeader('header1'), diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/private/integration.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/private/integration.test.ts index 8cda89e3d2390..a7649b1fb8620 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/private/integration.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/private/integration.test.ts @@ -8,7 +8,7 @@ describe('HttpPrivateIntegration', () => { const stack = new Stack(); class DummyPrivateIntegration extends HttpPrivateIntegration { constructor() { - super(); + super('DummyPrivateIntegration'); } public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts index e037004cada0e..1d3ece56f2cd8 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/http/service-discovery.test.ts @@ -21,10 +21,7 @@ describe('HttpServiceDiscoveryIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpServiceDiscoveryIntegration({ - vpcLink, - service, - }), + integration: new HttpServiceDiscoveryIntegration('Integration', service, { vpcLink }), routeKey: HttpRouteKey.with('/pets'), }); @@ -61,9 +58,8 @@ describe('HttpServiceDiscoveryIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpServiceDiscoveryIntegration({ + integration: new HttpServiceDiscoveryIntegration('Integration', service, { vpcLink, - service, method: HttpMethod.PATCH, }), routeKey: HttpRouteKey.with('/pets'), @@ -87,10 +83,7 @@ describe('HttpServiceDiscoveryIntegration', () => { expect(() => new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpServiceDiscoveryIntegration({ - service, - method: HttpMethod.PATCH, - }), + integration: new HttpServiceDiscoveryIntegration('Integration', service, { method: HttpMethod.PATCH }), routeKey: HttpRouteKey.with('/pets'), })).toThrow(/vpcLink property is mandatory/); }); @@ -110,9 +103,8 @@ describe('HttpServiceDiscoveryIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpServiceDiscoveryIntegration({ + integration: new HttpServiceDiscoveryIntegration('Integration', service, { vpcLink, - service, secureServerName: 'name-to-verify', }), routeKey: HttpRouteKey.with('/pets'), @@ -141,9 +133,8 @@ describe('HttpServiceDiscoveryIntegration', () => { const api = new HttpApi(stack, 'HttpApi'); new HttpRoute(stack, 'HttpProxyPrivateRoute', { httpApi: api, - integration: new HttpServiceDiscoveryIntegration({ + integration: new HttpServiceDiscoveryIntegration('Integration', service, { vpcLink, - service, parameterMapping: new ParameterMapping() .appendHeader('header2', MappingValue.requestHeader('header1')) .removeHeader('header1'), diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json index 54a0f51203342..6b344f8f1688f 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json @@ -208,7 +208,7 @@ "RouteSelectionExpression": "$request.body.action" } }, - "mywsapiconnectRouteWebSocketApiIntegmywsapiconnectRoute456CB290Permission2D0BC294": { + "mywsapiconnectRouteConnectIntegrationPermission719B6E63": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -245,7 +245,7 @@ } } }, - "mywsapiconnectRouteWebSocketIntegration3025fc0297cc8d73dae555b46106edcd38569D62": { + "mywsapiconnectRouteConnectIntegrationE101DB9B": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -290,14 +290,14 @@ [ "integrations/", { - "Ref": "mywsapiconnectRouteWebSocketIntegration3025fc0297cc8d73dae555b46106edcd38569D62" + "Ref": "mywsapiconnectRouteConnectIntegrationE101DB9B" } ] ] } } }, - "mywsapidisconnectRouteWebSocketApiIntegmywsapidisconnectRoute26B84CF3PermissionB3F6D0A8": { + "mywsapidisconnectRouteDisconnectIntegrationPermissionA8197C41": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -334,7 +334,7 @@ } } }, - "mywsapidisconnectRouteWebSocketIntegrationfc84ffd6c52488b90783abae35d28ebdAE5C6063": { + "mywsapidisconnectRouteDisconnectIntegrationF927D904": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -379,14 +379,14 @@ [ "integrations/", { - "Ref": "mywsapidisconnectRouteWebSocketIntegrationfc84ffd6c52488b90783abae35d28ebdAE5C6063" + "Ref": "mywsapidisconnectRouteDisconnectIntegrationF927D904" } ] ] } } }, - "mywsapidefaultRouteWebSocketApiIntegmywsapidefaultRouteA13D926BPermission58B64FCE": { + "mywsapidefaultRouteDefaultIntegrationPermission3B7F9CA1": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -423,7 +423,7 @@ } } }, - "mywsapidefaultRouteWebSocketIntegrationa07b7cec9837e31a8c70446e1e1f1fd5055B3083": { + "mywsapidefaultRouteDefaultIntegrationFFCB3BA9": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -468,14 +468,14 @@ [ "integrations/", { - "Ref": "mywsapidefaultRouteWebSocketIntegrationa07b7cec9837e31a8c70446e1e1f1fd5055B3083" + "Ref": "mywsapidefaultRouteDefaultIntegrationFFCB3BA9" } ] ] } } }, - "mywsapisendmessageRouteWebSocketApiIntegmywsapisendmessageRoute8A775F3CPermission660FB575": { + "mywsapisendmessageRouteSendMessageIntegrationPermission92C9841E": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -512,7 +512,7 @@ } } }, - "mywsapisendmessageRouteWebSocketIntegrationeb46e3593c10ed57eb0ca9ef3247823d74153661": { + "mywsapisendmessageRouteSendMessageIntegrationD29E12F9": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -557,7 +557,7 @@ [ "integrations/", { - "Ref": "mywsapisendmessageRouteWebSocketIntegrationeb46e3593c10ed57eb0ca9ef3247823d74153661" + "Ref": "mywsapisendmessageRouteSendMessageIntegrationD29E12F9" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.ts index 01e25f906b0f8..963cc4dad0f67 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.ts @@ -1,7 +1,7 @@ import { WebSocketApi, WebSocketStage } from '@aws-cdk/aws-apigatewayv2'; import * as lambda from '@aws-cdk/aws-lambda'; import { App, CfnOutput, Stack } from '@aws-cdk/core'; -import { LambdaWebSocketIntegration } from '../../lib'; +import { WebSocketLambdaIntegration } from '../../lib'; /* * Stack verification steps: @@ -39,9 +39,9 @@ const messageHandler = new lambda.Function(stack, 'MessageHandler', { }); const webSocketApi = new WebSocketApi(stack, 'mywsapi', { - connectRouteOptions: { integration: new LambdaWebSocketIntegration({ handler: connectHandler }) }, - disconnectRouteOptions: { integration: new LambdaWebSocketIntegration({ handler: disconnetHandler }) }, - defaultRouteOptions: { integration: new LambdaWebSocketIntegration({ handler: defaultHandler }) }, + connectRouteOptions: { integration: new WebSocketLambdaIntegration('ConnectIntegration', connectHandler) }, + disconnectRouteOptions: { integration: new WebSocketLambdaIntegration('DisconnectIntegration', disconnetHandler) }, + defaultRouteOptions: { integration: new WebSocketLambdaIntegration('DefaultIntegration', defaultHandler) }, }); const stage = new WebSocketStage(stack, 'mystage', { webSocketApi, @@ -49,6 +49,6 @@ const stage = new WebSocketStage(stack, 'mystage', { autoDeploy: true, }); -webSocketApi.addRoute('sendmessage', { integration: new LambdaWebSocketIntegration({ handler: messageHandler }) }); +webSocketApi.addRoute('sendmessage', { integration: new WebSocketLambdaIntegration('SendMessageIntegration', messageHandler) }); new CfnOutput(stack, 'ApiEndpoint', { value: stage.url }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts index e12b09f75ed50..d5c6a99097ec8 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts @@ -2,7 +2,7 @@ import { Template } from '@aws-cdk/assertions'; import { WebSocketApi } from '@aws-cdk/aws-apigatewayv2'; import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; import { Stack } from '@aws-cdk/core'; -import { LambdaWebSocketIntegration } from '../../lib'; +import { WebSocketLambdaIntegration } from '../../lib'; describe('LambdaWebSocketIntegration', () => { @@ -14,7 +14,7 @@ describe('LambdaWebSocketIntegration', () => { // WHEN new WebSocketApi(stack, 'Api', { connectRouteOptions: { - integration: new LambdaWebSocketIntegration({ handler: fooFn }), + integration: new WebSocketLambdaIntegration('Integration', fooFn), }, }); diff --git a/packages/@aws-cdk/aws-apigatewayv2/README.md b/packages/@aws-cdk/aws-apigatewayv2/README.md index 89dcb79f6409d..6c0697287c08d 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2/README.md @@ -76,16 +76,12 @@ As an early example, the following code snippet configures a route `GET /books` configures all other HTTP method calls to `/books` to a lambda proxy. ```ts -import { HttpProxyIntegration, LambdaProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpUrlIntegration, HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; -const getBooksIntegration = new HttpProxyIntegration({ - url: 'https://get-books-proxy.myproxy.internal', -}); +const getBooksIntegration = new HttpUrlIntegration('GetBooksIntegration' 'https://get-books-proxy.myproxy.internal'); declare const booksDefaultFn: lambda.Function; -const booksDefaultIntegration = new LambdaProxyIntegration({ - handler: booksDefaultFn, -}); +const booksDefaultIntegration = new HttpLambdaIntegration('BooksIntegration', booksDefaultFn); const httpApi = new apigwv2.HttpApi(this, 'HttpApi'); @@ -113,12 +109,10 @@ The `defaultIntegration` option while defining HTTP APIs lets you create a defau matched when a client reaches a route that is not explicitly defined. ```ts -import { HttpProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; new apigwv2.HttpApi(this, 'HttpProxyApi', { - defaultIntegration: new HttpProxyIntegration({ - url:'http://example.com', - }), + defaultIntegration: new HttpUrlIntegration('DefaultIntegration', 'https://example.com'), }); ``` @@ -183,7 +177,7 @@ custom domain to the `$default` stage of the API. ```ts import * as acm from '@aws-cdk/aws-certificatemanager'; -import { LambdaProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; const certArn = 'arn:aws:acm:us-east-1:111111111111:certificate'; const domainName = 'example.com'; @@ -195,7 +189,7 @@ const dn = new apigwv2.DomainName(this, 'DN', { declare const handler: lambda.Function; const api = new apigwv2.HttpApi(this, 'HttpProxyProdApi', { - defaultIntegration: new LambdaProxyIntegration({ handler }), + defaultIntegration: new HttpLambdaIntegration('DefaultIntegration', handler), // https://${dn.domainName}/foo goes to prodApi $default stage defaultDomainMapping: { domainName: dn, @@ -228,13 +222,13 @@ api.addStage('beta', { The same domain name can be associated with stages across different `HttpApi` as so - ```ts -import { LambdaProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; declare const handler: lambda.Function; declare const dn: apigwv2.DomainName; const apiDemo = new apigwv2.HttpApi(this, 'DemoApi', { - defaultIntegration: new LambdaProxyIntegration({ handler }), + defaultIntegration: new HttpLambdaIntegration('DefaultIntegration', handler), // https://${dn.domainName}/demo goes to apiDemo $default stage defaultDomainMapping: { domainName: dn, @@ -344,7 +338,7 @@ Private integrations enable integrating an HTTP API route with private resources Amazon ECS container-based applications. Using private integrations, resources in a VPC can be exposed for access by clients outside of the VPC. -These integrations can be found in the [APIGatewayV2-Integrations](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-apigatewayv2-integrations-readme.html) constructs library. +These integrations can be found in the [aws-apigatewayv2-integrations](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-apigatewayv2-integrations-readme.html) constructs library. ## WebSocket API @@ -365,16 +359,16 @@ Integrations are available in the `aws-apigatewayv2-integrations` module and mor To add the default WebSocket routes supported by API Gateway (`$connect`, `$disconnect` and `$default`), configure them as part of api props: ```ts -import { LambdaWebSocketIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { WebSocketLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; declare const connectHandler: lambda.Function; declare const disconnectHandler: lambda.Function; declare const defaultHandler: lambda.Function; const webSocketApi = new apigwv2.WebSocketApi(this, 'mywsapi', { - connectRouteOptions: { integration: new LambdaWebSocketIntegration({ handler: connectHandler }) }, - disconnectRouteOptions: { integration: new LambdaWebSocketIntegration({ handler: disconnectHandler }) }, - defaultRouteOptions: { integration: new LambdaWebSocketIntegration({ handler: defaultHandler }) }, + connectRouteOptions: { integration: new WebSocketLambdaIntegration('ConnectIntegration', connectHandler) }, + disconnectRouteOptions: { integration: new WebSocketLambdaIntegration('DisconnectIntegration',disconnectHandler) }, + defaultRouteOptions: { integration: new WebSocketLambdaIntegration('DefaultIntegration', defaultHandler) }, }); new apigwv2.WebSocketStage(this, 'mystage', { @@ -398,14 +392,12 @@ const callbackURL = webSocketStage.callbackUrl; To add any other route: ```ts -import { LambdaWebSocketIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; +import { WebSocketLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; declare const messageHandler: lambda.Function; const webSocketApi = new apigwv2.WebSocketApi(this, 'mywsapi'); webSocketApi.addRoute('sendmessage', { - integration: new LambdaWebSocketIntegration({ - handler: messageHandler, - }), + integration: new WebSocketLambdaIntegration('SendMessageIntegration', messageHandler), }); ``` diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts index 6865875af5c80..857ef57657736 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integration.ts @@ -1,6 +1,4 @@ -/* eslint-disable quotes */ -import * as crypto from 'crypto'; -import { Resource, Stack } from '@aws-cdk/core'; +import { Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnIntegration } from '../apigatewayv2.generated'; import { IIntegration } from '../common'; @@ -195,6 +193,12 @@ export interface HttpRouteIntegrationBindOptions { export abstract class HttpRouteIntegration { private integration?: HttpIntegration; + /** + * Initialize an integration for a route on http api. + * @param id id of the underlying `HttpIntegration` construct. + */ + constructor(private readonly id: string) {} + /** * Internal method called when binding this integration to the route. * @internal @@ -207,7 +211,7 @@ export abstract class HttpRouteIntegration { if (!this.integration) { const config = this.bind(options); - this.integration = new HttpIntegration(options.scope, `HttpIntegration-${hash(config)}`, { + this.integration = new HttpIntegration(options.scope, this.id, { httpApi: options.route.httpApi, integrationType: config.type, integrationUri: config.uri, @@ -218,12 +222,6 @@ export abstract class HttpRouteIntegration { secureServerName: config.secureServerName, parameterMapping: config.parameterMapping, }); - - function hash(x: any) { - const stringifiedConfig = JSON.stringify(Stack.of(options.scope).resolve(x)); - const configHash = crypto.createHash('md5').update(stringifiedConfig).digest('hex'); - return configHash; - } } return { integrationId: this.integration.integrationId }; } diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/integration.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/integration.ts index 3c59269b474f6..b5366be83f2ba 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/integration.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/websocket/integration.ts @@ -1,5 +1,4 @@ -import * as crypto from 'crypto'; -import { Resource, Stack } from '@aws-cdk/core'; +import { Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnIntegration } from '../apigatewayv2.generated'; import { IIntegration } from '../common'; @@ -91,6 +90,12 @@ export interface WebSocketRouteIntegrationBindOptions { export abstract class WebSocketRouteIntegration { private integration?: WebSocketIntegration; + /** + * Initialize an integration for a route on websocket api. + * @param id id of the underlying `WebSocketIntegration` construct. + */ + constructor(private readonly id: string) {} + /** * Internal method called when binding this integration to the route. * @internal @@ -103,17 +108,11 @@ export abstract class WebSocketRouteIntegration { if (!this.integration) { const config = this.bind(options); - this.integration = new WebSocketIntegration(options.scope, `WebSocketIntegration-${hash(config)}`, { + this.integration = new WebSocketIntegration(options.scope, this.id, { webSocketApi: options.route.webSocketApi, integrationType: config.type, integrationUri: config.uri, }); - - function hash(x: any) { - const stringifiedConfig = JSON.stringify(Stack.of(options.scope).resolve(x)); - const configHash = crypto.createHash('md5').update(stringifiedConfig).digest('hex'); - return configHash; - } } return { integrationId: this.integration.integrationId }; diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts index 658b139193612..bb123c6815adc 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts @@ -532,6 +532,10 @@ describe('HttpApi', () => { }); class DummyRouteIntegration extends HttpRouteIntegration { + constructor() { + super('DummyRouteIntegration'); + } + public bind(_: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { return { payloadFormatVersion: PayloadFormatVersion.VERSION_2_0, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts index b5ddae7919a62..df917fffe0ac8 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/route.test.ts @@ -28,7 +28,7 @@ describe('HttpRoute', () => { [ 'integrations/', { - Ref: 'HttpRouteHttpIntegrationcff2618c192d3bd8581dd2a4093464f6FB1097D0', + Ref: 'HttpRouteDummyIntegration10F77519', }, ], ], @@ -187,7 +187,7 @@ describe('HttpRoute', () => { // WHEN new HttpRoute(stack, 'HttpRoute', { httpApi, - integration: new PrivateIntegration(), + integration: new PrivateIntegration('PrivateIntegration'), routeKey: HttpRouteKey.with('/books', HttpMethod.GET), }); @@ -229,7 +229,7 @@ describe('HttpRoute', () => { // WHEN new HttpRoute(stack, 'HttpRoute', { httpApi, - integration: new PrivateIntegration(), + integration: new PrivateIntegration('PrivateIntegration'), routeKey: HttpRouteKey.with('/books', HttpMethod.GET), }); @@ -311,6 +311,10 @@ describe('HttpRoute', () => { }); class DummyIntegration extends HttpRouteIntegration { + constructor(name?: string) { + super(name ?? 'DummyIntegration'); + } + public bind(): HttpRouteIntegrationConfig { return { type: HttpIntegrationType.HTTP_PROXY, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts index 0a5e7c05b706d..50e973d445731 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts @@ -127,6 +127,10 @@ describe('WebSocketApi', () => { }); class DummyIntegration extends WebSocketRouteIntegration { + constructor() { + super('DummyIntegration'); + } + bind(_options: WebSocketRouteIntegrationBindOptions): WebSocketRouteIntegrationConfig { return { type: WebSocketIntegrationType.AWS_PROXY, diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts index 512006fb8a2a4..655390f31165f 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts @@ -28,7 +28,7 @@ describe('WebSocketRoute', () => { [ 'integrations/', { - Ref: 'RouteWebSocketIntegrationb7742333c7ab20d7b2b178df59bb17f20338431E', + Ref: 'RouteDummyIntegrationE40E82B4', }, ], ], @@ -85,6 +85,10 @@ describe('WebSocketRoute', () => { class DummyIntegration extends WebSocketRouteIntegration { + constructor(name?: string) { + super(name ?? 'DummyIntegration'); + } + bind(_options: WebSocketRouteIntegrationBindOptions): WebSocketRouteIntegrationConfig { return { type: WebSocketIntegrationType.AWS_PROXY, diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.expected.json index c6a6abaa89273..6f0435b70af0b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.expected.json @@ -17,7 +17,7 @@ "AutoDeploy": true } }, - "MyHttpApiANYCallHttpApiIntegMyHttpApiANY7E6F12A3Permission59116CA6": { + "MyHttpApiANYDefaultIntegrationPermissionAB8301EF": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -54,7 +54,7 @@ } } }, - "MyHttpApiANYHttpIntegration71abbf75d6f8e5ea93ec2120c0d78b754BBCECF5": { + "MyHttpApiANYDefaultIntegration5FAD8850": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -84,7 +84,7 @@ [ "integrations/", { - "Ref": "MyHttpApiANYHttpIntegration71abbf75d6f8e5ea93ec2120c0d78b754BBCECF5" + "Ref": "MyHttpApiANYDefaultIntegration5FAD8850" } ] ] diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.ts index 214f2e5a25ba9..aad59d754950d 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/apigateway/integ.call-http-api.ts @@ -24,9 +24,7 @@ const handler = new lambda.Function(stack, 'HelloHandler', { }); httpApi.addRoutes({ path: '/', - integration: new integrations.LambdaProxyIntegration({ - handler, - }), + integration: new integrations.HttpLambdaIntegration('DefaultIntegration', handler), }); const callEndpointJob = new CallApiGatewayHttpApiEndpoint(stack, 'Call APIGW', { From 5fc0141bebad0a3491fee4ff8abf1f962b930365 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 30 Nov 2021 10:28:20 +0200 Subject: [PATCH 34/82] chore: avoid runtime dependency between cfnspec and pkglint (#17751) Our build pipeline is currently failing because `cfnspec` (which is a public package) takes a runtime dependency on `pkglint` (which is a private package). This was introduced in https://github.com/aws/aws-cdk/pull/17696. To resolve this, we moved the functionality that generates new L1 library code from `lib/` to `build-tools/` since it's only needed in CDK build context (technically this is breaking public API, but we could not see any use case for external users to generate L1 modules in CDK-repository format). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts | 5 +++-- packages/@aws-cdk/cfnspec/lib/index.ts | 1 - packages/@aws-cdk/cfnspec/package.json | 2 +- tools/@aws-cdk/pkglint/lib/index.ts | 2 +- .../@aws-cdk/pkglint}/lib/library-creation.ts | 4 ++-- .../@aws-cdk/pkglint}/test/libary-creation.test.ts | 0 tools/@aws-cdk/ubergen/bin/ubergen.ts | 4 ++-- tools/@aws-cdk/ubergen/package.json | 1 + 8 files changed, 10 insertions(+), 9 deletions(-) rename {packages/@aws-cdk/cfnspec => tools/@aws-cdk/pkglint}/lib/library-creation.ts (94%) rename {packages/@aws-cdk/cfnspec => tools/@aws-cdk/pkglint}/test/libary-creation.test.ts (100%) diff --git a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts index b6fa4a44c6f7f..260058d60d154 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -6,6 +6,7 @@ */ import * as path from 'path'; +import * as pkglint from '@aws-cdk/pkglint'; import * as fs from 'fs-extra'; import * as cfnspec from '../lib'; @@ -24,7 +25,7 @@ async function main() { // iterate over all cloudformation namespaces for (const namespace of cfnspec.namespaces()) { - const module = cfnspec.createModuleDefinitionFromCfnNamespace(namespace); + const module = pkglint.createModuleDefinitionFromCfnNamespace(namespace); const lowcaseModuleName = module.moduleName.toLocaleLowerCase(); const packagePath = path.join(root, module.moduleName); @@ -260,7 +261,7 @@ async function main() { '});', ]); - await cfnspec.createLibraryReadme(namespace, path.join(packagePath, 'README.md')); + await pkglint.createLibraryReadme(namespace, path.join(packagePath, 'README.md')); await write('.eslintrc.js', [ "const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc');", diff --git a/packages/@aws-cdk/cfnspec/lib/index.ts b/packages/@aws-cdk/cfnspec/lib/index.ts index 17ef1bde49c36..6ab020d9580cc 100644 --- a/packages/@aws-cdk/cfnspec/lib/index.ts +++ b/packages/@aws-cdk/cfnspec/lib/index.ts @@ -3,7 +3,6 @@ import { CfnLintFileSchema } from './_private_schema/cfn-lint'; import * as schema from './schema'; export { schema }; export * from './canned-metrics'; -export * from './library-creation'; /** * The complete AWS CloudFormation Resource specification, having any CDK patches and enhancements included in it. diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index fa705c6fbe312..828529273ae87 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -30,6 +30,7 @@ "types": "lib/index.d.ts", "devDependencies": { "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/jest": "^27.0.3", "@types/md5": "^2.3.1", @@ -39,7 +40,6 @@ "sort-json": "^2.0.0" }, "dependencies": { - "@aws-cdk/pkglint": "0.0.0", "fs-extra": "^9.1.0", "md5": "^2.3.0" }, diff --git a/tools/@aws-cdk/pkglint/lib/index.ts b/tools/@aws-cdk/pkglint/lib/index.ts index e63f0c6bf1b52..4b6c0ec9de117 100644 --- a/tools/@aws-cdk/pkglint/lib/index.ts +++ b/tools/@aws-cdk/pkglint/lib/index.ts @@ -1,3 +1,3 @@ export * from './packagejson'; export * from './rules'; -export * from './readme-contents'; +export * from './library-creation'; diff --git a/packages/@aws-cdk/cfnspec/lib/library-creation.ts b/tools/@aws-cdk/pkglint/lib/library-creation.ts similarity index 94% rename from packages/@aws-cdk/cfnspec/lib/library-creation.ts rename to tools/@aws-cdk/pkglint/lib/library-creation.ts index 4471a1bf6dc75..04b13ffbaead3 100644 --- a/packages/@aws-cdk/cfnspec/lib/library-creation.ts +++ b/tools/@aws-cdk/pkglint/lib/library-creation.ts @@ -1,5 +1,5 @@ -import * as pkglint from '@aws-cdk/pkglint'; import * as fs from 'fs-extra'; +import { cfnOnlyReadmeContents } from './readme-contents'; export interface ModuleDefinition { readonly namespace: string; @@ -59,7 +59,7 @@ export function createModuleDefinitionFromCfnNamespace(namespace: string): Modul export async function createLibraryReadme(namespace: string, readmePath: string) { const module = createModuleDefinitionFromCfnNamespace(namespace); - await fs.writeFile(readmePath, pkglint.cfnOnlyReadmeContents({ + await fs.writeFile(readmePath, cfnOnlyReadmeContents({ cfnNamespace: namespace, packageName: module.packageName, })); diff --git a/packages/@aws-cdk/cfnspec/test/libary-creation.test.ts b/tools/@aws-cdk/pkglint/test/libary-creation.test.ts similarity index 100% rename from packages/@aws-cdk/cfnspec/test/libary-creation.test.ts rename to tools/@aws-cdk/pkglint/test/libary-creation.test.ts diff --git a/tools/@aws-cdk/ubergen/bin/ubergen.ts b/tools/@aws-cdk/ubergen/bin/ubergen.ts index ea08678bd1a43..dfe8af6fca4e1 100644 --- a/tools/@aws-cdk/ubergen/bin/ubergen.ts +++ b/tools/@aws-cdk/ubergen/bin/ubergen.ts @@ -2,7 +2,7 @@ import * as console from 'console'; import * as path from 'path'; import * as process from 'process'; import cfn2ts from '@aws-cdk/cfn2ts'; -import * as cfnspec from '@aws-cdk/cfnspec'; +import * as pkglint from '@aws-cdk/pkglint'; import * as awsCdkMigration from 'aws-cdk-migration'; import * as fs from 'fs-extra'; @@ -352,7 +352,7 @@ async function transformPackage( cfnScopes.map(s => (s === 'AWS::Serverless' ? 'AWS::SAM' : s).split('::')[1].toLocaleLowerCase()) .map(s => `export * from './${s}.generated';`) .join('\n')); - await cfnspec.createLibraryReadme(cfnScopes[0], path.join(destination, 'README.md')); + await pkglint.createLibraryReadme(cfnScopes[0], path.join(destination, 'README.md')); await copyOrTransformFiles(destination, destination, allLibraries, uberPackageJson); } else { diff --git a/tools/@aws-cdk/ubergen/package.json b/tools/@aws-cdk/ubergen/package.json index 0c5b2058babf4..711943a779be9 100644 --- a/tools/@aws-cdk/ubergen/package.json +++ b/tools/@aws-cdk/ubergen/package.json @@ -35,6 +35,7 @@ }, "dependencies": { "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@aws-cdk/cfnspec": "0.0.0", "aws-cdk-migration": "0.0.0", "fs-extra": "^9.1.0", From 446f5fdede08749d65d8da6695301e5217cbae49 Mon Sep 17 00:00:00 2001 From: kaizen3031593 <36202692+kaizen3031593@users.noreply.github.com> Date: Tue, 30 Nov 2021 04:43:31 -0500 Subject: [PATCH 35/82] chore(generate-examples): generate fixtures (#17737) Motivation: we want the ability for `rosetta:extract` to be called after `generate-examples`. Currently, this results in errors because the generated examples are only stored in the assembly, and only the visible source, so they fail compilation when we attempt to extract them. Solution: while we generate examples, we also generate a fixture per assembly, `_generated.ts-fixture`, that stores the necessary import statement for compilation. Then, when we later (might) call extract, we have a fixture to place the example in. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../generate-examples/lib/assemblies.ts | 24 +++++++++++++++- .../lib/generate-missing-examples.ts | 28 +++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/tools/@aws-cdk/generate-examples/lib/assemblies.ts b/tools/@aws-cdk/generate-examples/lib/assemblies.ts index 5efa530849ea2..94a1c0d1f652a 100644 --- a/tools/@aws-cdk/generate-examples/lib/assemblies.ts +++ b/tools/@aws-cdk/generate-examples/lib/assemblies.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import * as spec from '@jsii/spec'; import * as fs from 'fs-extra'; import { TypeScriptSnippet } from 'jsii-rosetta'; +import { FIXTURE_NAME } from './generate-missing-examples'; /** * Replaces the file where the original assembly file *should* be found with a new assembly file. @@ -15,6 +16,18 @@ export async function replaceAssembly(assembly: spec.Assembly, directory: string }); } +export function addFixtureToRosetta(directory: string, fileName: string, fixture: string) { + const rosettaPath = path.join(directory, 'rosetta'); + if (!fs.existsSync(rosettaPath)) { + fs.mkdirSync(rosettaPath); + } + const filePath = path.join(rosettaPath, fileName); + if (fs.existsSync(filePath)) { + return; + } + fs.writeFileSync(filePath, fixture); +} + /** * Replaces the old fingerprint with '***********'. * @@ -35,6 +48,15 @@ export function insertExample(example: TypeScriptSnippet, type: spec.Type): void if (type.docs) { type.docs.example = example.visibleSource; } else { - type.docs = { example: example.visibleSource }; + type.docs = { + example: example.visibleSource, + }; + } + if (type.docs.custom) { + type.docs.custom.exampleMetadata = `fixture=${FIXTURE_NAME}`; + } else { + type.docs.custom = { + exampleMetadata: `fixture=${FIXTURE_NAME}`, + }; } } diff --git a/tools/@aws-cdk/generate-examples/lib/generate-missing-examples.ts b/tools/@aws-cdk/generate-examples/lib/generate-missing-examples.ts index d11db83e4cf79..d08a44cc8dd6d 100644 --- a/tools/@aws-cdk/generate-examples/lib/generate-missing-examples.ts +++ b/tools/@aws-cdk/generate-examples/lib/generate-missing-examples.ts @@ -4,7 +4,7 @@ import { Assembly, ClassType, InterfaceType, TypeSystem } from 'jsii-reflect'; // This import should come from @jsii/spec. Replace when that is possible. import { LanguageTablet, RosettaTranslator, SnippetLocation, SnippetParameters, TypeScriptSnippet, typeScriptSnippetFromCompleteSource } from 'jsii-rosetta'; -import { insertExample, replaceAssembly } from './assemblies'; +import { insertExample, replaceAssembly, addFixtureToRosetta } from './assemblies'; import { generateAssignmentStatement } from './generate'; const COMMENT_WARNING = [ @@ -12,6 +12,8 @@ const COMMENT_WARNING = [ '// The values are placeholders you should change.', ]; +export const FIXTURE_NAME = '_generated'; + export interface GenerateExamplesOptions { readonly cacheFromTablet?: string; readonly appendToTablet?: string; @@ -31,7 +33,7 @@ export async function generateMissingExamples(assemblyLocations: string[], optio return { assemblyLocation, assembly: await typesystem.load(assemblyLocation, { validate: false }) }; })); - const snippets = loadedAssemblies.flatMap(({ assembly }) => { + const snippets = loadedAssemblies.flatMap(({ assembly, assemblyLocation }) => { // Classes and structs const documentableTypes: Array = []; for (const m of [assembly, ...assembly.allSubmodules]) { @@ -39,6 +41,14 @@ export async function generateMissingExamples(assemblyLocations: string[], optio documentableTypes.push(...m.interfaces.filter(c => !c.docs.example && c.datatype)); } + // add fixture to assembly's rosetta folder if it doesn't exist yet + const fixture = generateFixture(assembly); + addFixtureToRosetta( + assemblyLocation, + `${FIXTURE_NAME}.ts-fixture`, + fixture, + ); + console.log(`${assembly.name}: ${documentableTypes.length} classes to document`); if (documentableTypes.length === 0) { return []; } @@ -73,6 +83,7 @@ export async function generateMissingExamples(assemblyLocations: string[], optio true, { [SnippetParameters.$COMPILATION_DIRECTORY]: options.directory ?? process.cwd(), + [SnippetParameters.$PROJECT_DIRECTORY]: assemblyLocation, }); insertExample(tsSnippet, classType.spec); @@ -153,4 +164,15 @@ function correctConstructImport(assembly: Assembly) { } return 'import { Construct } from "constructs";'; -} \ No newline at end of file +} + +function generateFixture(assembly: Assembly): string { + return [ + correctConstructImport(assembly), + 'class MyConstruct extends Construct {', + 'constructor(scope: Construct, id: string) {', + 'super(scope, id);', + '/// here', + '} }', + ].join('\n').trimLeft(); +} From 245c059eabf59d0fb0b352dac5e49d5ab4ef9ee2 Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Tue, 30 Nov 2021 06:05:56 -0700 Subject: [PATCH 36/82] feat(ec2): add vt1 instances (#17756) `vt1` instances release note: https://aws.amazon.com/blogs/aws/new-amazon-ec2-vt1-instances-for-live-multi-stream-video-transcoding/ Docs have already been updated a while ago: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-instancetype ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/instance-types.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index 018291783ef94..a177f3ca1ddbf 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -585,6 +585,16 @@ export enum InstanceClass { * Macintosh instances built on Apple Mac mini computers, 1st generation with Intel procesors */ MAC1 = 'mac1', + + /** + * Multi-stream video transcoding instances for resolutions up to 4K UHD, 1st generation + */ + VIDEO_TRANSCODING1 = 'vt1', + + /** + * Multi-stream video transcoding instances for resolutions up to 4K UHD, 1st generation + */ + VT1 = 'vt1', } /** From b06f120916acd63293c020eef368401b4428ce0a Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Tue, 30 Nov 2021 06:48:20 -0700 Subject: [PATCH 37/82] feat(ec2): add m6a instances (#17764) New `m6a` instances release notes: https://aws.amazon.com/blogs/aws/new-amazon-ec2-m6a-instances-powered-by-3rd-gen-amd-epyc-processors/ ![image](https://user-images.githubusercontent.com/31543/143961046-99e865fd-e79d-420e-8e27-02963967454b.png) CFN docs have already been updated: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-instancetype ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/instance-types.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index a177f3ca1ddbf..73639cedd37cd 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -546,6 +546,16 @@ export enum InstanceClass { */ M6I = 'm6i', + /** + * Standard instances based on 3rd Gen AMD EPYC processors, 6th generation. + */ + STANDARD6_AMD = 'm6a', + + /** + * Standard instances based on 3rd Gen AMD EPYC processors, 6th generation. + */ + M6A = 'm6a', + /** * Standard instances, 6th generation with Graviton2 processors and local NVME drive */ From 1799f7e08d06b8846c9918f1cb130f20570a99be Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Tue, 30 Nov 2021 07:30:45 -0700 Subject: [PATCH 38/82] feat(ec2): add g5g instances (#17765) New `g5g` instances release notes: https://aws.amazon.com/blogs/aws/new-amazon-ec2-g5g-instances-powered-by-aws-graviton2-processors-and-nvidia-t4g-tensor-core-gpus/ ![image](https://user-images.githubusercontent.com/31543/143961493-528f208d-f941-43d8-ba23-7f1d6b813913.png) Docs have already been updated a while ago: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-instancetype ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/instance-types.ts | 10 ++++++++++ packages/@aws-cdk/aws-ec2/test/instance.test.ts | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index 73639cedd37cd..65d7f60c5836c 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -486,6 +486,16 @@ export enum InstanceClass { */ G5 = 'g5', + /** + * Graphics-optimized instances powered by AWS Graviton2 Processors and NVIDIA T4G Tensor Core GPUs, 5th generation + */ + GRAPHICS5_GRAVITON2 = 'g5g', + + /** + * Graphics-optimized instances powered by AWS Graviton2 Processors and NVIDIA T4G Tensor Core GPUs, 5th generation + */ + G5G = 'g5g', + /** * Parallel-processing optimized instances, 2nd generation */ diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index 632a1f7b7e10f..a53092b6a41d4 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -122,7 +122,7 @@ describe('instance', () => { test('instance architecture is correctly discerned for arm instances', () => { // GIVEN const sampleInstanceClasses = [ - 'a1', 't4g', 'c6g', 'c6gd', 'c6gn', 'm6g', 'm6gd', 'r6g', 'r6gd', // current Graviton-based instance classes + 'a1', 't4g', 'c6g', 'c6gd', 'c6gn', 'm6g', 'm6gd', 'r6g', 'r6gd', 'g5g', // current Graviton-based instance classes 'a13', 't11g', 'y10ng', 'z11ngd', // theoretical future Graviton-based instance classes ]; From 719f33e20c723f161fc35230fafd7e99bca66a61 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Tue, 30 Nov 2021 15:13:48 +0000 Subject: [PATCH 39/82] chore(apigatewayv2-authorizers): re-organize authorizer api (#17772) This is a follow on to a previous commit 29039e8b. Update the ergonomics of the authorizer construct APIs to be aligned with the rest of the module, specifically the integration construct APIs. The API now takes the construct id and the integration target as part of the constructor, instead of in the props class. In most cases, except in the case of jwt, all properties in the props struct become optional, which improves API ergonomics. It also removes the need for `authorizerName` property to be required. BREAKING CHANGE: The default value for the prop `authorizerName` in `HttpJwtAuthorizerProps` has changed. * **apigatewayv2-authorizers:** `HttpJwtAuthorizer` now takes the construct id and the target jwt issuer as part of its constructor. * **apigatewayv2-authorizers:** `HttpLambdaAuthorizer` now takes the construct id and the target lambda function handler as part of its constructor. * **apigatewayv2-authorizers:** The default value for the prop `authorizerName` in `HttpUserPoolAuthorizerProps` has changed. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-apigatewayv2-authorizers/README.md | 22 ++++------- .../lib/http/jwt.ts | 28 +++++++------- .../lib/http/lambda.ts | 31 +++++++++------- .../lib/http/user-pool.ts | 37 +++++++++++-------- .../test/http/integ.lambda.expected.json | 8 ++-- .../test/http/integ.lambda.ts | 3 +- .../test/http/integ.user-pool.expected.json | 4 +- .../test/http/integ.user-pool.ts | 7 +--- .../test/http/jwt.test.ts | 7 ++-- .../test/http/lambda.test.ts | 24 +++--------- .../test/http/user-pool.test.ts | 18 +++------ 11 files changed, 82 insertions(+), 107 deletions(-) diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md index df0a69a82b11e..d1aebb7477b82 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md @@ -48,9 +48,9 @@ In the example below, all routes will require the `manage:books` scope present i ```ts import { HttpJwtAuthorizer } from '@aws-cdk/aws-apigatewayv2-authorizers'; -const authorizer = new HttpJwtAuthorizer({ +const issuer = 'https://test.us.auth0.com'; +const authorizer = new HttpJwtAuthorizer('DefaultAuthorizer', issuer, { jwtAudience: ['3131231'], - jwtIssuer: 'https://test.us.auth0.com', }); const api = new apigwv2.HttpApi(this, 'HttpApi', { @@ -73,9 +73,9 @@ The example below showcases default authorization, along with route authorizatio import { HttpJwtAuthorizer } from '@aws-cdk/aws-apigatewayv2-authorizers'; import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; -const authorizer = new HttpJwtAuthorizer({ +const issuer = 'https://test.us.auth0.com'; +const authorizer = new HttpJwtAuthorizer('DefaultAuthorizer', issuer, { jwtAudience: ['3131231'], - jwtIssuer: 'https://test.us.auth0.com', }); const api = new apigwv2.HttpApi(this, 'HttpApi', { @@ -130,9 +130,9 @@ Clients that fail authorization are presented with either 2 responses: import { HttpJwtAuthorizer } from '@aws-cdk/aws-apigatewayv2-authorizers'; import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; -const authorizer = new HttpJwtAuthorizer({ +const issuer = 'https://test.us.auth0.com'; +const authorizer = new HttpJwtAuthorizer('BooksAuthorizer', issuer, { jwtAudience: ['3131231'], - jwtIssuer: 'https://test.us.auth0.com', }); const api = new apigwv2.HttpApi(this, 'HttpApi'); @@ -158,12 +158,8 @@ import { HttpUserPoolAuthorizer } from '@aws-cdk/aws-apigatewayv2-authorizers'; import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; const userPool = new cognito.UserPool(this, 'UserPool'); -const userPoolClient = userPool.addClient('UserPoolClient'); -const authorizer = new HttpUserPoolAuthorizer({ - userPool, - userPoolClients: [userPoolClient], -}); +const authorizer = new HttpUserPoolAuthorizer('BooksAuthorizer', userPool); const api = new apigwv2.HttpApi(this, 'HttpApi'); @@ -188,10 +184,8 @@ import { HttpUrlIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; // This function handles your auth logic declare const authHandler: lambda.Function; -const authorizer = new HttpLambdaAuthorizer({ - authorizerName: 'lambda-authorizer', +const authorizer = new HttpLambdaAuthorizer('BooksAuthorizer', authHandler, { responseTypes: [HttpLambdaResponseType.SIMPLE], // Define if returns simple and/or iam response - handler: authHandler, }); const api = new apigwv2.HttpApi(this, 'HttpApi'); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/jwt.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/jwt.ts index 184d02f3382b6..94e4f1e230e62 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/jwt.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/jwt.ts @@ -5,7 +5,6 @@ import { HttpRouteAuthorizerConfig, IHttpRouteAuthorizer, } from '@aws-cdk/aws-apigatewayv2'; -import { Token } from '@aws-cdk/core'; /** * Properties to initialize HttpJwtAuthorizer. @@ -14,7 +13,7 @@ export interface HttpJwtAuthorizerProps { /** * The name of the authorizer - * @default 'JwtAuthorizer' + * @default - same value as `id` passed in the constructor */ readonly authorizerName?: string; @@ -30,11 +29,6 @@ export interface HttpJwtAuthorizerProps { * A valid JWT must provide an aud that matches at least one entry in this list. */ readonly jwtAudience: string[] - - /** - * The base domain of the identity provider that issues JWT. - */ - readonly jwtIssuer: string; } /** @@ -44,21 +38,27 @@ export interface HttpJwtAuthorizerProps { export class HttpJwtAuthorizer implements IHttpRouteAuthorizer { private authorizer?: HttpAuthorizer; - constructor(private readonly props: HttpJwtAuthorizerProps) { + /** + * Initialize a JWT authorizer to be bound with HTTP route. + * @param id The id of the underlying construct + * @param jwtIssuer The base domain of the identity provider that issues JWT + * @param props Properties to configure the authorizer + */ + constructor( + private readonly id: string, + private readonly jwtIssuer: string, + private readonly props: HttpJwtAuthorizerProps) { } public bind(options: HttpRouteAuthorizerBindOptions): HttpRouteAuthorizerConfig { if (!this.authorizer) { - const id = this.props.authorizerName && !Token.isUnresolved(this.props.authorizerName) ? - this.props.authorizerName : 'JwtAuthorizer'; - - this.authorizer = new HttpAuthorizer(options.scope, id, { + this.authorizer = new HttpAuthorizer(options.scope, this.id, { httpApi: options.route.httpApi, identitySource: this.props.identitySource ?? ['$request.header.Authorization'], type: HttpAuthorizerType.JWT, - authorizerName: this.props.authorizerName, + authorizerName: this.props.authorizerName ?? this.id, jwtAudience: this.props.jwtAudience, - jwtIssuer: this.props.jwtIssuer, + jwtIssuer: this.jwtIssuer, }); } diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/lambda.ts index fcb4f327c08a2..2e56317c1a667 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/lambda.ts @@ -32,9 +32,10 @@ export enum HttpLambdaResponseType { export interface HttpLambdaAuthorizerProps { /** - * The name of the authorizer + * Friendly authorizer name + * @default - same value as `id` passed in the constructor. */ - readonly authorizerName: string; + readonly authorizerName?: string; /** * The identity source for which authorization is requested. @@ -43,11 +44,6 @@ export interface HttpLambdaAuthorizerProps { */ readonly identitySource?: string[]; - /** - * The lambda function used for authorization - */ - readonly handler: IFunction; - /** * How long APIGateway should cache the results. Max 1 hour. * Disable caching by setting this to `Duration.seconds(0)`. @@ -76,7 +72,16 @@ export class HttpLambdaAuthorizer implements IHttpRouteAuthorizer { private authorizer?: HttpAuthorizer; private httpApi?: IHttpApi; - constructor(private readonly props: HttpLambdaAuthorizerProps) { + /** + * Initialize a lambda authorizer to be bound with HTTP route. + * @param id The id of the underlying construct + * @param pool The lambda function handler to use for authorization + * @param props Properties to configure the authorizer + */ + constructor( + private readonly id: string, + private readonly handler: IFunction, + private readonly props: HttpLambdaAuthorizerProps = {}) { } public bind(options: HttpRouteAuthorizerBindOptions): HttpRouteAuthorizerConfig { @@ -85,26 +90,24 @@ export class HttpLambdaAuthorizer implements IHttpRouteAuthorizer { } if (!this.authorizer) { - const id = this.props.authorizerName; - const responseTypes = this.props.responseTypes ?? [HttpLambdaResponseType.IAM]; const enableSimpleResponses = responseTypes.includes(HttpLambdaResponseType.SIMPLE) || undefined; this.httpApi = options.route.httpApi; - this.authorizer = new HttpAuthorizer(options.scope, id, { + this.authorizer = new HttpAuthorizer(options.scope, this.id, { httpApi: options.route.httpApi, identitySource: this.props.identitySource ?? [ '$request.header.Authorization', ], type: HttpAuthorizerType.LAMBDA, - authorizerName: this.props.authorizerName, + authorizerName: this.props.authorizerName ?? this.id, enableSimpleResponses, payloadFormatVersion: enableSimpleResponses ? AuthorizerPayloadVersion.VERSION_2_0 : AuthorizerPayloadVersion.VERSION_1_0, - authorizerUri: lambdaAuthorizerArn(this.props.handler), + authorizerUri: lambdaAuthorizerArn(this.handler), resultsCacheTtl: this.props.resultsCacheTtl ?? Duration.minutes(5), }); - this.props.handler.addPermission(`${Names.nodeUniqueId(this.authorizer.node)}-Permission`, { + this.handler.addPermission(`${Names.nodeUniqueId(this.authorizer.node)}-Permission`, { scope: options.scope as CoreConstruct, principal: new ServicePrincipal('apigateway.amazonaws.com'), sourceArn: Stack.of(options.route).formatArn({ diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts index cd4e39ad03fea..22f46a92b9b8c 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/lib/http/user-pool.ts @@ -1,6 +1,6 @@ import { HttpAuthorizer, HttpAuthorizerType, HttpRouteAuthorizerBindOptions, HttpRouteAuthorizerConfig, IHttpRouteAuthorizer } from '@aws-cdk/aws-apigatewayv2'; import { IUserPool, IUserPoolClient } from '@aws-cdk/aws-cognito'; -import { Stack, Token } from '@aws-cdk/core'; +import { Stack } from '@aws-cdk/core'; /** * Properties to initialize HttpUserPoolAuthorizer. @@ -8,13 +8,9 @@ import { Stack, Token } from '@aws-cdk/core'; export interface HttpUserPoolAuthorizerProps { /** * The user pool clients that should be used to authorize requests with the user pool. + * @default - a new client will be created for the given user pool */ - readonly userPoolClients: IUserPoolClient[]; - - /** - * The associated user pool - */ - readonly userPool: IUserPool; + readonly userPoolClients?: IUserPoolClient[]; /** * The AWS region in which the user pool is present @@ -23,8 +19,8 @@ export interface HttpUserPoolAuthorizerProps { readonly userPoolRegion?: string; /** - * The name of the authorizer - * @default 'UserPoolAuthorizer' + * Friendly name of the authorizer + * @default - same value as `id` passed in the constructor */ readonly authorizerName?: string; @@ -43,21 +39,30 @@ export interface HttpUserPoolAuthorizerProps { export class HttpUserPoolAuthorizer implements IHttpRouteAuthorizer { private authorizer?: HttpAuthorizer; - constructor(private readonly props: HttpUserPoolAuthorizerProps) { + /** + * Initialize a Cognito user pool authorizer to be bound with HTTP route. + * @param id The id of the underlying construct + * @param pool The user pool to use for authorization + * @param props Properties to configure the authorizer + */ + constructor( + private readonly id: string, + private readonly pool: IUserPool, + private readonly props: HttpUserPoolAuthorizerProps = {}) { } public bind(options: HttpRouteAuthorizerBindOptions): HttpRouteAuthorizerConfig { if (!this.authorizer) { - const id = this.props.authorizerName && !Token.isUnresolved(this.props.authorizerName) ? - this.props.authorizerName : 'UserPoolAuthorizer'; const region = this.props.userPoolRegion ?? Stack.of(options.scope).region; - this.authorizer = new HttpAuthorizer(options.scope, id, { + const clients = this.props.userPoolClients ?? [this.pool.addClient('UserPoolAuthorizerClient')]; + + this.authorizer = new HttpAuthorizer(options.scope, this.id, { httpApi: options.route.httpApi, identitySource: this.props.identitySource ?? ['$request.header.Authorization'], type: HttpAuthorizerType.JWT, - authorizerName: this.props.authorizerName, - jwtAudience: this.props.userPoolClients.map((c) => c.userPoolClientId), - jwtIssuer: `https://cognito-idp.${region}.amazonaws.com/${this.props.userPool.userPoolId}`, + authorizerName: this.props.authorizerName ?? this.id, + jwtAudience: clients.map((c) => c.userPoolClientId), + jwtIssuer: `https://cognito-idp.${region}.amazonaws.com/${this.pool.userPoolId}`, }); } diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json index 29ee6fe741501..921b4b1876d8f 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.expected.json @@ -79,7 +79,7 @@ "RouteKey": "GET /", "AuthorizationType": "CUSTOM", "AuthorizerId": { - "Ref": "MyHttpApimysimpleauthorizer98398C16" + "Ref": "MyHttpApiLambdaAuthorizerB8A0E2A4" }, "Target": { "Fn::Join": [ @@ -94,7 +94,7 @@ } } }, - "MyHttpApimysimpleauthorizer98398C16": { + "MyHttpApiLambdaAuthorizerB8A0E2A4": { "Type": "AWS::ApiGatewayV2::Authorizer", "Properties": { "ApiId": { @@ -133,7 +133,7 @@ ] } }, - "MyHttpApiAuthorizerIntegMyHttpApimysimpleauthorizer0F14A472PermissionF37EF5C8": { + "MyHttpApiAuthorizerIntegMyHttpApiLambdaAuthorizerB89228D7Permission82260331": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -166,7 +166,7 @@ }, "/authorizers/", { - "Ref": "MyHttpApimysimpleauthorizer98398C16" + "Ref": "MyHttpApiLambdaAuthorizerB8A0E2A4" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts index 9bc2326da21c9..5e0c32bc401d7 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts @@ -24,10 +24,9 @@ const authHandler = new lambda.Function(stack, 'auth-function', { }); -const authorizer = new HttpLambdaAuthorizer({ +const authorizer = new HttpLambdaAuthorizer('LambdaAuthorizer', authHandler, { authorizerName: 'my-simple-authorizer', identitySource: ['$request.header.X-API-Key'], - handler: authHandler, responseTypes: [HttpLambdaResponseType.SIMPLE], }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json index 3e8577dfa278c..44055c596d865 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.expected.json @@ -108,7 +108,7 @@ "JwtConfiguration": { "Audience": [ { - "Ref": "userpoolmyclientFAD947AB" + "Ref": "userpoolUserPoolAuthorizerClient6A7486E8" } ], "Issuer": { @@ -160,7 +160,7 @@ "UpdateReplacePolicy": "Retain", "DeletionPolicy": "Retain" }, - "userpoolmyclientFAD947AB": { + "userpoolUserPoolAuthorizerClient6A7486E8": { "Type": "AWS::Cognito::UserPoolClient", "Properties": { "UserPoolId": { diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts index 6e9ddd8e69b5c..3c9318109dbf3 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/integ.user-pool.ts @@ -21,12 +21,7 @@ const httpApi = new HttpApi(stack, 'MyHttpApi'); const userPool = new cognito.UserPool(stack, 'userpool'); -const userPoolClient = userPool.addClient('my-client'); - -const authorizer = new HttpUserPoolAuthorizer({ - userPool, - userPoolClients: [userPoolClient], -}); +const authorizer = new HttpUserPoolAuthorizer('UserPoolAuthorizer', userPool); const handler = new lambda.Function(stack, 'lambda', { runtime: lambda.Runtime.NODEJS_12_X, diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts index 1d91a37438cfb..d26fff86503d1 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/jwt.test.ts @@ -10,9 +10,8 @@ describe('HttpJwtAuthorizer', () => { const stack = new Stack(); const api = new HttpApi(stack, 'HttpApi'); - const authorizer = new HttpJwtAuthorizer({ + const authorizer = new HttpJwtAuthorizer('BooksAuthorizer', 'https://test.us.auth0.com', { jwtAudience: ['3131231'], - jwtIssuer: 'https://test.us.auth0.com', }); // WHEN @@ -30,6 +29,7 @@ describe('HttpJwtAuthorizer', () => { Audience: ['3131231'], Issuer: 'https://test.us.auth0.com', }, + Name: 'BooksAuthorizer', }); }); @@ -38,9 +38,8 @@ describe('HttpJwtAuthorizer', () => { const stack = new Stack(); const api = new HttpApi(stack, 'HttpApi'); - const authorizer = new HttpJwtAuthorizer({ + const authorizer = new HttpJwtAuthorizer('BooksAuthorizer', 'https://test.us.auth0.com', { jwtAudience: ['3131231'], - jwtIssuer: 'https://test.us.auth0.com', }); // WHEN diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts index 8ced20b3c1e1e..78d5acf7b8dfe 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/lambda.test.ts @@ -18,10 +18,7 @@ describe('HttpLambdaAuthorizer', () => { handler: 'index.handler', }); - const authorizer = new HttpLambdaAuthorizer({ - authorizerName: 'default-authorizer', - handler, - }); + const authorizer = new HttpLambdaAuthorizer('BooksAuthorizer', handler); // WHEN api.addRoutes({ @@ -32,7 +29,7 @@ describe('HttpLambdaAuthorizer', () => { // THEN Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Authorizer', { - Name: 'default-authorizer', + Name: 'BooksAuthorizer', AuthorizerType: 'REQUEST', AuthorizerResultTtlInSeconds: 300, AuthorizerPayloadFormatVersion: '1.0', @@ -57,10 +54,8 @@ describe('HttpLambdaAuthorizer', () => { handler: 'index.handler', }); - const authorizer = new HttpLambdaAuthorizer({ - authorizerName: 'my-simple-authorizer', + const authorizer = new HttpLambdaAuthorizer('BooksAuthorizer', handler, { responseTypes: [HttpLambdaResponseType.SIMPLE], - handler, }); // WHEN @@ -88,10 +83,8 @@ describe('HttpLambdaAuthorizer', () => { handler: 'index.handler', }); - const authorizer = new HttpLambdaAuthorizer({ - authorizerName: 'my-iam-authorizer', + const authorizer = new HttpLambdaAuthorizer('BooksAuthorizer', handler, { responseTypes: [HttpLambdaResponseType.IAM], - handler, }); // WHEN @@ -119,10 +112,8 @@ describe('HttpLambdaAuthorizer', () => { handler: 'index.handler', }); - const authorizer = new HttpLambdaAuthorizer({ - authorizerName: 'my-simple-iam-authorizer', + const authorizer = new HttpLambdaAuthorizer('BooksAuthorizer', handler, { responseTypes: [HttpLambdaResponseType.IAM, HttpLambdaResponseType.SIMPLE], - handler, }); // WHEN @@ -150,10 +141,7 @@ describe('HttpLambdaAuthorizer', () => { handler: 'index.handler', }); - const authorizer = new HttpLambdaAuthorizer({ - authorizerName: 'my-simple-authorizer', - responseTypes: [HttpLambdaResponseType.SIMPLE], - handler, + const authorizer = new HttpLambdaAuthorizer('BooksAuthorizer', handler, { resultsCacheTtl: Duration.minutes(10), }); diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts index 21bda048b1a4d..e084bfb5dd983 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/test/http/user-pool.test.ts @@ -11,11 +11,7 @@ describe('HttpUserPoolAuthorizer', () => { const stack = new Stack(); const api = new HttpApi(stack, 'HttpApi'); const userPool = new UserPool(stack, 'UserPool'); - const userPoolClient = userPool.addClient('UserPoolClient'); - const authorizer = new HttpUserPoolAuthorizer({ - userPool, - userPoolClients: [userPoolClient], - }); + const authorizer = new HttpUserPoolAuthorizer('BooksAuthorizer', userPool); // WHEN api.addRoutes({ @@ -29,7 +25,7 @@ describe('HttpUserPoolAuthorizer', () => { AuthorizerType: 'JWT', IdentitySource: ['$request.header.Authorization'], JwtConfiguration: { - Audience: [stack.resolve(userPoolClient.userPoolClientId)], + Audience: [{ Ref: 'UserPoolUserPoolAuthorizerClient680A88B6' }], Issuer: { 'Fn::Join': [ '', @@ -42,6 +38,7 @@ describe('HttpUserPoolAuthorizer', () => { ], }, }, + Name: 'BooksAuthorizer', }); }); @@ -50,11 +47,7 @@ describe('HttpUserPoolAuthorizer', () => { const stack = new Stack(); const api = new HttpApi(stack, 'HttpApi'); const userPool = new UserPool(stack, 'UserPool'); - const userPoolClient = userPool.addClient('UserPoolClient'); - const authorizer = new HttpUserPoolAuthorizer({ - userPool, - userPoolClients: [userPoolClient], - }); + const authorizer = new HttpUserPoolAuthorizer('UserPoolAuthorizer', userPool); // WHEN api.addRoutes({ @@ -79,8 +72,7 @@ describe('HttpUserPoolAuthorizer', () => { const userPool = new UserPool(stack, 'UserPool'); const userPoolClient1 = userPool.addClient('UserPoolClient1'); const userPoolClient2 = userPool.addClient('UserPoolClient2'); - const authorizer = new HttpUserPoolAuthorizer({ - userPool, + const authorizer = new HttpUserPoolAuthorizer('BooksAuthorizer', userPool, { userPoolClients: [userPoolClient1, userPoolClient2], }); From c62377e14caae677deb7e4eae692eaccb2020c67 Mon Sep 17 00:00:00 2001 From: Mike Vosseller Date: Tue, 30 Nov 2021 10:56:52 -0500 Subject: [PATCH 40/82] feat(ec2): extend BastionHostLinux to support CloudFormationInit (#17507) Implements https://github.com/aws/aws-cdk/issues/17161 Extends the `BastionHostLinux` constructor to accept optional `CloudFormationInit` and `ApplyCloudFormationInitOptions` arguments to be passed to the underlying instance. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/bastion-host.ts | 21 +++++++++- .../aws-ec2/test/bastion-host.test.ts | 42 ++++++++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts b/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts index b0345f34b6b98..5f1d7d3c8709f 100644 --- a/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts +++ b/packages/@aws-cdk/aws-ec2/lib/bastion-host.ts @@ -2,8 +2,9 @@ import { IPrincipal, IRole, PolicyStatement } from '@aws-cdk/aws-iam'; import { CfnOutput, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { AmazonLinuxGeneration, InstanceArchitecture, InstanceClass, InstanceSize, InstanceType } from '.'; +import { CloudFormationInit } from './cfn-init'; import { Connections } from './connections'; -import { IInstance, Instance } from './instance'; +import { ApplyCloudFormationInitOptions, IInstance, Instance } from './instance'; import { AmazonLinuxCpuType, IMachineImage, MachineImage } from './machine-image'; import { IPeer } from './peer'; import { Port } from './port'; @@ -80,6 +81,22 @@ export interface BastionHostLinuxProps { * @default - Uses the block device mapping of the AMI */ readonly blockDevices?: BlockDevice[]; + + /** + * Apply the given CloudFormation Init configuration to the instance at startup + * + * @default - no CloudFormation init + */ + readonly init?: CloudFormationInit; + + /** + * Use the given options for applying CloudFormation Init + * + * Describes the configsets to use and the timeout to wait + * + * @default - default options + */ + readonly initOptions?: ApplyCloudFormationInitOptions; } /** @@ -159,6 +176,8 @@ export class BastionHostLinux extends Resource implements IInstance { }), vpcSubnets: props.subnetSelection ?? {}, blockDevices: props.blockDevices ?? undefined, + init: props.init, + initOptions: props.initOptions, }); this.instance.addToRolePolicy(new PolicyStatement({ actions: [ diff --git a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts index 42e2dd8cd7e0a..38570e3306f8a 100644 --- a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts @@ -1,6 +1,7 @@ import '@aws-cdk/assert-internal/jest'; -import { Stack } from '@aws-cdk/core'; -import { BastionHostLinux, BlockDeviceVolume, InstanceClass, InstanceSize, InstanceType, SubnetType, Vpc } from '../lib'; +import { ResourcePart } from '@aws-cdk/assert-internal'; +import { Duration, Stack } from '@aws-cdk/core'; +import { BastionHostLinux, BlockDeviceVolume, CloudFormationInit, InitCommand, InstanceClass, InstanceSize, InstanceType, SubnetType, Vpc } from '../lib'; describe('bastion host', () => { test('default instance is created in basic', () => { @@ -123,4 +124,41 @@ describe('bastion host', () => { }); + + test('add CloudFormation Init to instance', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + + // WHEN + new BastionHostLinux(stack, 'Bastion', { + vpc, + initOptions: { + timeout: Duration.minutes(30), + }, + init: CloudFormationInit.fromElements( + InitCommand.shellCommand('echo hello'), + ), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::EC2::Instance', { + CreationPolicy: { + ResourceSignal: { + Timeout: 'PT30M', + }, + }, + Metadata: { + 'AWS::CloudFormation::Init': { + config: { + commands: { + '000': { + command: 'echo hello', + }, + }, + }, + }, + }, + }, ResourcePart.CompleteDefinition); + }); }); From d911c5878c59498a2d0e14ff536e0f8f9f503bfe Mon Sep 17 00:00:00 2001 From: Pahud Hsieh Date: Wed, 1 Dec 2021 00:39:59 +0800 Subject: [PATCH 41/82] fix(apprunner): startCommand and environment are ignored in imageConfiguration (#16939) This PR addresses the following issues 1. custom environment variables and start commands should be allowed for `imageConfiguration` 2. buildCommand, environment and startCommand should be allowed for `codeConfigurationValues` Fixes: #16812 - [x] add tests - [x] implementation ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-apprunner/lib/service.ts | 46 ++++- .../aws-apprunner/test/service.test.ts | 167 ++++++++++++++++++ 2 files changed, 204 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/aws-apprunner/lib/service.ts b/packages/@aws-cdk/aws-apprunner/lib/service.ts index 32e5151da9cbd..68d2fb0e65702 100644 --- a/packages/@aws-cdk/aws-apprunner/lib/service.ts +++ b/packages/@aws-cdk/aws-apprunner/lib/service.ts @@ -118,6 +118,13 @@ export class Runtime { private constructor(public readonly name: string) { } } +/** + * The environment variable for the service. + */ +interface EnvironmentVariable { + readonly name: string; + readonly value: string; +} /** * Result of binding `Source` into a `Service`. @@ -707,6 +714,10 @@ export class Service extends cdk.Resource { private readonly props: ServiceProps; private accessRole?: iam.IRole; private source: SourceConfig; + /** + * Environment variables for this service + */ + private environment?: { [key: string]: string } = {}; /** * The ARN of the Service. @@ -798,22 +809,39 @@ export class Service extends cdk.Resource { } private renderCodeConfigurationValues(props: CodeConfigurationValues): any { + this.environment = props.environment; return { - ...props, + port: props.port, + buildCommand: props.buildCommand, runtime: props.runtime.name, + runtimeEnvironmentVariables: this.renderEnvironmentVariables(), + startCommand: props.startCommand, }; } private renderImageRepository(): any { const repo = this.source.imageRepository!; - if (repo.imageConfiguration?.port) { - // convert port from type number to string - return Object.assign(repo, { - imageConfiguration: { - port: repo.imageConfiguration.port.toString(), - }, - }); + this.environment = repo.imageConfiguration?.environment; + return Object.assign(repo, { + imageConfiguration: { + port: repo.imageConfiguration?.port?.toString(), + startCommand: repo.imageConfiguration?.startCommand, + runtimeEnvironmentVariables: this.renderEnvironmentVariables(), + }, + }); + } + + private renderEnvironmentVariables(): EnvironmentVariable[] | undefined { + if (this.environment) { + let env: EnvironmentVariable[] = []; + for (const [key, value] of Object.entries(this.environment)) { + if (key.startsWith('AWSAPPRUNNER')) { + throw new Error(`Environment variable key ${key} with a prefix of AWSAPPRUNNER is not allowed`); + } + env.push({ name: key, value: value }); + } + return env; } else { - return repo; + return undefined; } } diff --git a/packages/@aws-cdk/aws-apprunner/test/service.test.ts b/packages/@aws-cdk/aws-apprunner/test/service.test.ts index a36cc97950119..412ff09cd14e9 100644 --- a/packages/@aws-cdk/aws-apprunner/test/service.test.ts +++ b/packages/@aws-cdk/aws-apprunner/test/service.test.ts @@ -1,4 +1,5 @@ import * as path from 'path'; +import '@aws-cdk/assert-internal/jest'; import { Template } from '@aws-cdk/assertions'; import * as ecr from '@aws-cdk/aws-ecr'; import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; @@ -32,6 +33,92 @@ test('create a service with ECR Public(image repository type: ECR_PUBLIC)', () = }); }); +test('custom environment variables and start commands are allowed for imageConfiguration with defined port', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageConfiguration: { + port: 8000, + environment: { + foo: 'fooval', + bar: 'barval', + }, + startCommand: '/root/start-command.sh', + }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + }); + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: {}, + ImageRepository: { + ImageConfiguration: { + Port: '8000', + RuntimeEnvironmentVariables: [ + { + Name: 'foo', + Value: 'fooval', + }, + { + Name: 'bar', + Value: 'barval', + }, + ], + StartCommand: '/root/start-command.sh', + }, + ImageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + ImageRepositoryType: 'ECR_PUBLIC', + }, + }, + }); +}); + +test('custom environment variables and start commands are allowed for imageConfiguration with port undefined', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageConfiguration: { + environment: { + foo: 'fooval', + bar: 'barval', + }, + startCommand: '/root/start-command.sh', + }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + }); + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: {}, + ImageRepository: { + ImageConfiguration: { + RuntimeEnvironmentVariables: [ + { + Name: 'foo', + Value: 'fooval', + }, + { + Name: 'bar', + Value: 'barval', + }, + ], + StartCommand: '/root/start-command.sh', + }, + ImageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + ImageRepositoryType: 'ECR_PUBLIC', + }, + }, + }); +}); + test('create a service from existing ECR repository(image repository type: ECR)', () => { // GIVEN const app = new cdk.App(); @@ -249,6 +336,66 @@ test('create a service with github repository - undefined branch name is allowed }); }); +test('create a service with github repository - buildCommand, environment and startCommand are allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + configurationSource: ConfigurationSourceType.API, + codeConfigurationValues: { + runtime: Runtime.PYTHON_3, + port: '8000', + buildCommand: '/root/build.sh', + environment: { + foo: 'fooval', + bar: 'barval', + }, + startCommand: '/root/start.sh', + }, + connection: GitHubConnection.fromConnectionArn('MOCK'), + }), + }); + + // THEN + // we should have the service with the branch value as 'main' + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + ConnectionArn: 'MOCK', + }, + CodeRepository: { + CodeConfiguration: { + CodeConfigurationValues: { + Port: '8000', + Runtime: 'PYTHON_3', + BuildCommand: '/root/build.sh', + RuntimeEnvironmentVariables: [ + { + Name: 'foo', + Value: 'fooval', + }, + { + Name: 'bar', + Value: 'barval', + }, + ], + StartCommand: '/root/start.sh', + }, + ConfigurationSource: 'API', + }, + RepositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + SourceCodeVersion: { + Type: 'BRANCH', + Value: 'main', + }, + }, + }, + }); +}); + test('import from service name', () => { // GIVEN @@ -417,3 +564,23 @@ test('custom cpu and memory units are allowed', () => { }, }); }); + +test('environment variable with a prefix of AWSAPPRUNNER should throw an error', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + // we should have the service + expect(() => { + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageConfiguration: { + environment: { + AWSAPPRUNNER_FOO: 'bar', + }, + }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + }); + }).toThrow('Environment variable key AWSAPPRUNNER_FOO with a prefix of AWSAPPRUNNER is not allowed'); +}); From 83e669dcdae9390990598236c75015832af766b4 Mon Sep 17 00:00:00 2001 From: Julian Michel Date: Tue, 30 Nov 2021 18:23:20 +0100 Subject: [PATCH 42/82] feat(neptune): add engine version 1.1.0.0 and instance types t4g, r6g (#17669) Add new instance types general-purpose T4g and memory-optimized R6g (see [announcement](https://aws.amazon.com/about-aws/whats-new/2021/11/aws-graviton2-based-instances-amazon-neptune/)). The specific instance types were copied from the [pricing page](https://aws.amazon.com/de/neptune/pricing/). Add new Neptune engine version 1.1.0.0 which was part of the announcement, too. Deployment tested successfully in region us-east-1: ```ts new neptune.DatabaseCluster(this, 'Database', { vpc, instanceType: neptune.InstanceType.T4G_MEDIUM, engineVersion: neptune.EngineVersion.V1_1_0_0, }); new neptune.DatabaseCluster(this, 'Database2', { vpc, instanceType: neptune.InstanceType.R6G_LARGE, engineVersion: neptune.EngineVersion.V1_1_0_0, }); ``` ---- *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-neptune/lib/cluster.ts | 4 ++ packages/@aws-cdk/aws-neptune/lib/instance.ts | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/packages/@aws-cdk/aws-neptune/lib/cluster.ts b/packages/@aws-cdk/aws-neptune/lib/cluster.ts index af8061ad6c21e..cf5245d33c476 100644 --- a/packages/@aws-cdk/aws-neptune/lib/cluster.ts +++ b/packages/@aws-cdk/aws-neptune/lib/cluster.ts @@ -50,6 +50,10 @@ export class EngineVersion { * Neptune engine version 1.0.5.0 */ public static readonly V1_0_5_0 = new EngineVersion('1.0.5.0'); + /** + * Neptune engine version 1.1.0.0 + */ + public static readonly V1_1_0_0 = new EngineVersion('1.1.0.0'); /** * Constructor for specifying a custom engine version diff --git a/packages/@aws-cdk/aws-neptune/lib/instance.ts b/packages/@aws-cdk/aws-neptune/lib/instance.ts index 12920fe95444b..b05003dffcb40 100644 --- a/packages/@aws-cdk/aws-neptune/lib/instance.ts +++ b/packages/@aws-cdk/aws-neptune/lib/instance.ts @@ -12,6 +12,46 @@ import { IParameterGroup } from './parameter-group'; */ export class InstanceType { + /** + * db.r6g.large + */ + public static readonly R6G_LARGE = InstanceType.of('db.r6g.large'); + + /** + * db.r6g.xlarge + */ + public static readonly R6G_XLARGE = InstanceType.of('db.r6g.xlarge'); + + /** + * db.r6g.2xlarge + */ + public static readonly R6G_2XLARGE = InstanceType.of('db.r6g.2xlarge'); + + /** + * db.r6g.4xlarge + */ + public static readonly R6G_4XLARGE = InstanceType.of('db.r6g.4xlarge'); + + /** + * db.r6g.8xlarge + */ + public static readonly R6G_8XLARGE = InstanceType.of('db.r6g.8xlarge'); + + /** + * db.r6g.12xlarge + */ + public static readonly R6G_12XLARGE = InstanceType.of('db.r6g.12xlarge'); + + /** + * db.r6g.16xlarge + */ + public static readonly R6G_16XLARGE = InstanceType.of('db.r6g.16xlarge'); + + /** + * db.t4g.medium + */ + public static readonly T4G_MEDIUM = InstanceType.of('db.t4g.medium'); + /** * db.r5.large */ From 986f291a51cee46299428298ca6b39a9636d6dd2 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Tue, 30 Nov 2021 19:07:02 +0100 Subject: [PATCH 43/82] fix(lambda-nodejs): bundling with `nodeModules` fails with paths containing spaces (#17632) Enclose paths with double quotes (`"`). Closes #17631 ---- *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-lambda-nodejs/lib/bundling.ts | 10 +++++----- .../@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 31fedbafc6e3d..7994859706379 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -305,22 +305,22 @@ class OsCommand { public writeJson(filePath: string, data: any): string { const stringifiedData = JSON.stringify(data); if (this.osPlatform === 'win32') { - return `echo ^${stringifiedData}^ > ${filePath}`; + return `echo ^${stringifiedData}^ > "${filePath}"`; } - return `echo '${stringifiedData}' > ${filePath}`; + return `echo '${stringifiedData}' > "${filePath}"`; } public copy(src: string, dest: string): string { if (this.osPlatform === 'win32') { - return `copy ${src} ${dest}`; + return `copy "${src}" "${dest}"`; } - return `cp ${src} ${dest}`; + return `cp "${src}" "${dest}"`; } public changeDirectory(dir: string): string { - return `cd ${dir}`; + return `cd "${dir}"`; } } diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts index 9ef40545baf31..2f8b823dcce45 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -169,9 +169,9 @@ test('esbuild bundling with externals and dependencies', () => { 'bash', '-c', [ 'esbuild --bundle "/asset-input/test/bundling.test.js" --target=node12 --platform=node --outfile="/asset-output/index.js" --external:abc --external:delay', - `echo \'{\"dependencies\":{\"delay\":\"${delayVersion}\"}}\' > /asset-output/package.json`, - 'cp /asset-input/package-lock.json /asset-output/package-lock.json', - 'cd /asset-output', + `echo \'{\"dependencies\":{\"delay\":\"${delayVersion}\"}}\' > "/asset-output/package.json"`, + 'cp "/asset-input/package-lock.json" "/asset-output/package-lock.json"', + 'cd "/asset-output"', 'npm ci', ].join(' && '), ], @@ -550,9 +550,9 @@ test('esbuild bundling with projectRoot and externals and dependencies', () => { 'bash', '-c', [ 'esbuild --bundle "/asset-input/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.js" --target=node12 --platform=node --outfile="/asset-output/index.js" --external:abc --external:delay', - `echo \'{\"dependencies\":{\"delay\":\"${delayVersion}\"}}\' > /asset-output/package.json`, - 'cp /asset-input/common/package-lock.json /asset-output/package-lock.json', - 'cd /asset-output', + `echo \'{\"dependencies\":{\"delay\":\"${delayVersion}\"}}\' > "/asset-output/package.json"`, + 'cp "/asset-input/common/package-lock.json" "/asset-output/package-lock.json"', + 'cd "/asset-output"', 'npm ci', ].join(' && '), ], From 3623982fc1a64c2c67a0dba18a6d3eeeb171e898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christophe=20Boug=C3=A8re?= Date: Tue, 30 Nov 2021 19:49:40 +0100 Subject: [PATCH 44/82] feat(lambda-event-sources): sqs: support reportBatchItemFailures (#17733) Fixes #17690 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-lambda-event-sources/README.md | 1 + .../aws-lambda-event-sources/lib/sqs.ts | 10 ++++++++++ .../aws-lambda-event-sources/test/sqs.test.ts | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/packages/@aws-cdk/aws-lambda-event-sources/README.md b/packages/@aws-cdk/aws-lambda-event-sources/README.md index 9abd6e59d9669..ab00703b729bb 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/README.md +++ b/packages/@aws-cdk/aws-lambda-event-sources/README.md @@ -71,6 +71,7 @@ declare const fn: lambda.Function; fn.addEventSource(new SqsEventSource(queue, { batchSize: 10, // default maxBatchingWindow: Duration.minutes(5), + reportBatchItemFailures: true, // default to false })); ``` diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts index ba900178d006a..c6cba08abd13d 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts @@ -24,6 +24,15 @@ export interface SqsEventSourceProps { */ readonly maxBatchingWindow?: Duration; + /** + * Allow functions to return partially successful responses for a batch of records. + * + * @see https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html#services-sqs-batchfailurereporting + * + * @default false + */ + readonly reportBatchItemFailures?: boolean; + /** * If the SQS event source mapping should be enabled. * @@ -61,6 +70,7 @@ export class SqsEventSource implements lambda.IEventSource { const eventSourceMapping = target.addEventSourceMapping(`SqsEventSource:${Names.nodeUniqueId(this.queue.node)}`, { batchSize: this.props.batchSize, maxBatchingWindow: this.props.maxBatchingWindow, + reportBatchItemFailures: this.props.reportBatchItemFailures, enabled: this.props.enabled, eventSourceArn: this.queue.queueArn, }); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/sqs.test.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/sqs.test.ts index 807b1a4fb107a..0f019671460af 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/sqs.test.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/sqs.test.ts @@ -264,5 +264,24 @@ describe('SQSEventSource', () => { }); + }); + + test('reportBatchItemFailures', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const q = new sqs.Queue(stack, 'Q'); + + // WHEN + fn.addEventSource(new sources.SqsEventSource(q, { + reportBatchItemFailures: true, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + 'FunctionResponseTypes': ['ReportBatchItemFailures'], + }); + + }); }); From a01678b838a7feb2bde40c435c6c585473d35b22 Mon Sep 17 00:00:00 2001 From: Kyle Laker Date: Tue, 30 Nov 2021 14:31:09 -0500 Subject: [PATCH 45/82] feat(secretsmanager): support secrets rotation in GovCloud (#17673) This follows the same general setup as #14608 to add Secrets Manager rotation support in the `aws-us-gov` partition, GovCloud (US). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .gitallowed | 2 ++ .../test/integ.cluster-rotation.lit.expected.json | 4 ++++ .../aws-rds/test/integ.cluster-rotation.lit.expected.json | 4 ++++ .../aws-rds/test/integ.instance.lit.expected.json | 4 ++++ .../@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts | 8 ++++++++ 5 files changed, 22 insertions(+) diff --git a/.gitallowed b/.gitallowed index abe8ccb913ca4..a7cacaea4980e 100644 --- a/.gitallowed +++ b/.gitallowed @@ -32,3 +32,5 @@ account: '919830735681' #cn-northwest-1 account: '297356227824' # partition aws-cn account: '193023089310' +# partition aws-us-gov +account: '023102451235' diff --git a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json index a2c3c5d8138a4..c800f1fbedba1 100644 --- a/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-docdb/test/integ.cluster-rotation.lit.expected.json @@ -823,6 +823,10 @@ "aws-cn": { "applicationId": "arn:aws-cn:serverlessrepo:cn-north-1:193023089310:applications/SecretsManagerMongoDBRotationSingleUser", "semanticVersion": "1.1.37" + }, + "aws-us-gov": { + "applicationId": "arn:aws-us-gov:serverlessrepo:us-gov-west-1:023102451235:applications/SecretsManagerMongoDBRotationSingleUser", + "semanticVersion": "1.1.93" } } } diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json index 19fbeabb515b1..4992aa9ac3383 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-rotation.lit.expected.json @@ -846,6 +846,10 @@ "aws-cn": { "applicationId": "arn:aws-cn:serverlessrepo:cn-north-1:193023089310:applications/SecretsManagerRDSMySQLRotationSingleUser", "semanticVersion": "1.1.37" + }, + "aws-us-gov": { + "applicationId": "arn:aws-us-gov:serverlessrepo:us-gov-west-1:023102451235:applications/SecretsManagerRDSMySQLRotationSingleUser", + "semanticVersion": "1.1.93" } } } diff --git a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json index 7b4328ccc3341..e5a193d0d68c4 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.instance.lit.expected.json @@ -1136,6 +1136,10 @@ "aws-cn": { "applicationId": "arn:aws-cn:serverlessrepo:cn-north-1:193023089310:applications/SecretsManagerRDSOracleRotationSingleUser", "semanticVersion": "1.1.37" + }, + "aws-us-gov": { + "applicationId": "arn:aws-us-gov:serverlessrepo:us-gov-west-1:023102451235:applications/SecretsManagerRDSOracleRotationSingleUser", + "semanticVersion": "1.1.93" } } }, diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts index 7311288279a51..3519616fe1308 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts @@ -149,6 +149,8 @@ export class SecretRotationApplication { return this.applicationId; } else if (partition === 'aws-cn') { return `arn:aws-cn:serverlessrepo:cn-north-1:193023089310:applications/${this.applicationName}`; + } else if (partition === 'aws-us-gov') { + return `arn:aws-us-gov:serverlessrepo:us-gov-west-1:023102451235:applications/${this.applicationName}`; } else { throw new Error(`unsupported partition: ${partition}`); } @@ -163,6 +165,8 @@ export class SecretRotationApplication { return this.semanticVersion; } else if (partition === 'aws-cn') { return '1.1.37'; + } else if (partition === 'aws-us-gov') { + return '1.1.93'; } else { throw new Error(`unsupported partition: ${partition}`); } @@ -316,6 +320,10 @@ export class SecretRotation extends CoreConstruct { applicationId: props.application.applicationArnForPartition('aws-cn'), semanticVersion: props.application.semanticVersionForPartition('aws-cn'), }, + 'aws-us-gov': { + applicationId: props.application.applicationArnForPartition('aws-us-gov'), + semanticVersion: props.application.semanticVersionForPartition('aws-us-gov'), + }, }, }); const application = new serverless.CfnApplication(this, 'Resource', { From 845be1012593a9f28457c73c9054bd98ea44d659 Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Tue, 30 Nov 2021 13:13:19 -0700 Subject: [PATCH 46/82] feat(ec2): add m5zn instances (#17757) `m5zn` instances release notes: https://aws.amazon.com/blogs/aws/new-ec2-m5zn-instances-fastest-intel-xeon-scalable-cpu-in-the-cloud/ Docs have already been updated a while ago: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-instancetype ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/instance-types.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts index 65d7f60c5836c..e377b0f1edb9b 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance-types.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance-types.ts @@ -88,6 +88,16 @@ export enum InstanceClass { */ M5DN = 'm5dn', + /** + * Standard instances with high memory and compute capacity based on Intel Xeon Scalable (Cascade Lake) processors, 5nd generation + */ + STANDARD5_HIGH_COMPUTE = 'm5zn', + + /** + * Standard instances with high memory and compute capacity based on Intel Xeon Scalable (Cascade Lake) processors, 5nd generation + */ + M5ZN = 'm5zn', + /** * Memory optimized instances, 3rd generation */ From 0ae435da17c651ef4428d9254c7164de25297a41 Mon Sep 17 00:00:00 2001 From: Christian Takle Date: Tue, 30 Nov 2021 23:37:47 +0000 Subject: [PATCH 47/82] chore(iot): readme typo (#17784) ---- *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-iot/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iot/README.md b/packages/@aws-cdk/aws-iot/README.md index 402036b531dfc..cddb8ae91cf5c 100644 --- a/packages/@aws-cdk/aws-iot/README.md +++ b/packages/@aws-cdk/aws-iot/README.md @@ -60,7 +60,7 @@ const func = new lambda.Function(this, 'MyFunction', { new iot.TopicRule(this, 'TopicRule', { topicRuleName: 'MyTopicRule', // optional - description: 'invokes the lambda finction', // optional + description: 'invokes the lambda function', // optional sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, timestamp() as timestamp FROM 'device/+/data'"), actions: [new actions.LambdaFunctionAction(func)], }); From f38e0ac5b90bd83630a5a602e9ada2556689d826 Mon Sep 17 00:00:00 2001 From: Alex Varju Date: Tue, 30 Nov 2021 19:13:31 -0800 Subject: [PATCH 48/82] fix(dynamodb): add missing DynamoDB operations to enum (#17738) While trying to modernize some of my application's hand-rolled alarms, I discovered that the Operations enum doesn't include all of the operation names listed under "Dimensions for DynamoDB Metrics" in https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/metrics-dimensions.html This PR adds this missing operation names to the enum. ---- *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-dynamodb/lib/table.ts | 15 +++++++++++++++ .../@aws-cdk/aws-dynamodb/test/dynamodb.test.ts | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index 6e6b79d253d1a..78d2851d513f7 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -72,6 +72,21 @@ export enum Operation { /** BatchWriteItem */ BATCH_WRITE_ITEM = 'BatchWriteItem', + /** TransactWriteItems */ + TRANSACT_WRITE_ITEMS = 'TransactWriteItems', + + /** TransactGetItems */ + TRANSACT_GET_ITEMS = 'TransactGetItems', + + /** ExecuteTransaction */ + EXECUTE_TRANSACTION = 'ExecuteTransaction', + + /** BatchExecuteStatement */ + BATCH_EXECUTE_STATEMENT = 'BatchExecuteStatement', + + /** ExecuteStatement */ + EXECUTE_STATEMENT = 'ExecuteStatement', + } /** diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index ded635da9983f..a0760b22761da 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -1600,6 +1600,11 @@ describe('metrics', () => { 'deleteitem', 'updateitem', 'batchwriteitem', + 'transactwriteitems', + 'transactgetitems', + 'executetransaction', + 'batchexecutestatement', + 'executestatement', ]); }); From b25590ff15d92a8a6ddc1f3a37263f90793b15f4 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Wed, 1 Dec 2021 10:15:27 +0000 Subject: [PATCH 49/82] =?UTF-8?q?feat(apigatewayv2):=20constructs=20for=20?= =?UTF-8?q?http=20api=20are=20now=20stable!=20=F0=9F=A4=98=20(#17773)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-apigatewayv2-authorizers/README.md | 22 +++++++++++++------ .../aws-apigatewayv2-authorizers/package.json | 10 +++++++++ .../aws-apigatewayv2-integrations/README.md | 20 ++++++++++++----- .../package.json | 10 +++++++++ packages/@aws-cdk/aws-apigatewayv2/README.md | 7 +++++- .../@aws-cdk/aws-apigatewayv2/package.json | 2 +- 6 files changed, 56 insertions(+), 15 deletions(-) diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md index d1aebb7477b82..c923a19e241a1 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md @@ -1,21 +1,29 @@ # AWS APIGatewayv2 Authorizers - --- -![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) +Features | Stability +--------------------------------------|------------------------------------------------------------- +Authorizer classes for HTTP APIs | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) +Authorizer classes for Websocket APIs | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) + +> **Experimental:** Higher level constructs in this module that are marked as experimental are +> under active development. They are subject to non-backward compatible changes or removal in any +> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and +> breaking changes will be announced in the release notes. This means that while you may use them, +> you may need to update your source code when upgrading to a newer version of this package. -> The APIs of higher level constructs in this module are experimental and under active development. -> They are subject to non-backward compatible changes or removal in any future version. These are -> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be -> announced in the release notes. This means that while you may use them, you may need to update -> your source code when upgrading to a newer version of this package. + + +> **Stable:** Higher level constructs in this module that are marked stable will not undergo any +> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model. --- + ## Table of Contents - [Introduction](#introduction) diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index e4dae38af4135..da4730ef59258 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -109,6 +109,16 @@ }, "stability": "experimental", "maturity": "experimental", + "features": [ + { + "name": "Authorizer classes for HTTP APIs", + "stability": "Stable" + }, + { + "name": "Authorizer classes for Websocket APIs", + "stability": "Experimental" + } + ], "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md b/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md index 07c2d3310cc5b..8dd9164eae6bc 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md @@ -3,13 +3,21 @@ --- -![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) +Features | Stability +---------------------------------------|------------------------------------------------------------ +Integration classes for HTTP APIs | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) +Integration classes for Websocket APIs | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) -> The APIs of higher level constructs in this module are experimental and under active development. -> They are subject to non-backward compatible changes or removal in any future version. These are -> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be -> announced in the release notes. This means that while you may use them, you may need to update -> your source code when upgrading to a newer version of this package. +> **Experimental:** Higher level constructs in this module that are marked as experimental are +> under active development. They are subject to non-backward compatible changes or removal in any +> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and +> breaking changes will be announced in the release notes. This means that while you may use them, +> you may need to update your source code when upgrading to a newer version of this package. + + + +> **Stable:** Higher level constructs in this module that are marked stable will not undergo any +> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model. --- diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index 87b5a43c1f9cb..c066a2e71989c 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -108,6 +108,16 @@ }, "stability": "experimental", "maturity": "experimental", + "features": [ + { + "name": "Integration classes for HTTP APIs", + "stability": "Stable" + }, + { + "name": "Integration classes for Websocket APIs", + "stability": "Experimental" + } + ], "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-apigatewayv2/README.md b/packages/@aws-cdk/aws-apigatewayv2/README.md index 6c0697287c08d..d00adb1b27f73 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2/README.md @@ -6,7 +6,7 @@ Features | Stability -------------------------------------------|-------------------------------------------------------- CFN Resources | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) -Higher level constructs for HTTP APIs | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) +Higher level constructs for HTTP APIs | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) Higher level constructs for Websocket APIs | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) > **CFN Resources:** All classes with the `Cfn` prefix in this module ([CFN Resources]) are always @@ -22,6 +22,11 @@ Higher level constructs for Websocket APIs | ![Experimental](https://img.shields > breaking changes will be announced in the release notes. This means that while you may use them, > you may need to update your source code when upgrading to a newer version of this package. + + +> **Stable:** Higher level constructs in this module that are marked stable will not undergo any +> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model. + --- diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index 6e12d9613fa27..cdf67e92d7760 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -124,7 +124,7 @@ "features": [ { "name": "Higher level constructs for HTTP APIs", - "stability": "Experimental" + "stability": "Stable" }, { "name": "Higher level constructs for Websocket APIs", From 9307a325f61e032f3c1fe0940a726bf0e8f67c37 Mon Sep 17 00:00:00 2001 From: Addi Horowitz Date: Wed, 1 Dec 2021 15:00:47 +0200 Subject: [PATCH 50/82] chore(readme): add constuct hub to list if resources (#17796) Add a link to Construct Hub ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 480d3ea597e85..6f9bb422faa7d 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,7 @@ this capability, please see the ## More Resources * [CDK Workshop](https://cdkworkshop.com/) +* [Construct Hub](https://constructs.dev) - Find and use open-source Cloud Development Kit (CDK) libraries * **[CDK Construction Zone](https://www.twitch.tv/collections/9kCOGphNZBYVdA)** - A Twitch live coding series hosted by the CDK team, season one episodes: * Triggers: Join us as we implement [Triggers](https://github.com/aws/aws-cdk-rfcs/issues/71), a Construct for configuring deploy time actions. Episodes 1-3: * [S1E1](https://www.twitch.tv/videos/917691798): Triggers (part 1); **Participants:** @NetaNir, @eladb, @richardhboyd From a75d5fd4921f0f55d01dc37e5d319621babb04f5 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Wed, 1 Dec 2021 16:09:43 +0200 Subject: [PATCH 51/82] chore: re-allow monocdk deep imports (#17791) #17707 added an `exports` section to the `package.json` files of `aws-cdk-lib` and `monocdk` in order to prevent users from accidentally "deep importing" modules. This broke a large number of `monocdk` users. Since these teams are going to migrate to v2 (`aws-cdk-lib`) soon anyway, we decided to revert this change for `monocdk` so they are unblocked in the meantime. To do this, we introduced two new configuration options for `ubergen`: `libRoot`, which can be used to control where submodules are going to be collected (defaults to the root of the uber package) and `explicitExports` which controls whether the `exports` section is added or not (defaults to true). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/monocdk/package.json | 234 +------------------------- tools/@aws-cdk/ubergen/bin/ubergen.ts | 74 ++++++-- 2 files changed, 64 insertions(+), 244 deletions(-) diff --git a/packages/monocdk/package.json b/packages/monocdk/package.json index c194f59d3d9c9..8a5fdac82c75f 100644 --- a/packages/monocdk/package.json +++ b/packages/monocdk/package.json @@ -2,8 +2,8 @@ "name": "monocdk", "version": "0.0.0", "description": "An experiment to bundle the entire CDK into a single module", - "main": "index.js", - "types": "index.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "repository": { "type": "git", "url": "https://github.com/aws/aws-cdk.git", @@ -37,6 +37,8 @@ } }, "ubergen": { + "explicitExports": false, + "libRoot": "lib", "deprecatedPackages": [ "@aws-cdk/aws-dynamodb-global", "@aws-cdk/cdk-assets-schema" @@ -357,233 +359,5 @@ }, "publishConfig": { "tag": "latest" - }, - "exports": { - ".": "./index.js", - "./package.json": "./package.json", - "./.jsii": "./.jsii", - "./.warnings.jsii.js": "./.warnings.jsii.js", - "./alexa-ask": "./alexa-ask/index.js", - "./app-delivery": "./app-delivery/index.js", - "./assertions": "./assertions/index.js", - "./assets": "./assets/index.js", - "./aws-accessanalyzer": "./aws-accessanalyzer/index.js", - "./aws-acmpca": "./aws-acmpca/index.js", - "./aws-amazonmq": "./aws-amazonmq/index.js", - "./aws-amplify": "./aws-amplify/index.js", - "./aws-apigateway": "./aws-apigateway/index.js", - "./aws-apigatewayv2": "./aws-apigatewayv2/index.js", - "./aws-apigatewayv2-authorizers": "./aws-apigatewayv2-authorizers/index.js", - "./aws-apigatewayv2-integrations": "./aws-apigatewayv2-integrations/index.js", - "./aws-appconfig": "./aws-appconfig/index.js", - "./aws-appflow": "./aws-appflow/index.js", - "./aws-appintegrations": "./aws-appintegrations/index.js", - "./aws-applicationautoscaling": "./aws-applicationautoscaling/index.js", - "./aws-applicationinsights": "./aws-applicationinsights/index.js", - "./aws-appmesh": "./aws-appmesh/index.js", - "./aws-apprunner": "./aws-apprunner/index.js", - "./aws-appstream": "./aws-appstream/index.js", - "./aws-appsync": "./aws-appsync/index.js", - "./aws-aps": "./aws-aps/index.js", - "./aws-athena": "./aws-athena/index.js", - "./aws-auditmanager": "./aws-auditmanager/index.js", - "./aws-autoscaling": "./aws-autoscaling/index.js", - "./aws-autoscaling-common": "./aws-autoscaling-common/index.js", - "./aws-autoscaling-hooktargets": "./aws-autoscaling-hooktargets/index.js", - "./aws-autoscalingplans": "./aws-autoscalingplans/index.js", - "./aws-backup": "./aws-backup/index.js", - "./aws-batch": "./aws-batch/index.js", - "./aws-budgets": "./aws-budgets/index.js", - "./aws-cassandra": "./aws-cassandra/index.js", - "./aws-ce": "./aws-ce/index.js", - "./aws-certificatemanager": "./aws-certificatemanager/index.js", - "./aws-chatbot": "./aws-chatbot/index.js", - "./aws-cloud9": "./aws-cloud9/index.js", - "./aws-cloudformation": "./aws-cloudformation/index.js", - "./aws-cloudfront": "./aws-cloudfront/index.js", - "./aws-cloudfront-origins": "./aws-cloudfront-origins/index.js", - "./aws-cloudtrail": "./aws-cloudtrail/index.js", - "./aws-cloudwatch": "./aws-cloudwatch/index.js", - "./aws-cloudwatch-actions": "./aws-cloudwatch-actions/index.js", - "./aws-codeartifact": "./aws-codeartifact/index.js", - "./aws-codebuild": "./aws-codebuild/index.js", - "./aws-codecommit": "./aws-codecommit/index.js", - "./aws-codedeploy": "./aws-codedeploy/index.js", - "./aws-codeguruprofiler": "./aws-codeguruprofiler/index.js", - "./aws-codegurureviewer": "./aws-codegurureviewer/index.js", - "./aws-codepipeline": "./aws-codepipeline/index.js", - "./aws-codepipeline-actions": "./aws-codepipeline-actions/index.js", - "./aws-codestar": "./aws-codestar/index.js", - "./aws-codestarconnections": "./aws-codestarconnections/index.js", - "./aws-codestarnotifications": "./aws-codestarnotifications/index.js", - "./aws-cognito": "./aws-cognito/index.js", - "./aws-config": "./aws-config/index.js", - "./aws-connect": "./aws-connect/index.js", - "./aws-cur": "./aws-cur/index.js", - "./aws-customerprofiles": "./aws-customerprofiles/index.js", - "./aws-databrew": "./aws-databrew/index.js", - "./aws-datapipeline": "./aws-datapipeline/index.js", - "./aws-datasync": "./aws-datasync/index.js", - "./aws-dax": "./aws-dax/index.js", - "./aws-detective": "./aws-detective/index.js", - "./aws-devopsguru": "./aws-devopsguru/index.js", - "./aws-directoryservice": "./aws-directoryservice/index.js", - "./aws-dlm": "./aws-dlm/index.js", - "./aws-dms": "./aws-dms/index.js", - "./aws-docdb": "./aws-docdb/index.js", - "./aws-dynamodb": "./aws-dynamodb/index.js", - "./aws-ec2": "./aws-ec2/index.js", - "./aws-ecr": "./aws-ecr/index.js", - "./aws-ecr-assets": "./aws-ecr-assets/index.js", - "./aws-ecs": "./aws-ecs/index.js", - "./aws-ecs-patterns": "./aws-ecs-patterns/index.js", - "./aws-efs": "./aws-efs/index.js", - "./aws-eks": "./aws-eks/index.js", - "./aws-eks-legacy": "./aws-eks-legacy/index.js", - "./aws-elasticache": "./aws-elasticache/index.js", - "./aws-elasticbeanstalk": "./aws-elasticbeanstalk/index.js", - "./aws-elasticloadbalancing": "./aws-elasticloadbalancing/index.js", - "./aws-elasticloadbalancingv2": "./aws-elasticloadbalancingv2/index.js", - "./aws-elasticloadbalancingv2-actions": "./aws-elasticloadbalancingv2-actions/index.js", - "./aws-elasticloadbalancingv2-targets": "./aws-elasticloadbalancingv2-targets/index.js", - "./aws-elasticsearch": "./aws-elasticsearch/index.js", - "./aws-emr": "./aws-emr/index.js", - "./aws-emrcontainers": "./aws-emrcontainers/index.js", - "./aws-events": "./aws-events/index.js", - "./aws-events-targets": "./aws-events-targets/index.js", - "./aws-eventschemas": "./aws-eventschemas/index.js", - "./aws-finspace": "./aws-finspace/index.js", - "./aws-fis": "./aws-fis/index.js", - "./aws-fms": "./aws-fms/index.js", - "./aws-frauddetector": "./aws-frauddetector/index.js", - "./aws-fsx": "./aws-fsx/index.js", - "./aws-gamelift": "./aws-gamelift/index.js", - "./aws-globalaccelerator": "./aws-globalaccelerator/index.js", - "./aws-globalaccelerator-endpoints": "./aws-globalaccelerator-endpoints/index.js", - "./aws-glue": "./aws-glue/index.js", - "./aws-greengrass": "./aws-greengrass/index.js", - "./aws-greengrassv2": "./aws-greengrassv2/index.js", - "./aws-groundstation": "./aws-groundstation/index.js", - "./aws-guardduty": "./aws-guardduty/index.js", - "./aws-healthlake": "./aws-healthlake/index.js", - "./aws-iam": "./aws-iam/index.js", - "./aws-imagebuilder": "./aws-imagebuilder/index.js", - "./aws-inspector": "./aws-inspector/index.js", - "./aws-iot": "./aws-iot/index.js", - "./aws-iot-actions": "./aws-iot-actions/index.js", - "./aws-iot1click": "./aws-iot1click/index.js", - "./aws-iotanalytics": "./aws-iotanalytics/index.js", - "./aws-iotcoredeviceadvisor": "./aws-iotcoredeviceadvisor/index.js", - "./aws-iotevents": "./aws-iotevents/index.js", - "./aws-iotfleethub": "./aws-iotfleethub/index.js", - "./aws-iotsitewise": "./aws-iotsitewise/index.js", - "./aws-iotthingsgraph": "./aws-iotthingsgraph/index.js", - "./aws-iotwireless": "./aws-iotwireless/index.js", - "./aws-ivs": "./aws-ivs/index.js", - "./aws-kendra": "./aws-kendra/index.js", - "./aws-kinesis": "./aws-kinesis/index.js", - "./aws-kinesisanalytics": "./aws-kinesisanalytics/index.js", - "./aws-kinesisanalytics-flink": "./aws-kinesisanalytics-flink/index.js", - "./aws-kinesisfirehose": "./aws-kinesisfirehose/index.js", - "./aws-kinesisfirehose-destinations": "./aws-kinesisfirehose-destinations/index.js", - "./aws-kms": "./aws-kms/index.js", - "./aws-lakeformation": "./aws-lakeformation/index.js", - "./aws-lambda": "./aws-lambda/index.js", - "./aws-lambda-destinations": "./aws-lambda-destinations/index.js", - "./aws-lambda-event-sources": "./aws-lambda-event-sources/index.js", - "./aws-lambda-go": "./aws-lambda-go/index.js", - "./aws-lambda-nodejs": "./aws-lambda-nodejs/index.js", - "./aws-lambda-python": "./aws-lambda-python/index.js", - "./aws-licensemanager": "./aws-licensemanager/index.js", - "./aws-lightsail": "./aws-lightsail/index.js", - "./aws-location": "./aws-location/index.js", - "./aws-logs": "./aws-logs/index.js", - "./aws-logs-destinations": "./aws-logs-destinations/index.js", - "./aws-lookoutequipment": "./aws-lookoutequipment/index.js", - "./aws-lookoutmetrics": "./aws-lookoutmetrics/index.js", - "./aws-lookoutvision": "./aws-lookoutvision/index.js", - "./aws-macie": "./aws-macie/index.js", - "./aws-managedblockchain": "./aws-managedblockchain/index.js", - "./aws-mediaconnect": "./aws-mediaconnect/index.js", - "./aws-mediaconvert": "./aws-mediaconvert/index.js", - "./aws-medialive": "./aws-medialive/index.js", - "./aws-mediapackage": "./aws-mediapackage/index.js", - "./aws-mediastore": "./aws-mediastore/index.js", - "./aws-memorydb": "./aws-memorydb/index.js", - "./aws-msk": "./aws-msk/index.js", - "./aws-mwaa": "./aws-mwaa/index.js", - "./aws-neptune": "./aws-neptune/index.js", - "./aws-networkfirewall": "./aws-networkfirewall/index.js", - "./aws-networkmanager": "./aws-networkmanager/index.js", - "./aws-nimblestudio": "./aws-nimblestudio/index.js", - "./aws-opensearchservice": "./aws-opensearchservice/index.js", - "./aws-opsworks": "./aws-opsworks/index.js", - "./aws-opsworkscm": "./aws-opsworkscm/index.js", - "./aws-panorama": "./aws-panorama/index.js", - "./aws-pinpoint": "./aws-pinpoint/index.js", - "./aws-pinpointemail": "./aws-pinpointemail/index.js", - "./aws-qldb": "./aws-qldb/index.js", - "./aws-quicksight": "./aws-quicksight/index.js", - "./aws-ram": "./aws-ram/index.js", - "./aws-rds": "./aws-rds/index.js", - "./aws-redshift": "./aws-redshift/index.js", - "./aws-rekognition": "./aws-rekognition/index.js", - "./aws-resourcegroups": "./aws-resourcegroups/index.js", - "./aws-robomaker": "./aws-robomaker/index.js", - "./aws-route53": "./aws-route53/index.js", - "./aws-route53-patterns": "./aws-route53-patterns/index.js", - "./aws-route53-targets": "./aws-route53-targets/index.js", - "./aws-route53recoverycontrol": "./aws-route53recoverycontrol/index.js", - "./aws-route53recoveryreadiness": "./aws-route53recoveryreadiness/index.js", - "./aws-route53resolver": "./aws-route53resolver/index.js", - "./aws-s3": "./aws-s3/index.js", - "./aws-s3-assets": "./aws-s3-assets/index.js", - "./aws-s3-deployment": "./aws-s3-deployment/index.js", - "./aws-s3-notifications": "./aws-s3-notifications/index.js", - "./aws-s3objectlambda": "./aws-s3objectlambda/index.js", - "./aws-s3outposts": "./aws-s3outposts/index.js", - "./aws-sagemaker": "./aws-sagemaker/index.js", - "./aws-sam": "./aws-sam/index.js", - "./aws-sdb": "./aws-sdb/index.js", - "./aws-secretsmanager": "./aws-secretsmanager/index.js", - "./aws-securityhub": "./aws-securityhub/index.js", - "./aws-servicecatalog": "./aws-servicecatalog/index.js", - "./aws-servicecatalogappregistry": "./aws-servicecatalogappregistry/index.js", - "./aws-servicediscovery": "./aws-servicediscovery/index.js", - "./aws-ses": "./aws-ses/index.js", - "./aws-ses-actions": "./aws-ses-actions/index.js", - "./aws-signer": "./aws-signer/index.js", - "./aws-sns": "./aws-sns/index.js", - "./aws-sns-subscriptions": "./aws-sns-subscriptions/index.js", - "./aws-sqs": "./aws-sqs/index.js", - "./aws-ssm": "./aws-ssm/index.js", - "./aws-ssmcontacts": "./aws-ssmcontacts/index.js", - "./aws-ssmincidents": "./aws-ssmincidents/index.js", - "./aws-sso": "./aws-sso/index.js", - "./aws-stepfunctions": "./aws-stepfunctions/index.js", - "./aws-stepfunctions-tasks": "./aws-stepfunctions-tasks/index.js", - "./aws-synthetics": "./aws-synthetics/index.js", - "./aws-timestream": "./aws-timestream/index.js", - "./aws-transfer": "./aws-transfer/index.js", - "./aws-waf": "./aws-waf/index.js", - "./aws-wafregional": "./aws-wafregional/index.js", - "./aws-wafv2": "./aws-wafv2/index.js", - "./aws-wisdom": "./aws-wisdom/index.js", - "./aws-workspaces": "./aws-workspaces/index.js", - "./aws-xray": "./aws-xray/index.js", - "./cloud-assembly-schema": "./cloud-assembly-schema/index.js", - "./cloudformation-include": "./cloudformation-include/index.js", - "./custom-resources": "./custom-resources/index.js", - "./cx-api": "./cx-api/index.js", - "./lambda-layer-awscli": "./lambda-layer-awscli/index.js", - "./lambda-layer-kubectl": "./lambda-layer-kubectl/index.js", - "./lambda-layer-node-proxy-agent": "./lambda-layer-node-proxy-agent/index.js", - "./pipelines": "./pipelines/index.js", - "./pipelines/package.json": "./pipelines/package.json", - "./pipelines/.jsii": "./pipelines/.jsii", - "./pipelines/.warnings.jsii.js": "./pipelines/.warnings.jsii.js", - "./pipelines/lib/helpers-internal": "./pipelines/lib/helpers-internal/index.js", - "./region-info": "./region-info/index.js", - "./yaml-cfn": "./yaml-cfn/index.js" } } diff --git a/tools/@aws-cdk/ubergen/bin/ubergen.ts b/tools/@aws-cdk/ubergen/bin/ubergen.ts index dfe8af6fca4e1..f12c86e353d9e 100644 --- a/tools/@aws-cdk/ubergen/bin/ubergen.ts +++ b/tools/@aws-cdk/ubergen/bin/ubergen.ts @@ -10,22 +10,23 @@ import * as fs from 'fs-extra'; // The directory where our 'package.json' lives const MONOPACKAGE_ROOT = process.cwd(); -// The directory where we're going to collect all the libraries. Currently -// purposely the same as the monopackage root so that our two import styles -// resolve to the same files. -const LIB_ROOT = MONOPACKAGE_ROOT; - const ROOT_PATH = findWorkspacePath(); const UBER_PACKAGE_JSON_PATH = path.join(MONOPACKAGE_ROOT, 'package.json'); async function main() { console.log(`🌴 workspace root path is: ${ROOT_PATH}`); - const uberPackageJson = await fs.readJson(UBER_PACKAGE_JSON_PATH); + const uberPackageJson = await fs.readJson(UBER_PACKAGE_JSON_PATH) as PackageJson; const libraries = await findLibrariesToPackage(uberPackageJson); await verifyDependencies(uberPackageJson, libraries); await prepareSourceFiles(libraries, uberPackageJson); await combineRosettaFixtures(libraries, uberPackageJson); + // if explicitExports is set to `false`, remove the "exports" section from package.json + const explicitExports = uberPackageJson.ubergen?.explicitExports ?? true; + if (!explicitExports) { + delete uberPackageJson.exports; + } + // Rewrite package.json (exports will have changed) await fs.writeJson(UBER_PACKAGE_JSON_PATH, uberPackageJson, { spaces: 2 }); } @@ -79,6 +80,21 @@ interface PackageJson { readonly ubergen?: { readonly deprecatedPackages?: readonly string[]; readonly excludeExperimentalModules?: boolean; + + /** + * The directory where we're going to collect all the libraries. + * + * @default - root of the ubergen package + */ + readonly libRoot?: string; + + /** + * Adds an `exports` section to the ubergen package.json file to ensure that + * consumers won't be able to accidentally import a private file. + * + * @default true + */ + readonly explicitExports?: boolean; }; exports?: Record; } @@ -236,9 +252,11 @@ async function prepareSourceFiles(libraries: readonly LibraryReference[], packag console.log('\t 👩🏻‍🔬 \'excludeExperimentalModules\' enabled. Regenerating all experimental modules as L1s using cfn2ts...'); } + const libRoot = resolveLibRoot(packageJson); + // Should not remove collection directory if we're currently in it. The OS would be unhappy. - if (LIB_ROOT !== process.cwd()) { - await fs.remove(LIB_ROOT); + if (libRoot !== process.cwd()) { + await fs.remove(libRoot); } // Control 'exports' field of the 'package.json'. This will control what kind of 'import' statements are @@ -257,7 +275,7 @@ async function prepareSourceFiles(libraries: readonly LibraryReference[], packag const indexStatements = new Array(); for (const library of libraries) { - const libDir = path.join(LIB_ROOT, library.shortName); + const libDir = path.join(libRoot, library.shortName); const copied = await transformPackage(library, packageJson, libDir, libraries); if (!copied) { @@ -271,7 +289,7 @@ async function prepareSourceFiles(libraries: readonly LibraryReference[], packag } } - await fs.writeFile(path.join(LIB_ROOT, 'index.ts'), indexStatements.join('\n'), { encoding: 'utf8' }); + await fs.writeFile(path.join(libRoot, 'index.ts'), indexStatements.join('\n'), { encoding: 'utf8' }); console.log('\t🍺 Success!'); } @@ -375,6 +393,19 @@ async function transformPackage( { spaces: 2 }, ); } + + // if libRoot is _not_ under the root of the package, generate a file at the + // root that will refer to the one under lib/ so that users can still import + // from "monocdk/aws-lambda". + const relativeLibRoot = uberPackageJson.ubergen?.libRoot; + if (relativeLibRoot && relativeLibRoot !== '.') { + await fs.writeFile( + path.resolve(MONOPACKAGE_ROOT, `${library.shortName}.ts`), + `export * from './${relativeLibRoot}/${library.shortName}';\n`, + { encoding: 'utf8' }, + ); + } + return true; } @@ -414,6 +445,7 @@ function transformTargets(monoConfig: PackageJson['jsii']['targets'], targets: P } async function copyOrTransformFiles(from: string, to: string, libraries: readonly LibraryReference[], uberPackageJson: PackageJson) { + const libRoot = resolveLibRoot(uberPackageJson); const promises = (await fs.readdir(from)).map(async name => { if (shouldIgnoreFile(name)) { return; } @@ -436,7 +468,7 @@ async function copyOrTransformFiles(from: string, to: string, libraries: readonl if (name.endsWith('.ts')) { return fs.writeFile( destination, - await rewriteLibraryImports(source, to, libraries), + await rewriteLibraryImports(source, to, libRoot, libraries), { encoding: 'utf8' }, ); } else if (name === 'cfn-types-2-classes.json') { @@ -483,7 +515,7 @@ async function rewriteReadmeImports(fromFile: string, libName: string): Promise< /** * Rewrites imports in libaries, using the relative path (i.e. '../../assertions'). */ -async function rewriteLibraryImports(fromFile: string, targetDir: string, libraries: readonly LibraryReference[]): Promise { +async function rewriteLibraryImports(fromFile: string, targetDir: string, libRoot: string, libraries: readonly LibraryReference[]): Promise { const source = await fs.readFile(fromFile, { encoding: 'utf8' }); return awsCdkMigration.rewriteImports(source, relativeImport); @@ -496,8 +528,8 @@ async function rewriteLibraryImports(fromFile: string, targetDir: string, librar if (sourceLibrary == null) { return undefined; } const importedFile = modulePath === sourceLibrary.packageJson.name - ? path.join(LIB_ROOT, sourceLibrary.shortName) - : path.join(LIB_ROOT, sourceLibrary.shortName, modulePath.substr(sourceLibrary.packageJson.name.length + 1)); + ? path.join(libRoot, sourceLibrary.shortName) + : path.join(libRoot, sourceLibrary.shortName, modulePath.substr(sourceLibrary.packageJson.name.length + 1)); return path.relative(targetDir, importedFile); } @@ -545,4 +577,18 @@ function sortObject(obj: Record): Record { */ function unixPath(x: string) { return x.replace(/\\/g, '/'); +} + +/** + * Resolves the directory where we're going to collect all the libraries. + * + * By default, this is purposely the same as the monopackage root so that our + * two import styles resolve to the same files but it can be overridden by + * seeting `ubergen.libRoot` in the package.json of the uber package. + * + * @param uberPackageJson package.json contents of the uber package + * @returns The directory where we should collect all the libraries. + */ +function resolveLibRoot(uberPackageJson: PackageJson): string { + return path.resolve(uberPackageJson.ubergen?.libRoot ?? MONOPACKAGE_ROOT); } \ No newline at end of file From ba6a8efc65288bd96ebf004d81026ab61485ff06 Mon Sep 17 00:00:00 2001 From: Toon Lamberigts Date: Wed, 1 Dec 2021 17:01:56 +0100 Subject: [PATCH 52/82] fix(aws-ec2): imported VPC subnets never recognized as PRIVATE_ISOLATED (#17496) fixes https://github.com/aws/aws-cdk/issues/17035 I do want to note that this does not cover all cases. For example, it could also be that there is a NAT instance used for internet routing instead of a NAT gateway. It's however near impossible to figure out if a route to an instance is a route to a NAT instance or just a random EC2 instance. Next to that, it can also be that the NAT gateway is running in a private subnet to do routing between different VPCs instead of the internet. In that case, the subnet would not match any of the current "variations" that are defined in the `aws-cdk` documentation (https://docs.aws.amazon.com/cdk/api/latest/docs/aws-ec2-readme.html). But since the types are referred to as `PRIVATE_WITH_NAT` and `PRIVATE_WITHOUT_NAT`, I assume this implementation to be sufficient. I did add an extra check on the destination CIDR block being `0.0.0.0/0` since that is what someone would commonly use if the purpose of the NAT gateway is internet routing in any case. See f.e. https://docs.aws.amazon.com/vpc/latest/userguide/route-table-options.html#route-tables-nat. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-cdk/lib/context-providers/vpcs.ts | 22 +- .../context-providers/asymmetric-vpcs.test.ts | 280 +++++++++++++++++- .../test/context-providers/vpcs.test.ts | 190 +++++++++++- 3 files changed, 469 insertions(+), 23 deletions(-) diff --git a/packages/aws-cdk/lib/context-providers/vpcs.ts b/packages/aws-cdk/lib/context-providers/vpcs.ts index 9b37eadee7aef..d8aacbc1959db 100644 --- a/packages/aws-cdk/lib/context-providers/vpcs.ts +++ b/packages/aws-cdk/lib/context-providers/vpcs.ts @@ -56,8 +56,12 @@ export class VpcNetworkContextProviderPlugin implements ContextProviderPlugin { // Now comes our job to separate these subnets out into AZs and subnet groups (Public, Private, Isolated) // We have the following attributes to go on: // - Type tag, we tag subnets with their type. In absence of this tag, we - // fall back to MapPublicIpOnLaunch => must be a Public subnet, anything - // else is considered Priate. + // determine the subnet must be Public if either: + // a) it has the property MapPublicIpOnLaunch + // b) it has a route to an Internet Gateway + // If both of the above is false but the subnet has a route to a NAT Gateway + // and the destination CIDR block is "0.0.0.0/0", we assume it to be a Private subnet. + // Anything else is considered Isolated. // - Name tag, we tag subnets with their subnet group name. In absence of this tag, // we use the type as the name. @@ -68,7 +72,8 @@ export class VpcNetworkContextProviderPlugin implements ContextProviderPlugin { let type = getTag('aws-cdk:subnet-type', subnet.Tags); if (type === undefined && subnet.MapPublicIpOnLaunch) { type = SubnetType.Public; } if (type === undefined && routeTables.hasRouteToIgw(subnet.SubnetId)) { type = SubnetType.Public; } - if (type === undefined) { type = SubnetType.Private; } + if (type === undefined && routeTables.hasRouteToNatGateway(subnet.SubnetId)) { type = SubnetType.Private; } + if (type === undefined) { type = SubnetType.Isolated; } if (!isValidSubnetType(type)) { // eslint-disable-next-line max-len @@ -154,11 +159,20 @@ class RouteTables { return (table && table.RouteTableId) || (this.mainRouteTable && this.mainRouteTable.RouteTableId); } + /** + * Whether the given subnet has a route to a NAT Gateway + */ + public hasRouteToNatGateway(subnetId: string | undefined): boolean { + const table = this.tableForSubnet(subnetId) || this.mainRouteTable; + + return !!table && !!table.Routes && table.Routes.some(route => !!route.NatGatewayId && route.DestinationCidrBlock === '0.0.0.0/0'); + } + /** * Whether the given subnet has a route to an IGW */ public hasRouteToIgw(subnetId: string | undefined): boolean { - const table = this.tableForSubnet(subnetId); + const table = this.tableForSubnet(subnetId) || this.mainRouteTable; return !!table && !!table.Routes && table.Routes.some(route => !!route.GatewayId && route.GatewayId.startsWith('igw-')); } diff --git a/packages/aws-cdk/test/context-providers/asymmetric-vpcs.test.ts b/packages/aws-cdk/test/context-providers/asymmetric-vpcs.test.ts index 6b3be787bd134..81a107ecad720 100644 --- a/packages/aws-cdk/test/context-providers/asymmetric-vpcs.test.ts +++ b/packages/aws-cdk/test/context-providers/asymmetric-vpcs.test.ts @@ -21,8 +21,42 @@ test('looks up the requested (symmetric) VPC', async () => { { SubnetId: 'sub-789012', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false, CidrBlock: '1.1.2.1/24' }, ], routeTables: [ - { Associations: [{ SubnetId: 'sub-123456' }], RouteTableId: 'rtb-123456' }, - { Associations: [{ SubnetId: 'sub-789012' }], RouteTableId: 'rtb-789012' }, + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '1.1.1.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + GatewayId: 'igw-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + { + Associations: [{ SubnetId: 'sub-789012' }], + RouteTableId: 'rtb-789012', + Routes: [ + { + DestinationCidrBlock: '1.1.2.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + NatGatewayId: 'nat-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, ], vpnGateways: [{ VpnGatewayId: 'gw-abcdef' }], @@ -115,8 +149,42 @@ test('uses the VPC main route table when a subnet has no specific association', { SubnetId: 'sub-789012', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false, CidrBlock: '1.1.2.1/24' }, ], routeTables: [ - { Associations: [{ SubnetId: 'sub-123456' }], RouteTableId: 'rtb-123456' }, - { Associations: [{ Main: true }], RouteTableId: 'rtb-789012' }, + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '1.1.1.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + GatewayId: 'igw-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + { + Associations: [{ Main: true }], + RouteTableId: 'rtb-789012', + Routes: [ + { + DestinationCidrBlock: '1.1.2.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + NatGatewayId: 'nat-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, ], vpnGateways: [{ VpnGatewayId: 'gw-abcdef' }], }); @@ -189,7 +257,7 @@ test('Recognize public subnet by route table', async () => { VpcPeeringConnectionId: 'pcx-xxxxxx', }, { - DestinationCidrBlock: '10.0.1.0/24', + DestinationCidrBlock: '1.1.1.1/24', GatewayId: 'local', Origin: 'CreateRouteTable', State: 'active', @@ -245,6 +313,142 @@ test('Recognize public subnet by route table', async () => { }); }); +test('Recognize isolated subnet by route table', async () => { + // GIVEN + mockVpcLookup({ + subnets: [ + { SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }, + ], + routeTables: [ + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '1.1.2.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + ], + }, + ], + }); + + // WHEN + const result = await new VpcNetworkContextProviderPlugin(mockSDK).getValue({ + account: '1234', + region: 'us-east-1', + filter: { foo: 'bar' }, + returnAsymmetricSubnets: true, + }); + + // THEN + expect(result).toEqual({ + availabilityZones: [], + vpcCidrBlock: '1.1.1.1/16', + isolatedSubnetIds: undefined, + isolatedSubnetNames: undefined, + isolatedSubnetRouteTableIds: undefined, + privateSubnetIds: undefined, + privateSubnetNames: undefined, + privateSubnetRouteTableIds: undefined, + publicSubnetIds: undefined, + publicSubnetNames: undefined, + publicSubnetRouteTableIds: undefined, + subnetGroups: [ + { + name: 'Isolated', + type: 'Isolated', + subnets: [ + { + subnetId: 'sub-123456', + availabilityZone: 'bermuda-triangle-1337', + routeTableId: 'rtb-123456', + cidr: undefined, + }, + ], + }, + ], + vpcId: 'vpc-1234567', + vpnGatewayId: undefined, + }); +}); + +test('Recognize private subnet by route table', async () => { + // GIVEN + mockVpcLookup({ + subnets: [ + { SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }, + ], + routeTables: [ + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '10.0.2.0/26', + Origin: 'CreateRoute', + State: 'active', + VpcPeeringConnectionId: 'pcx-xxxxxx', + }, + { + DestinationCidrBlock: '1.1.2.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + NatGatewayId: 'nat-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + ], + }); + + // WHEN + const result = await new VpcNetworkContextProviderPlugin(mockSDK).getValue({ + account: '1234', + region: 'us-east-1', + filter: { foo: 'bar' }, + returnAsymmetricSubnets: true, + }); + + // THEN + expect(result).toEqual({ + availabilityZones: [], + vpcCidrBlock: '1.1.1.1/16', + isolatedSubnetIds: undefined, + isolatedSubnetNames: undefined, + isolatedSubnetRouteTableIds: undefined, + privateSubnetIds: undefined, + privateSubnetNames: undefined, + privateSubnetRouteTableIds: undefined, + publicSubnetIds: undefined, + publicSubnetNames: undefined, + publicSubnetRouteTableIds: undefined, + subnetGroups: [ + { + name: 'Private', + type: 'Private', + subnets: [ + { + subnetId: 'sub-123456', + availabilityZone: 'bermuda-triangle-1337', + routeTableId: 'rtb-123456', + cidr: undefined, + }, + ], + }, + ], + vpcId: 'vpc-1234567', + vpnGatewayId: undefined, + }); +}); + test('works for asymmetric subnets (not spanning the same Availability Zones)', async () => { // GIVEN mockVpcLookup({ @@ -255,7 +459,30 @@ test('works for asymmetric subnets (not spanning the same Availability Zones)', { SubnetId: 'pub-sub-in-1a', AvailabilityZone: 'us-west-1a', MapPublicIpOnLaunch: true, CidrBlock: '1.1.4.1/24' }, ], routeTables: [ - { Associations: [{ Main: true }], RouteTableId: 'rtb-123' }, + { + Associations: [{ SubnetId: 'pri-sub-in-1b' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '0.0.0.0/0', + NatGatewayId: 'nat-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + { + Associations: [{ Main: true }], + RouteTableId: 'rtb-789012', + Routes: [ + { + DestinationCidrBlock: '0.0.0.0/0', + GatewayId: 'igw-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, ], }); @@ -288,7 +515,7 @@ test('works for asymmetric subnets (not spanning the same Availability Zones)', { subnetId: 'pri-sub-in-1b', availabilityZone: 'us-west-1b', - routeTableId: 'rtb-123', + routeTableId: 'rtb-123456', cidr: '1.1.1.1/24', }, ], @@ -300,19 +527,19 @@ test('works for asymmetric subnets (not spanning the same Availability Zones)', { subnetId: 'pub-sub-in-1a', availabilityZone: 'us-west-1a', - routeTableId: 'rtb-123', + routeTableId: 'rtb-789012', cidr: '1.1.4.1/24', }, { subnetId: 'pub-sub-in-1b', availabilityZone: 'us-west-1b', - routeTableId: 'rtb-123', + routeTableId: 'rtb-789012', cidr: '1.1.3.1/24', }, { subnetId: 'pub-sub-in-1c', availabilityZone: 'us-west-1c', - routeTableId: 'rtb-123', + routeTableId: 'rtb-789012', cidr: '1.1.2.1/24', }, ], @@ -361,7 +588,30 @@ test('allows specifying the subnet group name tag', async () => { }, ], routeTables: [ - { Associations: [{ Main: true }], RouteTableId: 'rtb-123' }, + { + Associations: [{ SubnetId: 'pri-sub-in-1b' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '0.0.0.0/0', + NatGatewayId: 'nat-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + { + Associations: [{ Main: true }], + RouteTableId: 'rtb-789012', + Routes: [ + { + DestinationCidrBlock: '0.0.0.0/0', + GatewayId: 'igw-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, ], }); @@ -393,7 +643,7 @@ test('allows specifying the subnet group name tag', async () => { { subnetId: 'pri-sub-in-1b', availabilityZone: 'us-west-1b', - routeTableId: 'rtb-123', + routeTableId: 'rtb-123456', cidr: undefined, }, ], @@ -405,19 +655,19 @@ test('allows specifying the subnet group name tag', async () => { { subnetId: 'pub-sub-in-1a', availabilityZone: 'us-west-1a', - routeTableId: 'rtb-123', + routeTableId: 'rtb-789012', cidr: undefined, }, { subnetId: 'pub-sub-in-1b', availabilityZone: 'us-west-1b', - routeTableId: 'rtb-123', + routeTableId: 'rtb-789012', cidr: undefined, }, { subnetId: 'pub-sub-in-1c', availabilityZone: 'us-west-1c', - routeTableId: 'rtb-123', + routeTableId: 'rtb-789012', cidr: undefined, }, ], diff --git a/packages/aws-cdk/test/context-providers/vpcs.test.ts b/packages/aws-cdk/test/context-providers/vpcs.test.ts index 27506742a9f81..e97090666d710 100644 --- a/packages/aws-cdk/test/context-providers/vpcs.test.ts +++ b/packages/aws-cdk/test/context-providers/vpcs.test.ts @@ -25,8 +25,42 @@ test('looks up the requested VPC', async () => { { SubnetId: 'sub-789012', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }, ], routeTables: [ - { Associations: [{ SubnetId: 'sub-123456' }], RouteTableId: 'rtb-123456' }, - { Associations: [{ SubnetId: 'sub-789012' }], RouteTableId: 'rtb-789012' }, + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '1.1.1.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + GatewayId: 'igw-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + { + Associations: [{ SubnetId: 'sub-789012' }], + RouteTableId: 'rtb-789012', + Routes: [ + { + DestinationCidrBlock: '1.1.2.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + NatGatewayId: 'nat-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, ], vpnGateways: [{ VpnGatewayId: 'gw-abcdef' }], @@ -105,8 +139,42 @@ test('uses the VPC main route table when a subnet has no specific association', { SubnetId: 'sub-789012', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }, ], routeTables: [ - { Associations: [{ SubnetId: 'sub-123456' }], RouteTableId: 'rtb-123456' }, - { Associations: [{ Main: true }], RouteTableId: 'rtb-789012' }, + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '1.1.1.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + GatewayId: 'igw-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + { + Associations: [{ Main: true }], + RouteTableId: 'rtb-789012', + Routes: [ + { + DestinationCidrBlock: '1.1.2.1/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + NatGatewayId: 'nat-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, ], vpnGateways: [{ VpnGatewayId: 'gw-abcdef' }], }); @@ -200,6 +268,120 @@ test('Recognize public subnet by route table', async () => { }); }); +test('Recognize private subnet by route table', async () => { + // GIVEN + const filter = { foo: 'bar' }; + const provider = new VpcNetworkContextProviderPlugin(mockSDK); + + mockVpcLookup({ + subnets: [ + { SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }, + ], + routeTables: [ + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '10.0.2.0/26', + Origin: 'CreateRoute', + State: 'active', + VpcPeeringConnectionId: 'pcx-xxxxxx', + }, + { + DestinationCidrBlock: '10.0.1.0/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + NatGatewayId: 'nat-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + ], + }); + + // WHEN + const result = await provider.getValue({ + account: '1234', + region: 'us-east-1', + filter, + }); + + // THEN + expect(result).toEqual({ + vpcId: 'vpc-1234567', + vpcCidrBlock: '1.1.1.1/16', + availabilityZones: ['bermuda-triangle-1337'], + isolatedSubnetIds: undefined, + isolatedSubnetNames: undefined, + isolatedSubnetRouteTableIds: undefined, + privateSubnetIds: ['sub-123456'], + privateSubnetNames: ['Private'], + privateSubnetRouteTableIds: ['rtb-123456'], + publicSubnetIds: undefined, + publicSubnetNames: undefined, + publicSubnetRouteTableIds: undefined, + vpnGatewayId: undefined, + subnetGroups: undefined, + }); +}); + +test('Recognize isolated subnet by route table', async () => { + // GIVEN + const filter = { foo: 'bar' }; + const provider = new VpcNetworkContextProviderPlugin(mockSDK); + + mockVpcLookup({ + subnets: [ + { SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }, + ], + routeTables: [ + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '10.0.1.0/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + ], + }, + ], + }); + + // WHEN + const result = await provider.getValue({ + account: '1234', + region: 'us-east-1', + filter, + }); + + // THEN + expect(result).toEqual({ + vpcId: 'vpc-1234567', + vpcCidrBlock: '1.1.1.1/16', + availabilityZones: ['bermuda-triangle-1337'], + isolatedSubnetIds: ['sub-123456'], + isolatedSubnetNames: ['Isolated'], + isolatedSubnetRouteTableIds: ['rtb-123456'], + privateSubnetIds: undefined, + privateSubnetNames: undefined, + privateSubnetRouteTableIds: undefined, + publicSubnetIds: undefined, + publicSubnetNames: undefined, + publicSubnetRouteTableIds: undefined, + vpnGatewayId: undefined, + subnetGroups: undefined, + }); +}); + interface VpcLookupOptions { subnets: aws.EC2.Subnet[]; routeTables: aws.EC2.RouteTable[]; From 534babde886646b6cd01f8799e3b4ed6db221263 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Wed, 1 Dec 2021 17:21:57 +0000 Subject: [PATCH 53/82] chore: transfer ownership of modules nija-at owns (#17800) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .github/workflows/issue-label-assign.yml | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index c2f5743ffb04b..3960766b73e2f 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -23,17 +23,17 @@ jobs: {"area":"package/tools","keywords":["cli","command line","init","synth","diff","bootstrap"],"labels":["package/tools"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/alexa-ask","keywords":["alexa-ask","alexa", "cfnskill"],"labels":["@aws-cdk/alexa-ask"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/app-delivery","keywords":["app-delivery","PipelineDeployStackAction"],"labels":["@aws-cdk/app-delivery"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/assert","keywords":["assert"],"labels":["@aws-cdk/assert"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/assertions","keywords":["assertions"],"labels":["@aws-cdk/assertions"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/assert","keywords":["assert"],"labels":["@aws-cdk/assert"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/assertions","keywords":["assertions"],"labels":["@aws-cdk/assertions"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/assets","keywords":["assets","staging"],"labels":["@aws-cdk/assets"],"assignees":["eladb"]}, {"area":"@aws-cdk/aws-accessanalyzer","keywords":["aws-accessanalyzer","accessanalyzer","cfnanalyzer"],"labels":["@aws-cdk/aws-accessanalyzer"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-acmpca","keywords":["aws-acmpca","acmpca","certificateauthority"],"labels":["@aws-cdk/aws-acmpca"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-amazonmq","keywords":["aws-amazonmq","amazonmq","cfnbroker"],"labels":["@aws-cdk/aws-amazonmq"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-amplify","keywords":["aws-amplify","amplify","GitHubSourceCodeProvider","CodeCommitSourceCodeProvider","GitLabSourceCodeProvider"],"labels":["@aws-cdk/aws-amplify"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-apigateway","keywords":["aws-apigateway","api-gateway"],"labels":["@aws-cdk/aws-apigateway"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/aws-apigatewayv2","keywords":["aws-apigatewayv2","api-gateway-v2","apimapping","httpapi","httproute","httpstage","httpauthorizer","httpintegration"],"labels":["@aws-cdk/aws-apigatewayv2"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/aws-apigatewayv2-authorizers","keywords":["(aws-apigatewayv2-authorizers)","(apigatewayv2-authorizers)"],"labels":["@aws-cdk/aws-apigatewayv2-authorizers"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/aws-apigatewayv2-integrations","keywords":["aws-apigatewayv2-integrations","api-gateway-v2-integrations","httpalbintegration","httpnlbintegration","httpproxyintegration","lambdaproxyintegration","httpservicediscoveryintegration","lambdawebsocketintegration"],"labels":["@aws-cdk/aws-apigatewayv2-integrations"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/aws-apigateway","keywords":["aws-apigateway","api-gateway"],"labels":["@aws-cdk/aws-apigateway"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-apigatewayv2","keywords":["aws-apigatewayv2","api-gateway-v2","apimapping","httpapi","httproute","httpstage","httpauthorizer","httpintegration"],"labels":["@aws-cdk/aws-apigatewayv2"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-apigatewayv2-authorizers","keywords":["(aws-apigatewayv2-authorizers)","(apigatewayv2-authorizers)"],"labels":["@aws-cdk/aws-apigatewayv2-authorizers"],"assignees":["otaviomacedo"]}, + {"area":"@aws-cdk/aws-apigatewayv2-integrations","keywords":["aws-apigatewayv2-integrations","api-gateway-v2-integrations","httpalbintegration","httpnlbintegration","httpproxyintegration","lambdaproxyintegration","httpservicediscoveryintegration","lambdawebsocketintegration"],"labels":["@aws-cdk/aws-apigatewayv2-integrations"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-appconfig","keywords":["aws-appconfig","app-config"],"labels":["@aws-cdk/aws-appconfig"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-appflow","keywords":["aws-appflow","appflow"],"labels":["@aws-cdk/aws-appflow"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-appintegrations","keywords":["(aws-appintegrations)","(appintegrations)"],"labels":["@aws-cdk/aws-appintegrations"],"assignees":["skinny85"]}, @@ -74,7 +74,7 @@ jobs: {"area":"@aws-cdk/aws-codestar","keywords":["aws-codestar","codestar","githubrepository"],"labels":["@aws-cdk/aws-codestar"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-codestarconnections","keywords":["aws-codestarconnections","codestar-connections"],"labels":["@aws-cdk/aws-codestarconnections"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-codestarnotifications","keywords":["aws-codestarnotifications","codestar-notifications"],"labels":["@aws-cdk/aws-codestarnotifications"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-cognito","keywords":["aws-cognito","cognito","userpool","userpoolclient","userpooldomain"],"labels":["@aws-cdk/aws-cognito"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/aws-cognito","keywords":["aws-cognito","cognito","userpool","userpoolclient","userpooldomain"],"labels":["@aws-cdk/aws-cognito"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-config","keywords":["aws-config","accesskeysrotated","CloudFormationStackDriftDetectionCheck","CloudFormationStackNotificationCheck","managedrule"],"labels":["@aws-cdk/aws-config"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-customerprofiles","keywords":["(aws-customerprofiles)","(customerprofiles)"],"labels":["@aws-cdk/aws-customerprofiles"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-databrew","keywords":["(aws-databrew)","(databrew)"],"labels":["@aws-cdk/aws-databrew"],"assignees":["kaizen3031593"]}, @@ -82,7 +82,7 @@ jobs: {"area":"@aws-cdk/aws-datasync","keywords":["(aws-datasync)","(datasync)"],"labels":["@aws-cdk/aws-datasync"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-dax","keywords":["aws-dax","dax"],"labels":["@aws-cdk/aws-dax"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-detective","keywords":["aws-detective","detective"],"labels":["@aws-cdk/aws-detective"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-devopsguru","keywords":["(aws-devopsguru)","(devopsguru)"],"labels":["@aws-cdk/aws-devopsguru"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/aws-devopsguru","keywords":["(aws-devopsguru)","(devopsguru)"],"labels":["@aws-cdk/aws-devopsguru"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-directoryservice","keywords":["aws-directoryservice","directory-service"],"labels":["@aws-cdk/aws-directoryservice"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-dlm","keywords":["aws-dlm","dlm"],"labels":["@aws-cdk/aws-dlm"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-dms","keywords":["aws-dms","dms"],"labels":["@aws-cdk/aws-dms"],"assignees":["njlynch"]}, @@ -94,7 +94,7 @@ jobs: {"area":"@aws-cdk/aws-ecr-assets","keywords":["aws-ecr-assets","ecrassets"],"labels":["@aws-cdk/aws-ecr-assets"],"assignees":["eladb"]}, {"area":"@aws-cdk/aws-ecs","keywords":["(aws-ecs)","(ecs)"],"labels":["@aws-cdk/aws-ecs"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-ecs-patterns","keywords":["(aws-ecs-patterns)","(ecs-patterns)"],"labels":["@aws-cdk/aws-ecs-patterns"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-efs","keywords":["aws-efs","efs","accesspoint"],"labels":["@aws-cdk/aws-efs"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/aws-efs","keywords":["aws-efs","efs","accesspoint"],"labels":["@aws-cdk/aws-efs"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-eks","keywords":["aws-eks","eks","fargateprofile","fargatecluster"],"labels":["@aws-cdk/aws-eks"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-eks-legacy","keywords":["(aws-eks-legacy)","(eks-legacy)"],"labels":["@aws-cdk/aws-eks-legacy"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-elasticache","keywords":["aws-elasticache","elastic-cache"],"labels":["@aws-cdk/aws-elasticache"],"assignees":["otaviomacedo"]}, @@ -142,12 +142,12 @@ jobs: {"area":"@aws-cdk/aws-kinesisfirehose","keywords":["aws-kinesisfirehose","kinesisfirehose"],"labels":["@aws-cdk/aws-kinesisfirehose"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-kms","keywords":["key-management-service","aws-kms","kms"],"labels":["@aws-cdk/aws-kms"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-lakeformation","keywords":["data-lake","aws-lakeformation","lakeformation"],"labels":["@aws-cdk/aws-lakeformation"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-lambda","keywords":["function","layerversion","aws-lambda","lambda"],"labels":["@aws-cdk/aws-lambda"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/aws-lambda-destinations","keywords":["(aws-lambda-destinations)","(lambda-destinations)"],"labels":["@aws-cdk/aws-lambda-destinations"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/aws-lambda-event-sources","keywords":["dynamoeventsource","aws-lambda-event-sources","lambda-event-sources","apieventsource","kinesiseventsource"],"labels":["@aws-cdk/aws-lambda-event-sources"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/aws-lambda-go","keywords":["(aws-lambda-go)","(lambda-go)"],"labels":["@aws-cdk/aws-lambda-go"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/aws-lambda-nodejs","keywords":["nodejsfunction","aws-lambda-nodejs","lambda-nodejs"],"labels":["@aws-cdk/aws-lambda-nodejs"],"assignees":["nija-at"]}, - {"area":"@aws-cdk/aws-lambda-python","keywords":["aws-lambda-python","lambda-python","pythonfunction"],"labels":["@aws-cdk/aws-lambda-python"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/aws-lambda","keywords":["function","layerversion","aws-lambda","lambda"],"labels":["@aws-cdk/aws-lambda"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-lambda-destinations","keywords":["(aws-lambda-destinations)","(lambda-destinations)"],"labels":["@aws-cdk/aws-lambda-destinations"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-lambda-event-sources","keywords":["dynamoeventsource","aws-lambda-event-sources","lambda-event-sources","apieventsource","kinesiseventsource"],"labels":["@aws-cdk/aws-lambda-event-sources"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-lambda-go","keywords":["(aws-lambda-go)","(lambda-go)"],"labels":["@aws-cdk/aws-lambda-go"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/aws-lambda-nodejs","keywords":["nodejsfunction","aws-lambda-nodejs","lambda-nodejs"],"labels":["@aws-cdk/aws-lambda-nodejs"],"assignees":["corymhall"]}, + {"area":"@aws-cdk/aws-lambda-python","keywords":["aws-lambda-python","lambda-python","pythonfunction"],"labels":["@aws-cdk/aws-lambda-python"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-licensemanager","keywords":["(aws-licensemanager)","(licensemanager)"],"labels":["@aws-cdk/aws-licensemanager"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-logs","keywords":["loggroup","aws-logs","logs","logretention"],"labels":["@aws-cdk/aws-logs"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-logs-destinations","keywords":["aws-logs-destinations","lambdadestination","kinesisdestination","logs-destinations"],"labels":["@aws-cdk/aws-logs-destinations"],"assignees":["rix0rrr"]}, @@ -187,7 +187,7 @@ jobs: {"area":"@aws-cdk/aws-s3-assets","keywords":["aws-s3-assets","s3-assets"],"labels":["@aws-cdk/aws-s3-assets"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-s3-deployment","keywords":["aws-s3-deployment","s3-deployment"],"labels":["@aws-cdk/aws-s3-deployment"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-s3-notifications","keywords":["aws-s3-notifications","s3-notifications"],"labels":["@aws-cdk/aws-s3-notifications"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-s3objectlambda","keywords":["(aws-s3objectlambda)","(s3objectlambda)"],"labels":["@aws-cdk/aws-s3objectlambda"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/aws-s3objectlambda","keywords":["(aws-s3objectlambda)","(s3objectlambda)"],"labels":["@aws-cdk/aws-s3objectlambda"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-s3outposts","keywords":["(aws-s3outposts)","(s3outposts)"],"labels":["@aws-cdk/aws-s3outposts"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-sagemaker","keywords":["aws-sagemaker","sagemaker"],"labels":["@aws-cdk/aws-sagemaker"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-sam","keywords":["serverless-application-model","aws-sam","sam"],"labels":["@aws-cdk/aws-sam"],"assignees":["njlynch"]}, @@ -199,7 +199,7 @@ jobs: {"area":"@aws-cdk/aws-servicediscovery","keywords":["aws-servicediscovery","service-discovery"],"labels":["@aws-cdk/aws-servicediscovery"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-ses","keywords":["recipet-filter","reciept-rule","aws-ses","ses"],"labels":["@aws-cdk/aws-ses"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-ses-actions","keywords":["aws-ses-actions","ses-actions"],"labels":["@aws-cdk/aws-ses-actions"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-signer","keywords":["aws-signer","signer"],"labels":["@aws-cdk/aws-signer"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/aws-signer","keywords":["aws-signer","signer"],"labels":["@aws-cdk/aws-signer"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-sns","keywords":["simple-notification-service","aws-sns","sns","topic"],"labels":["@aws-cdk/aws-sns"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-sns-subscriptions","keywords":["aws-sns-subscriptions","sns-subscriptions","subscription"],"labels":["@aws-cdk/aws-sns-subscriptions"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-sqs","keywords":["queue","simple-queue-service","aws-sqs","sqs","fifo"],"labels":["@aws-cdk/aws-sqs"],"assignees":["njlynch"]}, @@ -214,7 +214,7 @@ jobs: {"area":"@aws-cdk/aws-wafregional","keywords":["wafregional","cfnwebacl"],"labels":["@aws-cdk/aws-wafregional"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-wafv2","keywords":["wafv2","aws-wafv2"],"labels":["@aws-cdk/aws-wafv2"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-workspaces","keywords":["aws-workspaces","workspaces"],"labels":["@aws-cdk/aws-workspaces"],"assignees":["madeline-k"]}, - {"area":"@aws-cdk/aws-xray","keywords":["(aws-xray)","(xray)"],"labels":["@aws-cdk/aws-xray"],"assignees":["nija-at"]}, + {"area":"@aws-cdk/aws-xray","keywords":["(aws-xray)","(xray)"],"labels":["@aws-cdk/aws-xray"],"assignees":["corymhall"]}, {"area":"@aws-cdk/cfnspec","keywords":["cfn-spec"],"labels":["@aws-cdk/cfnspec"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/cloud-assembly-schema","keywords":["cloud-assembly-schema","manifest"],"labels":["@aws-cdk/cloud-assembly-schema"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/cloudformation-diff","keywords":["cloudformation-diff","cfn-diff"],"labels":["@aws-cdk/cloudformation-diff"],"assignees":["skinny85"]}, @@ -226,8 +226,8 @@ jobs: {"area":"@aws-cdk/aws-lambda-layer-kubectl","keywords":["(aws-lambda-layer-kubectl)","(lambda-layer-kubectl)"],"labels":["@aws-cdk/aws-lambda-layer-kubectl"],"assignees":["eladb"]}, {"area":"@aws-cdk/pipelines","keywords":["pipelines","cdk-pipelines","sourceaction","synthaction"],"labels":["@aws-cdk/pipelines"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/region-info","keywords":["region-info","fact"],"labels":["@aws-cdk/region-info"],"assignees":["skinny85"]}, - {"area":"aws-cdk-lib","keywords":["aws-cdk-lib","cdk-v2","v2","ubergen"],"labels":["aws-cdk-lib"],"assignees":["nija-at"]}, - {"area":"monocdk","keywords":["monocdk","monocdk-experiment"],"labels":["monocdk"],"assignees":["nija-at"]}, + {"area":"aws-cdk-lib","keywords":["aws-cdk-lib","cdk-v2","v2","ubergen"],"labels":["aws-cdk-lib"],"assignees":["njlynch"]}, + {"area":"monocdk","keywords":["monocdk","monocdk-experiment"],"labels":["monocdk"],"assignees":["njlynch"]}, {"area":"@aws-cdk/yaml-cfn","keywords":["(aws-yaml-cfn)","(yaml-cfn)"],"labels":["@aws-cdk/aws-yaml-cfn"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-apprunner","keywords":["apprunner","aws-apprunner"],"labels":["@aws-cdk/aws-apprunner"],"assignees":["corymhall"]}, {"area":"@aws-cdk/aws-lightsail","keywords":["lightsail","aws-lightsail"],"labels":["@aws-cdk/aws-lightsail"],"assignees":["corymhall"]}, From 12fcb18212c8d9e74f5292b07f42ce24cd7b02b3 Mon Sep 17 00:00:00 2001 From: hanukoon Date: Thu, 2 Dec 2021 07:37:11 +0900 Subject: [PATCH 54/82] feat(backup): enable WindowsVss Backup (#15934) Closes #14803. Reference Pull Request : #14891 Lets you set the 'WindowsVss' option when you create a new backup plan like this: ```ts const plan = new BackupPlan(stack, 'Plan', { windowsVss: true, }); ``` ---- *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-backup/README.md | 11 +++++++ packages/@aws-cdk/aws-backup/lib/plan.ts | 22 ++++++++++++++ .../@aws-cdk/aws-backup/test/plan.test.ts | 30 +++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/packages/@aws-cdk/aws-backup/README.md b/packages/@aws-cdk/aws-backup/README.md index b59d5307f9d67..6c7f50d4ad73f 100644 --- a/packages/@aws-cdk/aws-backup/README.md +++ b/packages/@aws-cdk/aws-backup/README.md @@ -82,6 +82,17 @@ const plan = backup.BackupPlan.daily35DayRetention(this, 'Plan', myVault); // Us plan.addRule(backup.BackupPlanRule.monthly1Year(otherVault)); // Use `otherVault` for this specific rule ``` +You can [backup](https://docs.aws.amazon.com/aws-backup/latest/devguide/windows-backups.html) +VSS-enabled Windows applications running on Amazon EC2 instances by setting the `windowsVss` +parameter to `true`. If the application has VSS writer registered with Windows VSS, +then AWS Backup creates a snapshot that will be consistent for that application. + +```ts +const plan = new backup.BackupPlan(this, 'Plan', { + windowsVss: true, +}); +``` + ## Backup vault In AWS Backup, a *backup vault* is a container that you organize your backups in. You can use backup diff --git a/packages/@aws-cdk/aws-backup/lib/plan.ts b/packages/@aws-cdk/aws-backup/lib/plan.ts index 70240e778969b..0257ae39c5fe2 100644 --- a/packages/@aws-cdk/aws-backup/lib/plan.ts +++ b/packages/@aws-cdk/aws-backup/lib/plan.ts @@ -43,6 +43,15 @@ export interface BackupPlanProps { * @default - use `addRule()` to add rules */ readonly backupPlanRules?: BackupPlanRule[]; + + /** + * Enable Windows VSS backup. + * + * @see https://docs.aws.amazon.com/aws-backup/latest/devguide/windows-backups.html + * + * @default false + */ + readonly windowsVss?: boolean; } /** @@ -124,6 +133,7 @@ export class BackupPlan extends Resource implements IBackupPlan { const plan = new CfnBackupPlan(this, 'Resource', { backupPlan: { + advancedBackupSettings: this.advancedBackupSettings(props), backupPlanName: props.backupPlanName || id, backupPlanRule: Lazy.any({ produce: () => this.rules }, { omitEmptyArray: true }), }, @@ -140,6 +150,18 @@ export class BackupPlan extends Resource implements IBackupPlan { } } + private advancedBackupSettings(props: BackupPlanProps) { + if (!props.windowsVss) { + return undefined; + } + return [{ + backupOptions: { + WindowsVSS: 'enabled', + }, + resourceType: 'EC2', + }]; + } + /** * Adds a rule to a plan * diff --git a/packages/@aws-cdk/aws-backup/test/plan.test.ts b/packages/@aws-cdk/aws-backup/test/plan.test.ts index 401e961129838..365b66bd384c3 100644 --- a/packages/@aws-cdk/aws-backup/test/plan.test.ts +++ b/packages/@aws-cdk/aws-backup/test/plan.test.ts @@ -70,6 +70,36 @@ test('create a plan and add rules', () => { }); }); +test('create a plan and add rules - add BackupPlan.AdvancedBackupSettings.BackupOptions', () => { + const vault = new BackupVault(stack, 'Vault'); + const otherVault = new BackupVault(stack, 'OtherVault'); + + // WHEN + const plan = new BackupPlan(stack, 'Plan', { + windowsVss: true, + backupVault: vault, + backupPlanRules: [ + new BackupPlanRule({ + completionWindow: Duration.hours(2), + startWindow: Duration.hours(1), + scheduleExpression: events.Schedule.cron({ + day: '15', + hour: '3', + minute: '30', + }), + moveToColdStorageAfter: Duration.days(30), + }), + ], + }); + plan.addRule(BackupPlanRule.monthly5Year(otherVault)); + + Template.fromStack(stack).hasResourceProperties('AWS::Backup::BackupPlan', { + BackupPlan: { + AdvancedBackupSettings: [{ BackupOptions: { WindowsVSS: 'enabled' }, ResourceType: 'EC2' }], + }, + }); +}); + test('daily35DayRetention', () => { // WHEN BackupPlan.daily35DayRetention(stack, 'D35'); From b284ebae0117960dfc9ad10ea0b6c51f81443b69 Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Thu, 2 Dec 2021 10:55:33 +0000 Subject: [PATCH 55/82] =?UTF-8?q?chore:=20Revert=20"feat(apigatewayv2):=20?= =?UTF-8?q?constructs=20for=20http=20api=20are=20now=20stable!=20?= =?UTF-8?q?=F0=9F=A4=98(#17773)"=20(#17809)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b25590ff15d92a8a6ddc1f3a37263f90793b15f4. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-apigatewayv2-authorizers/README.md | 22 ++++++------------- .../aws-apigatewayv2-authorizers/package.json | 10 --------- .../aws-apigatewayv2-integrations/README.md | 20 +++++------------ .../package.json | 10 --------- packages/@aws-cdk/aws-apigatewayv2/README.md | 7 +----- .../@aws-cdk/aws-apigatewayv2/package.json | 2 +- 6 files changed, 15 insertions(+), 56 deletions(-) diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md index c923a19e241a1..d1aebb7477b82 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/README.md @@ -1,29 +1,21 @@ # AWS APIGatewayv2 Authorizers + --- -Features | Stability ---------------------------------------|------------------------------------------------------------- -Authorizer classes for HTTP APIs | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) -Authorizer classes for Websocket APIs | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) - -> **Experimental:** Higher level constructs in this module that are marked as experimental are -> under active development. They are subject to non-backward compatible changes or removal in any -> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and -> breaking changes will be announced in the release notes. This means that while you may use them, -> you may need to update your source code when upgrading to a newer version of this package. +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) - - -> **Stable:** Higher level constructs in this module that are marked stable will not undergo any -> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model. +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. --- - ## Table of Contents - [Introduction](#introduction) diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index da4730ef59258..e4dae38af4135 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -109,16 +109,6 @@ }, "stability": "experimental", "maturity": "experimental", - "features": [ - { - "name": "Authorizer classes for HTTP APIs", - "stability": "Stable" - }, - { - "name": "Authorizer classes for Websocket APIs", - "stability": "Experimental" - } - ], "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md b/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md index 8dd9164eae6bc..07c2d3310cc5b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/README.md @@ -3,21 +3,13 @@ --- -Features | Stability ----------------------------------------|------------------------------------------------------------ -Integration classes for HTTP APIs | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) -Integration classes for Websocket APIs | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) -> **Experimental:** Higher level constructs in this module that are marked as experimental are -> under active development. They are subject to non-backward compatible changes or removal in any -> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and -> breaking changes will be announced in the release notes. This means that while you may use them, -> you may need to update your source code when upgrading to a newer version of this package. - - - -> **Stable:** Higher level constructs in this module that are marked stable will not undergo any -> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model. +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. --- diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index c066a2e71989c..87b5a43c1f9cb 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -108,16 +108,6 @@ }, "stability": "experimental", "maturity": "experimental", - "features": [ - { - "name": "Integration classes for HTTP APIs", - "stability": "Stable" - }, - { - "name": "Integration classes for Websocket APIs", - "stability": "Experimental" - } - ], "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-apigatewayv2/README.md b/packages/@aws-cdk/aws-apigatewayv2/README.md index d00adb1b27f73..6c0697287c08d 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2/README.md @@ -6,7 +6,7 @@ Features | Stability -------------------------------------------|-------------------------------------------------------- CFN Resources | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) -Higher level constructs for HTTP APIs | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge) +Higher level constructs for HTTP APIs | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) Higher level constructs for Websocket APIs | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge) > **CFN Resources:** All classes with the `Cfn` prefix in this module ([CFN Resources]) are always @@ -22,11 +22,6 @@ Higher level constructs for Websocket APIs | ![Experimental](https://img.shields > breaking changes will be announced in the release notes. This means that while you may use them, > you may need to update your source code when upgrading to a newer version of this package. - - -> **Stable:** Higher level constructs in this module that are marked stable will not undergo any -> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model. - --- diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index cdf67e92d7760..6e12d9613fa27 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -124,7 +124,7 @@ "features": [ { "name": "Higher level constructs for HTTP APIs", - "stability": "Stable" + "stability": "Experimental" }, { "name": "Higher level constructs for Websocket APIs", From 9a67ce7a1792a111e7668cbc7b7f0799314bd7d6 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Thu, 2 Dec 2021 14:17:33 +0000 Subject: [PATCH 56/82] feat(assertions): major improvements to the capture feature (#17713) There are three major changes around the capture feature of assertions. Firstly, when there are multiple targets (say, Resource in the CloudFormation template) that matches the given condition, any `Capture` defined in the condition will contain only the last matched resource. Convert the `Capture` class into an iterable so all matching values can be retrieved. Secondly, add support to allow sub-patterns to be specified to the `Capture` class. This allows further conditions be specified, via Matchers or literals, when a value is to be captured. Finally, this fixes a bug with the current implementation where `Capture` contains the results of the last matched section, irrespective of whether that section matched with the rest of the matcher or not. fixes #17009 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/assertions/README.md | 64 +++++++++++++ packages/@aws-cdk/assertions/lib/capture.ts | 85 ++++++++++++----- packages/@aws-cdk/assertions/lib/match.ts | 72 +++++++++++--- packages/@aws-cdk/assertions/lib/matcher.ts | 95 ++++++++++++++++--- .../assertions/lib/private/matchers/absent.ts | 6 +- .../assertions/lib/private/section.ts | 1 + .../@aws-cdk/assertions/test/capture.test.ts | 80 +++++++++++++--- .../@aws-cdk/assertions/test/template.test.ts | 29 +++++- .../pipelines/test/compliance/assets.test.ts | 9 +- 9 files changed, 372 insertions(+), 69 deletions(-) diff --git a/packages/@aws-cdk/assertions/README.md b/packages/@aws-cdk/assertions/README.md index 158397d1e4af1..55b8d3520d550 100644 --- a/packages/@aws-cdk/assertions/README.md +++ b/packages/@aws-cdk/assertions/README.md @@ -399,3 +399,67 @@ template.hasResourceProperties('Foo::Bar', { fredCapture.asArray(); // returns ["Flob", "Cat"] waldoCapture.asString(); // returns "Qux" ``` + +With captures, a nested pattern can also be specified, so that only targets +that match the nested pattern will be captured. This pattern can be literals or +further Matchers. + +```ts +// Given a template - +// { +// "Resources": { +// "MyBar1": { +// "Type": "Foo::Bar", +// "Properties": { +// "Fred": ["Flob", "Cat"], +// } +// } +// "MyBar2": { +// "Type": "Foo::Bar", +// "Properties": { +// "Fred": ["Qix", "Qux"], +// } +// } +// } +// } + +const capture = new Capture(Match.arrayWith(['Cat'])); +template.hasResourceProperties('Foo::Bar', { + Fred: capture, +}); + +capture.asArray(); // returns ['Flob', 'Cat'] +``` + +When multiple resources match the given condition, each `Capture` defined in +the condition will capture all matching values. They can be paged through using +the `next()` API. The following example illustrates this - + +```ts +// Given a template - +// { +// "Resources": { +// "MyBar": { +// "Type": "Foo::Bar", +// "Properties": { +// "Fred": "Flob", +// } +// }, +// "MyBaz": { +// "Type": "Foo::Bar", +// "Properties": { +// "Fred": "Quib", +// } +// } +// } +// } + +const fredCapture = new Capture(); +template.hasResourceProperties('Foo::Bar', { + Fred: fredCapture, +}); + +fredCapture.asString(); // returns "Flob" +fredCapture.next(); // returns true +fredCapture.asString(); // returns "Quib" +``` diff --git a/packages/@aws-cdk/assertions/lib/capture.ts b/packages/@aws-cdk/assertions/lib/capture.ts index c639dec79583f..c91997998330c 100644 --- a/packages/@aws-cdk/assertions/lib/capture.ts +++ b/packages/@aws-cdk/assertions/lib/capture.ts @@ -1,3 +1,4 @@ +import { Match } from '.'; import { Matcher, MatchResult } from './matcher'; import { Type, getType } from './private/type'; @@ -8,31 +9,63 @@ import { Type, getType } from './private/type'; */ export class Capture extends Matcher { public readonly name: string; - private value: any = null; + /** @internal */ + public _captured: any[] = []; + private idx = 0; - constructor() { + /** + * Initialize a new capture + * @param pattern a nested pattern or Matcher. + * If a nested pattern is provided `objectLike()` matching is applied. + */ + constructor(private readonly pattern?: any) { super(); this.name = 'Capture'; } public test(actual: any): MatchResult { - this.value = actual; - const result = new MatchResult(actual); if (actual == null) { - result.push(this, [], `Can only capture non-nullish values. Found ${actual}`); + return result.recordFailure({ + matcher: this, + path: [], + message: `Can only capture non-nullish values. Found ${actual}`, + }); } + + if (this.pattern !== undefined) { + const innerMatcher = Matcher.isMatcher(this.pattern) ? this.pattern : Match.objectLike(this.pattern); + const innerResult = innerMatcher.test(actual); + if (innerResult.hasFailed()) { + return innerResult; + } + } + + result.recordCapture({ capture: this, value: actual }); return result; } + /** + * When multiple results are captured, move the iterator to the next result. + * @returns true if another capture is present, false otherwise + */ + public next(): boolean { + if (this.idx < this._captured.length - 1) { + this.idx++; + return true; + } + return false; + } + /** * Retrieve the captured value as a string. * An error is generated if no value is captured or if the value is not a string. */ public asString(): string { - this.checkNotNull(); - if (getType(this.value) === 'string') { - return this.value; + this.validate(); + const val = this._captured[this.idx]; + if (getType(val) === 'string') { + return val; } this.reportIncorrectType('string'); } @@ -42,9 +75,10 @@ export class Capture extends Matcher { * An error is generated if no value is captured or if the value is not a number. */ public asNumber(): number { - this.checkNotNull(); - if (getType(this.value) === 'number') { - return this.value; + this.validate(); + const val = this._captured[this.idx]; + if (getType(val) === 'number') { + return val; } this.reportIncorrectType('number'); } @@ -54,9 +88,10 @@ export class Capture extends Matcher { * An error is generated if no value is captured or if the value is not a boolean. */ public asBoolean(): boolean { - this.checkNotNull(); - if (getType(this.value) === 'boolean') { - return this.value; + this.validate(); + const val = this._captured[this.idx]; + if (getType(val) === 'boolean') { + return val; } this.reportIncorrectType('boolean'); } @@ -66,9 +101,10 @@ export class Capture extends Matcher { * An error is generated if no value is captured or if the value is not an array. */ public asArray(): any[] { - this.checkNotNull(); - if (getType(this.value) === 'array') { - return this.value; + this.validate(); + const val = this._captured[this.idx]; + if (getType(val) === 'array') { + return val; } this.reportIncorrectType('array'); } @@ -78,21 +114,22 @@ export class Capture extends Matcher { * An error is generated if no value is captured or if the value is not an object. */ public asObject(): { [key: string]: any } { - this.checkNotNull(); - if (getType(this.value) === 'object') { - return this.value; + this.validate(); + const val = this._captured[this.idx]; + if (getType(val) === 'object') { + return val; } this.reportIncorrectType('object'); } - private checkNotNull(): void { - if (this.value == null) { + private validate(): void { + if (this._captured.length === 0) { throw new Error('No value captured'); } } private reportIncorrectType(expected: Type): never { - throw new Error(`Captured value is expected to be ${expected} but found ${getType(this.value)}. ` + - `Value is ${JSON.stringify(this.value, undefined, 2)}`); + throw new Error(`Captured value is expected to be ${expected} but found ${getType(this._captured[this.idx])}. ` + + `Value is ${JSON.stringify(this._captured[this.idx], undefined, 2)}`); } } \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/match.ts b/packages/@aws-cdk/assertions/lib/match.ts index 70ad96dbee300..e3afa681e6541 100644 --- a/packages/@aws-cdk/assertions/lib/match.ts +++ b/packages/@aws-cdk/assertions/lib/match.ts @@ -124,12 +124,20 @@ class LiteralMatch extends Matcher { const result = new MatchResult(actual); if (typeof this.pattern !== typeof actual) { - result.push(this, [], `Expected type ${typeof this.pattern} but received ${getType(actual)}`); + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}`, + }); return result; } if (actual !== this.pattern) { - result.push(this, [], `Expected ${this.pattern} but received ${actual}`); + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}`, + }); } return result; @@ -166,10 +174,18 @@ class ArrayMatch extends Matcher { public test(actual: any): MatchResult { if (!Array.isArray(actual)) { - return new MatchResult(actual).push(this, [], `Expected type array but received ${getType(actual)}`); + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}`, + }); } if (!this.subsequence && this.pattern.length !== actual.length) { - return new MatchResult(actual).push(this, [], `Expected array of length ${this.pattern.length} but received ${actual.length}`); + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected array of length ${this.pattern.length} but received ${actual.length}`, + }); } let patternIdx = 0; @@ -200,7 +216,11 @@ class ArrayMatch extends Matcher { for (; patternIdx < this.pattern.length; patternIdx++) { const pattern = this.pattern[patternIdx]; const element = (Matcher.isMatcher(pattern) || typeof pattern === 'object') ? ' ' : ` [${pattern}] `; - result.push(this, [], `Missing element${element}at pattern index ${patternIdx}`); + result.recordFailure({ + matcher: this, + path: [], + message: `Missing element${element}at pattern index ${patternIdx}`, + }); } return result; @@ -236,21 +256,33 @@ class ObjectMatch extends Matcher { public test(actual: any): MatchResult { if (typeof actual !== 'object' || Array.isArray(actual)) { - return new MatchResult(actual).push(this, [], `Expected type object but received ${getType(actual)}`); + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}`, + }); } const result = new MatchResult(actual); if (!this.partial) { for (const a of Object.keys(actual)) { if (!(a in this.pattern)) { - result.push(this, [`/${a}`], 'Unexpected key'); + result.recordFailure({ + matcher: this, + path: [`/${a}`], + message: 'Unexpected key', + }); } } } for (const [patternKey, patternVal] of Object.entries(this.pattern)) { if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { - result.push(this, [`/${patternKey}`], 'Missing key'); + result.recordFailure({ + matcher: this, + path: [`/${patternKey}`], + message: 'Missing key', + }); continue; } const matcher = Matcher.isMatcher(patternVal) ? @@ -275,7 +307,11 @@ class SerializedJson extends Matcher { public test(actual: any): MatchResult { const result = new MatchResult(actual); if (getType(actual) !== 'string') { - result.push(this, [], `Expected JSON as a string but found ${getType(actual)}`); + result.recordFailure({ + matcher: this, + path: [], + message: `Expected JSON as a string but found ${getType(actual)}`, + }); return result; } let parsed; @@ -283,7 +319,11 @@ class SerializedJson extends Matcher { parsed = JSON.parse(actual); } catch (err) { if (err instanceof SyntaxError) { - result.push(this, [], `Invalid JSON string: ${actual}`); + result.recordFailure({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}`, + }); return result; } else { throw err; @@ -311,7 +351,11 @@ class NotMatch extends Matcher { const innerResult = matcher.test(actual); const result = new MatchResult(actual); if (innerResult.failCount === 0) { - result.push(this, [], `Found unexpected match: ${JSON.stringify(actual, undefined, 2)}`); + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, undefined, 2)}`, + }); } return result; } @@ -325,7 +369,11 @@ class AnyMatch extends Matcher { public test(actual: any): MatchResult { const result = new MatchResult(actual); if (actual == null) { - result.push(this, [], 'Expected a value but found none'); + result.recordFailure({ + matcher: this, + path: [], + message: 'Expected a value but found none', + }); } return result; } diff --git a/packages/@aws-cdk/assertions/lib/matcher.ts b/packages/@aws-cdk/assertions/lib/matcher.ts index fdf8954a90b93..4ddf9320b492a 100644 --- a/packages/@aws-cdk/assertions/lib/matcher.ts +++ b/packages/@aws-cdk/assertions/lib/matcher.ts @@ -1,3 +1,5 @@ +import { Capture } from './capture'; + /** * Represents a matcher that can perform special data matching * capabilities between a given pattern and a target. @@ -25,6 +27,43 @@ export abstract class Matcher { public abstract test(actual: any): MatchResult; } +/** + * Match failure details + */ +export interface MatchFailure { + /** + * The matcher that had the failure + */ + readonly matcher: Matcher; + + /** + * The relative path in the target where the failure occurred. + * If the failure occurred at root of the match tree, set the path to an empty list. + * If it occurs in the 5th index of an array nested within the 'foo' key of an object, + * set the path as `['/foo', '[5]']`. + */ + readonly path: string[]; + + /** + * Failure message + */ + readonly message: string; +} + +/** + * Information about a value captured during match + */ +export interface MatchCapture { + /** + * The instance of Capture class to which this capture is associated with. + */ + readonly capture: Capture; + /** + * The value that was captured + */ + readonly value: any; +} + /** * The result of `Match.test()`. */ @@ -34,21 +73,26 @@ export class MatchResult { */ public readonly target: any; private readonly failures: MatchFailure[] = []; + private readonly captures: Map = new Map(); + private finalized: boolean = false; constructor(target: any) { this.target = target; } /** - * Push a new failure into this result at a specific path. - * If the failure occurred at root of the match tree, set the path to an empty list. - * If it occurs in the 5th index of an array nested within the 'foo' key of an object, - * set the path as `['/foo', '[5]']`. - * @param path the path at which the failure occurred. - * @param message the failure + * DEPRECATED + * @deprecated use recordFailure() */ public push(matcher: Matcher, path: string[], message: string): this { - this.failures.push({ matcher, path, message }); + return this.recordFailure({ matcher, path, message }); + } + + /** + * Record a new failure into this result at a specific path. + */ + public recordFailure(failure: MatchFailure): this { + this.failures.push(failure); return this; } @@ -67,10 +111,29 @@ export class MatchResult { * @param id the id of the parent tree. */ public compose(id: string, inner: MatchResult): this { - const innerF = (inner as any).failures as MatchFailure[]; + const innerF = inner.failures; this.failures.push(...innerF.map(f => { return { path: [id, ...f.path], message: f.message, matcher: f.matcher }; })); + inner.captures.forEach((vals, capture) => { + vals.forEach(value => this.recordCapture({ capture, value })); + }); + return this; + } + + /** + * Prepare the result to be analyzed. + * This API *must* be called prior to analyzing these results. + */ + public finalize(): this { + if (this.finalized) { + return this; + } + + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; return this; } @@ -83,10 +146,16 @@ export class MatchResult { return '' + r.message + loc + ` (using ${r.matcher.name} matcher)`; }); } -} -type MatchFailure = { - matcher: Matcher; - path: string[]; - message: string; + /** + * Record a capture against in this match result. + */ + public recordCapture(options: MatchCapture): void { + let values = this.captures.get(options.capture); + if (values === undefined) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } } \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/private/matchers/absent.ts b/packages/@aws-cdk/assertions/lib/private/matchers/absent.ts index 0681f8ada8214..5da57bcc884fc 100644 --- a/packages/@aws-cdk/assertions/lib/private/matchers/absent.ts +++ b/packages/@aws-cdk/assertions/lib/private/matchers/absent.ts @@ -8,7 +8,11 @@ export class AbsentMatch extends Matcher { public test(actual: any): MatchResult { const result = new MatchResult(actual); if (actual !== undefined) { - result.push(this, [], `Received ${actual}, but key should be absent`); + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent`, + }); } return result; } diff --git a/packages/@aws-cdk/assertions/lib/private/section.ts b/packages/@aws-cdk/assertions/lib/private/section.ts index 89242bc3d6005..64e61191de2ec 100644 --- a/packages/@aws-cdk/assertions/lib/private/section.ts +++ b/packages/@aws-cdk/assertions/lib/private/section.ts @@ -15,6 +15,7 @@ export function matchSection(section: any, props: any): MatchSuccess | MatchFail (logicalId, entry) => { const result = matcher.test(entry); + result.finalize(); if (!result.hasFailed()) { matching[logicalId] = entry; } else { diff --git a/packages/@aws-cdk/assertions/test/capture.test.ts b/packages/@aws-cdk/assertions/test/capture.test.ts index 818592fa35baf..7fe30742e15aa 100644 --- a/packages/@aws-cdk/assertions/test/capture.test.ts +++ b/packages/@aws-cdk/assertions/test/capture.test.ts @@ -15,14 +15,23 @@ describe('Capture', () => { expect(result.toHumanStrings()[0]).toMatch(/Can only capture non-nullish values/); }); + test('no captures if not finalized', () => { + const capture = new Capture(); + const matcher = Match.objectEquals({ foo: capture }); + + matcher.test({ foo: 'bar' }); // Not calling finalize() + expect(() => capture.asString()).toThrow(/No value captured/); + }); + test('asString()', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: 'bar' }); - expect(capture.asString()).toEqual('bar'); + matcher.test({ foo: 'bar' }).finalize(); + matcher.test({ foo: 3 }).finalize(); - matcher.test({ foo: 3 }); + expect(capture.asString()).toEqual('bar'); + expect(capture.next()).toEqual(true); expect(() => capture.asString()).toThrow(/expected to be string but found number/); }); @@ -30,10 +39,11 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: 3 }); - expect(capture.asNumber()).toEqual(3); + matcher.test({ foo: 3 }).finalize(); + matcher.test({ foo: 'bar' }).finalize(); - matcher.test({ foo: 'bar' }); + expect(capture.asNumber()).toEqual(3); + expect(capture.next()).toEqual(true); expect(() => capture.asNumber()).toThrow(/expected to be number but found string/); }); @@ -41,10 +51,11 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: ['bar'] }); - expect(capture.asArray()).toEqual(['bar']); + matcher.test({ foo: ['bar'] }).finalize(); + matcher.test({ foo: 'bar' }).finalize(); - matcher.test({ foo: 'bar' }); + expect(capture.asArray()).toEqual(['bar']); + expect(capture.next()).toEqual(true); expect(() => capture.asArray()).toThrow(/expected to be array but found string/); }); @@ -52,10 +63,11 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: { fred: 'waldo' } }); - expect(capture.asObject()).toEqual({ fred: 'waldo' }); + matcher.test({ foo: { fred: 'waldo' } }).finalize(); + matcher.test({ foo: 'bar' }).finalize(); - matcher.test({ foo: 'bar' }); + expect(capture.asObject()).toEqual({ fred: 'waldo' }); + expect(capture.next()).toEqual(true); expect(() => capture.asObject()).toThrow(/expected to be object but found string/); }); @@ -63,7 +75,49 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: ['bar', capture] }); - matcher.test({ foo: ['bar', 'baz'] }); + matcher.test({ foo: ['bar', 'baz'] }).finalize(); expect(capture.asString()).toEqual('baz'); }); + + test('multiple captures', () => { + const capture = new Capture(); + const matcher = Match.objectEquals({ foo: capture, real: true }); + + matcher.test({ foo: 3, real: true }).finalize(); + matcher.test({ foo: 5, real: true }).finalize(); + matcher.test({ foo: 7, real: false }).finalize(); + + expect(capture.asNumber()).toEqual(3); + expect(capture.next()).toEqual(true); + expect(capture.asNumber()).toEqual(5); + expect(capture.next()).toEqual(false); + }); + + test('nested pattern match', () => { + const capture = new Capture(Match.objectLike({ bar: 'baz' })); + const matcher = Match.objectLike({ foo: capture }); + + matcher.test({ + foo: { + bar: 'baz', + fred: 'waldo', + }, + }).finalize(); + + expect(capture.asObject()).toEqual({ bar: 'baz', fred: 'waldo' }); + expect(capture.next()).toEqual(false); + }); + + test('nested pattern does not match', () => { + const capture = new Capture(Match.objectLike({ bar: 'baz' })); + const matcher = Match.objectLike({ foo: capture }); + + matcher.test({ + foo: { + fred: 'waldo', + }, + }).finalize(); + + expect(() => capture.asObject()).toThrow(/No value captured/); + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/test/template.test.ts b/packages/@aws-cdk/assertions/test/template.test.ts index 64141edf52e89..f5068cede6265 100644 --- a/packages/@aws-cdk/assertions/test/template.test.ts +++ b/packages/@aws-cdk/assertions/test/template.test.ts @@ -1,6 +1,6 @@ import { App, CfnMapping, CfnOutput, CfnResource, NestedStack, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { Match, Template } from '../lib'; +import { Capture, Match, Template } from '../lib'; describe('Template', () => { test('fromString', () => { @@ -293,6 +293,33 @@ describe('Template', () => { Properties: Match.objectLike({ baz: 'qux' }), })).toThrow(/No resource/); }); + + test('capture', () => { + const stack = new Stack(); + new CfnResource(stack, 'Bar1', { + type: 'Foo::Bar', + properties: { baz: 'qux', real: true }, + }); + new CfnResource(stack, 'Bar2', { + type: 'Foo::Bar', + properties: { baz: 'waldo', real: true }, + }); + new CfnResource(stack, 'Bar3', { + type: 'Foo::Bar', + properties: { baz: 'fred', real: false }, + }); + + const capture = new Capture(); + const inspect = Template.fromStack(stack); + inspect.hasResource('Foo::Bar', { + Properties: Match.objectLike({ baz: capture, real: true }), + }); + + expect(capture.asString()).toEqual('qux'); + expect(capture.next()).toEqual(true); + expect(capture.asString()).toEqual('waldo'); + expect(capture.next()).toEqual(false); + }); }); describe('hasResourceProperties', () => { diff --git a/packages/@aws-cdk/pipelines/test/compliance/assets.test.ts b/packages/@aws-cdk/pipelines/test/compliance/assets.test.ts index 68b10d259683f..b8aed3fd714bf 100644 --- a/packages/@aws-cdk/pipelines/test/compliance/assets.test.ts +++ b/packages/@aws-cdk/pipelines/test/compliance/assets.test.ts @@ -742,7 +742,7 @@ describe('pipeline with single asset publisher', () => { function THEN_codePipelineExpectation() { // THEN - const buildSpecName = new Capture(); + const buildSpecName = new Capture(stringLike('buildspec-*.yaml')); Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { Stages: Match.arrayWith([{ Name: 'Assets', @@ -764,7 +764,6 @@ describe('pipeline with single asset publisher', () => { const actualFileName = buildSpecName.asString(); - expect(actualFileName).toMatch(/^buildspec-.*\.yaml$/); const buildSpec = JSON.parse(fs.readFileSync(path.join(assembly.directory, actualFileName), { encoding: 'utf-8' })); expect(buildSpec.phases.build.commands).toContain(`cdk-assets --path "assembly-FileAssetApp/FileAssetAppStackEADD68C5.assets.json" --verbose publish "${FILE_ASSET_SOURCE_HASH}:current_account-current_region"`); expect(buildSpec.phases.build.commands).toContain(`cdk-assets --path "assembly-FileAssetApp/FileAssetAppStackEADD68C5.assets.json" --verbose publish "${FILE_ASSET_SOURCE_HASH2}:current_account-current_region"`); @@ -804,8 +803,8 @@ describe('pipeline with single asset publisher', () => { function THEN_codePipelineExpectation(pipelineStack2: Stack) { // THEN - const buildSpecName1 = new Capture(); - const buildSpecName2 = new Capture(); + const buildSpecName1 = new Capture(stringLike('buildspec-*.yaml')); + const buildSpecName2 = new Capture(stringLike('buildspec-*.yaml')); Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodeBuild::Project', { Source: { BuildSpec: buildSpecName1, @@ -870,7 +869,7 @@ describe('pipeline with custom asset publisher BuildSpec', () => { function THEN_codePipelineExpectation() { - const buildSpecName = new Capture(); + const buildSpecName = new Capture(stringLike('buildspec-*')); Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodePipeline::Pipeline', { Stages: Match.arrayWith([{ From c52430787064d5d8b677ead2b735725058e84468 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Fri, 3 Dec 2021 12:37:59 +0000 Subject: [PATCH 57/82] chore: define new distribution tag strategy for v1 packages (#17823) Packages which are published for both v1 and v2 with the same name must have the 'latest-1' tag to avoid overwriting the v2 versions (which are now 'latest'). Packages which are only v1 (e.g., most service packages) can (and should) remain as 'latest' on v1 (somewhat confusingly). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/assert/package.json | 2 +- .../cloud-assembly-schema/package.json | 2 +- .../@aws-cdk/cloudformation-diff/package.json | 2 +- packages/@aws-cdk/cx-api/package.json | 2 +- packages/@aws-cdk/region-info/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/awslint/package.json | 2 +- packages/cdk-assets/package.json | 2 +- tools/@aws-cdk/pkglint/lib/rules.ts | 25 +++++++++++++------ 9 files changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index 093567d66de12..165ba1622daa9 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -74,6 +74,6 @@ "stability": "experimental", "maturity": "developer-preview", "publishConfig": { - "tag": "latest" + "tag": "latest-1" } } diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index b10afb22968b4..3a5e37c07083e 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -99,6 +99,6 @@ }, "maturity": "stable", "publishConfig": { - "tag": "latest" + "tag": "latest-1" } } diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 20919ad4e721b..3c5f3a575db18 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -56,6 +56,6 @@ "stability": "stable", "maturity": "stable", "publishConfig": { - "tag": "latest" + "tag": "latest-1" } } diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index f971aeb080c53..4f6a8e8386e83 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -157,6 +157,6 @@ "announce": false }, "publishConfig": { - "tag": "latest" + "tag": "latest-1" } } diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index 66139d405ce53..c271c3112e1e2 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -90,6 +90,6 @@ "announce": false }, "publishConfig": { - "tag": "latest" + "tag": "latest-1" } } diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 238e2567af258..9280c439c8487 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -122,6 +122,6 @@ "stability": "stable", "maturity": "stable", "publishConfig": { - "tag": "latest" + "tag": "latest-1" } } diff --git a/packages/awslint/package.json b/packages/awslint/package.json index 5599c2897f4d6..ffcb3e78268ce 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -69,6 +69,6 @@ ] }, "publishConfig": { - "tag": "latest" + "tag": "latest-1" } } diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 17f5f60098edd..fd14204b7f862 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -78,6 +78,6 @@ "stability": "experimental", "maturity": "experimental", "publishConfig": { - "tag": "latest" + "tag": "latest-1" } } diff --git a/tools/@aws-cdk/pkglint/lib/rules.ts b/tools/@aws-cdk/pkglint/lib/rules.ts index b65c9af096e24..0ff12f6485520 100644 --- a/tools/@aws-cdk/pkglint/lib/rules.ts +++ b/tools/@aws-cdk/pkglint/lib/rules.ts @@ -54,16 +54,25 @@ export class DescriptionIsRequired extends ValidationRule { export class PublishConfigTagIsRequired extends ValidationRule { public readonly name = 'package-info/publish-config-tag'; + // The list of packages that are publicly published in both v1 and v2. + private readonly SHARED_PACKAGES = [ + '@aws-cdk/assert', + '@aws-cdk/cloud-assembly-schema', + '@aws-cdk/cloudformation-diff', + '@aws-cdk/cx-api', + '@aws-cdk/region-info', + 'aws-cdk', + 'awslint', + 'cdk-assets', + ]; + public validate(pkg: PackageJson): void { if (pkg.json.private) { return; } - // While v2 is still under development, we publish all v2 packages with the 'next' - // distribution tag, while still tagging all v1 packages as 'latest'. - // There are two sets of exceptions: - // 'aws-cdk-lib' (new v2 package) and all of the '*-alpha' modules, since they are also new packages for v2. - const newV2Packages = ['aws-cdk-lib']; - const isNewPackageForV2 = newV2Packages.includes(pkg.json.name) || pkg.packageName.endsWith('-alpha'); - const defaultPublishTag = (cdkMajorVersion() === 2 && !isNewPackageForV2) ? 'next' : 'latest'; + // v1 packages that are v1-only (e.g., `@aws-cdk/aws-s3`) are always published as `latest`. + // Packages that are published with the same namespace to both v1 and v2 are published as `latest-1` on v1 and `latest` on v2. + // All v2-only packages are just `latest`. + const defaultPublishTag = (cdkMajorVersion() === 2 || !this.SHARED_PACKAGES.includes(pkg.packageName)) ? 'latest' : 'latest-1'; if (pkg.json.publishConfig?.tag !== defaultPublishTag) { pkg.report({ @@ -1872,4 +1881,4 @@ function beginEndRegex(label: string) { function readIfExists(filename: string): string | undefined { return fs.existsSync(filename) ? fs.readFileSync(filename, { encoding: 'utf8' }) : undefined; -} \ No newline at end of file +} From c838d44d48b57920923abf6d9db3354df5e80515 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Fri, 3 Dec 2021 15:13:43 +0000 Subject: [PATCH 58/82] chore: fix start-job-run.test --- .../test/emrcontainers/start-job-run.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/start-job-run.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/start-job-run.test.ts index 63dbfdc6eee48..3a49ce2b0cf6d 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/start-job-run.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/emrcontainers/start-job-run.test.ts @@ -224,7 +224,7 @@ describe('Invoke EMR Containers Start Job Run with ', () => { 's3:GetBucket*', 's3:List*', 's3:DeleteObject*', - 's3:PutObject*', + 's3:PutObject', 's3:Abort*', ], Effect: 'Allow', @@ -346,7 +346,7 @@ describe('Invoke EMR Containers Start Job Run with ', () => { 's3:GetBucket*', 's3:List*', 's3:DeleteObject*', - 's3:PutObject*', + 's3:PutObject', 's3:Abort*', ], Effect: 'Allow', @@ -995,4 +995,4 @@ test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration patt integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, }); }).toThrow(/Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE,RUN_JOB. Received: WAIT_FOR_TASK_TOKEN/); -}); \ No newline at end of file +}); From b60dc63f99ede0cfaa859cdef33a6f4ddd2d1d25 Mon Sep 17 00:00:00 2001 From: Naseem <24660299+naseemkullah@users.noreply.github.com> Date: Fri, 3 Dec 2021 10:17:21 -0500 Subject: [PATCH 59/82] feat(aws-s3-deployment): log retention option (#17779) ---- *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-deployment/README.md | 13 ++++++------- .../lib/bucket-deployment.ts | 10 ++++++++++ .../@aws-cdk/aws-s3-deployment/package.json | 2 ++ .../test/bucket-deployment.test.ts | 19 ++++++++++++++++++- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/aws-s3-deployment/README.md b/packages/@aws-cdk/aws-s3-deployment/README.md index 9aa1927fbed24..37a571b075f40 100644 --- a/packages/@aws-cdk/aws-s3-deployment/README.md +++ b/packages/@aws-cdk/aws-s3-deployment/README.md @@ -44,19 +44,18 @@ This is what happens under the hood: `websiteBucket`). If there is more than one source, the sources will be downloaded and merged pre-deployment at this step. - ## Supported sources The following source types are supported for bucket deployments: - - Local .zip file: `s3deploy.Source.asset('/path/to/local/file.zip')` - - Local directory: `s3deploy.Source.asset('/path/to/local/directory')` - - Another bucket: `s3deploy.Source.bucket(bucket, zipObjectKey)` +- Local .zip file: `s3deploy.Source.asset('/path/to/local/file.zip')` +- Local directory: `s3deploy.Source.asset('/path/to/local/directory')` +- Another bucket: `s3deploy.Source.bucket(bucket, zipObjectKey)` To create a source from a single file, you can pass `AssetOptions` to exclude all but a single file: - - Single file: `s3deploy.Source.asset('/path/to/local/directory', { exclude: ['**', '!onlyThisFile.txt'] })` +- Single file: `s3deploy.Source.asset('/path/to/local/directory', { exclude: ['**', '!onlyThisFile.txt'] })` **IMPORTANT** The `aws-s3-deployment` module is only intended to be used with zip files from trusted sources. Directories bundled by the CDK CLI (by using @@ -243,7 +242,7 @@ size of the AWS Lambda resource handler. ## EFS Support -If your workflow needs more disk space than default (512 MB) disk space, you may attach an EFS storage to underlying +If your workflow needs more disk space than default (512 MB) disk space, you may attach an EFS storage to underlying lambda function. To Enable EFS support set `efs` and `vpc` props for BucketDeployment. Check sample usage below. @@ -288,4 +287,4 @@ might be tricky to build on Windows. ## Roadmap - - [ ] Support "blue/green" deployments ([#954](https://github.com/aws/aws-cdk/issues/954)) +- [ ] Support "blue/green" deployments ([#954](https://github.com/aws/aws-cdk/issues/954)) diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts index fb7aed2d65479..76bbae6a4b290 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts @@ -4,6 +4,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as efs from '@aws-cdk/aws-efs'; import * as iam from '@aws-cdk/aws-iam'; 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 { AwsCliLayer } from '@aws-cdk/lambda-layer-awscli'; @@ -101,6 +102,14 @@ export interface BucketDeploymentProps { */ readonly distributionPaths?: string[]; + + /** + * The number of days that the lambda function's log events are kept in CloudWatch Logs. + * + * @default logs.RetentionDays.INFINITE + */ + readonly logRetention?: logs.RetentionDays; + /** * The amount of memory (in MiB) to allocate to the AWS Lambda function which * replicates the files from the CDK bucket to the destination bucket. @@ -297,6 +306,7 @@ export class BucketDeployment extends CoreConstruct { accessPoint, mountPath, ) : undefined, + logRetention: props.logRetention, }); const handlerRole = handler.role; diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 1101a604a650f..cf0788bbf6e0c 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -92,6 +92,7 @@ "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -106,6 +107,7 @@ "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts index 2517288e84cd9..38023cc0154e6 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts +++ b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts @@ -1,9 +1,10 @@ -import '@aws-cdk/assert-internal/jest'; import * as path from 'path'; import { MatchStyle, objectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; +import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import { testDeprecated, testFutureBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; @@ -75,6 +76,22 @@ test('deploy from local directory asset', () => { }); }); +test('deploy with configured log retention', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Dest'); + + // WHEN + new s3deploy.BucketDeployment(stack, 'Deploy', { + sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'))], + destinationBucket: bucket, + logRetention: logs.RetentionDays.ONE_WEEK, + }); + + // THEN + expect(stack).toHaveResourceLike('Custom::LogRetention', { RetentionInDays: 7 }); +}); + test('deploy from local directory assets', () => { // GIVEN const stack = new cdk.Stack(); From 4cede4c7a21b303cd0d08c68e48e21f50e5fa629 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Fri, 3 Dec 2021 16:50:11 +0000 Subject: [PATCH 60/82] chore: update construct import --- .../ecs-service-extensions/lib/extensions/queue/queue.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/queue.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/queue.ts index bda38fb81c355..8fff61170176d 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/queue.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/queue/queue.ts @@ -10,14 +10,11 @@ import * as sns from '@aws-cdk/aws-sns'; import * as subscription from '@aws-cdk/aws-sns-subscriptions'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; import { Service } from '../../service'; import { Container } from '../container'; import { ContainerMutatingHook, ServiceExtension } from '../extension-interfaces'; -// Keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - /** * An interface that will be implemented by all the resources that can be subscribed to. */ @@ -415,4 +412,4 @@ export class QueueExtension extends ServiceExtension { public get autoscalingOptions() : QueueAutoScalingOptions | undefined { return this._autoscalingOptions; } -} \ No newline at end of file +} From b606a2321769d5e8f15072a62848aaba35bb1d35 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Fri, 3 Dec 2021 21:40:55 +0100 Subject: [PATCH 61/82] feat(rds): parameter group for replica instances (#17822) Move `parameterGroup` from `DatabaseInstanceSourceProps` to `DatabaseInstanceNewProps` since the parameter group of a replica instance can be customized. Closes #17580 ---- *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/lib/instance.ts | 18 ++++++------- .../@aws-cdk/aws-rds/test/instance.test.ts | 27 +++++++++++++++++++ .../test/integ.read-replica.expected.json | 13 +++++++++ .../aws-rds/test/integ.read-replica.ts | 8 ++++++ 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index d893720fed46e..065f4c4fb947b 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -359,6 +359,13 @@ export interface DatabaseInstanceNewProps { */ readonly port?: number; + /** + * The DB parameter group to associate with the instance. + * + * @default - no parameter group + */ + readonly parameterGroup?: IParameterGroup; + /** * The option group to associate with the instance. * @@ -709,6 +716,7 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData ? props.instanceIdentifier?.toLowerCase() : props.instanceIdentifier; + const instanceParameterGroupConfig = props.parameterGroup?.bindToInstance({}); this.newCfnProps = { autoMinorVersionUpgrade: props.autoMinorVersionUpgrade, availabilityZone: props.multiAz ? undefined : props.availabilityZone, @@ -732,6 +740,7 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData monitoringInterval: props.monitoringInterval?.toSeconds(), monitoringRoleArn: monitoringRole?.roleArn, multiAz: props.multiAz, + dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName, optionGroupName: props.optionGroup?.optionGroupName, performanceInsightsKmsKeyId: props.performanceInsightEncryptionKey?.keyArn, performanceInsightsRetentionPeriod: enablePerformanceInsights @@ -813,13 +822,6 @@ export interface DatabaseInstanceSourceProps extends DatabaseInstanceNewProps { * @default - no name */ readonly databaseName?: string; - - /** - * The DB parameter group to associate with the instance. - * - * @default - no parameter group - */ - readonly parameterGroup?: IParameterGroup; } /** @@ -875,7 +877,6 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa this.instanceType = props.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE); - const instanceParameterGroupConfig = props.parameterGroup?.bindToInstance({}); this.sourceCfnProps = { ...this.newCfnProps, associatedRoles: instanceAssociatedRoles.length > 0 ? instanceAssociatedRoles : undefined, @@ -883,7 +884,6 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa allocatedStorage: props.allocatedStorage?.toString() ?? '100', allowMajorVersionUpgrade: props.allowMajorVersionUpgrade, dbName: props.databaseName, - dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName, engine: engineType, engineVersion: props.engine.engineVersion?.fullVersion, licenseModel: props.licenseModel, diff --git a/packages/@aws-cdk/aws-rds/test/instance.test.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts index e159a8971b204..fd6519b6fb6bc 100644 --- a/packages/@aws-cdk/aws-rds/test/instance.test.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -1603,6 +1603,33 @@ describe('instance', () => { }); }).toThrow(/Cannot set 'backupRetention', as engine 'postgres-13' does not support automatic backups for read replicas/); }); + + test('can set parameter group on read replica', () => { + // GIVEN + const instanceType = ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL); + const engine = rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_13 }); + const parameterGroup = new rds.ParameterGroup(stack, 'ParameterGroup', { engine }); + const source = new rds.DatabaseInstance(stack, 'Source', { + engine, + instanceType, + vpc, + }); + + // WHEN + new rds.DatabaseInstanceReadReplica(stack, 'Replica', { + sourceDatabaseInstance: source, + parameterGroup, + instanceType, + vpc, + }); + + // THEN + expect(stack).toHaveResource('AWS::RDS::DBInstance', { + DBParameterGroupName: { + Ref: 'ParameterGroup5E32DECB', + }, + }); + }); }); test.each([ diff --git a/packages/@aws-cdk/aws-rds/test/integ.read-replica.expected.json b/packages/@aws-cdk/aws-rds/test/integ.read-replica.expected.json index d27f653c3e6ac..1d6b9bd4b18ce 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.read-replica.expected.json +++ b/packages/@aws-cdk/aws-rds/test/integ.read-replica.expected.json @@ -422,6 +422,16 @@ "UpdateReplacePolicy": "Snapshot", "DeletionPolicy": "Snapshot" }, + "ReplicaParameterGroup4BE5EE70": { + "Type": "AWS::RDS::DBParameterGroup", + "Properties": { + "Description": "Parameter group for mysql8.0", + "Family": "mysql8.0", + "Parameters": { + "wait_timeout": "86400" + } + } + }, "MysqlReplicaSubnetGroup79E1F72A": { "Type": "AWS::RDS::DBSubnetGroup", "Properties": { @@ -458,6 +468,9 @@ "DBInstanceClass": "db.t3.small", "BackupRetentionPeriod": 3, "CopyTagsToSnapshot": true, + "DBParameterGroupName": { + "Ref": "ReplicaParameterGroup4BE5EE70" + }, "DBSubnetGroupName": { "Ref": "MysqlReplicaSubnetGroup79E1F72A" }, diff --git a/packages/@aws-cdk/aws-rds/test/integ.read-replica.ts b/packages/@aws-cdk/aws-rds/test/integ.read-replica.ts index 7ebbd176049b4..0ad308bcf8776 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.read-replica.ts +++ b/packages/@aws-cdk/aws-rds/test/integ.read-replica.ts @@ -44,12 +44,20 @@ class TestStack extends Stack { vpcSubnets, }); + const parameterGroup = new rds.ParameterGroup(this, 'ReplicaParameterGroup', { + engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0 }), + parameters: { + wait_timeout: '86400', + }, + }); + new rds.DatabaseInstanceReadReplica(this, 'MysqlReplica', { sourceDatabaseInstance: mysqlSource, backupRetention: Duration.days(3), instanceType, vpc, vpcSubnets, + parameterGroup, }); } } From e232ab70b42f6648668529f44df6eb7312259209 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Sun, 5 Dec 2021 11:48:28 +0000 Subject: [PATCH 62/82] chore: fix check-api-compatibility after change in distribution tags (#17833) The change in #17823 introduced the `latest-1` distribution tags for the shared packages published in v1. This change broke the `check-api-compat` script because -- for bump builds -- it compares compatibility against the tag in npm. With a new tag introduced, this doesn't work. Instead, simply default to the latest at the same major version; this is equivalent and more robust. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- scripts/check-api-compatibility.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/check-api-compatibility.sh b/scripts/check-api-compatibility.sh index 1b99f9e05f188..3cc97cdca81e7 100755 --- a/scripts/check-api-compatibility.sh +++ b/scripts/check-api-compatibility.sh @@ -9,10 +9,6 @@ package_name() { node -pe "require('$1/package.json').name" } -package_name_and_dist_tag() { - node -pe "const pkg = require('$1/package.json'); pkg.name + '@' + pkg.publishConfig.tag" -} - # Determine whether an NPM package exists on NPM # # Doesn't use 'npm view' as that is slow. Direct curl'ing npmjs is better @@ -48,7 +44,6 @@ dirs_for_existing_pkgs() { } export -f package_name -export -f package_name_and_dist_tag export -f package_exists_on_npm export -f dirs_for_existing_pkgs @@ -64,8 +59,9 @@ if ! ${SKIP_DOWNLOAD:-false}; then echo " Current version is $version." >&2 if ! package_exists_on_npm aws-cdk $version; then - echo " Version $version does not exist in npm. Falling back to package dist tags" >&2 - existing_names=$(echo "$existing_pkg_dirs" | xargs -n1 -P4 -I {} bash -c 'package_name_and_dist_tag "$@"' _ {}) + major_version=$(echo "$version" | sed -e 's/\..*//g') + echo " Version $version does not exist in npm. Falling back to package major version ${major_version}" >&2 + existing_names=$(echo "$existing_names" | sed -e "s/$/@$major_version/") else echo "Using version '$version' as the baseline..." existing_names=$(echo "$existing_names" | sed -e "s/$/@$version/") From 36b8fdb026c7e82eb590c1a8d604ca3b44642900 Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Mon, 6 Dec 2021 02:45:24 -0800 Subject: [PATCH 63/82] fix(dynamodb): changing `waitForReplicationToFinish` fails deployment (#17842) Our CFN Custom Resource for global DynamoDB Tables did not correctly handle changing the `waitForReplicationToFinish` parameter introduced in #16983 - adding it to an existing replica would error out by attempting to re-create the existing replica. Fix this by adding a check in the Custom Resource whether a replica already exists. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-dynamodb/lib/replica-handler/index.ts | 54 ++++++++++++------- packages/@aws-cdk/aws-dynamodb/lib/table.ts | 6 ++- .../aws-dynamodb/test/dynamodb.test.ts | 4 +- .../test/replica-provider.test.ts | 50 +++++++++++++---- 4 files changed, 82 insertions(+), 32 deletions(-) diff --git a/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts b/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts index 38109b1a4a614..36e12cc113ffe 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts @@ -7,31 +7,45 @@ export async function onEventHandler(event: OnEventRequest): Promise replica.RegionName === region); + updateTableAction = replicaExists ? undefined : 'Create'; } - const data = await dynamodb.updateTable({ - TableName: event.ResourceProperties.TableName, - ReplicaUpdates: [ - { - [updateTableAction]: { - RegionName: event.ResourceProperties.Region, + if (updateTableAction) { + const data = await dynamodb.updateTable({ + TableName: tableName, + ReplicaUpdates: [ + { + [updateTableAction]: { + RegionName: region, + }, }, - }, - ], - }).promise(); - console.log('Update table: %j', data); + ], + }).promise(); + console.log('Update table: %j', data); + } else { + console.log("Skipping updating Table, as a replica in '%s' already exists", region); + } return event.RequestType === 'Create' || event.RequestType === 'Update' - ? { PhysicalResourceId: `${event.ResourceProperties.TableName}-${event.ResourceProperties.Region}` } + ? { PhysicalResourceId: `${tableName}-${region}` } : {}; } @@ -45,11 +59,11 @@ export async function isCompleteHandler(event: IsCompleteRequest): Promise r.RegionName === event.ResourceProperties.Region); - const replicaActive = !!(regionReplica?.ReplicaStatus === 'ACTIVE'); - const skipReplicationCompletedWait = event.ResourceProperties.SkipReplicationCompletedWait ?? false; + const replicaActive = regionReplica?.ReplicaStatus === 'ACTIVE'; + const skipReplicationCompletedWait = event.ResourceProperties.SkipReplicationCompletedWait === 'true'; switch (event.RequestType) { case 'Create': diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index 78d2851d513f7..3fdcc7f557b7e 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -1557,7 +1557,11 @@ export class Table extends TableBase { properties: { TableName: this.tableName, Region: region, - SkipReplicationCompletedWait: waitForReplicationToFinish === undefined ? undefined : !waitForReplicationToFinish, + SkipReplicationCompletedWait: waitForReplicationToFinish == null + ? undefined + // CFN changes Custom Resource properties to strings anyways, + // so let's do that ourselves to make it clear in the handler this is a string, not a boolean + : (!waitForReplicationToFinish).toString(), }, }); currentRegion.node.addDependency( diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index a0760b22761da..3c125c1bc0061 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -2468,7 +2468,7 @@ describe('global', () => { Ref: 'TableCD117FA1', }, Region: 'eu-west-2', - SkipReplicationCompletedWait: true, + SkipReplicationCompletedWait: 'true', }, Condition: 'TableStackRegionNotEqualseuwest2A03859E7', }, ResourcePart.CompleteDefinition); @@ -2479,7 +2479,7 @@ describe('global', () => { Ref: 'TableCD117FA1', }, Region: 'eu-central-1', - SkipReplicationCompletedWait: true, + SkipReplicationCompletedWait: 'true', }, Condition: 'TableStackRegionNotEqualseucentral199D46FC0', }, ResourcePart.CompleteDefinition); diff --git a/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts b/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts index 4b5acef3d15cb..b0a522f7353c0 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts @@ -16,11 +16,13 @@ afterAll(() => { AWS.setSDK(require.resolve('aws-sdk')); +const REGION = 'eu-west-2'; + const createEvent: OnEventRequest = { RequestType: 'Create', ResourceProperties: { TableName: 'my-table', - Region: 'eu-west-2', + Region: REGION, ServiceToken: 'token', }, ServiceToken: 'token', @@ -47,7 +49,7 @@ test('on event', async () => { ReplicaUpdates: [ { Create: { - RegionName: 'eu-west-2', + RegionName: REGION, }, }, ], @@ -58,9 +60,16 @@ test('on event', async () => { }); }); -test('on event calls updateTable with Create for Update requests with table replacement', async () => { - const updateTableMock = sinon.fake.resolves({}); +test("on Update event from CFN calls updateTable with Create if a replica in the region doesn't exist", async () => { + AWS.mock('DynamoDB', 'describeTable', sinon.fake.resolves({ + Table: { + Replicas: [ + // no replicas exist yet + ], + }, + })); + const updateTableMock = sinon.fake.resolves({}); AWS.mock('DynamoDB', 'updateTable', updateTableMock); const data = await onEventHandler({ @@ -76,7 +85,7 @@ test('on event calls updateTable with Create for Update requests with table repl ReplicaUpdates: [ { Create: { - RegionName: 'eu-west-2', + RegionName: REGION, }, }, ], @@ -87,6 +96,29 @@ test('on event calls updateTable with Create for Update requests with table repl }); }); +test("on Update event from CFN calls doesn't call updateTable if a replica in the region does exist", async () => { + AWS.mock('DynamoDB', 'describeTable', sinon.fake.resolves({ + Table: { + Replicas: [ + { RegionName: REGION }, + ], + }, + })); + + const updateTableMock = sinon.fake.resolves({}); + AWS.mock('DynamoDB', 'updateTable', updateTableMock); + + await onEventHandler({ + ...createEvent, + OldResourceProperties: { + TableName: 'my-old-table', + }, + RequestType: 'Update', + }); + + sinon.assert.notCalled(updateTableMock); +}); + test('on event calls updateTable with Delete', async () => { const updateTableMock = sinon.fake.resolves({}); @@ -102,7 +134,7 @@ test('on event calls updateTable with Delete', async () => { ReplicaUpdates: [ { Delete: { - RegionName: 'eu-west-2', + RegionName: REGION, }, }, ], @@ -129,7 +161,7 @@ test('is complete for create returns false when replica is not active', async () Table: { Replicas: [ { - RegionName: 'eu-west-2', + RegionName: REGION, ReplicaStatus: 'CREATING', }, ], @@ -148,7 +180,7 @@ test('is complete for create returns false when table is not active', async () = Table: { Replicas: [ { - RegionName: 'eu-west-2', + RegionName: REGION, ReplicaStatus: 'ACTIVE', }, ], @@ -168,7 +200,7 @@ test('is complete for create returns true when replica is active', async () => { Table: { Replicas: [ { - RegionName: 'eu-west-2', + RegionName: REGION, ReplicaStatus: 'ACTIVE', }, ], From 0f40af17769d7b5728aba409133dfff44b2aacbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Dec 2021 11:27:51 +0000 Subject: [PATCH 64/82] chore(deps): bump actions/setup-node from 2.4.1 to 2.5.0 (#17859) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 2.4.1 to 2.5.0.
Release notes

Sourced from actions/setup-node's releases.

Adding Node.js version file support

In scope of this release we add the node-version-file input and update actions/cache dependency to the latest version.

Adding Node.js version file support

The new input (node-version-file) provides functionality to specify the path to the file containing Node.js's version with such behaviour:

  • If the file does not exist the action will throw an error.
  • If you specify both node-version and node-version-file inputs, the action will use value from the node-version input and throw the following warning: Both node-version and node-version-file inputs are specified, only node-version will be used.
  • For now the action does not support all of the variety of values for Node.js version files. The action can handle values according to the documentation and values with v prefix (v14)
steps:
  - uses: actions/checkout@v2
  - name: Setup node from node version file
    uses: actions/setup-node@v2
    with:
      node-version-file: '.nvmrc'
  - run: npm install
  - run: npm test

Update actions/cache dependency to 1.0.8 version.

We updated actions/cache dependency to the latest version (1.0.8). For more information please refer to the toolkit/cache.

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-node&package-manager=github_actions&previous-version=2.4.1&new-version=2.5.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/yarn-upgrade.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/yarn-upgrade.yml b/.github/workflows/yarn-upgrade.yml index 0389380b2a404..f47143f65188f 100644 --- a/.github/workflows/yarn-upgrade.yml +++ b/.github/workflows/yarn-upgrade.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Node - uses: actions/setup-node@v2.4.1 + uses: actions/setup-node@v2.5.0 with: node-version: 12 From c291c4427480472402ef6b0a7c854ac38505ae97 Mon Sep 17 00:00:00 2001 From: WinterYukky <49480575+WinterYukky@users.noreply.github.com> Date: Tue, 7 Dec 2021 00:07:42 +0900 Subject: [PATCH 65/82] feat(s3): add GLACIER_IR storage class (#17829) Add S3 Glacier Instant Retrieval storage class that announced by [this blog](https://aws.amazon.com/about-aws/whats-new/2021/11/amazon-s3-glacier-instant-retrieval-storage-class/). It is also described in the [CloudFormation documentation](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-lifecycleconfig-rule-noncurrentversiontransition.html). ---- *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/lib/rule.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/@aws-cdk/aws-s3/lib/rule.ts b/packages/@aws-cdk/aws-s3/lib/rule.ts index 92ad24e2cf6a8..bd9492c44ab84 100644 --- a/packages/@aws-cdk/aws-s3/lib/rule.ts +++ b/packages/@aws-cdk/aws-s3/lib/rule.ts @@ -184,6 +184,17 @@ export class StorageClass { */ public static readonly GLACIER = new StorageClass('GLACIER'); + /** + * Storage class for long-term archival that can be accessed in a few milliseconds. + * + * It is ideal for data that is accessed once or twice per quarter, and + * that requires immediate access. Data stored in the GLACIER_IR storage class + * has a minimum storage duration period of 90 days and can be accessed in + * as milliseconds. If you delete an object before the 90-day minimum, + * you are charged for 90 days. + */ + public static readonly GLACIER_INSTANT_RETRIEVAL = new StorageClass('GLACIER_IR'); + /** * Use for archiving data that rarely needs to be accessed. Data stored in the * DEEP_ARCHIVE storage class has a minimum storage duration period of 180 From 7f45de4ba3cdf99846ca1966549b1630929aebbe Mon Sep 17 00:00:00 2001 From: Thomas Chia Date: Mon, 6 Dec 2021 23:49:54 +0800 Subject: [PATCH 66/82] feat(cognito): user pool: adds custom sender (Email/SMS) lambda triggers (#17740) ### Motivation I would like to use the Custom Sender triggers in my CDK app. They are supported by raw CF (despite the docs claiming otherwise). I do not wish to use the CfnUserPool construct as I am unable to pass the pool as a reference to other constructs (e.g. API Gateway authorisers/User Pool App Clients/etc.). I do not wish to follow the method recommended by the docs either (using the CLI to update the pool post-deployment), as it is hard to automate (requiring me to fetch the ARNs of my functions and KMS Key, not to mention it overrides other properties of the User Pool), and leaks my stack configuration out from CDK and into some post-deploy script. Please find this PR in support of adding the triggers to CDK. ### Description Adds support for 2 extra lambda triggers (`CustomEmailSender` and `CustomSMSSender`). These triggers have a different format, requiring both function ARN and version (only supported value is `V1_0`). Additionally, specifying either of these requires a `KMSKeyId` be specified as well, which appears as a property of the `LambdaTriggers` property in CF. Additionally, specifying the `CustomSMSSender` requires the `smsRole` be specified (allowing `sns:publish`). Neither of these requirements are enforced in the code, but CF will throw helpful (IMO) errors if they are not satisfied. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-cognito/lib/user-pool.ts | 83 +++++++- packages/@aws-cdk/aws-cognito/package.json | 2 + ...nteg.user-pool-custom-sender.expected.json | 198 ++++++++++++++++++ .../test/integ.user-pool-custom-sender.ts | 47 +++++ .../aws-cognito/test/user-pool.test.ts | 83 +++++++- 5 files changed, 406 insertions(+), 7 deletions(-) create mode 100644 packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.expected.json create mode 100644 packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.ts diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index 731b382e20f76..59f3ce09f2057 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -1,4 +1,5 @@ import { IRole, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import { IKey } from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import { ArnFormat, Duration, IResource, Lazy, Names, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -138,6 +139,20 @@ export interface UserPoolTriggers { */ readonly verifyAuthChallengeResponse?: lambda.IFunction; + /** + * Amazon Cognito invokes this trigger to send email notifications to users. + * @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-email-sender.html + * @default - no trigger configured + */ + readonly customEmailSender?: lambda.IFunction + + /** + * Amazon Cognito invokes this trigger to send SMS notifications to users. + * @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-sms-sender.html + * @default - no trigger configured + */ + readonly customSmsSender?: lambda.IFunction + /** * Index signature */ @@ -208,6 +223,18 @@ export class UserPoolOperation { */ public static readonly VERIFY_AUTH_CHALLENGE_RESPONSE = new UserPoolOperation('verifyAuthChallengeResponse'); + /** + * Amazon Cognito invokes this trigger to send email notifications to users. + * @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-email-sender.html + */ + public static readonly CUSTOM_EMAIL_SENDER = new UserPoolOperation('customEmailSender'); + + /** + * Amazon Cognito invokes this trigger to send email notifications to users. + * @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-sms-sender.html + */ + public static readonly CUSTOM_SMS_SENDER = new UserPoolOperation('customSmsSender'); + /** A custom user pool operation */ public static of(name: string): UserPoolOperation { const lowerCamelCase = name.charAt(0).toLowerCase() + name.slice(1); @@ -616,6 +643,13 @@ export interface UserPoolProps { * @default - see defaults on each property of DeviceTracking. */ readonly deviceTracking?: DeviceTracking; + + /** + * This key will be used to encrypt temporary passwords and authorization codes that Amazon Cognito generates. + * @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-sender-triggers.html + * @default - no key ID configured + */ + readonly customSenderKmsKey?: IKey; } /** @@ -766,12 +800,37 @@ export class UserPool extends UserPoolBase { const signIn = this.signInConfiguration(props); + if (props.customSenderKmsKey) { + const kmsKey = props.customSenderKmsKey; + (this.triggers as any).kmsKeyId = kmsKey.keyArn; + } + if (props.lambdaTriggers) { for (const t of Object.keys(props.lambdaTriggers)) { - const trigger = props.lambdaTriggers[t]; - if (trigger !== undefined) { - this.addLambdaPermission(trigger as lambda.IFunction, t); - (this.triggers as any)[t] = (trigger as lambda.IFunction).functionArn; + let trigger: lambda.IFunction | undefined; + switch (t) { + case 'customSmsSender': + case 'customEmailSender': + if (!this.triggers.kmsKeyId) { + throw new Error('you must specify a KMS key if you are using customSmsSender or customEmailSender.'); + } + trigger = props.lambdaTriggers[t]; + const version = 'V1_0'; + if (trigger !== undefined) { + this.addLambdaPermission(trigger as lambda.IFunction, t); + (this.triggers as any)[t] = { + lambdaArn: trigger.functionArn, + lambdaVersion: version, + }; + } + break; + default: + trigger = props.lambdaTriggers[t] as lambda.IFunction | undefined; + if (trigger !== undefined) { + this.addLambdaPermission(trigger as lambda.IFunction, t); + (this.triggers as any)[t] = (trigger as lambda.IFunction).functionArn; + } + break; } } } @@ -848,7 +907,21 @@ export class UserPool extends UserPoolBase { } this.addLambdaPermission(fn, operation.operationName); - (this.triggers as any)[operation.operationName] = fn.functionArn; + switch (operation.operationName) { + case 'customEmailSender': + case 'customSmsSender': + if (!this.triggers.kmsKeyId) { + throw new Error('you must specify a KMS key if you are using customSmsSender or customEmailSender.'); + } + (this.triggers as any)[operation.operationName] = { + lambdaArn: fn.functionArn, + lambdaVersion: 'V1_0', + }; + break; + default: + (this.triggers as any)[operation.operationName] = fn.functionArn; + } + } private addLambdaPermission(fn: lambda.IFunction, name: string): void { diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index 2e72772c1c43d..92e3fb622a3ce 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -84,6 +84,7 @@ "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", @@ -94,6 +95,7 @@ "peerDependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.expected.json new file mode 100644 index 0000000000000..c28251be02c92 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.expected.json @@ -0,0 +1,198 @@ +{ + "Resources": { + "emailLambdaServiceRole7569D9F6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "emailLambda61F82360": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = function(event, ctx, cb) { console.log(\"Mocked custom email send\");return cb(null, \"success\"); }" + }, + "Role": { + "Fn::GetAtt": [ + "emailLambdaServiceRole7569D9F6", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "emailLambdaServiceRole7569D9F6" + ] + }, + "emailLambdaCustomEmailSenderCognito5E15D907": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "emailLambda61F82360", + "Arn" + ] + }, + "Principal": "cognito-idp.amazonaws.com" + } + }, + "keyFEDD6EC0": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "pool056F3F7E": { + "Type": "AWS::Cognito::UserPool", + "Properties": { + "AccountRecoverySetting": { + "RecoveryMechanisms": [ + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } + ] + }, + "AdminCreateUserConfig": { + "AllowAdminCreateUserOnly": false + }, + "AutoVerifiedAttributes": [ + "email" + ], + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "LambdaConfig": { + "CustomEmailSender": { + "LambdaArn": { + "Fn::GetAtt": [ + "emailLambda61F82360", + "Arn" + ] + }, + "LambdaVersion": "V1_0" + }, + "KMSKeyID": { + "Fn::GetAtt": [ + "keyFEDD6EC0", + "Arn" + ] + } + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", + "UsernameAttributes": [ + "email" + ], + "VerificationMessageTemplate": { + "DefaultEmailOption": "CONFIRM_WITH_CODE", + "EmailMessage": "The verification code to your new account is {####}", + "EmailSubject": "Verify your new account", + "SmsMessage": "The verification code to your new account is {####}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "poolclient2623294C": { + "Type": "AWS::Cognito::UserPoolClient", + "Properties": { + "UserPoolId": { + "Ref": "pool056F3F7E" + }, + "AllowedOAuthFlows": [ + "implicit", + "code" + ], + "AllowedOAuthFlowsUserPoolClient": true, + "AllowedOAuthScopes": [ + "profile", + "phone", + "email", + "openid", + "aws.cognito.signin.user.admin" + ], + "CallbackURLs": [ + "https://example.com" + ], + "ExplicitAuthFlows": [ + "ALLOW_USER_SRP_AUTH", + "ALLOW_REFRESH_TOKEN_AUTH" + ], + "SupportedIdentityProviders": [ + "COGNITO" + ] + } + } + }, + "Outputs": { + "UserPoolId": { + "Value": { + "Ref": "pool056F3F7E" + } + }, + "ClientId": { + "Value": { + "Ref": "poolclient2623294C" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.ts new file mode 100644 index 0000000000000..802d8bc6baa21 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-custom-sender.ts @@ -0,0 +1,47 @@ +import * as kms from '@aws-cdk/aws-kms'; +import * as lambda from '@aws-cdk/aws-lambda'; +import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; +import { UserPool } from '../lib'; + +/* + * Stack verification steps + * * Sign up to the created user pool using an email address as the username, and password. + * * Verify the CustomEmailSender lambda was called via logged message in CloudWatch. + */ +const app = new App(); +const stack = new Stack(app, 'integ-user-pool-custom-sender'); + +const customSenderLambda = new lambda.Function(stack, 'emailLambda', { + runtime: lambda.Runtime.NODEJS_14_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { console.log("Mocked custom email send");return cb(null, "success"); }'), +}); + +const userpool = new UserPool(stack, 'pool', { + autoVerify: { + email: true, + }, + selfSignUpEnabled: true, + signInAliases: { + email: true, + }, + customSenderKmsKey: new kms.Key(stack, 'key'), + lambdaTriggers: { + customEmailSender: customSenderLambda, + }, + removalPolicy: RemovalPolicy.DESTROY, +}); + +const client = userpool.addClient('client', { + authFlows: { + userSrp: true, + }, +}); + +new CfnOutput(stack, 'UserPoolId', { + value: userpool.userPoolId, +}); + +new CfnOutput(stack, 'ClientId', { + value: client.userPoolClientId, +}); diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index 9d89be13d6fef..df252d401a000 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -1,5 +1,6 @@ import { Match, Template } from '@aws-cdk/assertions'; import { Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import { testDeprecated } from '@aws-cdk/cdk-build-tools'; import { CfnParameter, Duration, Stack, Tags } from '@aws-cdk/core'; @@ -331,9 +332,69 @@ describe('User Pool', () => { }); }); + test('custom sender lambda triggers via properties are correctly configured', () => { + // GIVEN + const stack = new Stack(); + const kmsKey = fooKey(stack, 'TestKMSKey'); + const emailFn = fooFunction(stack, 'customEmailSender'); + const smsFn = fooFunction(stack, 'customSmsSender'); + + // WHEN + new UserPool(stack, 'Pool', { + customSenderKmsKey: kmsKey, + lambdaTriggers: { + customEmailSender: emailFn, + customSmsSender: smsFn, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { + LambdaConfig: { + CustomEmailSender: { + LambdaArn: stack.resolve(emailFn.functionArn), + LambdaVersion: 'V1_0', + }, + CustomSMSSender: { + LambdaArn: stack.resolve(smsFn.functionArn), + LambdaVersion: 'V1_0', + }, + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: stack.resolve(emailFn.functionArn), + Principal: 'cognito-idp.amazonaws.com', + }); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: stack.resolve(smsFn.functionArn), + Principal: 'cognito-idp.amazonaws.com', + }); + }); + + test('lambda trigger KMS Key ID via properties is correctly configured', () => { + // GIVEN + const stack = new Stack(); + const kmsKey = fooKey(stack, 'TestKMSKey'); + + // WHEN + new UserPool(stack, 'Pool', { + customSenderKmsKey: kmsKey, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { + LambdaConfig: { + KMSKeyID: { 'Fn::GetAtt': ['TestKMSKey32509532', 'Arn'] }, + }, + }); + }); + test('add* API correctly appends triggers', () => { // GIVEN const stack = new Stack(); + const kmsKey = fooKey(stack, 'TestKMSKey'); const createAuthChallenge = fooFunction(stack, 'createAuthChallenge'); const customMessage = fooFunction(stack, 'customMessage'); @@ -345,9 +406,13 @@ describe('User Pool', () => { const preTokenGeneration = fooFunction(stack, 'preTokenGeneration'); const userMigration = fooFunction(stack, 'userMigration'); const verifyAuthChallengeResponse = fooFunction(stack, 'verifyAuthChallengeResponse'); + const customEmailSender = fooFunction(stack, 'customEmailSender'); + const customSmsSender = fooFunction(stack, 'customSmsSender'); // WHEN - const pool = new UserPool(stack, 'Pool'); + const pool = new UserPool(stack, 'Pool', { + customSenderKmsKey: kmsKey, + }); pool.addTrigger(UserPoolOperation.CREATE_AUTH_CHALLENGE, createAuthChallenge); pool.addTrigger(UserPoolOperation.CUSTOM_MESSAGE, customMessage); pool.addTrigger(UserPoolOperation.DEFINE_AUTH_CHALLENGE, defineAuthChallenge); @@ -358,6 +423,8 @@ describe('User Pool', () => { pool.addTrigger(UserPoolOperation.PRE_TOKEN_GENERATION, preTokenGeneration); pool.addTrigger(UserPoolOperation.USER_MIGRATION, userMigration); pool.addTrigger(UserPoolOperation.VERIFY_AUTH_CHALLENGE_RESPONSE, verifyAuthChallengeResponse); + pool.addTrigger(UserPoolOperation.CUSTOM_EMAIL_SENDER, customEmailSender); + pool.addTrigger(UserPoolOperation.CUSTOM_SMS_SENDER, customSmsSender); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { @@ -372,12 +439,20 @@ describe('User Pool', () => { PreTokenGeneration: stack.resolve(preTokenGeneration.functionArn), UserMigration: stack.resolve(userMigration.functionArn), VerifyAuthChallengeResponse: stack.resolve(verifyAuthChallengeResponse.functionArn), + CustomEmailSender: { + LambdaArn: stack.resolve(customEmailSender.functionArn), + LambdaVersion: 'V1_0', + }, + CustomSMSSender: { + LambdaArn: stack.resolve(customSmsSender.functionArn), + LambdaVersion: 'V1_0', + }, }, }); [createAuthChallenge, customMessage, defineAuthChallenge, postAuthentication, postConfirmation, preAuthentication, preSignUp, preTokenGeneration, userMigration, - verifyAuthChallengeResponse].forEach((fn) => { + verifyAuthChallengeResponse, customEmailSender, customSmsSender].forEach((fn) => { Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: stack.resolve(fn.functionArn), @@ -1700,3 +1775,7 @@ function fooFunction(scope: Construct, name: string): lambda.IFunction { handler: 'index.handler', }); } + +function fooKey(scope: Construct, name: string): kms.Key { + return new kms.Key(scope, name); +} \ No newline at end of file From 6bb4a46792d0b9665e4a72896869a063e8fa1af9 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Mon, 6 Dec 2021 16:01:42 +0000 Subject: [PATCH 67/82] fix(aws-cdk): `cdk diff` always fails on diff (#17862) In v1, the original behavior was that `cdk diff` exited 0 on a clean diff (no changes), and exited 1 on changes. #4721 introduced a new feature flag to always have `cdk diff` exit 0. As is standard, the "default" for the flag was `false`, but the future behavior was `true`, meaning any new CDK project created after that release (v1.19.0) defaulted to always exiting 0. In v2, the feature flag was expired, meaning users could no longer set it. Typically, the behavior (`FeatureFlags.isEnabled`) checks and errors if an expired flag is explicitly set, and always returns true for expired flags otherwise. However, the CDK CLI helper function did not contain this functionality. That means for current v2 projects, the v1-ported default value is used (false). This means `cdk diff` *always* exits 1 when there's a diff, and there's no way for a user to disable this behavior. This change updates the CLI behavior to default to true for expired flags, same as any other feature flag check; this means `cdk diff` will return to exiting 0, as v1 apps have been doing for years. The `FeatureFlags.isEnabled` method can't be used, as it requires a Construct node. I also took the liberty of explicitly setting the "default" to true for all expired flags, so any other direct access of the flag (not using the FeatureFlag library) will have the same consistent behavior. --- packages/@aws-cdk/cx-api/lib/features.ts | 16 ++++++++-------- packages/aws-cdk/bin/cdk.ts | 5 ++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 645ca1d9fb291..70dfce119e15f 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -213,17 +213,17 @@ export const FUTURE_FLAGS_EXPIRED: string[] = [ */ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { [APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: true, - [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: false, - [ENABLE_DIFF_NO_FAIL_CONTEXT]: false, + [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: true, + [ENABLE_DIFF_NO_FAIL_CONTEXT]: true, [STACK_RELATIVE_EXPORTS_CONTEXT]: true, [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: true, - [DOCKER_IGNORE_SUPPORT]: false, - [SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME]: false, - [KMS_DEFAULT_KEY_POLICIES]: false, - [S3_GRANT_WRITE_WITHOUT_ACL]: false, - [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: false, + [DOCKER_IGNORE_SUPPORT]: true, + [SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME]: true, + [KMS_DEFAULT_KEY_POLICIES]: true, + [S3_GRANT_WRITE_WITHOUT_ACL]: true, + [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: true, [RDS_LOWERCASE_DB_IDENTIFIER]: true, - [EFS_DEFAULT_ENCRYPTION_AT_REST]: false, + [EFS_DEFAULT_ENCRYPTION_AT_REST]: true, [LAMBDA_RECOGNIZE_VERSION_PROPS]: false, [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, }; diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index 3f90dfc8ff3e2..b119907ba94e2 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -479,7 +479,10 @@ function determineV2BootstrapSource(args: { template?: string }): BootstrapSourc } function isFeatureEnabled(configuration: Configuration, featureFlag: string) { - return configuration.context.get(featureFlag) ?? cxapi.futureFlagDefault(featureFlag); + const context = configuration.context.get(featureFlag); + return cxapi.FUTURE_FLAGS_EXPIRED.includes(featureFlag) + ? true + : context ?? cxapi.futureFlagDefault(featureFlag); } /** From a1da77272fa35b9722694557a4d5bdc83e2ad834 Mon Sep 17 00:00:00 2001 From: Kaizen Conroy <36202692+kaizen3031593@users.noreply.github.com> Date: Mon, 6 Dec 2021 11:31:54 -0500 Subject: [PATCH 68/82] fix(stepfunctions): prefixes not appended to states in parallel branches (#17806) There is an order mismatch issue when calling `Parallel.branch()`. `branch` used to immediately create the state graph of the branch which locks in the `stateIds` of the branch states. This fails to take into account the following scenario: ```ts class ParallelMachineFragment extends stepfunctions.StateMachineFragment { public readonly startState: stepfunctions.State; public readonly endStates: stepfunctions.INextable[]; constructor(scope: Construct, id: string) { super(scope, id); const step1 = new stepfunctions.Pass(this, 'Step 1'); const parallelState = new stepfunctions.Parallel(this, 'Parallel State'); const chain = parallelState.branch(step1); this.startState = parallelState; this.endStates = [chain]; } } class MyStack extends Stack { constructor(scope: Construct, id: string) { const fragment1 = new ParallelMachineFragment(this, 'Fragment 1').prefixStates(); const fragment2 = new ParallelMachineFragment(this, 'Fragment 2').prefixStates(); new stepfunctions.StateMachine(stack, 'State Machine', { definition: fragment1.next(fragment2), }); } } ``` Here, the branches in the `parallelState` do not get prefixes before they are evaluated, causing an error since they have the same `stateId`. The fix is to make the state graph creation late-bound; it now happens when we call `Parallel.bindToGraph()`. At this point, it will know of any prefixes. Fixes #17354. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-stepfunctions/lib/states/parallel.ts | 17 +++++- .../test/state-machine-fragment.test.ts | 57 +++++++++++++++++++ .../test/states-language.test.ts | 7 ++- 3 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 packages/@aws-cdk/aws-stepfunctions/test/state-machine-fragment.test.ts diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/states/parallel.ts b/packages/@aws-cdk/aws-stepfunctions/lib/states/parallel.ts index 9167c7d0d0355..e565549b7a38d 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/states/parallel.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/states/parallel.ts @@ -71,6 +71,7 @@ export interface ParallelProps { */ export class Parallel extends State implements INextable { public readonly endStates: INextable[]; + private readonly _branches: IChainable[] = []; constructor(scope: Construct, id: string, props: ParallelProps = {}) { super(scope, id, props); @@ -112,11 +113,23 @@ export class Parallel extends State implements INextable { * Define one or more branches to run in parallel */ public branch(...branches: IChainable[]): Parallel { - for (const branch of branches) { + // Store branches for late-bound stategraph creation when we call bindToGraph. + this._branches.push(...branches); + return this; + } + + /** + * Overwrites State.bindToGraph. Adds branches to + * the Parallel state here so that any necessary + * prefixes are appended first. + */ + public bindToGraph(graph: StateGraph) { + for (const branch of this._branches) { const name = `Parallel '${this.stateId}' branch ${this.branches.length + 1}`; super.addBranch(new StateGraph(branch.startState, name)); } - return this; + this._branches.splice(0, this._branches.length); + return super.bindToGraph(graph); } /** diff --git a/packages/@aws-cdk/aws-stepfunctions/test/state-machine-fragment.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/state-machine-fragment.test.ts new file mode 100644 index 0000000000000..1264e41d62952 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions/test/state-machine-fragment.test.ts @@ -0,0 +1,57 @@ +import { Match, Template } from '@aws-cdk/assertions'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as stepfunctions from '../lib'; + +describe('State Machine Fragment', () => { + test('Prefix applied correctly on Fragments with Parallel states', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const fragment1 = new ParallelMachineFragment(stack, 'Fragment 1').prefixStates(); + const fragment2 = new ParallelMachineFragment(stack, 'Fragment 2').prefixStates(); + + new stepfunctions.StateMachine(stack, 'State Machine', { + definition: fragment1.next(fragment2), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::StepFunctions::StateMachine', { + DefinitionString: Match.serializedJson({ + StartAt: 'Fragment 1: Parallel State', + States: { + 'Fragment 1: Parallel State': Match.objectLike({ + Branches: [Match.objectLike({ + States: { + 'Fragment 1: Step 1': Match.anyValue(), + }, + })], + }), + 'Fragment 2: Parallel State': Match.objectLike({ + Branches: [Match.objectLike({ + States: { + 'Fragment 2: Step 1': Match.anyValue(), + }, + })], + }), + }, + }), + }); + }); +}); + +class ParallelMachineFragment extends stepfunctions.StateMachineFragment { + public readonly startState: stepfunctions.State; + public readonly endStates: stepfunctions.INextable[]; + + constructor(scope: Construct, id: string) { + super(scope, id); + + const step1 = new stepfunctions.Pass(this, 'Step 1'); + const parallelState = new stepfunctions.Parallel(this, 'Parallel State'); + const chain = parallelState.branch(step1); + this.startState = parallelState; + this.endStates = [chain]; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions/test/states-language.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/states-language.test.ts index 1ddddaae31cab..2e034bfb099a0 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/states-language.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/states-language.test.ts @@ -613,9 +613,12 @@ describe('States Language', () => { const state1 = new stepfunctions.Pass(stack, 'State1'); const state2 = new stepfunctions.Pass(stack, 'State2'); - expect(() => new stepfunctions.Parallel(stack, 'Parallel') + const parallel = new stepfunctions.Parallel(stack, 'Parallel') .branch(state1.next(state2)) - .branch(state2)).toThrow(); + .branch(state2); + + // WHEN + expect(() => render(parallel)).toThrow(); }), describe('findReachableStates', () => { From d64057f9462f8261f61795c6584d21ef56a9be34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Skrip?= Date: Mon, 6 Dec 2021 18:17:09 +0100 Subject: [PATCH 69/82] feat(core): add applyRemovalPolicy to IResource (#17746) The motivation behind this change is in both the linked issue and the added test case: change removal policy of a child resource with an interface type. Thanks @skinny85 for pointing me in the right direction. Closes #17728 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../client-vpn-authorization-rule.test.ts | 4 +++ .../@aws-cdk/aws-lambda/lib/function-base.ts | 1 + packages/@aws-cdk/core/lib/resource.ts | 13 +++++++++ packages/@aws-cdk/core/test/resource.test.ts | 29 ++++++++++++++++++- 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ec2/test/client-vpn-authorization-rule.test.ts b/packages/@aws-cdk/aws-ec2/test/client-vpn-authorization-rule.test.ts index 8570fa4fafacc..33ac16d355f15 100644 --- a/packages/@aws-cdk/aws-ec2/test/client-vpn-authorization-rule.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/client-vpn-authorization-rule.test.ts @@ -23,6 +23,7 @@ describe('ClientVpnAuthorizationRule constructor', () => { env: { account: 'myAccount', region: 'us-east-1' }, connections: new Connections(), node: stack.node, + applyRemovalPolicy: () => { }, }; new ClientVpnAuthorizationRule(stack, 'NormalRule', { cidr: '10.0.10.0/32', @@ -50,6 +51,7 @@ describe('ClientVpnAuthorizationRule constructor', () => { env: { account: 'myAccount', region: 'us-east-1' }, connections: new Connections(), node: stack.node, + applyRemovalPolicy: () => { }, }; const clientVpnEndpoint: IClientVpnEndpoint = { endpointId: 'myClientVpnEndpoint', @@ -58,6 +60,7 @@ describe('ClientVpnAuthorizationRule constructor', () => { env: { account: 'myAccount', region: 'us-east-1' }, connections: new Connections(), node: stack.node, + applyRemovalPolicy: () => { }, }; expect(() => { new ClientVpnAuthorizationRule(stack, 'RuleBothEndointAndEndpoint', { @@ -88,6 +91,7 @@ describe('ClientVpnAuthorizationRule constructor', () => { env: { account: 'myAccount', region: 'us-east-1' }, connections: new Connections(), node: stack.node, + applyRemovalPolicy: () => { }, }; new ClientVpnAuthorizationRule(stack, 'RuleWithEndointTypo', { cidr: '10.0.10.0/32', diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index 8a28f2e423657..9b231b4c802c5 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -334,6 +334,7 @@ export abstract class FunctionBase extends Resource implements IFunction, ec2.IC node: this.node, stack: this.stack, env: this.env, + applyRemovalPolicy: this.applyRemovalPolicy, }, }); this._invocationGrants[identifier] = grant; diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index afcadc6529963..cdd116afd86b9 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -58,6 +58,19 @@ export interface IResource extends IConstruct { * that might be different than the stack they were imported into. */ readonly env: ResourceEnvironment; + + /** + * Apply the given removal policy to this resource + * + * The Removal Policy controls what happens to this resource when it stops + * being managed by CloudFormation, either because you've removed it from the + * CDK application or because you've made a change that requires the resource + * to be replaced. + * + * The resource can be deleted (`RemovalPolicy.DESTROY`), or left in your AWS + * account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). + */ + applyRemovalPolicy(policy: RemovalPolicy): void; } /** diff --git a/packages/@aws-cdk/core/test/resource.test.ts b/packages/@aws-cdk/core/test/resource.test.ts index 5e46f9918c2a8..f7773fdb4540b 100644 --- a/packages/@aws-cdk/core/test/resource.test.ts +++ b/packages/@aws-cdk/core/test/resource.test.ts @@ -2,7 +2,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import { App, App as Root, CfnCondition, CfnDeletionPolicy, CfnResource, Construct, - Fn, RemovalPolicy, Resource, Stack, + Fn, IResource, RemovalPolicy, Resource, Stack, } from '../lib'; import { synthesize } from '../lib/private/synthesis'; import { toCloudFormation } from './util'; @@ -318,6 +318,33 @@ describe('resource', () => { }); + test('applyRemovalPolicy available for interface resources', () => { + class Child extends Resource { + constructor(scope: Construct, id: string) { + super(scope, id); + + new CfnResource(this, 'Resource', { + type: 'ChildResourceType', + }); + } + } + + const stack = new Stack(); + const child: IResource = new Child(stack, 'Child'); + + child.applyRemovalPolicy(RemovalPolicy.RETAIN); + + expect(toCloudFormation(stack)).toEqual({ + Resources: { + ChildDAB30558: { + DeletionPolicy: 'Retain', + Type: 'ChildResourceType', + UpdateReplacePolicy: 'Retain', + }, + }, + }); + }); + test('addDependency adds all dependencyElements of dependent constructs', () => { class C1 extends Construct { From cd8a377d90871d1f6856a2f640231f1b2ba35469 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Mon, 6 Dec 2021 18:01:49 +0000 Subject: [PATCH 70/82] chore: remove experimental badge from aws-cdk-lib README (#17827) The package was marked as stable, but this bit in the README was missed. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk-lib/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/aws-cdk-lib/README.md b/packages/aws-cdk-lib/README.md index 1de8bb1a9fb41..d08d5b4495bb6 100644 --- a/packages/aws-cdk-lib/README.md +++ b/packages/aws-cdk-lib/README.md @@ -1,7 +1,5 @@ # AWS Cloud Development Kit Library -[![experimental](http://badges.github.io/stability-badges/dist/experimental.svg)](http://github.com/badges/stability-badges) - The AWS CDK construct library provides APIs to define your CDK application and add CDK constructs to the application. From 86e77806391dc3fe8cd254fec773320cdb425dec Mon Sep 17 00:00:00 2001 From: Bryan Pan Date: Mon, 6 Dec 2021 11:07:35 -0800 Subject: [PATCH 71/82] fix(appsync): remove 'id' suffix to union definition key (#17787) Removing an unnecessary suffix from union definitions. Fixes: #17771 ---- *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-appsync/lib/schema-intermediate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts b/packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts index 6236a00ce1803..a661d4e4baf61 100644 --- a/packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts +++ b/packages/@aws-cdk/aws-appsync/lib/schema-intermediate.ts @@ -381,7 +381,7 @@ export class UnionType implements IIntermediateType { if (options.field && !(options.field.intermediateType instanceof ObjectType)) { throw new Error('Fields for Union Types must be Object Types.'); } - this.definition[options.field?.toString() + 'id'] = options.field; + this.definition[options.field.toString()] = options.field; } /** From 5737c336b3a2d7942196ffcad9291b4af6a23375 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Mon, 6 Dec 2021 20:58:10 +0100 Subject: [PATCH 72/82] fix(lambda-nodejs): bundling fails with a file dependency in `nodeModules` (#17851) If the dependency version is a `file:`, find its absolute path so that we can install it in the temporary bundling folder. Closes #17830 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/package-installation.ts | 4 +-- .../@aws-cdk/aws-lambda-nodejs/lib/util.ts | 35 ++++++++++++++----- .../test/package-installation.test.ts | 4 +-- .../aws-lambda-nodejs/test/util.test.ts | 16 +++++++++ 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/package-installation.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/package-installation.ts index 789246badcceb..66dfc0b6e9583 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/package-installation.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/package-installation.ts @@ -1,5 +1,5 @@ import { spawnSync } from 'child_process'; -import { tryGetModuleVersion } from './util'; +import { tryGetModuleVersionFromRequire } from './util'; /** * Package installation @@ -8,7 +8,7 @@ export abstract class PackageInstallation { public static detect(module: string): PackageInstallation | undefined { try { // Check local version first - const version = tryGetModuleVersion(module); + const version = tryGetModuleVersionFromRequire(module); if (version) { return { isLocal: true, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts index af24d3b4ae371..bc754185cf7a6 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts @@ -73,7 +73,7 @@ export function exec(cmd: string, args: string[], options?: SpawnSyncOptions) { /** * Returns a module version by requiring its package.json file */ -export function tryGetModuleVersion(mod: string): string | undefined { +export function tryGetModuleVersionFromRequire(mod: string): string | undefined { try { // eslint-disable-next-line @typescript-eslint/no-require-imports return require(`${mod}/package.json`).version; @@ -82,6 +82,30 @@ export function tryGetModuleVersion(mod: string): string | undefined { } } +/** + * Gets module version from package.json content + */ +export function tryGetModuleVersionFromPkg(mod: string, pkgJson: { [key: string]: any }, pkgPath: string): string | undefined { + const dependencies = { + ...pkgJson.dependencies ?? {}, + ...pkgJson.devDependencies ?? {}, + ...pkgJson.peerDependencies ?? {}, + }; + + if (!dependencies[mod]) { + return undefined; + } + + // If it's a "file:" version, make it absolute + const fileMatch = dependencies[mod].match(/file:(.+)/); + if (fileMatch && !path.isAbsolute(fileMatch[1])) { + const absoluteFilePath = path.join(path.dirname(pkgPath), fileMatch[1]); + return `file:${absoluteFilePath}`; + }; + + return dependencies[mod]; +} + /** * Extract versions for a list of modules. * @@ -94,14 +118,9 @@ export function extractDependencies(pkgPath: string, modules: string[]): { [key: // Use require for cache const pkgJson = require(pkgPath); // eslint-disable-line @typescript-eslint/no-require-imports - const pkgDependencies = { - ...pkgJson.dependencies ?? {}, - ...pkgJson.devDependencies ?? {}, - ...pkgJson.peerDependencies ?? {}, - }; - for (const mod of modules) { - const version = pkgDependencies[mod] ?? tryGetModuleVersion(mod); + const version = tryGetModuleVersionFromPkg(mod, pkgJson, pkgPath) + ?? tryGetModuleVersionFromRequire(mod); if (!version) { throw new Error(`Cannot extract version for module '${mod}'. Check that it's referenced in your package.json or installed.`); } diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/package-installation.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/package-installation.test.ts index e7afddc09fdbb..ce30fdb0bb148 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/package-installation.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/package-installation.test.ts @@ -13,7 +13,7 @@ test('detects local version', () => { }); test('checks global version if local detection fails', () => { - const getModuleVersionMock = jest.spyOn(util, 'tryGetModuleVersion').mockReturnValue(undefined); + const getModuleVersionMock = jest.spyOn(util, 'tryGetModuleVersionFromRequire').mockReturnValue(undefined); const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ status: 0, stderr: Buffer.from('stderr'), @@ -33,7 +33,7 @@ test('checks global version if local detection fails', () => { }); test('returns undefined on error', () => { - const getModuleVersionMock = jest.spyOn(util, 'tryGetModuleVersion').mockReturnValue(undefined); + const getModuleVersionMock = jest.spyOn(util, 'tryGetModuleVersionFromRequire').mockReturnValue(undefined); const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ error: new Error('bad error'), status: 0, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts index 4962ed203b31f..763a5ac499c86 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts @@ -1,4 +1,5 @@ import * as child_process from 'child_process'; +import * as fs from 'fs'; import * as path from 'path'; import { callsites, exec, extractDependencies, findUp } from '../lib/util'; @@ -119,4 +120,19 @@ describe('extractDependencies', () => { ['unknown'], )).toThrow(/Cannot extract version for module 'unknown'/); }); + + test('with file dependency', () => { + const pkgPath = path.join(__dirname, 'package-file.json'); + fs.writeFileSync(pkgPath, JSON.stringify({ + dependencies: { + 'my-module': 'file:../../core', + }, + })); + + expect(extractDependencies(pkgPath, ['my-module'])).toEqual({ + 'my-module': expect.stringMatching(/aws-cdk\/packages\/@aws-cdk\/core/), + }); + + fs.unlinkSync(pkgPath); + }); }); From 52b535bda5f26b07377fcdfca63a75c62eb5f883 Mon Sep 17 00:00:00 2001 From: Kyle Villegas <86266231+kylevillegas93@users.noreply.github.com> Date: Mon, 6 Dec 2021 14:26:16 -0700 Subject: [PATCH 73/82] fix(appsync): add caching config to AppSync resolvers (#17815) While trying to add caching config to some of my application's resolvers, I discovered that the BaseResolverProps do not include caching configuration like the CfnResolver does. This PR adds this missing caching configuration to the BaseResolverProps and adds the configuration as part of the creation of the CfnResolver. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-appsync/lib/caching-config.ts | 22 ++++ .../@aws-cdk/aws-appsync/lib/caching-key.ts | 4 + packages/@aws-cdk/aws-appsync/lib/index.ts | 2 + packages/@aws-cdk/aws-appsync/lib/resolver.ts | 25 +++- .../test/appsync-caching-config.test.ts | 109 ++++++++++++++++++ .../test/integ.api-import.expected.json | 3 + .../test/integ.appsync-lambda.expected.json | 4 + .../test/integ.auth-apikey.expected.json | 2 + .../integ.graphql-elasticsearch.expected.json | 1 + .../test/integ.graphql-iam.expected.json | 3 + .../test/integ.graphql-schema.expected.json | 2 + .../test/integ.graphql.expected.json | 24 ++++ 12 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 packages/@aws-cdk/aws-appsync/lib/caching-config.ts create mode 100644 packages/@aws-cdk/aws-appsync/lib/caching-key.ts create mode 100644 packages/@aws-cdk/aws-appsync/test/appsync-caching-config.test.ts diff --git a/packages/@aws-cdk/aws-appsync/lib/caching-config.ts b/packages/@aws-cdk/aws-appsync/lib/caching-config.ts new file mode 100644 index 0000000000000..bd189e41ee321 --- /dev/null +++ b/packages/@aws-cdk/aws-appsync/lib/caching-config.ts @@ -0,0 +1,22 @@ +import { Duration } from '@aws-cdk/core'; + +/** + * CachingConfig for AppSync resolvers + */ +export interface CachingConfig { + /** + * The caching keys for a resolver that has caching enabled. + * Valid values are entries from the $context.arguments, $context.source, and $context.identity maps. + * + * @default - No caching keys + */ + readonly cachingKeys?: string[]; + + /** + * The TTL in seconds for a resolver that has caching enabled. + * Valid values are between 1 and 3600 seconds. + * + * @default - No TTL + */ + readonly ttl?: Duration; +} diff --git a/packages/@aws-cdk/aws-appsync/lib/caching-key.ts b/packages/@aws-cdk/aws-appsync/lib/caching-key.ts new file mode 100644 index 0000000000000..a20f9e636b676 --- /dev/null +++ b/packages/@aws-cdk/aws-appsync/lib/caching-key.ts @@ -0,0 +1,4 @@ +export const CONTEXT_ARGUMENTS_CACHING_KEY = '$context.arguments'; +export const CONTEXT_SOURCE_CACHING_KEY = '$context.source'; +export const CONTEXT_IDENTITY_CACHING_KEY = '$context.identity'; +export const BASE_CACHING_KEYS = [CONTEXT_ARGUMENTS_CACHING_KEY, CONTEXT_SOURCE_CACHING_KEY, CONTEXT_IDENTITY_CACHING_KEY]; diff --git a/packages/@aws-cdk/aws-appsync/lib/index.ts b/packages/@aws-cdk/aws-appsync/lib/index.ts index 5b0f12cf75844..a102b16ac37a1 100644 --- a/packages/@aws-cdk/aws-appsync/lib/index.ts +++ b/packages/@aws-cdk/aws-appsync/lib/index.ts @@ -1,6 +1,8 @@ // AWS::AppSync CloudFormation Resources: export * from './appsync-function'; export * from './appsync.generated'; +export * from './caching-config'; +export * from './caching-key'; export * from './key'; export * from './data-source'; export * from './mapping-template'; diff --git a/packages/@aws-cdk/aws-appsync/lib/resolver.ts b/packages/@aws-cdk/aws-appsync/lib/resolver.ts index eb65a59f494fd..ea2a4a99d900a 100644 --- a/packages/@aws-cdk/aws-appsync/lib/resolver.ts +++ b/packages/@aws-cdk/aws-appsync/lib/resolver.ts @@ -1,13 +1,15 @@ import { Construct } from 'constructs'; import { IAppsyncFunction } from './appsync-function'; import { CfnResolver } from './appsync.generated'; +import { CachingConfig } from './caching-config'; +import { BASE_CACHING_KEYS } from './caching-key'; import { BaseDataSource } from './data-source'; import { IGraphqlApi } from './graphqlapi-base'; import { MappingTemplate } from './mapping-template'; // v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch. // eslint-disable-next-line -import { Construct as CoreConstruct } from '@aws-cdk/core'; +import { Construct as CoreConstruct, Token } from '@aws-cdk/core'; /** * Basic properties for an AppSync resolver @@ -40,6 +42,12 @@ export interface BaseResolverProps { * @default - No mapping template */ readonly responseMappingTemplate?: MappingTemplate; + /** + * The caching configuration for this resolver + * + * @default - No caching configuration + */ + readonly cachingConfig?: CachingConfig; } /** @@ -86,6 +94,17 @@ export class Resolver extends CoreConstruct { throw new Error(`Pipeline Resolver cannot have data source. Received: ${props.dataSource.name}`); } + if (props.cachingConfig?.ttl && (props.cachingConfig.ttl.toSeconds() < 1 || props.cachingConfig.ttl.toSeconds() > 3600)) { + throw new Error(`Caching config TTL must be between 1 and 3600 seconds. Received: ${props.cachingConfig.ttl.toSeconds()}`); + } + + if (props.cachingConfig?.cachingKeys) { + if (props.cachingConfig.cachingKeys.find(cachingKey => + !Token.isUnresolved(cachingKey) && !BASE_CACHING_KEYS.find(baseCachingKey => cachingKey.startsWith(baseCachingKey)))) { + throw new Error(`Caching config keys must begin with $context.arguments, $context.source or $context.identity. Received: ${props.cachingConfig.cachingKeys}`); + } + } + this.resolver = new CfnResolver(this, 'Resource', { apiId: props.api.apiId, typeName: props.typeName, @@ -95,6 +114,10 @@ export class Resolver extends CoreConstruct { pipelineConfig: pipelineConfig, requestMappingTemplate: props.requestMappingTemplate ? props.requestMappingTemplate.renderTemplate() : undefined, responseMappingTemplate: props.responseMappingTemplate ? props.responseMappingTemplate.renderTemplate() : undefined, + cachingConfig: { + cachingKeys: props.cachingConfig?.cachingKeys, + ttl: props.cachingConfig?.ttl?.toSeconds(), + }, }); props.api.addSchemaDependency(this.resolver); if (props.dataSource) { diff --git a/packages/@aws-cdk/aws-appsync/test/appsync-caching-config.test.ts b/packages/@aws-cdk/aws-appsync/test/appsync-caching-config.test.ts new file mode 100644 index 0000000000000..716dfb9d1bba6 --- /dev/null +++ b/packages/@aws-cdk/aws-appsync/test/appsync-caching-config.test.ts @@ -0,0 +1,109 @@ +import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import { Duration } from '@aws-cdk/core'; +import * as appsync from '../lib'; + +let stack: cdk.Stack; +let api: appsync.GraphqlApi; + +beforeEach(() => { + // GIVEN + stack = new cdk.Stack(); + api = new appsync.GraphqlApi(stack, 'api', { + name: 'api', + schema: appsync.Schema.fromAsset(path.join(__dirname, 'appsync.lambda.graphql')), + }); +}); + +describe('Lambda caching config', () => { + // GIVEN + let func: lambda.Function; + + beforeEach(() => { + func = new lambda.Function(stack, 'func', { + code: lambda.Code.fromAsset(path.join(__dirname, 'verify/lambda-tutorial')), + handler: 'lambda-tutorial.handler', + runtime: lambda.Runtime.NODEJS_12_X, + }); + }); + + test('Lambda resolver contains caching config with caching key and TTL', () => { + // WHEN + const lambdaDS = api.addLambdaDataSource('LambdaDS', func); + + lambdaDS.createResolver({ + typeName: 'Query', + fieldName: 'allPosts', + cachingConfig: { + cachingKeys: ['$context.arguments', '$context.source', '$context.identity'], + ttl: Duration.seconds(300), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppSync::Resolver', { + TypeName: 'Query', + FieldName: 'allPosts', + CachingConfig: { + CachingKeys: ['$context.arguments', '$context.source', '$context.identity'], + Ttl: 300, + }, + }); + }); + + test('Lambda resolver throws error when caching config with TTL is less than 1 second', () => { + // WHEN + const ttlInSconds = 0; + const lambdaDS = api.addLambdaDataSource('LambdaDS', func); + + // THEN + expect(() => { + lambdaDS.createResolver({ + typeName: 'Query', + fieldName: 'allPosts', + cachingConfig: { + cachingKeys: ['$context.identity'], + ttl: Duration.seconds(0), + }, + }); + }).toThrowError(`Caching config TTL must be between 1 and 3600 seconds. Received: ${ttlInSconds}`); + }); + + test('Lambda resolver throws error when caching config with TTL is greater than 3600 seconds', () => { + // WHEN + const ttlInSconds = 4200; + const lambdaDS = api.addLambdaDataSource('LambdaDS', func); + + // THEN + expect(() => { + lambdaDS.createResolver({ + typeName: 'Query', + fieldName: 'allPosts', + cachingConfig: { + cachingKeys: ['$context.identity'], + ttl: Duration.seconds(ttlInSconds), + }, + }); + }).toThrowError(`Caching config TTL must be between 1 and 3600 seconds. Received: ${ttlInSconds}`); + }); + + test('Lambda resolver throws error when caching config has invalid caching keys', () => { + // WHEN + const invalidCachingKeys = ['$context.metadata']; + const lambdaDS = api.addLambdaDataSource('LambdaDS', func); + + // THEN + expect(() => { + lambdaDS.createResolver({ + typeName: 'Query', + fieldName: 'allPosts', + cachingConfig: { + cachingKeys: invalidCachingKeys, + ttl: Duration.seconds(300), + }, + }); + }).toThrowError(`Caching config keys must begin with $context.arguments, $context.source or $context.identity. Received: ${invalidCachingKeys}`); + }); +}); diff --git a/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json index e4b54f04116fc..844eca96cfb86 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json @@ -143,6 +143,7 @@ }, "FieldName": "getTests", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "ds", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Scan\"}", @@ -160,6 +161,7 @@ }, "FieldName": "addTest", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "ds", "Kind": "UNIT", "RequestMappingTemplate": "\n #set($input = $ctx.args.test)\n \n {\n \"version\": \"2017-02-28\",\n \"operation\": \"PutItem\",\n \"key\" : {\n \"id\" : $util.dynamodb.toDynamoDBJson($util.autoId())\n },\n \"attributeValues\": $util.dynamodb.toMapValuesJson($input)\n }", @@ -223,6 +225,7 @@ }, "FieldName": "version", "TypeName": "test", + "CachingConfig": {}, "Kind": "PIPELINE", "PipelineConfig": { "Functions": [ diff --git a/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json index f4bd20a97d90e..157cde0ccdced 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.expected.json @@ -114,6 +114,7 @@ }, "FieldName": "getPost", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "LambdaDS", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\": \"2017-02-28\", \"operation\": \"Invoke\", \"payload\": { \"field\": \"getPost\", \"arguments\": $utils.toJson($context.arguments)}}", @@ -135,6 +136,7 @@ }, "FieldName": "allPosts", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "LambdaDS", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\": \"2017-02-28\", \"operation\": \"Invoke\", \"payload\": { \"field\": \"allPosts\"}}", @@ -156,6 +158,7 @@ }, "FieldName": "addPost", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "LambdaDS", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\": \"2017-02-28\", \"operation\": \"Invoke\", \"payload\": { \"field\": \"addPost\", \"arguments\": $utils.toJson($context.arguments)}}", @@ -177,6 +180,7 @@ }, "FieldName": "relatedPosts", "TypeName": "Post", + "CachingConfig": {}, "DataSourceName": "LambdaDS", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\": \"2017-02-28\", \"operation\": \"BatchInvoke\", \"payload\": { \"field\": \"relatedPosts\", \"source\": $utils.toJson($context.source)}}", diff --git a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json index ed0307de0e72f..68ec8c15d8ad3 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json @@ -132,6 +132,7 @@ }, "FieldName": "getTests", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "testDataSource", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Scan\"}", @@ -153,6 +154,7 @@ }, "FieldName": "addTest", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "testDataSource", "Kind": "UNIT", "RequestMappingTemplate": "\n #set($input = $ctx.args.test)\n \n {\n \"version\": \"2017-02-28\",\n \"operation\": \"PutItem\",\n \"key\" : {\n \"id\" : $util.dynamodb.toDynamoDBJson($util.autoId())\n },\n \"attributeValues\": $util.dynamodb.toMapValuesJson($input)\n }", diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.expected.json index 22e64957700e9..c0a78de80a219 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-elasticsearch.expected.json @@ -196,6 +196,7 @@ }, "FieldName": "getTests", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "ds", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\":\"2017-02-28\",\"operation\":\"GET\",\"path\":\"/id/post/_search\",\"params\":{\"headers\":{},\"queryString\":{},\"body\":{\"from\":0,\"size\":50}}}", diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json index 374a89dc33d14..268ca24ae7d13 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json @@ -163,6 +163,7 @@ }, "FieldName": "getTest", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "testDataSource", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\": \"2017-02-28\", \"operation\": \"GetItem\", \"key\": {\"id\": $util.dynamodb.toDynamoDBJson($ctx.args.id)}}", @@ -184,6 +185,7 @@ }, "FieldName": "getTests", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "testDataSource", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Scan\"}", @@ -205,6 +207,7 @@ }, "FieldName": "addTest", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "testDataSource", "Kind": "UNIT", "RequestMappingTemplate": "\n #set($input = $ctx.args.test)\n \n {\n \"version\": \"2017-02-28\",\n \"operation\": \"PutItem\",\n \"key\" : {\n \"id\" : $util.dynamodb.toDynamoDBJson($util.autoId())\n },\n \"attributeValues\": $util.dynamodb.toMapValuesJson($input)\n }", diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json index a6e5ff5764331..9cccc3b45ef44 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json @@ -131,6 +131,7 @@ }, "FieldName": "getPlanets", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "planets", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Scan\"}", @@ -152,6 +153,7 @@ }, "FieldName": "addPlanet", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "planets", "Kind": "UNIT", "RequestMappingTemplate": "\n #set($input = $context.arguments)\n $util.qr($input.put(\"name\", $context.arguments.name))\n$util.qr($input.put(\"diameter\", $context.arguments.diameter))\n$util.qr($input.put(\"rotationPeriod\", $context.arguments.rotationPeriod))\n$util.qr($input.put(\"orbitalPeriod\", $context.arguments.orbitalPeriod))\n$util.qr($input.put(\"gravityPeriod\", $context.arguments.gravity))\n$util.qr($input.put(\"population\", $context.arguments.population))\n$util.qr($input.put(\"climates\", $context.arguments.climates))\n$util.qr($input.put(\"terrains\", $context.arguments.terrains))\n$util.qr($input.put(\"surfaceWater\", $context.arguments.surfaceWater))\n {\n \"version\": \"2017-02-28\",\n \"operation\": \"PutItem\",\n \"key\" : {\n \"id\" : $util.dynamodb.toDynamoDBJson($util.autoId())\n },\n \"attributeValues\": $util.dynamodb.toMapValuesJson($input)\n }", diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json index 6f9fd9c12d899..a6acba469e336 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json @@ -103,6 +103,7 @@ }, "FieldName": "getServiceVersion", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "None", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\":\"2017-02-28\"}", @@ -211,6 +212,7 @@ }, "FieldName": "getCustomers", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Customer", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Scan\"}", @@ -232,6 +234,7 @@ }, "FieldName": "getCustomer", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Customer", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\": \"2017-02-28\", \"operation\": \"GetItem\", \"key\": {\"id\": $util.dynamodb.toDynamoDBJson($ctx.args.id)}}", @@ -253,6 +256,7 @@ }, "FieldName": "addCustomer", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "Customer", "Kind": "UNIT", "RequestMappingTemplate": "\n #set($input = $ctx.args.customer)\n \n {\n \"version\": \"2017-02-28\",\n \"operation\": \"PutItem\",\n \"key\" : {\n \"id\" : $util.dynamodb.toDynamoDBJson($util.autoId())\n },\n \"attributeValues\": $util.dynamodb.toMapValuesJson($input)\n }", @@ -274,6 +278,7 @@ }, "FieldName": "saveCustomer", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "Customer", "Kind": "UNIT", "RequestMappingTemplate": "\n #set($input = $ctx.args.customer)\n \n {\n \"version\": \"2017-02-28\",\n \"operation\": \"PutItem\",\n \"key\" : {\n \"id\" : $util.dynamodb.toDynamoDBJson($ctx.args.id)\n },\n \"attributeValues\": $util.dynamodb.toMapValuesJson($input)\n }", @@ -295,6 +300,7 @@ }, "FieldName": "saveCustomerWithFirstOrder", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "Customer", "Kind": "UNIT", "RequestMappingTemplate": "\n #set($input = $ctx.args.order)\n $util.qr($input.put(\"referral\", referral))\n {\n \"version\": \"2017-02-28\",\n \"operation\": \"PutItem\",\n \"key\" : {\n \"order\" : $util.dynamodb.toDynamoDBJson($util.autoId()),\"customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer.id)\n },\n \"attributeValues\": $util.dynamodb.toMapValuesJson($input)\n }", @@ -316,6 +322,7 @@ }, "FieldName": "removeCustomer", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "Customer", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\": \"2017-02-28\", \"operation\": \"DeleteItem\", \"key\": {\"id\": $util.dynamodb.toDynamoDBJson($ctx.args.id)}}", @@ -435,6 +442,7 @@ }, "FieldName": "getCustomerOrdersEq", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"query\" : {\n \"expression\" : \"#customer = :customer\",\n \"expressionNames\" : {\n \"#customer\" : \"customer\"\n },\n \"expressionValues\" : {\n \":customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer)\n }\n }}", @@ -456,6 +464,7 @@ }, "FieldName": "getOrderCustomersEq", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"index\" : \"orderIndex\", \"query\" : {\n \"expression\" : \"#order = :order\",\n \"expressionNames\" : {\n \"#order\" : \"order\"\n },\n \"expressionValues\" : {\n \":order\" : $util.dynamodb.toDynamoDBJson($ctx.args.order)\n }\n }}", @@ -477,6 +486,7 @@ }, "FieldName": "getCustomerOrdersLt", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"query\" : {\n \"expression\" : \"#customer < :customer\",\n \"expressionNames\" : {\n \"#customer\" : \"customer\"\n },\n \"expressionValues\" : {\n \":customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer)\n }\n }}", @@ -498,6 +508,7 @@ }, "FieldName": "getOrderCustomersLt", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"index\" : \"orderIndex\", \"query\" : {\n \"expression\" : \"#order < :order\",\n \"expressionNames\" : {\n \"#order\" : \"order\"\n },\n \"expressionValues\" : {\n \":order\" : $util.dynamodb.toDynamoDBJson($ctx.args.order)\n }\n }}", @@ -519,6 +530,7 @@ }, "FieldName": "getCustomerOrdersLe", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"query\" : {\n \"expression\" : \"#customer <= :customer\",\n \"expressionNames\" : {\n \"#customer\" : \"customer\"\n },\n \"expressionValues\" : {\n \":customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer)\n }\n }}", @@ -540,6 +552,7 @@ }, "FieldName": "getOrderCustomersLe", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"index\" : \"orderIndex\", \"query\" : {\n \"expression\" : \"#order <= :order\",\n \"expressionNames\" : {\n \"#order\" : \"order\"\n },\n \"expressionValues\" : {\n \":order\" : $util.dynamodb.toDynamoDBJson($ctx.args.order)\n }\n }}", @@ -561,6 +574,7 @@ }, "FieldName": "getCustomerOrdersGt", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"query\" : {\n \"expression\" : \"#customer > :customer\",\n \"expressionNames\" : {\n \"#customer\" : \"customer\"\n },\n \"expressionValues\" : {\n \":customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer)\n }\n }}", @@ -582,6 +596,7 @@ }, "FieldName": "getOrderCustomersGt", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"index\" : \"orderIndex\", \"query\" : {\n \"expression\" : \"#order > :order\",\n \"expressionNames\" : {\n \"#order\" : \"order\"\n },\n \"expressionValues\" : {\n \":order\" : $util.dynamodb.toDynamoDBJson($ctx.args.order)\n }\n }}", @@ -603,6 +618,7 @@ }, "FieldName": "getCustomerOrdersGe", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"query\" : {\n \"expression\" : \"#customer >= :customer\",\n \"expressionNames\" : {\n \"#customer\" : \"customer\"\n },\n \"expressionValues\" : {\n \":customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer)\n }\n }}", @@ -624,6 +640,7 @@ }, "FieldName": "getOrderCustomersGe", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"index\" : \"orderIndex\", \"query\" : {\n \"expression\" : \"#order >= :order\",\n \"expressionNames\" : {\n \"#order\" : \"order\"\n },\n \"expressionValues\" : {\n \":order\" : $util.dynamodb.toDynamoDBJson($ctx.args.order)\n }\n }}", @@ -645,6 +662,7 @@ }, "FieldName": "getCustomerOrdersFilter", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"query\" : {\n \"expression\" : \"#customer = :customer AND begins_with(#order, :order)\",\n \"expressionNames\" : {\n \"#customer\" : \"customer\", \"#order\" : \"order\"\n },\n \"expressionValues\" : {\n \":customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer), \":order\" : $util.dynamodb.toDynamoDBJson($ctx.args.order)\n }\n }}", @@ -666,6 +684,7 @@ }, "FieldName": "getCustomerOrdersBetween", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"query\" : {\n \"expression\" : \"#customer = :customer AND #order BETWEEN :order1 AND :order2\",\n \"expressionNames\" : {\n \"#customer\" : \"customer\", \"#order\" : \"order\"\n },\n \"expressionValues\" : {\n \":customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer), \":order1\" : $util.dynamodb.toDynamoDBJson($ctx.args.order1), \":order2\" : $util.dynamodb.toDynamoDBJson($ctx.args.order2)\n }\n }}", @@ -687,6 +706,7 @@ }, "FieldName": "getOrderCustomersFilter", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"query\" : {\n \"expression\" : \"#order = :order AND begins_with(#customer, :customer)\",\n \"expressionNames\" : {\n \"#order\" : \"order\", \"#customer\" : \"customer\"\n },\n \"expressionValues\" : {\n \":order\" : $util.dynamodb.toDynamoDBJson($ctx.args.order), \":customer\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer)\n }\n }}", @@ -708,6 +728,7 @@ }, "FieldName": "getOrderCustomersBetween", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Order", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\" : \"2017-02-28\", \"operation\" : \"Query\", \"index\" : \"orderIndex\", \"query\" : {\n \"expression\" : \"#order = :order AND #customer BETWEEN :customer1 AND :customer2\",\n \"expressionNames\" : {\n \"#order\" : \"order\", \"#customer\" : \"customer\"\n },\n \"expressionValues\" : {\n \":order\" : $util.dynamodb.toDynamoDBJson($ctx.args.order), \":customer1\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer1), \":customer2\" : $util.dynamodb.toDynamoDBJson($ctx.args.customer2)\n }\n }}", @@ -828,6 +849,7 @@ }, "FieldName": "getPayment", "TypeName": "Query", + "CachingConfig": {}, "DataSourceName": "Payment", "Kind": "UNIT", "RequestMappingTemplate": "{\"version\": \"2017-02-28\", \"operation\": \"GetItem\", \"key\": {\"id\": $util.dynamodb.toDynamoDBJson($ctx.args.id)}}", @@ -849,6 +871,7 @@ }, "FieldName": "savePayment", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "Payment", "Kind": "UNIT", "RequestMappingTemplate": "\n #set($input = $ctx.args.payment)\n \n {\n \"version\": \"2017-02-28\",\n \"operation\": \"PutItem\",\n \"key\" : {\n \"id\" : $util.dynamodb.toDynamoDBJson($util.autoId())\n },\n \"attributeValues\": $util.dynamodb.toMapValuesJson($input)\n }", @@ -909,6 +932,7 @@ }, "FieldName": "doPostOnAws", "TypeName": "Mutation", + "CachingConfig": {}, "DataSourceName": "http", "Kind": "UNIT", "RequestMappingTemplate": "{\n \"version\": \"2018-05-29\",\n \"method\": \"POST\",\n # if full path is https://api.xxxxxxxxx.com/posts then resourcePath would be /posts\n \"resourcePath\": \"/path/123\",\n \"params\":{\n \"body\": $util.toJson($ctx.args),\n \"headers\":{\n \"Content-Type\": \"application/json\",\n \"Authorization\": \"$ctx.request.headers.Authorization\"\n }\n }\n }", From 8e3269b11ae013c74fd46046697ebd4d647bb7ed Mon Sep 17 00:00:00 2001 From: Kaizen Conroy <36202692+kaizen3031593@users.noreply.github.com> Date: Mon, 6 Dec 2021 18:06:17 -0500 Subject: [PATCH 74/82] chore(lambda): fix doc typo in `permissions` (#17870) Closes #17567. ---- *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-lambda/lib/permission.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/permission.ts b/packages/@aws-cdk/aws-lambda/lib/permission.ts index 65264d0c96a7f..a4ca4ef3d1e7f 100644 --- a/packages/@aws-cdk/aws-lambda/lib/permission.ts +++ b/packages/@aws-cdk/aws-lambda/lib/permission.ts @@ -2,8 +2,8 @@ import * as iam from '@aws-cdk/aws-iam'; import { Construct } from '@aws-cdk/core'; /** - * Represents a permission statement that can be added to a Lambda's resource policy - * via the `addToResourcePolicy` method. + * Represents a permission statement that can be added to a Lambda function's + * resource policy via the `addPermissions()` method. */ export interface Permission { /** From 927142558257f21c54709ed8b8a14795fc3b3be7 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 7 Dec 2021 11:16:05 +0100 Subject: [PATCH 75/82] chore(assertions): rename `finalize` to `finished` (#17880) `finalize` is a magic member function in Java, and we cannot just call any method `finalize`. The presence of this member causes pack failures. See https://github.com/aws/jsii/issues/3237 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/assertions/lib/matcher.ts | 4 +-- .../assertions/lib/private/section.ts | 4 +-- .../@aws-cdk/assertions/test/capture.test.ts | 34 +++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/@aws-cdk/assertions/lib/matcher.ts b/packages/@aws-cdk/assertions/lib/matcher.ts index 4ddf9320b492a..da345fcbd1932 100644 --- a/packages/@aws-cdk/assertions/lib/matcher.ts +++ b/packages/@aws-cdk/assertions/lib/matcher.ts @@ -125,7 +125,7 @@ export class MatchResult { * Prepare the result to be analyzed. * This API *must* be called prior to analyzing these results. */ - public finalize(): this { + public finished(): this { if (this.finalized) { return this; } @@ -158,4 +158,4 @@ export class MatchResult { values.push(options.value); this.captures.set(options.capture, values); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/assertions/lib/private/section.ts b/packages/@aws-cdk/assertions/lib/private/section.ts index 64e61191de2ec..d2dd96800da08 100644 --- a/packages/@aws-cdk/assertions/lib/private/section.ts +++ b/packages/@aws-cdk/assertions/lib/private/section.ts @@ -15,7 +15,7 @@ export function matchSection(section: any, props: any): MatchSuccess | MatchFail (logicalId, entry) => { const result = matcher.test(entry); - result.finalize(); + result.finished(); if (!result.hasFailed()) { matching[logicalId] = entry; } else { @@ -64,4 +64,4 @@ export function filterLogicalId(section: { [key: string]: {} }, logicalId: strin return Object.entries(section ?? {}) .filter(([k, _]) => k === logicalId) .reduce((agg, [k, v]) => { return { ...agg, [k]: v }; }, {}); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/assertions/test/capture.test.ts b/packages/@aws-cdk/assertions/test/capture.test.ts index 7fe30742e15aa..27f8f91d1c3d0 100644 --- a/packages/@aws-cdk/assertions/test/capture.test.ts +++ b/packages/@aws-cdk/assertions/test/capture.test.ts @@ -15,11 +15,11 @@ describe('Capture', () => { expect(result.toHumanStrings()[0]).toMatch(/Can only capture non-nullish values/); }); - test('no captures if not finalized', () => { + test('no captures if not finished', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: 'bar' }); // Not calling finalize() + matcher.test({ foo: 'bar' }); // Not calling finished() expect(() => capture.asString()).toThrow(/No value captured/); }); @@ -27,8 +27,8 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: 'bar' }).finalize(); - matcher.test({ foo: 3 }).finalize(); + matcher.test({ foo: 'bar' }).finished(); + matcher.test({ foo: 3 }).finished(); expect(capture.asString()).toEqual('bar'); expect(capture.next()).toEqual(true); @@ -39,8 +39,8 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: 3 }).finalize(); - matcher.test({ foo: 'bar' }).finalize(); + matcher.test({ foo: 3 }).finished(); + matcher.test({ foo: 'bar' }).finished(); expect(capture.asNumber()).toEqual(3); expect(capture.next()).toEqual(true); @@ -51,8 +51,8 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: ['bar'] }).finalize(); - matcher.test({ foo: 'bar' }).finalize(); + matcher.test({ foo: ['bar'] }).finished(); + matcher.test({ foo: 'bar' }).finished(); expect(capture.asArray()).toEqual(['bar']); expect(capture.next()).toEqual(true); @@ -63,8 +63,8 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture }); - matcher.test({ foo: { fred: 'waldo' } }).finalize(); - matcher.test({ foo: 'bar' }).finalize(); + matcher.test({ foo: { fred: 'waldo' } }).finished(); + matcher.test({ foo: 'bar' }).finished(); expect(capture.asObject()).toEqual({ fred: 'waldo' }); expect(capture.next()).toEqual(true); @@ -75,7 +75,7 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: ['bar', capture] }); - matcher.test({ foo: ['bar', 'baz'] }).finalize(); + matcher.test({ foo: ['bar', 'baz'] }).finished(); expect(capture.asString()).toEqual('baz'); }); @@ -83,9 +83,9 @@ describe('Capture', () => { const capture = new Capture(); const matcher = Match.objectEquals({ foo: capture, real: true }); - matcher.test({ foo: 3, real: true }).finalize(); - matcher.test({ foo: 5, real: true }).finalize(); - matcher.test({ foo: 7, real: false }).finalize(); + matcher.test({ foo: 3, real: true }).finished(); + matcher.test({ foo: 5, real: true }).finished(); + matcher.test({ foo: 7, real: false }).finished(); expect(capture.asNumber()).toEqual(3); expect(capture.next()).toEqual(true); @@ -102,7 +102,7 @@ describe('Capture', () => { bar: 'baz', fred: 'waldo', }, - }).finalize(); + }).finished(); expect(capture.asObject()).toEqual({ bar: 'baz', fred: 'waldo' }); expect(capture.next()).toEqual(false); @@ -116,8 +116,8 @@ describe('Capture', () => { foo: { fred: 'waldo', }, - }).finalize(); + }).finished(); expect(() => capture.asObject()).toThrow(/No value captured/); }); -}); \ No newline at end of file +}); From 7fb639af1d9fa3c0d910df6d3af21aac6aaff5eb Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Tue, 7 Dec 2021 11:29:21 +0000 Subject: [PATCH 76/82] fix(ecs-patterns): removeDefaultDesiredCount feature flag not expired properly (#17865) The `@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount` feature flag was expired as part of V2; however, the way the feature flag was accessed meant that the flag wasn't handled the same way all other expired flags were, leading to the incorrect behavior. This fixes the access and evaluation of the flag to match intended behavior, and updates the tests appropriately. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/base/queue-processing-service-base.ts | 4 ++-- .../application-load-balanced-ecs-service.ts | 3 ++- ...tion-multiple-target-groups-ecs-service.ts | 3 ++- .../ecs/network-load-balanced-ecs-service.ts | 3 ++- ...work-multiple-target-groups-ecs-service.ts | 3 ++- .../lib/ecs/queue-processing-ecs-service.ts | 3 ++- ...plication-load-balanced-fargate-service.ts | 3 ++- ...-multiple-target-groups-fargate-service.ts | 3 ++- .../network-load-balanced-fargate-service.ts | 3 ++- ...-multiple-target-groups-fargate-service.ts | 3 ++- .../queue-processing-fargate-service.ts | 3 ++- ...on-load-balanced-ecs-service.expected.json | 1 - .../aws-ecs-patterns/test/ec2/l3s-v2.test.ts | 2 -- .../aws-ecs-patterns/test/ec2/l3s.test.ts | 19 +++++++++---------- .../ec2/queue-processing-ecs-service.test.ts | 14 +++++--------- ...eg.alb-fargate-service-https.expected.json | 3 +-- .../fargate/integ.asset-image.expected.json | 3 +-- ...oad-balanced-fargate-service.expected.json | 3 +-- ...e-processing-fargate-service.expected.json | 3 +-- .../fargate/integ.executionrole.expected.json | 3 +-- .../fargate/integ.l3-autocreate.expected.json | 4 +--- .../fargate/integ.l3-vpconly.expected.json | 2 -- .../test/fargate/integ.l3.expected.json | 4 +--- ...oad-balanced-fargate-service.expected.json | 1 - ...ing-fargate-service-isolated.expected.json | 3 +-- ...ssing-fargate-service-public.expected.json | 3 +-- ...e-processing-fargate-service.expected.json | 1 - .../integ.special-listener.expected.json | 2 -- .../load-balanced-fargate-service-v2.test.ts | 3 --- .../queue-processing-fargate-service.test.ts | 14 +++++--------- .../test/integ.alb-target.expected.json | 1 - 31 files changed, 50 insertions(+), 73 deletions(-) diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts index 8e380e2612232..9c26567978f5d 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts @@ -5,7 +5,7 @@ import { ICluster, LogDriver, PropagatedTagSource, Secret, } from '@aws-cdk/aws-ecs'; import { IQueue, Queue } from '@aws-cdk/aws-sqs'; -import { CfnOutput, Duration, Stack } from '@aws-cdk/core'; +import { CfnOutput, Duration, FeatureFlags, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; @@ -315,7 +315,7 @@ export abstract class QueueProcessingServiceBase extends Construct { this.desiredCount = props.desiredTaskCount ?? 1; // Determine the desired task count (minimum) and maximum scaling capacity - if (!this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT)) { + if (!FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT)) { this.minCapacity = props.minScalingCapacity ?? this.desiredCount; this.maxCapacity = props.maxScalingCapacity || (2 * this.desiredCount); } else { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts index 6d1809a68d18b..352bdf6dcd874 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts @@ -1,4 +1,5 @@ import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { ApplicationLoadBalancedServiceBase, ApplicationLoadBalancedServiceBaseProps } from '../base/application-load-balanced-service-base'; @@ -119,7 +120,7 @@ export class ApplicationLoadBalancedEc2Service extends ApplicationLoadBalancedSe throw new Error('You must specify one of: taskDefinition or image'); } - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; this.service = new Ec2Service(this, 'Service', { cluster: this.cluster, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-multiple-target-groups-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-multiple-target-groups-ecs-service.ts index f77e7e4dccdc3..c84518094662a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-multiple-target-groups-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-multiple-target-groups-ecs-service.ts @@ -1,5 +1,6 @@ import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; import { ApplicationTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { @@ -138,7 +139,7 @@ export class ApplicationMultipleTargetGroupsEc2Service extends ApplicationMultip } private createEc2Service(props: ApplicationMultipleTargetGroupsEc2ServiceProps): Ec2Service { - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; return new Ec2Service(this, 'Service', { cluster: this.cluster, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts index b8862dfbed338..451731dadc626 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts @@ -1,4 +1,5 @@ import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { NetworkLoadBalancedServiceBase, NetworkLoadBalancedServiceBaseProps } from '../base/network-load-balanced-service-base'; @@ -117,7 +118,7 @@ export class NetworkLoadBalancedEc2Service extends NetworkLoadBalancedServiceBas throw new Error('You must specify one of: taskDefinition or image'); } - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; this.service = new Ec2Service(this, 'Service', { cluster: this.cluster, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-multiple-target-groups-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-multiple-target-groups-ecs-service.ts index 12d5b25ce67fd..331cd40490517 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-multiple-target-groups-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-multiple-target-groups-ecs-service.ts @@ -1,5 +1,6 @@ import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; import { NetworkTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { @@ -138,7 +139,7 @@ export class NetworkMultipleTargetGroupsEc2Service extends NetworkMultipleTarget } private createEc2Service(props: NetworkMultipleTargetGroupsEc2ServiceProps): Ec2Service { - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; return new Ec2Service(this, 'Service', { cluster: this.cluster, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts index 0d9f612abfb76..e6042a66ea112 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts @@ -1,4 +1,5 @@ import { Ec2Service, Ec2TaskDefinition } from '@aws-cdk/aws-ecs'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { QueueProcessingServiceBase, QueueProcessingServiceBaseProps } from '../base/queue-processing-service-base'; @@ -108,7 +109,7 @@ export class QueueProcessingEc2Service extends QueueProcessingServiceBase { }); // The desiredCount should be removed from the fargate service when the feature flag is removed. - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? undefined : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? undefined : this.desiredCount; // Create an ECS service with the previously defined Task Definition and configure // autoscaling based on cpu utilization and number of messages visible in the SQS queue. diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts index 81f243f4a6fa6..80b6ceac06ae2 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts @@ -1,5 +1,6 @@ import { ISecurityGroup, SubnetSelection } from '@aws-cdk/aws-ec2'; import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { ApplicationLoadBalancedServiceBase, ApplicationLoadBalancedServiceBaseProps } from '../base/application-load-balanced-service-base'; @@ -155,7 +156,7 @@ export class ApplicationLoadBalancedFargateService extends ApplicationLoadBalanc throw new Error('You must specify one of: taskDefinition or image'); } - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; this.service = new FargateService(this, 'Service', { cluster: this.cluster, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-multiple-target-groups-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-multiple-target-groups-fargate-service.ts index 8052e0483b16a..c092c4d1ee111 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-multiple-target-groups-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-multiple-target-groups-fargate-service.ts @@ -1,5 +1,6 @@ import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { ApplicationTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { @@ -170,7 +171,7 @@ export class ApplicationMultipleTargetGroupsFargateService extends ApplicationMu } private createFargateService(props: ApplicationMultipleTargetGroupsFargateServiceProps): FargateService { - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; return new FargateService(this, 'Service', { cluster: this.cluster, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts index 9095be5cf2cd1..1f6c924205979 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts @@ -1,5 +1,6 @@ import { SubnetSelection } from '@aws-cdk/aws-ec2'; import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { NetworkLoadBalancedServiceBase, NetworkLoadBalancedServiceBaseProps } from '../base/network-load-balanced-service-base'; @@ -142,7 +143,7 @@ export class NetworkLoadBalancedFargateService extends NetworkLoadBalancedServic throw new Error('You must specify one of: taskDefinition or image'); } - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; this.service = new FargateService(this, 'Service', { cluster: this.cluster, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-multiple-target-groups-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-multiple-target-groups-fargate-service.ts index 1a185f642a558..37dde3a851757 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-multiple-target-groups-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-multiple-target-groups-fargate-service.ts @@ -1,5 +1,6 @@ import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { NetworkTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { @@ -170,7 +171,7 @@ export class NetworkMultipleTargetGroupsFargateService extends NetworkMultipleTa } private createFargateService(props: NetworkMultipleTargetGroupsFargateServiceProps): FargateService { - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? this.internalDesiredCount : this.desiredCount; return new FargateService(this, 'Service', { cluster: this.cluster, 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 033d19dc39612..21fbb4a59bd39 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,5 +1,6 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; +import { FeatureFlags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; import { QueueProcessingServiceBase, QueueProcessingServiceBaseProps } from '../base/queue-processing-service-base'; @@ -130,7 +131,7 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase { }); // The desiredCount should be removed from the fargate service when the feature flag is removed. - const desiredCount = this.node.tryGetContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? undefined : this.desiredCount; + const desiredCount = FeatureFlags.of(this).isEnabled(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT) ? undefined : this.desiredCount; // Create a Fargate service with the previously defined Task Definition and configure // autoscaling based on cpu utilization and number of messages visible in the SQS queue. diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json index 545757b15c65c..2364b79c8b0b5 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json @@ -1142,7 +1142,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "EC2", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts index 767c7a13f0df6..3681b7ab3e52d 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts @@ -47,7 +47,6 @@ describe('When Application Load Balancer', () => { expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'EC2', }); @@ -929,7 +928,6 @@ describe('When Network Load Balancer', () => { expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'EC2', }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts index c8f29cfbc695c..004b9c4dc4fd7 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts @@ -9,6 +9,7 @@ import { AsgCapacityProvider } from '@aws-cdk/aws-ecs'; import { ApplicationLoadBalancer, ApplicationProtocol, ApplicationProtocolVersion, NetworkLoadBalancer, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; import { PublicHostedZone } from '@aws-cdk/aws-route53'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; +import { testLegacyBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import * as ecsPatterns from '../../lib'; @@ -72,9 +73,9 @@ test('test ECS loadbalanced construct', () => { }); }); -test('ApplicationLoadBalancedEc2Service desiredCount can be undefined when feature flag is set', () => { +testLegacyBehavior('ApplicationLoadBalancedEc2Service desiredCount can be undefined when feature flag is set', cdk.App, (app) => { // GIVEN - const stack = new cdk.Stack(); + const stack = new cdk.Stack(app); stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -101,9 +102,9 @@ test('ApplicationLoadBalancedEc2Service desiredCount can be undefined when featu }); }); -test('ApplicationLoadBalancedFargateService desiredCount can be undefined when feature flag is set', () => { +testLegacyBehavior('ApplicationLoadBalancedFargateService desiredCount can be undefined when feature flag is set', cdk.App, (app) => { // GIVEN - const stack = new cdk.Stack(); + const stack = new cdk.Stack(app); stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -122,9 +123,9 @@ test('ApplicationLoadBalancedFargateService desiredCount can be undefined when f }); }); -test('NetworkLoadBalancedEc2Service desiredCount can be undefined when feature flag is set', () => { +testLegacyBehavior('NetworkLoadBalancedEc2Service desiredCount can be undefined when feature flag is set', cdk.App, (app) => { // GIVEN - const stack = new cdk.Stack(); + const stack = new cdk.Stack(app); stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -151,9 +152,9 @@ test('NetworkLoadBalancedEc2Service desiredCount can be undefined when feature f }); }); -test('NetworkLoadBalancedFargateService desiredCount can be undefined when feature flag is set', () => { +testLegacyBehavior('NetworkLoadBalancedFargateService desiredCount can be undefined when feature flag is set', cdk.App, (app) => { // GIVEN - const stack = new cdk.Stack(); + const stack = new cdk.Stack(app); stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -547,7 +548,6 @@ test('test Fargate loadbalanced construct with TLS', () => { }); expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'FARGATE', }); @@ -609,7 +609,6 @@ test('test Fargateloadbalanced construct with TLS and default certificate', () = }); expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'FARGATE', }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts index 9a64cfd40428e..3a6d058279fc3 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts @@ -7,7 +7,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import { AsgCapacityProvider } from '@aws-cdk/aws-ecs'; import * as ecs from '@aws-cdk/aws-ecs'; import * as sqs from '@aws-cdk/aws-sqs'; -import { testDeprecated } from '@aws-cdk/cdk-build-tools'; +import { testDeprecated, testLegacyBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import * as ecsPatterns from '../../lib'; @@ -34,7 +34,6 @@ test('test ECS queue worker service construct - with only required props', () => // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'EC2', }); @@ -89,9 +88,9 @@ test('test ECS queue worker service construct - with only required props', () => }); }); -test('test ECS queue worker service construct - with remove default desiredCount feature flag', () => { +testLegacyBehavior('test ECS queue worker service construct - with remove default desiredCount feature flag', cdk.App, (app) => { // GIVEN - const stack = new cdk.Stack(); + const stack = new cdk.Stack(app); stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -143,7 +142,6 @@ test('test ECS queue worker service construct - with optional props for queues', // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'EC2', }); @@ -222,7 +220,6 @@ testDeprecated('test ECS queue worker service construct - with optional props', image: ecs.ContainerImage.fromRegistry('test'), command: ['-c', '4', 'amazon.com'], enableLogging: false, - desiredTaskCount: 2, environment: { TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', @@ -239,7 +236,6 @@ testDeprecated('test ECS queue worker service construct - with optional props', // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set. expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 2, DeploymentConfiguration: { MinimumHealthyPercent: 60, MaximumPercent: 150, @@ -300,9 +296,9 @@ testDeprecated('test ECS queue worker service construct - with optional props', }); }); -testDeprecated('can set desiredTaskCount to 0', () => { +testLegacyBehavior('can set desiredTaskCount to 0', cdk.App, (app) => { // GIVEN - const stack = new cdk.Stack(); + const stack = new cdk.Stack(app); const vpc = new ec2.Vpc(stack, 'VPC'); const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); cluster.addAsgCapacityProvider(new AsgCapacityProvider(stack, 'DefaultAutoScalingGroupProvider', { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.alb-fargate-service-https.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.alb-fargate-service-https.expected.json index db8f3b70cd0ff..2792df3fec76c 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.alb-fargate-service-https.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.alb-fargate-service-https.expected.json @@ -669,7 +669,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": true, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -773,4 +772,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json index f1d4d3f932a97..cb53779993ebe 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.asset-image.expected.json @@ -643,7 +643,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -758,4 +757,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-load-balanced-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-load-balanced-fargate-service.expected.json index 8dce7a7620538..f14989568c592 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-load-balanced-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-load-balanced-fargate-service.expected.json @@ -599,7 +599,6 @@ "DeploymentController": { "Type": "ECS" }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -706,4 +705,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-queue-processing-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-queue-processing-fargate-service.expected.json index 11fe1e138e734..2796ddd5e9430 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-queue-processing-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.circuit-breaker-queue-processing-fargate-service.expected.json @@ -601,7 +601,6 @@ "DeploymentController": { "Type": "ECS" }, - "DesiredCount": 1, "EnableECSManagedTags": false, "LaunchType": "FARGATE", "NetworkConfiguration": { @@ -846,4 +845,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json index aa88f1305509d..8d71f92d6e8e8 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.executionrole.expected.json @@ -595,7 +595,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -702,4 +701,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json index 25e70118028a7..5c7ac18aa25cd 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-autocreate.expected.json @@ -234,7 +234,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -853,7 +852,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -947,4 +945,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json index 92df708ea01ee..cb4b8a5451e3a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3-vpconly.expected.json @@ -589,7 +589,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -853,7 +852,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json index 720daa10d651e..323c867f3ab32 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.l3.expected.json @@ -592,7 +592,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -853,7 +852,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -947,4 +945,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json index 76544288c076f..643ff38905d69 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.multiple-network-load-balanced-fargate-service.expected.json @@ -597,7 +597,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", 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 index deb6f5a1fd9c7..d9bceb202ebf2 100644 --- 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 @@ -903,7 +903,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "LaunchType": "FARGATE", "NetworkConfiguration": { @@ -1202,4 +1201,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json index c8a47202bfb06..60cf3f2347833 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.queue-processing-fargate-service-public.expected.json @@ -753,7 +753,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "LaunchType": "FARGATE", "NetworkConfiguration": { @@ -1001,4 +1000,4 @@ } } } -} \ No newline at end of file +} 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 index f70e493acdf02..48bab449fe610 100644 --- 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 @@ -594,7 +594,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "LaunchType": "FARGATE", "NetworkConfiguration": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json index 0d587d51e380f..91c1f4e575e23 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.special-listener.expected.json @@ -539,7 +539,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", @@ -832,7 +831,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts index 902d5412ee8bf..dcd2afff74c52 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts @@ -24,7 +24,6 @@ describe('When Application Load Balancer', () => { expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'FARGATE', LoadBalancers: [ { @@ -319,7 +318,6 @@ describe('When Application Load Balancer', () => { }); expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'FARGATE', LoadBalancers: [ { @@ -393,7 +391,6 @@ describe('When Network Load Balancer', () => { expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'FARGATE', LoadBalancers: [ { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts index 6f91b633d1249..e4fba5186e8dd 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts @@ -6,11 +6,13 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import { AsgCapacityProvider } from '@aws-cdk/aws-ecs'; import * as ecs from '@aws-cdk/aws-ecs'; import * as sqs from '@aws-cdk/aws-sqs'; -import { testDeprecated } from '@aws-cdk/cdk-build-tools'; +import { testDeprecated, testFutureBehavior } from '@aws-cdk/cdk-build-tools'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import * as ecsPatterns from '../../lib'; +const flags = { [cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT]: true }; + test('test fargate queue worker service construct - with only required props', () => { // GIVEN const stack = new cdk.Stack(); @@ -33,7 +35,6 @@ test('test fargate queue worker service construct - with only required props', ( // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'FARGATE', }); @@ -110,11 +111,9 @@ test('test fargate queue worker service construct - with only required props', ( }); }); -test('test fargate queue worker service construct - with remove default desiredCount feature flag', () => { +testFutureBehavior('test fargate queue worker service construct - with remove default desiredCount feature flag', flags, cdk.App, (app) => { // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - + const stack = new cdk.Stack(app); const vpc = new ec2.Vpc(stack, 'VPC'); const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); @@ -157,7 +156,6 @@ test('test fargate queue worker service construct - with optional props for queu // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 1, LaunchType: 'FARGATE', }); @@ -353,7 +351,6 @@ testDeprecated('test Fargate queue worker service construct - with optional prop image: ecs.ContainerImage.fromRegistry('test'), command: ['-c', '4', 'amazon.com'], enableLogging: false, - desiredTaskCount: 2, environment: { TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', @@ -370,7 +367,6 @@ testDeprecated('test Fargate queue worker service construct - with optional prop // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. expect(stack).toHaveResource('AWS::ECS::Service', { - DesiredCount: 2, DeploymentConfiguration: { MinimumHealthyPercent: 60, MaximumPercent: 150, diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json index 4ffc1cf776820..52646f224e4e3 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json @@ -484,7 +484,6 @@ "MaximumPercent": 200, "MinimumHealthyPercent": 50 }, - "DesiredCount": 1, "EnableECSManagedTags": false, "HealthCheckGracePeriodSeconds": 60, "LaunchType": "FARGATE", From cc48aa858b8997c74f5894b9f6811120ad350ed0 Mon Sep 17 00:00:00 2001 From: njlynch Date: Tue, 7 Dec 2021 11:54:33 +0000 Subject: [PATCH 77/82] automatic pkglint fixes --- packages/@aws-cdk/assert/package.json | 2 +- packages/@aws-cdk/cloud-assembly-schema/package.json | 2 +- packages/@aws-cdk/cloudformation-diff/package.json | 2 +- packages/@aws-cdk/cx-api/package.json | 2 +- packages/@aws-cdk/region-info/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/awslint/package.json | 2 +- packages/cdk-assets/package.json | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index da28b2d63ae55..336d554e8e81a 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -72,6 +72,6 @@ "stability": "experimental", "maturity": "developer-preview", "publishConfig": { - "tag": "latest-1" + "tag": "latest" } } diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 5d214c58781c9..b0ea12c37b9c8 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -99,6 +99,6 @@ }, "maturity": "stable", "publishConfig": { - "tag": "latest-1" + "tag": "latest" } } diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index c66cbaa59db14..df973a6c49a18 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -56,6 +56,6 @@ "stability": "stable", "maturity": "stable", "publishConfig": { - "tag": "latest-1" + "tag": "latest" } } diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 359d012bad153..afecc19afc310 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -157,6 +157,6 @@ "announce": false }, "publishConfig": { - "tag": "latest-1" + "tag": "latest" } } diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index b8ef41270b2f1..13d8e57a28538 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -90,6 +90,6 @@ "announce": false }, "publishConfig": { - "tag": "latest-1" + "tag": "latest" } } diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index f2c72b1d3e8ac..eb74ebbc7c1b2 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -120,6 +120,6 @@ "stability": "stable", "maturity": "stable", "publishConfig": { - "tag": "latest-1" + "tag": "latest" } } diff --git a/packages/awslint/package.json b/packages/awslint/package.json index 51be69db411f1..4ea76e3c3977f 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -69,6 +69,6 @@ ] }, "publishConfig": { - "tag": "latest-1" + "tag": "latest" } } diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 8bbd27227b4fc..492bd4ef9b11a 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -78,6 +78,6 @@ "stability": "experimental", "maturity": "experimental", "publishConfig": { - "tag": "latest-1" + "tag": "latest" } } From f19fc39032696ce133fc55aad0d058f616d9f9f8 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Tue, 7 Dec 2021 12:06:23 +0000 Subject: [PATCH 78/82] fix(lambda): recognizeVersionProps featureFlag not defaulting correctly (#17866) The `@aws-cdk/aws-lambda:recognizeVersionProps` feature flag has always had the "future" behavior set to "true", meaning any new projects get the flag set to true. All of these style flags were intended to default to true as well for v2, but this one was missed. The end result is that users who have created a new v1 project anytime in the last ~6 months, and then upgrade to v2, actually experience a _downgrade_ in behavior if following the offical migration guide (which instructs users to delete all feature flags). This change fixes the behavior to work as intended. Users who wish to opt out can continue to set `@aws-cdk/aws-lambda:recognizeVersionProps` to false in their `cdk.json`. fixes #17810 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-cloudfront/test/distribution.test.ts | 8 ++++---- .../test/experimental/edge-function.test.ts | 2 +- .../test/web-distribution.test.ts | 8 ++++---- .../aws-lambda/test/function-hash.test.ts | 18 +++++++++--------- .../aws-lambda/test/lambda-version.test.ts | 4 ++-- packages/@aws-cdk/cx-api/lib/features.ts | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts index 470be56acf0d5..0fc027fbc1d90 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts @@ -3,9 +3,9 @@ import '@aws-cdk/assert-internal/jest'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { App, Duration, Stack } from '@aws-cdk/core'; import { CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 } from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { CfnDistribution, Distribution, @@ -595,7 +595,7 @@ describe('with Lambda@Edge functions', () => { EventType: 'origin-request', IncludeBody: true, LambdaFunctionARN: { - Ref: 'FunctionCurrentVersion4E2B2261477a5ae8059bbaa7813f752292c0f65e', + Ref: 'FunctionCurrentVersion4E2B2261f9b8c8b9c774af866281167c3323362d', }, }, ], @@ -665,7 +665,7 @@ describe('with Lambda@Edge functions', () => { { EventType: 'viewer-request', LambdaFunctionARN: { - Ref: 'FunctionCurrentVersion4E2B2261477a5ae8059bbaa7813f752292c0f65e', + Ref: 'FunctionCurrentVersion4E2B2261f9b8c8b9c774af866281167c3323362d', }, }, ], @@ -771,7 +771,7 @@ describe('with Lambda@Edge functions', () => { { EventType: 'origin-request', LambdaFunctionARN: { - Ref: 'SingletonLambdasingletonforcloudfrontCurrentVersion0078406348a0962a52448a200cd0dbc0e22edb2a', + Ref: 'SingletonLambdasingletonforcloudfrontCurrentVersion00784063de5dfb6e46a8d2a0436a69c9a8bfabae', }, }, ], diff --git a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts index 55d6f3689103c..d7c970aa88746 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/experimental/edge-function.test.ts @@ -97,7 +97,7 @@ describe('stacks', () => { }); expect(fnStack).toHaveResource('AWS::SSM::Parameter', { Type: 'String', - Value: { Ref: 'MyFnCurrentVersion309B29FC29686ce94039b6e08d1645be854b3ac9' }, + Value: { Ref: 'MyFnCurrentVersion309B29FC37a9dfc56f4df872af37f8a33a191788' }, Name: '/cdk/EdgeFunctionArn/testregion/Stack/MyFn', }); }); 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 d7612633cf93c..850cbfae4efe6 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -290,7 +290,7 @@ describe('web distribution', () => { const sourceBucket = new s3.Bucket(stack, 'Bucket'); new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { - comment: `Adding a comment longer than 128 characters should be trimmed and + comment: `Adding a comment longer than 128 characters should be trimmed and added the ellipsis so a user would know there was more to read and everything beyond this point should not show up`, originConfigs: [ { @@ -344,8 +344,8 @@ added the ellipsis so a user would know there was more to read and everything be }, Compress: true, }, - Comment: `Adding a comment longer than 128 characters should be trimmed and -added the ellipsis so a user would know there was more to ...`, + Comment: `Adding a comment longer than 128 characters should be trimmed and +added the ellipsis so a user would know there was more to r...`, Enabled: true, IPV6Enabled: true, HttpVersion: 'http2', @@ -871,7 +871,7 @@ added the ellipsis so a user would know there was more to ...`, 'EventType': 'origin-request', 'IncludeBody': true, 'LambdaFunctionARN': { - 'Ref': 'LambdaCurrentVersionDF706F6A97fb843e9bd06fcd2bb15eeace80e13e', + 'Ref': 'LambdaCurrentVersionDF706F6A25bf7d67df4eb614ea2e1ea69c8759b6', }, }, ], diff --git a/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts index 1f7e3d4dc3b4f..505efb88558cc 100644 --- a/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts @@ -44,7 +44,7 @@ describe('function hash', () => { }); expect(calculateFunctionHash(fn1)).toEqual(calculateFunctionHash(fn2)); - expect(calculateFunctionHash(fn1)).toEqual('aea5463dba236007afe91d2832b3c836'); + expect(calculateFunctionHash(fn1)).toEqual('e5235e3cb7a9b70c42c1a665a3ebd77c'); }); }); @@ -61,8 +61,8 @@ describe('function hash', () => { handler: 'index.handler', }); - expect(calculateFunctionHash(fn1)).not.toEqual('aea5463dba236007afe91d2832b3c836'); - expect(calculateFunctionHash(fn1)).toEqual('979b4a14c6f174c745cdbcd1036cf844'); + expect(calculateFunctionHash(fn1)).not.toEqual('e5235e3cb7a9b70c42c1a665a3ebd77c'); + expect(calculateFunctionHash(fn1)).toEqual('bb95ae2489ebc480a23ff373362e453a'); }); test('environment variables impact hash', () => { @@ -91,8 +91,8 @@ describe('function hash', () => { }, }); - expect(calculateFunctionHash(fn1)).toEqual('d1bc824ac5022b7d62d8b12dbae6580c'); - expect(calculateFunctionHash(fn2)).toEqual('3b683d05465012b0aa9c4ff53b32f014'); + expect(calculateFunctionHash(fn1)).toEqual('a072f10967c25eb87c187e3d61d88f58'); + expect(calculateFunctionHash(fn2)).toEqual('29aa77e049793f5424d31e880d6ce535'); }); test('runtime impacts hash', () => { @@ -121,8 +121,8 @@ describe('function hash', () => { }, }); - expect(calculateFunctionHash(fn1)).toEqual('d1bc824ac5022b7d62d8b12dbae6580c'); - expect(calculateFunctionHash(fn2)).toEqual('0f168f0772463e8e547bb3800937e54d'); + expect(calculateFunctionHash(fn1)).toEqual('a072f10967c25eb87c187e3d61d88f58'); + expect(calculateFunctionHash(fn2)).toEqual('c27e1d43e5595311b185324306244f1b'); }); test('inline code change impacts the hash', () => { @@ -140,8 +140,8 @@ describe('function hash', () => { handler: 'index.handler', }); - expect(calculateFunctionHash(fn1)).toEqual('ebf2e871fc6a3062e8bdcc5ebe16db3f'); - expect(calculateFunctionHash(fn2)).toEqual('ffedf6424a18a594a513129dc97bf53c'); + expect(calculateFunctionHash(fn1)).toEqual('ae3a05e0797a7b59e850d453a2e8ea97'); + expect(calculateFunctionHash(fn2)).toEqual('bdce872a679fc58e06ab8b0cd30ffb37'); }); describe('impact of env variables order on hash', () => { diff --git a/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts b/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts index c5daabab66b5d..9c7709dd1b86e 100644 --- a/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts @@ -123,7 +123,7 @@ describe('lambda version', () => { }, FunctionVersion: { 'Fn::GetAtt': [ - 'FnCurrentVersion17A89ABBab5c765f3c55e4e61583b51b00a95742', + 'FnCurrentVersion17A89ABB60415807620115f34aaea569cf042980', 'Version', ], }, @@ -142,7 +142,7 @@ describe('lambda version', () => { const version = fn.currentVersion; // THEN - expect(stack.resolve(version.edgeArn)).toEqual({ Ref: 'FnCurrentVersion17A89ABB19ed45993ff69fd011ae9fd4ab6e2005' }); + expect(stack.resolve(version.edgeArn)).toEqual({ Ref: 'FnCurrentVersion17A89ABB60415807620115f34aaea569cf042980' }); }); test('edgeArn throws with $LATEST', () => { diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 70dfce119e15f..ff709a2bc06c0 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -224,7 +224,7 @@ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: true, [RDS_LOWERCASE_DB_IDENTIFIER]: true, [EFS_DEFAULT_ENCRYPTION_AT_REST]: true, - [LAMBDA_RECOGNIZE_VERSION_PROPS]: false, + [LAMBDA_RECOGNIZE_VERSION_PROPS]: true, [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, }; From 58c2c65509e6e2f61ac98840458f2e43f38d1d97 Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 7 Dec 2021 12:09:44 +0000 Subject: [PATCH 79/82] chore(apigateway): clarified the intent of `dataTraceEnabled` (#17861) Related to https://github.com/aws/aws-cdk/issues/17578. ---- *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-apigateway/lib/stage.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-apigateway/lib/stage.ts b/packages/@aws-cdk/aws-apigateway/lib/stage.ts index 67046e5ae3117..c8f69c3768f36 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/stage.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/stage.ts @@ -141,8 +141,10 @@ export interface MethodDeploymentOptions { readonly loggingLevel?: MethodLoggingLevel; /** - * Specifies whether data trace logging is enabled for this method, which - * effects the log entries pushed to Amazon CloudWatch Logs. + * Specifies whether data trace logging is enabled for this method. + * When enabled, API gateway will log the full API requests and responses. + * This can be useful to troubleshoot APIs, but can result in logging sensitive data. + * We recommend that you don't enable this feature for production APIs. * * @default false */ From d5c249f76cc756c335474852ad7187609b0c0c09 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Tue, 7 Dec 2021 13:53:18 +0000 Subject: [PATCH 80/82] chore(lambda-nodejs): fix test broken in CodeBuild (#17884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test fails in our CodeBuild environment with the following error: ``` FAIL test/util.test.js ● extractDependencies › with file dependency expect(received).toEqual(expected) // deep equality - Expected - 1 + Received + 1 Object { - "my-module": StringMatching /aws-cdk\/packages\/@aws-cdk\/core/, + "my-module": "file:/codebuild/output/src777018412/src/packages/@aws-cdk/core", } 130 | })); 131 | > 132 | expect(extractDependencies(pkgPath, ['my-module'])).toEqual({ | ^ 133 | 'my-module': expect.stringMatching(/aws-cdk\/packages\/@aws-cdk\/core/), 134 | }); 135 | at Object. (test/util.test.ts:132:57) ``` This is due to the source being located in .../src instead of .../aws-cdk. Fix the test by stopping the check at the 'packages' directory. ---- *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-lambda-nodejs/test/util.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts index 763a5ac499c86..ea68bbffa156b 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts @@ -130,7 +130,7 @@ describe('extractDependencies', () => { })); expect(extractDependencies(pkgPath, ['my-module'])).toEqual({ - 'my-module': expect.stringMatching(/aws-cdk\/packages\/@aws-cdk\/core/), + 'my-module': expect.stringMatching(/packages\/@aws-cdk\/core/), }); fs.unlinkSync(pkgPath); From 50011bbd43d1fc2dfcc98461373c99bd757cefed Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 7 Dec 2021 14:30:38 +0000 Subject: [PATCH 81/82] chore(lambda-nodejs): fix test broken in CodeBuild (backport #17884) (#17885) This is an automatic backport of pull request #17884 done by [Mergify](https://mergify.com). ---
Mergify commands and options
More conditions and actions can be found in the [documentation](https://docs.mergify.com/). You can also trigger Mergify actions by commenting on this pull request: - `@Mergifyio refresh` will re-evaluate the rules - `@Mergifyio rebase` will rebase this PR on its base branch - `@Mergifyio update` will merge the base branch into this PR - `@Mergifyio backport ` will backport this PR on `` branch Additionally, on Mergify [dashboard](https://dashboard.mergify.com/) you can: - look at your merge queues - generate the Mergify configuration with the config editor. Finally, you can contact us on https://mergify.com
--- packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts index 763a5ac499c86..ea68bbffa156b 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/util.test.ts @@ -130,7 +130,7 @@ describe('extractDependencies', () => { })); expect(extractDependencies(pkgPath, ['my-module'])).toEqual({ - 'my-module': expect.stringMatching(/aws-cdk\/packages\/@aws-cdk\/core/), + 'my-module': expect.stringMatching(/packages\/@aws-cdk\/core/), }); fs.unlinkSync(pkgPath); From fb94e3049436ff920c04e75555737334aaf32fba Mon Sep 17 00:00:00 2001 From: AWS CDK Team Date: Wed, 8 Dec 2021 10:56:51 +0000 Subject: [PATCH 82/82] chore(release): 2.1.0 --- CHANGELOG.v2.alpha.md | 68 +++++++++++++++++++++++++++++++++++++++++++ CHANGELOG.v2.md | 53 +++++++++++++++++++++++++++++++++ version.v2.json | 6 ++-- 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.v2.alpha.md b/CHANGELOG.v2.alpha.md index c994cbb74531f..127592751789b 100644 --- a/CHANGELOG.v2.alpha.md +++ b/CHANGELOG.v2.alpha.md @@ -2,6 +2,74 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.1.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.0.0-alpha.11...v2.1.0-alpha.0) (2021-12-08) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **apigatewayv2-authorizers:** The default value for the prop `authorizerName` +in `HttpJwtAuthorizerProps` has changed. +* **apigatewayv2-authorizers:** `HttpJwtAuthorizer` now takes the + construct id and the target jwt issuer as part of its constructor. +* **apigatewayv2-authorizers:** `HttpLambdaAuthorizer` now takes + the construct id and the target lambda function handler as part of + its constructor. +* **apigatewayv2-authorizers:** The default value for the prop + `authorizerName` in `HttpUserPoolAuthorizerProps` has changed. +* **apigatewayv2:** The `HttpIntegration` and `WebSocketIntegration` +classes require an "id" parameter to be provided during its initialization. +* **apigatewayv2-integrations:** The `LambdaWebSocketIntegration` is now + renamed to `WebSocketLambdaIntegration`. The new class accepts the + handler to the target lambda function directly in its constructor. +* **apigatewayv2-integrations:** `HttpProxyIntegration` and + `HttpProxyIntegrationProps` are now renamed to `HttpUrlIntegration` + and `HttpUrlIntegrationProps` respectively. The new class accepts the + target url directly in its constructor. +* **apigatewayv2-integrations:** `LambdaProxyIntegration` and + `LambdaProxyIntegrationProps` are now renamed to + `HttpLambdaIntegration` and `HttpLambdaIntegrationProps` respectively. + The new class accepts the lambda function handler directly in its + constructor. +* **apigatewayv2-integrations:** `HttpAlbIntegration` now accepts the + ELB listener directly in its constructor. +* **apigatewayv2-integrations:** `HttpNlbIntegration` now accepts the + ELB listener directly in its constructor. +* **apigatewayv2-integrations:** `HttpServiceDiscoveryIntegration` now + accepts the service discovery Service directly in its constructor. +* **apigatewayv2-authorizers:** `UserPoolAuthorizerProps` is now + renamed to `HttpUserPoolAuthorizerProps`. +* **apigatewayv2:** The interface `IHttpRouteIntegration` is replaced by +the abstract class `HttpRouteIntegration`. +* **apigatewayv2:** The interface `IWebSocketRouteIntegration` is now + replaced by the abstract class `WebSocketRouteIntegration`. +* **apigatewayv2:** Previously, we allowed the usage of integration + classes to be used with routes defined in multiple `HttpApi` instances + (or `WebSocketApi` instances). This is now disallowed, and separate + instances must be created for each instance of `HttpApi` or + `WebSocketApi`. + +### Features + +* **apigatewayv2:** constructs for http api are now stable! 🤘 ([#17773](https://github.com/aws/aws-cdk/issues/17773)) ([b25590f](https://github.com/aws/aws-cdk/commit/b25590ff15d92a8a6ddc1f3a37263f90793b15f4)) +* **iot:** add Action to capture CloudWatch metrics ([#17503](https://github.com/aws/aws-cdk/issues/17503)) ([ec4187c](https://github.com/aws/aws-cdk/commit/ec4187c26d68df970d72d0e766d7d27b42e8b784)), closes [/github.com/aws/aws-cdk/pull/16681#issuecomment-942233029](https://github.com/aws//github.com/aws/aws-cdk/pull/16681/issues/issuecomment-942233029) +* **neptune:** add engine version 1.1.0.0 and instance types t4g, r6g ([#17669](https://github.com/aws/aws-cdk/issues/17669)) ([83e669d](https://github.com/aws/aws-cdk/commit/83e669dcdae9390990598236c75015832af766b4)) +* **servicecatalog:** Add TagOptions to a CloudformationProduct ([#17672](https://github.com/aws/aws-cdk/issues/17672)) ([2d19e15](https://github.com/aws/aws-cdk/commit/2d19e1535586d2b006d43da787ffbb0fad8b4978)) + + +### Bug Fixes + +* **apigatewayv2:** integration class does not render an integration resource ([#17729](https://github.com/aws/aws-cdk/issues/17729)) ([3b5b97a](https://github.com/aws/aws-cdk/commit/3b5b97ac1f972f53240798df19af43d85ebf6f13)), closes [#13213](https://github.com/aws/aws-cdk/issues/13213) +* **apprunner:** startCommand and environment are ignored in imageConfiguration ([#16939](https://github.com/aws/aws-cdk/issues/16939)) ([d911c58](https://github.com/aws/aws-cdk/commit/d911c5878c59498a2d0e14ff536e0f8f9f503bfe)), closes [#16812](https://github.com/aws/aws-cdk/issues/16812) +* **appsync:** add caching config to AppSync resolvers ([#17815](https://github.com/aws/aws-cdk/issues/17815)) ([52b535b](https://github.com/aws/aws-cdk/commit/52b535bda5f26b07377fcdfca63a75c62eb5f883)) +* **appsync:** remove 'id' suffix to union definition key ([#17787](https://github.com/aws/aws-cdk/issues/17787)) ([86e7780](https://github.com/aws/aws-cdk/commit/86e77806391dc3fe8cd254fec773320cdb425dec)), closes [#17771](https://github.com/aws/aws-cdk/issues/17771) +* **assert:** support multiline strings with `stringLike()` ([#17692](https://github.com/aws/aws-cdk/issues/17692)) ([37596e6](https://github.com/aws/aws-cdk/commit/37596e6be4cf05432dcba3838955484e512beca6)) + + +### Miscellaneous Chores + +* **apigatewayv2:** integration api re-organization ([#17752](https://github.com/aws/aws-cdk/issues/17752)) ([29039e8](https://github.com/aws/aws-cdk/commit/29039e8bd13a4fdb7f84254038b3331c179273fd)) +* **apigatewayv2-authorizers:** re-organize authorizer api ([#17772](https://github.com/aws/aws-cdk/issues/17772)) ([719f33e](https://github.com/aws/aws-cdk/commit/719f33e20c723f161fc35230fafd7e99bca66a61)) + ## [2.0.0-alpha.11](https://github.com/aws/aws-cdk/compare/v2.0.0-alpha.10...v2.0.0-alpha.11) (2021-12-02) ## [2.0.0-alpha.10](https://github.com/aws/aws-cdk/compare/v2.0.0-alpha.9...v2.0.0-alpha.10) (2021-11-26) diff --git a/CHANGELOG.v2.md b/CHANGELOG.v2.md index a9fe352fba6f4..2b8d7d8ef4b04 100644 --- a/CHANGELOG.v2.md +++ b/CHANGELOG.v2.md @@ -2,6 +2,59 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.1.0](https://github.com/aws/aws-cdk/compare/v2.0.0...v2.1.0) (2021-12-08) + + +### Features + +* **apigateway:** step functions integration ([#16827](https://github.com/aws/aws-cdk/issues/16827)) ([cb31547](https://github.com/aws/aws-cdk/commit/cb3154789da52b94e4688d645adba87ef2ebf39f)), closes [#15081](https://github.com/aws/aws-cdk/issues/15081) +* **assertions:** major improvements to the capture feature ([#17713](https://github.com/aws/aws-cdk/issues/17713)) ([9a67ce7](https://github.com/aws/aws-cdk/commit/9a67ce7a1792a111e7668cbc7b7f0799314bd7d6)), closes [#17009](https://github.com/aws/aws-cdk/issues/17009) +* **aws-s3-deployment:** log retention option ([#17779](https://github.com/aws/aws-cdk/issues/17779)) ([b60dc63](https://github.com/aws/aws-cdk/commit/b60dc63f99ede0cfaa859cdef33a6f4ddd2d1d25)) +* **backup:** enable WindowsVss Backup ([#15934](https://github.com/aws/aws-cdk/issues/15934)) ([12fcb18](https://github.com/aws/aws-cdk/commit/12fcb18212c8d9e74f5292b07f42ce24cd7b02b3)), closes [#14803](https://github.com/aws/aws-cdk/issues/14803) [#14891](https://github.com/aws/aws-cdk/issues/14891) +* **cfnspec:** cloudformation spec v49.0.0 ([#17727](https://github.com/aws/aws-cdk/issues/17727)) ([7e0c9a3](https://github.com/aws/aws-cdk/commit/7e0c9a341e2bc2837d5c5d671339fe968714d9ce)) +* **cloudfront:** Add support for response headers policy ([#17359](https://github.com/aws/aws-cdk/issues/17359)) ([ea0acff](https://github.com/aws/aws-cdk/commit/ea0acff28c3f64c9511fdd580f52211df9460a45)), closes [#17290](https://github.com/aws/aws-cdk/issues/17290) +* **cognito:** user pool: adds custom sender (Email/SMS) lambda triggers ([#17740](https://github.com/aws/aws-cdk/issues/17740)) ([7f45de4](https://github.com/aws/aws-cdk/commit/7f45de4ba3cdf99846ca1966549b1630929aebbe)) +* **core:** add applyRemovalPolicy to IResource ([#17746](https://github.com/aws/aws-cdk/issues/17746)) ([d64057f](https://github.com/aws/aws-cdk/commit/d64057f9462f8261f61795c6584d21ef56a9be34)), closes [#17728](https://github.com/aws/aws-cdk/issues/17728) +* **custom-resources:** fixed Lambda function name ([#17670](https://github.com/aws/aws-cdk/issues/17670)) ([5710fe5](https://github.com/aws/aws-cdk/commit/5710fe5a80cd4cc6ef415ec624a3399e86a3e603)) +* **docdb:** implement audit and profiler logs ([#17570](https://github.com/aws/aws-cdk/issues/17570)) ([4982aca](https://github.com/aws/aws-cdk/commit/4982aca6f95ca864a285ed9955a9618a20ca0415)), closes [#17478](https://github.com/aws/aws-cdk/issues/17478) +* **ec2:** add g5g instances ([#17765](https://github.com/aws/aws-cdk/issues/17765)) ([1799f7e](https://github.com/aws/aws-cdk/commit/1799f7e08d06b8846c9918f1cb130f20570a99be)), closes [/docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2](https://github.com/aws//docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html/issues/cfn-ec2) +* **ec2:** add m5zn instances ([#17757](https://github.com/aws/aws-cdk/issues/17757)) ([845be10](https://github.com/aws/aws-cdk/commit/845be1012593a9f28457c73c9054bd98ea44d659)), closes [/docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2](https://github.com/aws//docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html/issues/cfn-ec2) +* **ec2:** add m6a instances ([#17764](https://github.com/aws/aws-cdk/issues/17764)) ([b06f120](https://github.com/aws/aws-cdk/commit/b06f120916acd63293c020eef368401b4428ce0a)), closes [/docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2](https://github.com/aws//docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html/issues/cfn-ec2) +* **ec2:** add mac1 instance ([#17677](https://github.com/aws/aws-cdk/issues/17677)) ([88a5204](https://github.com/aws/aws-cdk/commit/88a5204a295874e3cffcc041469d8fffbd32b57d)), closes [/docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2](https://github.com/aws//docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html/issues/cfn-ec2) [40aws-cdk/aws-ec2/lib/instance-types.ts#L573](https://github.com/40aws-cdk/aws-ec2/lib/instance-types.ts/issues/L573) +* **ec2:** add r6i instances ([#17663](https://github.com/aws/aws-cdk/issues/17663)) ([0138292](https://github.com/aws/aws-cdk/commit/01382921f979b944df1917964f080ce311e99ad2)), closes [/docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2](https://github.com/aws//docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html/issues/cfn-ec2) +* **ec2:** add vt1 instances ([#17756](https://github.com/aws/aws-cdk/issues/17756)) ([245c059](https://github.com/aws/aws-cdk/commit/245c059eabf59d0fb0b352dac5e49d5ab4ef9ee2)), closes [/docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2](https://github.com/aws//docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html/issues/cfn-ec2) +* **ec2:** explicit mapPublicIpOnLaunch configuration for public subnets ([#17346](https://github.com/aws/aws-cdk/issues/17346)) ([a1685c6](https://github.com/aws/aws-cdk/commit/a1685c62071846d41eb47234fbf2c94884453c17)) +* **ec2:** extend BastionHostLinux to support CloudFormationInit ([#17507](https://github.com/aws/aws-cdk/issues/17507)) ([c62377e](https://github.com/aws/aws-cdk/commit/c62377e14caae677deb7e4eae692eaccb2020c67)) +* **ecs-service-extensions:** Auto scaling for Queue Extension ([#17430](https://github.com/aws/aws-cdk/issues/17430)) ([df7b9b4](https://github.com/aws/aws-cdk/commit/df7b9b41bd99534abb8a6becccc23320a3b6cb41)) +* **iam:** support `fromGroupName()` for IAM groups ([#17243](https://github.com/aws/aws-cdk/issues/17243)) ([29b379c](https://github.com/aws/aws-cdk/commit/29b379cdc49dd396f793782b91d3eca215446a48)) +* **lambda:** function construct exposes configured timeout ([#17594](https://github.com/aws/aws-cdk/issues/17594)) ([87fd60f](https://github.com/aws/aws-cdk/commit/87fd60f047e9f1994459de874b54e901d1871e6e)) +* **lambda-event-sources:** sqs: support reportBatchItemFailures ([#17733](https://github.com/aws/aws-cdk/issues/17733)) ([3623982](https://github.com/aws/aws-cdk/commit/3623982fc1a64c2c67a0dba18a6d3eeeb171e898)), closes [#17690](https://github.com/aws/aws-cdk/issues/17690) +* **rds:** parameter group for replica instances ([#17822](https://github.com/aws/aws-cdk/issues/17822)) ([b606a23](https://github.com/aws/aws-cdk/commit/b606a2321769d5e8f15072a62848aaba35bb1d35)), closes [#17580](https://github.com/aws/aws-cdk/issues/17580) +* **s3:** add GLACIER_IR storage class ([#17829](https://github.com/aws/aws-cdk/issues/17829)) ([c291c44](https://github.com/aws/aws-cdk/commit/c291c4427480472402ef6b0a7c854ac38505ae97)) +* **s3:** support Transfer Acceleration ([#17636](https://github.com/aws/aws-cdk/issues/17636)) ([b432822](https://github.com/aws/aws-cdk/commit/b432822ae45e329a900293eb43712fa4a1d74aa5)), closes [#12570](https://github.com/aws/aws-cdk/issues/12570) +* **secretsmanager:** support secrets rotation in GovCloud ([#17673](https://github.com/aws/aws-cdk/issues/17673)) ([a01678b](https://github.com/aws/aws-cdk/commit/a01678b838a7feb2bde40c435c6c585473d35b22)), closes [#14608](https://github.com/aws/aws-cdk/issues/14608) +* **stepfunctions-tasks:** add 'Emr on Eks' tasks ([#17103](https://github.com/aws/aws-cdk/issues/17103)) ([f2bf322](https://github.com/aws/aws-cdk/commit/f2bf322e043ced0193a1b47ae4abd370b095ec1c)), closes [#15262](https://github.com/aws/aws-cdk/issues/15262) [#15234](https://github.com/aws/aws-cdk/issues/15234) + + +### Bug Fixes + +* **aws-cdk:** `cdk diff` always fails on diff ([#17862](https://github.com/aws/aws-cdk/issues/17862)) ([6bb4a46](https://github.com/aws/aws-cdk/commit/6bb4a46792d0b9665e4a72896869a063e8fa1af9)), closes [#4721](https://github.com/aws/aws-cdk/issues/4721) +* **aws-ec2:** imported VPC subnets never recognized as PRIVATE_ISOLATED ([#17496](https://github.com/aws/aws-cdk/issues/17496)) ([ba6a8ef](https://github.com/aws/aws-cdk/commit/ba6a8efc65288bd96ebf004d81026ab61485ff06)) +* **aws-elasticloadbalancingv2:** Set stickiness.enabled unless target type is lambda ([#17271](https://github.com/aws/aws-cdk/issues/17271)) ([168a98f](https://github.com/aws/aws-cdk/commit/168a98fb213184dfef29ae38b986704b5abeb99e)), closes [#17261](https://github.com/aws/aws-cdk/issues/17261) +* **cli:** S3 asset uploads are rejected by commonly referenced encryption SCP (introduces bootstrap stack v9) ([#17668](https://github.com/aws/aws-cdk/issues/17668)) ([8191f1f](https://github.com/aws/aws-cdk/commit/8191f1f1d4072feeba74844a31c942909cee7d83)), closes [#11265](https://github.com/aws/aws-cdk/issues/11265) +* **codepipeline:** cannot trigger on all tags anymore in EcrSourceAction ([#17270](https://github.com/aws/aws-cdk/issues/17270)) ([39fe11b](https://github.com/aws/aws-cdk/commit/39fe11bc1b0d12920111331dca560150006a0733)), closes [aws#13818](https://github.com/aws/aws/issues/13818) [aws#13818](https://github.com/aws/aws/issues/13818) +* **codepipeline:** cross-env pipeline cannot be created in `Stage` ([#17730](https://github.com/aws/aws-cdk/issues/17730)) ([f17f29e](https://github.com/aws/aws-cdk/commit/f17f29e94265eb450d8f11bdbdbe719f3e511ea2)), closes [#17643](https://github.com/aws/aws-cdk/issues/17643) +* **core:** bundling skipped with --exclusively option and stacks under stage ([#17210](https://github.com/aws/aws-cdk/issues/17210)) ([cda6601](https://github.com/aws/aws-cdk/commit/cda66013afa6f8aa16d802bb2ab08dab1e5124cf)), closes [#12898](https://github.com/aws/aws-cdk/issues/12898) [#15346](https://github.com/aws/aws-cdk/issues/15346) +* **docdb:** secret rotation ignores excluded characters in password ([#17609](https://github.com/aws/aws-cdk/issues/17609)) ([1fe2215](https://github.com/aws/aws-cdk/commit/1fe2215dc40eb58f1babc2c3fbca501a5e89b09f)), closes [#17347](https://github.com/aws/aws-cdk/issues/17347) [#17575](https://github.com/aws/aws-cdk/issues/17575) +* **dynamodb:** add missing DynamoDB operations to enum ([#17738](https://github.com/aws/aws-cdk/issues/17738)) ([f38e0ac](https://github.com/aws/aws-cdk/commit/f38e0ac5b90bd83630a5a602e9ada2556689d826)) +* **dynamodb:** changing `waitForReplicationToFinish` fails deployment ([#17842](https://github.com/aws/aws-cdk/issues/17842)) ([36b8fdb](https://github.com/aws/aws-cdk/commit/36b8fdb026c7e82eb590c1a8d604ca3b44642900)), closes [#16983](https://github.com/aws/aws-cdk/issues/16983) +* **ecs-patterns:** removeDefaultDesiredCount feature flag not expired properly ([#17865](https://github.com/aws/aws-cdk/issues/17865)) ([7fb639a](https://github.com/aws/aws-cdk/commit/7fb639af1d9fa3c0d910df6d3af21aac6aaff5eb)) +* **lambda:** recognizeVersionProps featureFlag not defaulting correctly ([#17866](https://github.com/aws/aws-cdk/issues/17866)) ([f19fc39](https://github.com/aws/aws-cdk/commit/f19fc39032696ce133fc55aad0d058f616d9f9f8)), closes [#17810](https://github.com/aws/aws-cdk/issues/17810) +* **lambda-nodejs:** bundling fails with a file dependency in `nodeModules` ([#17851](https://github.com/aws/aws-cdk/issues/17851)) ([5737c33](https://github.com/aws/aws-cdk/commit/5737c336b3a2d7942196ffcad9291b4af6a23375)), closes [#17830](https://github.com/aws/aws-cdk/issues/17830) +* **lambda-nodejs:** bundling with `nodeModules` fails with paths containing spaces ([#17632](https://github.com/aws/aws-cdk/issues/17632)) ([986f291](https://github.com/aws/aws-cdk/commit/986f291a51cee46299428298ca6b39a9636d6dd2)), closes [#17631](https://github.com/aws/aws-cdk/issues/17631) +* **pipelines:** stack outputs used in stackSteps not recognized ([#17311](https://github.com/aws/aws-cdk/issues/17311)) ([5e4a219](https://github.com/aws/aws-cdk/commit/5e4a21959e67ff967d163fce6b0405a053bafdc2)), closes [#17272](https://github.com/aws/aws-cdk/issues/17272) +* **stepfunctions:** prefixes not appended to states in parallel branches ([#17806](https://github.com/aws/aws-cdk/issues/17806)) ([a1da772](https://github.com/aws/aws-cdk/commit/a1da77272fa35b9722694557a4d5bdc83e2ad834)), closes [#17354](https://github.com/aws/aws-cdk/issues/17354) + ## [2.0.0](https://github.com/aws/aws-cdk/compare/v2.0.0-rc.33...v2.0.0) (2021-12-02) diff --git a/version.v2.json b/version.v2.json index 018182bf75a62..c2f04052df4f0 100644 --- a/version.v2.json +++ b/version.v2.json @@ -1,4 +1,4 @@ { - "version": "2.0.0", - "alphaVersion": "2.0.0-alpha.11" -} + "version": "2.1.0", + "alphaVersion": "2.1.0-alpha.0" +} \ No newline at end of file