diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index c8c28a35eff3e..6ad382cc4cef9 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -33,8 +33,9 @@ what is the error message you are seeing? - **CLI Version :** - **Framework Version:** + - **Node.js Version:** - **OS :** - - **Language :** + - **Language (Version):** ### Other diff --git a/.github/ISSUE_TEMPLATE/general-issues.md b/.github/ISSUE_TEMPLATE/general-issues.md index 8ed1e4209a644..edd2ef2798236 100644 --- a/.github/ISSUE_TEMPLATE/general-issues.md +++ b/.github/ISSUE_TEMPLATE/general-issues.md @@ -25,8 +25,9 @@ falling prey to the [X/Y problem][2]! - **CDK CLI Version:** - **Module Version:** + - **Node.js Version:** - **OS:** - - **Language:** + - **Language (Version):** ### Other information diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e4e7fd080d53..797f21440a6fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,55 @@ 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. +## [1.44.0](https://github.com/aws/aws-cdk/compare/v1.43.0...v1.44.0) (2020-06-04) + + +### Features + +* **ecs-patterns:** support min and max health percentage in queueprocessingservice ([#8312](https://github.com/aws/aws-cdk/issues/8312)) ([6da564d](https://github.com/aws/aws-cdk/commit/6da564d68c5195c88c5959b7375e2973c2b07676)) + +## [1.43.0](https://github.com/aws/aws-cdk/compare/v1.42.1...v1.43.0) (2020-06-03) + + +### ⚠ BREAKING CHANGES + +* **rds:** the default retention policy for RDS Cluster and DbInstance is now 'Snapshot' +* **cognito:** OAuth flows `authorizationCodeGrant` and +`implicitCodeGrant` in `UserPoolClient` are enabled by default. +* **cognito:** `callbackUrl` property in `UserPoolClient` is now +optional and has a default. +* **cognito:** All OAuth scopes in a `UserPoolClient` are now enabled +by default. + +### Features + +* **cfn-include:** add support for Conditions ([#8144](https://github.com/aws/aws-cdk/issues/8144)) ([33212d2](https://github.com/aws/aws-cdk/commit/33212d2c3adfc5a06ec4557787aea1b3cd1e8143)) +* **cognito:** addDomain() on an imported user pool ([#8123](https://github.com/aws/aws-cdk/issues/8123)) ([49c9f99](https://github.com/aws/aws-cdk/commit/49c9f99c4dfd73bf53a461a844a1d9b0c02d3761)) +* **cognito:** sign in url for a UserPoolDomain ([#8155](https://github.com/aws/aws-cdk/issues/8155)) ([e942936](https://github.com/aws/aws-cdk/commit/e94293675b0a9ebeb5876283d6a54427391469bd)) +* **cognito:** user pool identity provider with support for Facebook & Amazon ([#8134](https://github.com/aws/aws-cdk/issues/8134)) ([1ad919f](https://github.com/aws/aws-cdk/commit/1ad919fecf7cda45293efc3c0805b2eb5b49ed69)) +* **dynamodb:** allow providing indexes when importing a Table ([#8245](https://github.com/aws/aws-cdk/issues/8245)) ([9ee61eb](https://github.com/aws/aws-cdk/commit/9ee61eb96de54fcbb71e41a2db2c1c9ec6b7b8d9)), closes [#6392](https://github.com/aws/aws-cdk/issues/6392) +* **events-targets:** kinesis stream as event rule target ([#8176](https://github.com/aws/aws-cdk/issues/8176)) ([21ebc2d](https://github.com/aws/aws-cdk/commit/21ebc2dfdcc202bac47083d4c7d06e1ae4df0709)), closes [#2997](https://github.com/aws/aws-cdk/issues/2997) +* **lambda-nodejs:** allow passing env vars to container ([#8169](https://github.com/aws/aws-cdk/issues/8169)) ([1755cf2](https://github.com/aws/aws-cdk/commit/1755cf274b4da446272f109b55b20680beb34fe7)), closes [#8031](https://github.com/aws/aws-cdk/issues/8031) +* **rds:** change the default retention policy of Cluster and DB Instance to Snapshot ([#8023](https://github.com/aws/aws-cdk/issues/8023)) ([2d83328](https://github.com/aws/aws-cdk/commit/2d833280be7a8550ab4a713e7213f1dd351f9767)), closes [#3298](https://github.com/aws/aws-cdk/issues/3298) +* **redshift:** add initial L2 Redshift construct ([#5730](https://github.com/aws/aws-cdk/issues/5730)) ([703f0fa](https://github.com/aws/aws-cdk/commit/703f0fa6e2ba5e668d6a92200493d19d2af626c0)), closes [#5711](https://github.com/aws/aws-cdk/issues/5711) +* **s3:** supports RemovalPolicy for BucketPolicy ([#8158](https://github.com/aws/aws-cdk/issues/8158)) ([cb71f34](https://github.com/aws/aws-cdk/commit/cb71f340343011a2a2de9758879a56e898b8e12c)), closes [#7415](https://github.com/aws/aws-cdk/issues/7415) +* **stepfunctions-tasks:** start a nested state machine execution as a construct ([#8178](https://github.com/aws/aws-cdk/issues/8178)) ([3000dd5](https://github.com/aws/aws-cdk/commit/3000dd58cbe05cc483e30da6c8b18e9e3bf27e0f)) +* **stepfunctions-tasks:** task state construct to submit a job to AWS Batch ([#8115](https://github.com/aws/aws-cdk/issues/8115)) ([bc41cd5](https://github.com/aws/aws-cdk/commit/bc41cd5662314202c9bd8af87587990ad0b50282)) + + +### Bug Fixes + +* **apigateway:** deployment is not updated when OpenAPI definition is updated ([#8207](https://github.com/aws/aws-cdk/issues/8207)) ([d28c947](https://github.com/aws/aws-cdk/commit/d28c9473e0f480eba06e7dc9c260e4372501fc36)), closes [#8159](https://github.com/aws/aws-cdk/issues/8159) +* **app-delivery:** could not use PipelineDeployStackAction more than once in a Stage ([#8217](https://github.com/aws/aws-cdk/issues/8217)) ([9a54447](https://github.com/aws/aws-cdk/commit/9a54447f2a7d7e3a5d31a57bb3b2e2b0555430a1)), closes [#3984](https://github.com/aws/aws-cdk/issues/3984) [#8183](https://github.com/aws/aws-cdk/issues/8183) +* **cli:** termination protection not updated when change set has no changes ([#8275](https://github.com/aws/aws-cdk/issues/8275)) ([29d3145](https://github.com/aws/aws-cdk/commit/29d3145d1f4d7e17cd20f197d3c4955f48d07b37)) +* **codepipeline:** allow multiple CodeCommit source actions using events ([#8018](https://github.com/aws/aws-cdk/issues/8018)) ([103c144](https://github.com/aws/aws-cdk/commit/103c1449683ffc131b696faff8b16f0935a3c3f4)), closes [#7802](https://github.com/aws/aws-cdk/issues/7802) +* **codepipeline:** correctly handle CODEBUILD_CLONE_REF in BitBucket source ([#7107](https://github.com/aws/aws-cdk/issues/7107)) ([ac001b8](https://github.com/aws/aws-cdk/commit/ac001b86bbff1801005cac1509e4480a30bf8f15)) +* **codepipeline:** unhelpful artifact validation messages ([#8256](https://github.com/aws/aws-cdk/issues/8256)) ([2a2406e](https://github.com/aws/aws-cdk/commit/2a2406e5cc16e3bcce4e355f54b31ca8a7c2ace6)) +* **core:** CFN version and description template sections were merged incorrectly ([#8251](https://github.com/aws/aws-cdk/issues/8251)) ([b7e328d](https://github.com/aws/aws-cdk/commit/b7e328da4e7720c27bd7e828ffe3d3ae9dc1d070)), closes [#8151](https://github.com/aws/aws-cdk/issues/8151) +* **lambda:** `SingletonFunction.grantInvoke()` API fails with error 'No child with id' ([#8296](https://github.com/aws/aws-cdk/issues/8296)) ([a8b1815](https://github.com/aws/aws-cdk/commit/a8b1815f47b140b0fb06a3df0314c0fe28816fb6)), closes [#8240](https://github.com/aws/aws-cdk/issues/8240) +* **rds:** cannot delete a stack with DbCluster set to 'Retain' ([#8110](https://github.com/aws/aws-cdk/issues/8110)) ([c2e534e](https://github.com/aws/aws-cdk/commit/c2e534ecab219be8cd8174b60da3b58072dcfd47)), closes [#5282](https://github.com/aws/aws-cdk/issues/5282) +* **sqs:** unable to use CfnParameter 'valueAsNumber' to specify queue properties ([#8252](https://github.com/aws/aws-cdk/issues/8252)) ([8ec405f](https://github.com/aws/aws-cdk/commit/8ec405f5c016d0cbe1b9eeea6649e1e68f9b76e7)), closes [#7126](https://github.com/aws/aws-cdk/issues/7126) + ## [1.42.1](https://github.com/aws/aws-cdk/compare/v1.42.0...v1.42.1) (2020-06-01) diff --git a/design/aws-guidelines.md b/design/aws-guidelines.md index 56d0516417505..85082cae278a3 100644 --- a/design/aws-guidelines.md +++ b/design/aws-guidelines.md @@ -320,7 +320,7 @@ export interface IFoo extends cdk.IConstruct, ISomething { // attributes readonly fooArn: string; - readonly fooBoo: string; + readonly fooBoo: string[]; // security group connections (if applicable) readonly connections: ec2.Connections; diff --git a/fetch-dotnet-snk.sh b/fetch-dotnet-snk.sh index f4a399eeb97b0..d7c7caf39afb4 100644 --- a/fetch-dotnet-snk.sh +++ b/fetch-dotnet-snk.sh @@ -11,15 +11,14 @@ function echo_usage() { echo -e "\tDOTNET_STRONG_NAME_SECRET_ID=" } -if [ -z "${DOTNET_STRONG_NAME_ENABLED:-}" ]; then - echo "Environment variable DOTNET_STRONG_NAME_ENABLED is not set. Skipping strong-name signing." +if [ "${DOTNET_STRONG_NAME_ENABLED:-false}" != "true" ]; then + echo "Environment variable DOTNET_STRONG_NAME_ENABLED is not set to true. Skipping strong-name signing." exit 0 fi echo "Retrieving SNK..." -apt update -y -apt install jq -y +yum install jq -y if [ -z "${DOTNET_STRONG_NAME_ROLE_ARN:-}" ]; then echo "Strong name signing is enabled, but DOTNET_STRONG_NAME_ROLE_ARN is not set." diff --git a/lerna.json b/lerna.json index ed6fe98880477..9e6a0c4ba7b18 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "tools/*" ], "rejectCycles": "true", - "version": "1.42.1" + "version": "1.44.0" } diff --git a/package.json b/package.json index 6a465930f912c..199c117aa6641 100644 --- a/package.json +++ b/package.json @@ -15,11 +15,11 @@ }, "devDependencies": { "conventional-changelog-cli": "^2.0.34", - "fs-extra": "^8.1.0", - "jsii-diff": "^1.5.0", - "jsii-pacmak": "^1.5.0", - "jsii-rosetta": "^1.5.0", - "lerna": "^3.21.0", + "fs-extra": "^9.0.1", + "jsii-diff": "^1.6.0", + "jsii-pacmak": "^1.6.0", + "jsii-rosetta": "^1.6.0", + "lerna": "^3.22.0", "standard-version": "^8.0.0", "graceful-fs": "^4.2.4", "typescript": "~3.8.3" diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index 7892cc9fc6801..92cae774b8353 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -65,7 +65,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "@types/sinon": "^9.0.3", + "@types/sinon": "^9.0.4", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts index 70d5408009700..9215c28de1e61 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts @@ -170,7 +170,7 @@ export class TokenAuthorizer extends LambdaAuthorizer { name: props.authorizerName ?? this.node.uniqueId, restApiId, type: 'TOKEN', - authorizerUri: `arn:aws:apigateway:${Stack.of(this).region}:lambda:path/2015-03-31/functions/${props.handler.functionArn}/invocations`, + authorizerUri: lambdaAuthorizerArn(props.handler), authorizerCredentials: props.assumeRole?.roleArn, authorizerResultTtlInSeconds: props.resultsCacheTtl?.toSeconds(), identitySource: props.identitySource || 'method.request.header.Authorization', @@ -232,7 +232,7 @@ export class RequestAuthorizer extends LambdaAuthorizer { name: props.authorizerName ?? this.node.uniqueId, restApiId, type: 'REQUEST', - authorizerUri: `arn:aws:apigateway:${Stack.of(this).region}:lambda:path/2015-03-31/functions/${props.handler.functionArn}/invocations`, + authorizerUri: lambdaAuthorizerArn(props.handler), authorizerCredentials: props.assumeRole?.roleArn, authorizerResultTtlInSeconds: props.resultsCacheTtl?.toSeconds(), identitySource: props.identitySources.map(is => is.toString()).join(','), @@ -248,3 +248,10 @@ export class RequestAuthorizer extends LambdaAuthorizer { this.setupPermissions(); } } + +/** + * constructs the authorizerURIArn. + */ +function lambdaAuthorizerArn(handler: lambda.IFunction) { + return `arn:${Stack.of(handler).partition}:apigateway:${Stack.of(handler).region}:lambda:path/2015-03-31/functions/${handler.functionArn}/invocations`; +} diff --git a/packages/@aws-cdk/aws-apigateway/lib/integration.ts b/packages/@aws-cdk/aws-apigateway/lib/integration.ts index 05356a57a861e..d7a9ec74f3b34 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integration.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integration.ts @@ -113,9 +113,9 @@ export interface IntegrationProps { * - If you specify HTTP for the `type` property, specify the API endpoint URL. * - If you specify MOCK for the `type` property, don't specify this property. * - If you specify AWS for the `type` property, specify an AWS service that - * follows this form: `arn:aws:apigateway:region:subdomain.service|service:path|action/service_api.` + * follows this form: `arn:partition:apigateway:region:subdomain.service|service:path|action/service_api.` * For example, a Lambda function URI follows this form: - * arn:aws:apigateway:region:lambda:path/path. The path is usually in the + * arn:partition:apigateway:region:lambda:path/path. The path is usually in the * form /2015-03-31/functions/LambdaFunctionARN/invocations. * * @see https://docs.aws.amazon.com/apigateway/api-reference/resource/integration/#uri diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.expected.json index 25995111b8677..89ab550818465 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.expected.json @@ -131,30 +131,6 @@ "Name": "MyRestApi" } }, - "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyRestApi2D1F47A9" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "MyRestApiANY05143F93" - ] - }, - "MyRestApiDeploymentStageprodC33B8E5F": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "MyRestApi2D1F47A9" - }, - "DeploymentId": { - "Ref": "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb" - }, - "StageName": "prod" - } - }, "MyRestApiCloudWatchRoleD4042E8E": { "Type": "AWS::IAM::Role", "Properties": { @@ -200,6 +176,30 @@ "MyRestApi2D1F47A9" ] }, + "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyRestApi2D1F47A9" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "MyRestApiANY05143F93" + ] + }, + "MyRestApiDeploymentStageprodC33B8E5F": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "MyRestApi2D1F47A9" + }, + "DeploymentId": { + "Ref": "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb" + }, + "StageName": "prod" + } + }, "MyRestApiANY05143F93": { "Type": "AWS::ApiGateway::Method", "Properties": { @@ -247,7 +247,11 @@ "Fn::Join": [ "", [ - "arn:aws:apigateway:", + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", { "Ref": "AWS::Region" }, diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json index 97105a9490e83..339f10a1d17e0 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json @@ -119,7 +119,11 @@ "Fn::Join": [ "", [ - "arn:aws:apigateway:", + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", { "Ref": "AWS::Region" }, @@ -170,30 +174,6 @@ "Name": "MyRestApi" } }, - "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyRestApi2D1F47A9" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "MyRestApiANY05143F93" - ] - }, - "MyRestApiDeploymentStageprodC33B8E5F": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "MyRestApi2D1F47A9" - }, - "DeploymentId": { - "Ref": "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb" - }, - "StageName": "prod" - } - }, "MyRestApiCloudWatchRoleD4042E8E": { "Type": "AWS::IAM::Role", "Properties": { @@ -239,6 +219,30 @@ "MyRestApi2D1F47A9" ] }, + "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyRestApi2D1F47A9" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "MyRestApiANY05143F93" + ] + }, + "MyRestApiDeploymentStageprodC33B8E5F": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "MyRestApi2D1F47A9" + }, + "DeploymentId": { + "Ref": "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb" + }, + "StageName": "prod" + } + }, "MyRestApiANY05143F93": { "Type": "AWS::ApiGateway::Method", "Properties": { diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.expected.json b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.expected.json index 79102afef29f4..0d4f784d0362d 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.expected.json @@ -131,30 +131,6 @@ "Name": "MyRestApi" } }, - "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyRestApi2D1F47A9" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "MyRestApiANY05143F93" - ] - }, - "MyRestApiDeploymentStageprodC33B8E5F": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "MyRestApi2D1F47A9" - }, - "DeploymentId": { - "Ref": "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb" - }, - "StageName": "prod" - } - }, "MyRestApiCloudWatchRoleD4042E8E": { "Type": "AWS::IAM::Role", "Properties": { @@ -200,6 +176,30 @@ "MyRestApi2D1F47A9" ] }, + "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyRestApi2D1F47A9" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "MyRestApiANY05143F93" + ] + }, + "MyRestApiDeploymentStageprodC33B8E5F": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "MyRestApi2D1F47A9" + }, + "DeploymentId": { + "Ref": "MyRestApiDeploymentB555B582dcff966d69deeda8d47e3bf409ce29cb" + }, + "StageName": "prod" + } + }, "MyRestApiANY05143F93": { "Type": "AWS::ApiGateway::Method", "Properties": { @@ -247,7 +247,11 @@ "Fn::Join": [ "", [ - "arn:aws:apigateway:", + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", { "Ref": "AWS::Region" }, diff --git a/packages/@aws-cdk/aws-apigateway/test/authorizers/test.lambda.ts b/packages/@aws-cdk/aws-apigateway/test/authorizers/test.lambda.ts index 83a2ff959d9be..4741647d25347 100644 --- a/packages/@aws-cdk/aws-apigateway/test/authorizers/test.lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/test/authorizers/test.lambda.ts @@ -29,6 +29,26 @@ export = { Type: 'TOKEN', RestApiId: stack.resolve(restApi.restApiId), IdentitySource: 'method.request.header.Authorization', + AuthorizerUri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':lambda:path/2015-03-31/functions/', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + '/invocations', + ], + ], + }, })); expect(stack).to(haveResource('AWS::Lambda::Permission', { @@ -65,6 +85,26 @@ export = { expect(stack).to(haveResource('AWS::ApiGateway::Authorizer', { Type: 'REQUEST', RestApiId: stack.resolve(restApi.restApiId), + AuthorizerUri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':lambda:path/2015-03-31/functions/', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + '/invocations', + ], + ], + }, })); expect(stack).to(haveResource('AWS::Lambda::Permission', { @@ -125,6 +165,26 @@ export = { IdentityValidationExpression: 'a-hacker', Name: 'myauthorizer', AuthorizerResultTtlInSeconds: 60, + AuthorizerUri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':lambda:path/2015-03-31/functions/', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + '/invocations', + ], + ], + }, })); test.done(); @@ -158,6 +218,26 @@ export = { IdentitySource: 'method.request.header.whoami', Name: 'myauthorizer', AuthorizerResultTtlInSeconds: 60, + AuthorizerUri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':lambda:path/2015-03-31/functions/', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + '/invocations', + ], + ], + }, })); test.done(); @@ -191,6 +271,26 @@ export = { expect(stack).to(haveResource('AWS::ApiGateway::Authorizer', { Type: 'TOKEN', RestApiId: stack.resolve(restApi.restApiId), + AuthorizerUri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':lambda:path/2015-03-31/functions/', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + '/invocations', + ], + ], + }, })); expect(stack).to(haveResource('AWS::IAM::Role')); @@ -245,6 +345,26 @@ export = { expect(stack).to(haveResource('AWS::ApiGateway::Authorizer', { Type: 'REQUEST', RestApiId: stack.resolve(restApi.restApiId), + AuthorizerUri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':lambda:path/2015-03-31/functions/', + { + 'Fn::GetAtt': ['myfunction9B95E948', 'Arn'], + }, + '/invocations', + ], + ], + }, })); expect(stack).to(haveResource('AWS::IAM::Role')); diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json index 043b4d20bea46..2cbc9c1ebbbb8 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json @@ -6,34 +6,6 @@ "Name": "cors-api-test" } }, - "corsapitestDeployment2BF1633A228079ea05e5799220dd4ca13512b92d": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "corsapitest8682546E" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "corsapitesttwitchDELETEB4C94228", - "corsapitesttwitchGET4270341B", - "corsapitesttwitchOPTIONSE5EEB527", - "corsapitesttwitchPOSTB52CFB02", - "corsapitesttwitch0E3D1559" - ] - }, - "corsapitestDeploymentStageprod8F31F2AB": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "corsapitest8682546E" - }, - "DeploymentId": { - "Ref": "corsapitestDeployment2BF1633A228079ea05e5799220dd4ca13512b92d" - }, - "StageName": "prod" - } - }, "corsapitestCloudWatchRole9AF5A81A": { "Type": "AWS::IAM::Role", "Properties": { @@ -79,6 +51,34 @@ "corsapitest8682546E" ] }, + "corsapitestDeployment2BF1633A228079ea05e5799220dd4ca13512b92d": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "corsapitest8682546E" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "corsapitesttwitchDELETEB4C94228", + "corsapitesttwitchGET4270341B", + "corsapitesttwitchOPTIONSE5EEB527", + "corsapitesttwitchPOSTB52CFB02", + "corsapitesttwitch0E3D1559" + ] + }, + "corsapitestDeploymentStageprod8F31F2AB": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "corsapitest8682546E" + }, + "DeploymentId": { + "Ref": "corsapitestDeployment2BF1633A228079ea05e5799220dd4ca13512b92d" + }, + "StageName": "prod" + } + }, "corsapitesttwitch0E3D1559": { "Type": "AWS::ApiGateway::Resource", "Properties": { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.books.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.books.expected.json index 0d471973c58ca..8b679bd6c6239 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.books.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.books.expected.json @@ -156,36 +156,6 @@ "Name": "books-api" } }, - "booksapiDeployment308B08F132cc25cf8168bd5e99b9e6d4915866b5": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "booksapiE1885304" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "booksapiANYF4F0CDEB", - "booksapibooksbookidDELETE214F4059", - "booksapibooksbookidGETCCE21986", - "booksapibooksbookid5264BCA2", - "booksapibooksGETA776447A", - "booksapibooksPOSTF6C6559D", - "booksapibooks97D84727" - ] - }, - "booksapiDeploymentStageprod55D8E03E": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "booksapiE1885304" - }, - "DeploymentId": { - "Ref": "booksapiDeployment308B08F132cc25cf8168bd5e99b9e6d4915866b5" - }, - "StageName": "prod" - } - }, "booksapiCloudWatchRole089CB225": { "Type": "AWS::IAM::Role", "Properties": { @@ -231,6 +201,36 @@ "booksapiE1885304" ] }, + "booksapiDeployment308B08F132cc25cf8168bd5e99b9e6d4915866b5": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "booksapiE1885304" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "booksapiANYF4F0CDEB", + "booksapibooksbookidDELETE214F4059", + "booksapibooksbookidGETCCE21986", + "booksapibooksbookid5264BCA2", + "booksapibooksGETA776447A", + "booksapibooksPOSTF6C6559D", + "booksapibooks97D84727" + ] + }, + "booksapiDeploymentStageprod55D8E03E": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "booksapiE1885304" + }, + "DeploymentId": { + "Ref": "booksapiDeployment308B08F132cc25cf8168bd5e99b9e6d4915866b5" + }, + "StageName": "prod" + } + }, "booksapiANYApiPermissionrestapibooksexamplebooksapi4538F335ANY73B3CDDC": { "Type": "AWS::Lambda::Permission", "Properties": { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.defaults.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.defaults.expected.json index bf73644303e7d..ddc281809028d 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.defaults.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.defaults.expected.json @@ -6,30 +6,6 @@ "Name": "my-api" } }, - "myapiDeployment92F2CB4972a890db5063ec679071ba7eefc76f2a": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "myapi4C7BF186" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "myapiGETF990CE3C" - ] - }, - "myapiDeploymentStageprod298F01AF": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "myapi4C7BF186" - }, - "DeploymentId": { - "Ref": "myapiDeployment92F2CB4972a890db5063ec679071ba7eefc76f2a" - }, - "StageName": "prod" - } - }, "myapiCloudWatchRole095452E5": { "Type": "AWS::IAM::Role", "Properties": { @@ -75,6 +51,30 @@ "myapi4C7BF186" ] }, + "myapiDeployment92F2CB4972a890db5063ec679071ba7eefc76f2a": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "myapiGETF990CE3C" + ] + }, + "myapiDeploymentStageprod298F01AF": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "myapi4C7BF186" + }, + "DeploymentId": { + "Ref": "myapiDeployment92F2CB4972a890db5063ec679071ba7eefc76f2a" + }, + "StageName": "prod" + } + }, "myapiGETF990CE3C": { "Type": "AWS::ApiGateway::Method", "Properties": { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json index 9758c8c2e1b00..91af3471593eb 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json @@ -6,6 +6,51 @@ "Name": "my-api" } }, + "myapiCloudWatchRole095452E5": { + "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" + ] + ] + } + ] + } + }, + "myapiAccountEC421A0A": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "myapiCloudWatchRole095452E5", + "Arn" + ] + } + }, + "DependsOn": [ + "myapi4C7BF186" + ] + }, "myapiDeployment92F2CB4963d40685c54c6f8da21d80a83f16d3d5": { "Type": "AWS::ApiGateway::Deployment", "Properties": { @@ -57,51 +102,6 @@ "StageName": "beta" } }, - "myapiCloudWatchRole095452E5": { - "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" - ] - ] - } - ] - } - }, - "myapiAccountEC421A0A": { - "Type": "AWS::ApiGateway::Account", - "Properties": { - "CloudWatchRoleArn": { - "Fn::GetAtt": [ - "myapiCloudWatchRole095452E5", - "Arn" - ] - } - }, - "DependsOn": [ - "myapi4C7BF186" - ] - }, "myapiv113487378": { "Type": "AWS::ApiGateway::Resource", "Properties": { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.multistack.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.multistack.expected.json index 23a4100da8156..3404f37880155 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.multistack.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.multistack.expected.json @@ -75,32 +75,6 @@ "Name": "SecondRestAPI" } }, - "BooksApiDeployment86CA39AF7e6c771d47a1a3777eba99bffc037822": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "BooksApi60AC975F" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "BooksApiANY0C4EABE3", - "BooksApibooksGET6066BF7E", - "BooksApibooks1F745538" - ] - }, - "BooksApiDeploymentStageprod0693B760": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "BooksApi60AC975F" - }, - "DeploymentId": { - "Ref": "BooksApiDeployment86CA39AF7e6c771d47a1a3777eba99bffc037822" - }, - "StageName": "prod" - } - }, "BooksApiCloudWatchRoleB120ADBA": { "Type": "AWS::IAM::Role", "Properties": { @@ -146,6 +120,32 @@ "BooksApi60AC975F" ] }, + "BooksApiDeployment86CA39AF7e6c771d47a1a3777eba99bffc037822": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "BooksApi60AC975F" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "BooksApiANY0C4EABE3", + "BooksApibooksGET6066BF7E", + "BooksApibooks1F745538" + ] + }, + "BooksApiDeploymentStageprod0693B760": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "BooksApi60AC975F" + }, + "DeploymentId": { + "Ref": "BooksApiDeployment86CA39AF7e6c771d47a1a3777eba99bffc037822" + }, + "StageName": "prod" + } + }, "BooksApiANY0C4EABE3": { "Type": "AWS::ApiGateway::Method", "Properties": { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.multiuse.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.multiuse.expected.json index eb403f6d94d59..6a7cea680ef60 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.multiuse.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.multiuse.expected.json @@ -56,31 +56,6 @@ "Name": "hello-api" } }, - "helloapiDeploymentFA89AEEC3622d8c965f356a33fd95586d24bf138": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "helloapi4446A35B" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "helloapihelloGETE6A58337", - "helloapihello4AA00177" - ] - }, - "helloapiDeploymentStageprod677E2C4F": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "helloapi4446A35B" - }, - "DeploymentId": { - "Ref": "helloapiDeploymentFA89AEEC3622d8c965f356a33fd95586d24bf138" - }, - "StageName": "prod" - } - }, "helloapiCloudWatchRoleD13E913E": { "Type": "AWS::IAM::Role", "Properties": { @@ -126,6 +101,31 @@ "helloapi4446A35B" ] }, + "helloapiDeploymentFA89AEEC3622d8c965f356a33fd95586d24bf138": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "helloapi4446A35B" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "helloapihelloGETE6A58337", + "helloapihello4AA00177" + ] + }, + "helloapiDeploymentStageprod677E2C4F": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "helloapi4446A35B" + }, + "DeploymentId": { + "Ref": "helloapiDeploymentFA89AEEC3622d8c965f356a33fd95586d24bf138" + }, + "StageName": "prod" + } + }, "helloapihello4AA00177": { "Type": "AWS::ApiGateway::Resource", "Properties": { @@ -265,31 +265,6 @@ "Name": "second-api" } }, - "secondapiDeployment20F2C70088fa5a027620045bea3e5043c6d31f5a": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "secondapi730EF3C7" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "secondapihelloGETDC5BBB18", - "secondapihello7264EB69" - ] - }, - "secondapiDeploymentStageprod40491DF0": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "secondapi730EF3C7" - }, - "DeploymentId": { - "Ref": "secondapiDeployment20F2C70088fa5a027620045bea3e5043c6d31f5a" - }, - "StageName": "prod" - } - }, "secondapiCloudWatchRole7FEC1028": { "Type": "AWS::IAM::Role", "Properties": { @@ -335,6 +310,31 @@ "secondapi730EF3C7" ] }, + "secondapiDeployment20F2C70088fa5a027620045bea3e5043c6d31f5a": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "secondapi730EF3C7" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "secondapihelloGETDC5BBB18", + "secondapihello7264EB69" + ] + }, + "secondapiDeploymentStageprod40491DF0": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "secondapi730EF3C7" + }, + "DeploymentId": { + "Ref": "secondapiDeployment20F2C70088fa5a027620045bea3e5043c6d31f5a" + }, + "StageName": "prod" + } + }, "secondapihello7264EB69": { "Type": "AWS::ApiGateway::Resource", "Properties": { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.vpc-endpoint.expected.json b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.vpc-endpoint.expected.json index 21b7c8298d601..872513b9b89a2 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi.vpc-endpoint.expected.json +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi.vpc-endpoint.expected.json @@ -631,30 +631,6 @@ } } }, - "MyApiDeploymentECB0D05E7a475a505b0c925e193030293593b6dc": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyApi49610EDF" - }, - "Description": "Automatically created by the RestApi construct" - }, - "DependsOn": [ - "MyApiGETD0C7AA0C" - ] - }, - "MyApiDeploymentStageprodE1054AF0": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "RestApiId": { - "Ref": "MyApi49610EDF" - }, - "DeploymentId": { - "Ref": "MyApiDeploymentECB0D05E7a475a505b0c925e193030293593b6dc" - }, - "StageName": "prod" - } - }, "MyApiCloudWatchRole2BEC1A9C": { "Type": "AWS::IAM::Role", "Properties": { @@ -700,6 +676,30 @@ "MyApi49610EDF" ] }, + "MyApiDeploymentECB0D05E7a475a505b0c925e193030293593b6dc": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi49610EDF" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "MyApiGETD0C7AA0C" + ] + }, + "MyApiDeploymentStageprodE1054AF0": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "MyApi49610EDF" + }, + "DeploymentId": { + "Ref": "MyApiDeploymentECB0D05E7a475a505b0c925e193030293593b6dc" + }, + "StageName": "prod" + } + }, "MyApiGETD0C7AA0C": { "Type": "AWS::ApiGateway::Method", "Properties": { diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 3bf41e5ca126d..2384382bc90b2 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index cc2107d9dabab..2ed0d52f9378a 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -64,7 +64,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 40bc3b600f959..f380c06de5364 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -70,7 +70,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 4d1a07638ef0d..3290ef3d3f408 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -70,7 +70,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index 8f8cb92d237ef..65c3d3b886f1f 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-cloudtrail": "0.0.0", - "@types/lodash": "^4.14.153", + "@types/lodash": "^4.14.155", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index 229c6d1cbd00c..8ee0f57c7db5a 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -36,6 +36,7 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw - [Emails](#emails) - [Lambda Triggers](#lambda-triggers) - [Import](#importing-user-pools) + - [Identity Providers](#identity-providers) - [App Clients](#app-clients) - [Domains](#domains) @@ -334,6 +335,36 @@ const otherAwesomePool = UserPool.fromUserPoolArn(stack, 'other-awesome-user-poo 'arn:aws:cognito-idp:eu-west-1:123456789012:userpool/us-east-1_mtRyYQ14D'); ``` +### Identity Providers + +Users that are part of a user pool can sign in either directly through a user pool, or federate through a third-party +identity provider. Once configured, the Cognito backend will take care of integrating with the third-party provider. +Read more about [Adding User Pool Sign-in Through a Third +Party](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-identity-federation.html). + +The following third-party identity providers are currentlhy supported in the CDK - + +* [Login With Amazon](https://developer.amazon.com/apps-and-games/login-with-amazon) +* [Facebook Login](https://developers.facebook.com/docs/facebook-login/) + +The following code configures a user pool to federate with the third party provider, 'Login with Amazon'. The identity +provider needs to be configured with a set of credentials that the Cognito backend can use to federate with the +third-party identity provider. + +```ts +const userpool = new UserPool(stack, 'Pool'); + +const provider = new UserPoolIdentityProviderAmazon(stack, 'Amazon', { + clientId: 'amzn-client-id', + clientSecret: 'amzn-client-secret', + userPool: userpool, +}); +``` + +In order to allow users to sign in with a third-party identity provider, the app client that faces the user should be +configured to use the identity provider. See [App Clients](#app-clients) section to know more about App Clients. +The identity providers should be configured on `identityProviders` property available on the `UserPoolClient` construct. + ### App Clients An app is an entity within a user pool that has permission to call unauthenticated APIs (APIs that do not have an @@ -417,6 +448,22 @@ pool.addClient('app-client', { }); ``` +All identity providers created in the CDK app are automatically registered into the corresponding user pool. All app +clients created in the CDK have all of the identity providers enabled by default. The 'Cognito' identity provider, +that allows users to register and sign in directly with the Cognito user pool, is also enabled by default. +Alternatively, the list of supported identity providers for a client can be explicitly specified - + +```ts +const pool = new UserPool(this, 'Pool'); +pool.addClient('app-client', { + // ... + supportedIdentityProviders: [ + UserPoolClientIdentityProvider.AMAZON, + UserPoolClientIdentityProvider.COGNITO, + ] +}); +``` + ### Domains After setting up an [app client](#app-clients), the address for the user pool's sign-up and sign-in webpages can be @@ -446,7 +493,7 @@ pool.addDomain('CustomDomain', { Read more about [Using the Amazon Cognito Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-assign-domain-prefix.html) and [Using Your Own -Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html) +Domain](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html). The `signInUrl()` methods returns the fully qualified URL to the login page for the user pool. This page comes from the hosted UI configured with Cognito. Learn more at [Hosted UI with the Amazon Cognito @@ -474,4 +521,4 @@ const domain = userpool.addDomain('Domain', { const signInUrl = domain.signInUrl(client, { redirectUrl: 'https://myapp.com/home', // must be a URL configured under 'callbackUrls' with the client }) -``` \ No newline at end of file +``` diff --git a/packages/@aws-cdk/aws-cognito/lib/index.ts b/packages/@aws-cdk/aws-cognito/lib/index.ts index c7f8ba6547ceb..2da1e6121b69b 100644 --- a/packages/@aws-cdk/aws-cognito/lib/index.ts +++ b/packages/@aws-cdk/aws-cognito/lib/index.ts @@ -3,4 +3,6 @@ export * from './cognito.generated'; export * from './user-pool'; export * from './user-pool-attr'; export * from './user-pool-client'; -export * from './user-pool-domain'; \ No newline at end of file +export * from './user-pool-domain'; +export * from './user-pool-idp'; +export * from './user-pool-idps'; \ No newline at end of file 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 4c945a829aacf..b4b70c1c82a4a 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts @@ -145,6 +145,43 @@ export class OAuthScope { } } +/** + * Identity providers supported by the UserPoolClient + */ +export class UserPoolClientIdentityProvider { + /** + * Allow users to sign in using 'Facebook Login'. + * A `UserPoolIdentityProviderFacebook` must be attached to the user pool. + */ + public static readonly FACEBOOK = new UserPoolClientIdentityProvider('Facebook'); + + /** + * Allow users to sign in using 'Login With Amazon'. + * A `UserPoolIdentityProviderAmazon` must be attached to the user pool. + */ + public static readonly AMAZON = new UserPoolClientIdentityProvider('LoginWithAmazon'); + + /** + * Allow users to sign in directly as a user of the User Pool + */ + public static readonly COGNITO = new UserPoolClientIdentityProvider('COGNITO'); + + /** + * Specify a provider not yet supported by the CDK. + * @param name name of the identity provider as recognized by CloudFormation property `SupportedIdentityProviders` + */ + public static custom(name: string) { + return new UserPoolClientIdentityProvider(name); + } + + /** The name of the identity provider as recognized by CloudFormation property `SupportedIdentityProviders` */ + public readonly name: string; + + private constructor(name: string) { + this.name = name; + } +} + /** * Options to create a UserPoolClient */ @@ -182,6 +219,15 @@ export interface UserPoolClientOptions { * @default true for new stacks */ readonly preventUserExistenceErrors?: boolean; + + /** + * The list of identity providers that users should be able to use to sign in using this client. + * + * @default - supports all identity providers that are registered with the user pool. If the user pool and/or + * identity providers are imported, either specify this option explicitly or ensure that the identity providers are + * registered with the user pool using the `UserPool.registerIdentityProvider()` API. + */ + readonly supportedIdentityProviders?: UserPoolClientIdentityProvider[]; } /** @@ -262,7 +308,7 @@ export class UserPoolClient extends Resource implements IUserPoolClient { callbackUrLs: callbackUrls && callbackUrls.length > 0 ? callbackUrls : undefined, allowedOAuthFlowsUserPoolClient: props.oAuth ? true : undefined, preventUserExistenceErrors: this.configurePreventUserExistenceErrors(props.preventUserExistenceErrors), - supportedIdentityProviders: [ 'COGNITO' ], + supportedIdentityProviders: this.configureIdentityProviders(props), }); this.userPoolClientId = resource.ref; @@ -326,4 +372,17 @@ export class UserPoolClient extends Resource implements IUserPoolClient { } return prevent ? 'ENABLED' : 'LEGACY'; } + + private configureIdentityProviders(props: UserPoolClientProps): string[] | undefined { + let providers: string[]; + if (!props.supportedIdentityProviders) { + const providerSet = new Set(props.userPool.identityProviders.map((p) => p.providerName)); + providerSet.add('COGNITO'); + providers = Array.from(providerSet); + } else { + providers = props.supportedIdentityProviders.map((p) => p.name); + } + if (providers.length === 0) { return undefined; } + return Array.from(providers); + } } diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-idp.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-idp.ts new file mode 100644 index 0000000000000..30e8cb61bfe6d --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-idp.ts @@ -0,0 +1,31 @@ +import { Construct, IResource, Resource } from '@aws-cdk/core'; + +/** + * Represents a UserPoolIdentityProvider + */ +export interface IUserPoolIdentityProvider extends IResource { + /** + * The primary identifier of this identity provider + * @attribute + */ + readonly providerName: string; +} + +/** + * User pool third-party identity providers + */ +export class UserPoolIdentityProvider { + + /** + * Import an existing UserPoolIdentityProvider + */ + public static fromProviderName(scope: Construct, id: string, providerName: string): IUserPoolIdentityProvider { + class Import extends Resource implements IUserPoolIdentityProvider { + public readonly providerName: string = providerName; + } + + return new Import(scope, id); + } + + private constructor() {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/amazon.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/amazon.ts new file mode 100644 index 0000000000000..d5f4fd5402609 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/amazon.ts @@ -0,0 +1,52 @@ +import { Construct } from '@aws-cdk/core'; +import { CfnUserPoolIdentityProvider } from '../cognito.generated'; +import { UserPoolIdentityProviderBase, UserPoolIdentityProviderProps } from './base'; + +/** + * Properties to initialize UserPoolAmazonIdentityProvider + */ +export interface UserPoolIdentityProviderAmazonProps extends UserPoolIdentityProviderProps { + /** + * The client id recognized by 'Login with Amazon' APIs. + * @see https://developer.amazon.com/docs/login-with-amazon/security-profile.html#client-identifier + */ + readonly clientId: string; + /** + * The client secret to be accompanied with clientId for 'Login with Amazon' APIs to authenticate the client. + * @see https://developer.amazon.com/docs/login-with-amazon/security-profile.html#client-identifier + */ + readonly clientSecret: string; + /** + * The types of user profile data to obtain for the Amazon profile. + * @see https://developer.amazon.com/docs/login-with-amazon/customer-profile.html + * @default [ profile ] + */ + readonly scopes?: string[]; +} + +/** + * Represents a identity provider that integrates with 'Login with Amazon' + * @resource AWS::Cognito::UserPoolIdentityProvider + */ +export class UserPoolIdentityProviderAmazon extends UserPoolIdentityProviderBase { + public readonly providerName: string; + + constructor(scope: Construct, id: string, props: UserPoolIdentityProviderAmazonProps) { + super(scope, id, props); + + const scopes = props.scopes ?? [ 'profile' ]; + + const resource = new CfnUserPoolIdentityProvider(this, 'Resource', { + userPoolId: props.userPool.userPoolId, + providerName: 'LoginWithAmazon', // must be 'LoginWithAmazon' when the type is 'LoginWithAmazon' + providerType: 'LoginWithAmazon', + providerDetails: { + client_id: props.clientId, + client_secret: props.clientSecret, + authorize_scopes: scopes.join(' '), + }, + }); + + this.providerName = super.getResourceNameAttribute(resource.ref); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/base.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/base.ts new file mode 100644 index 0000000000000..b95ffd106a285 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/base.ts @@ -0,0 +1,25 @@ +import { Construct, Resource } from '@aws-cdk/core'; +import { IUserPool } from '../user-pool'; +import { IUserPoolIdentityProvider } from '../user-pool-idp'; + +/** + * Properties to create a new instance of UserPoolIdentityProvider + */ +export interface UserPoolIdentityProviderProps { + /** + * The user pool to which this construct provides identities. + */ + readonly userPool: IUserPool; +} + +/** + * Options to integrate with the various social identity providers. + */ +export abstract class UserPoolIdentityProviderBase extends Resource implements IUserPoolIdentityProvider { + public abstract readonly providerName: string; + + public constructor(scope: Construct, id: string, props: UserPoolIdentityProviderProps) { + super(scope, id); + props.userPool.registerIdentityProvider(this); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/facebook.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/facebook.ts new file mode 100644 index 0000000000000..d404c40965575 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/facebook.ts @@ -0,0 +1,57 @@ +import { Construct } from '@aws-cdk/core'; +import { CfnUserPoolIdentityProvider } from '../cognito.generated'; +import { UserPoolIdentityProviderBase, UserPoolIdentityProviderProps } from './base'; + +/** + * Properties to initialize UserPoolFacebookIdentityProvider + */ +export interface UserPoolIdentityProviderFacebookProps extends UserPoolIdentityProviderProps { + /** + * The client id recognized by Facebook APIs. + */ + readonly clientId: string; + /** + * The client secret to be accompanied with clientUd for Facebook to authenticate the client. + * @see https://developers.facebook.com/docs/facebook-login/security#appsecret + */ + readonly clientSecret: string; + /** + * The list of facebook permissions to obtain for getting access to the Facebook profile. + * @see https://developers.facebook.com/docs/facebook-login/permissions + * @default [ public_profile ] + */ + readonly scopes?: string[]; + /** + * The Facebook API version to use + * @default - to the oldest version supported by Facebook + */ + readonly apiVersion?: string; +} + +/** + * Represents a identity provider that integrates with 'Facebook Login' + * @resource AWS::Cognito::UserPoolIdentityProvider + */ +export class UserPoolIdentityProviderFacebook extends UserPoolIdentityProviderBase { + public readonly providerName: string; + + constructor(scope: Construct, id: string, props: UserPoolIdentityProviderFacebookProps) { + super(scope, id, props); + + const scopes = props.scopes ?? [ 'public_profile' ]; + + const resource = new CfnUserPoolIdentityProvider(this, 'Resource', { + userPoolId: props.userPool.userPoolId, + providerName: 'Facebook', // must be 'Facebook' when the type is 'Facebook' + providerType: 'Facebook', + providerDetails: { + client_id: props.clientId, + client_secret: props.clientSecret, + authorize_scopes: scopes.join(','), + api_version: props.apiVersion, + }, + }); + + this.providerName = super.getResourceNameAttribute(resource.ref); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/index.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/index.ts new file mode 100644 index 0000000000000..e0efb718962c4 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-idps/index.ts @@ -0,0 +1,3 @@ +export * from './base'; +export * from './amazon'; +export * from './facebook'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index a0bc9a32d2874..23af0723870ca 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -5,6 +5,7 @@ import { CfnUserPool } from './cognito.generated'; import { ICustomAttribute, RequiredAttributes } from './user-pool-attr'; import { UserPoolClient, UserPoolClientOptions } from './user-pool-client'; import { UserPoolDomain, UserPoolDomainOptions } from './user-pool-domain'; +import { IUserPoolIdentityProvider } from './user-pool-idp'; /** * The different ways in which users of this pool can sign up or sign in. @@ -525,6 +526,11 @@ export interface IUserPool extends IResource { */ readonly userPoolArn: string; + /** + * Get all identity providers registered with this user pool. + */ + readonly identityProviders: IUserPoolIdentityProvider[]; + /** * Add a new app client to this user pool. * @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html @@ -536,11 +542,17 @@ export interface IUserPool extends IResource { * @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-assign-domain.html */ addDomain(id: string, options: UserPoolDomainOptions): UserPoolDomain; + + /** + * Register an identity provider with this user pool. + */ + registerIdentityProvider(provider: IUserPoolIdentityProvider): void; } abstract class UserPoolBase extends Resource implements IUserPool { public abstract readonly userPoolId: string; public abstract readonly userPoolArn: string; + public readonly identityProviders: IUserPoolIdentityProvider[] = []; public addClient(id: string, options?: UserPoolClientOptions): UserPoolClient { return new UserPoolClient(this, id, { @@ -555,6 +567,10 @@ abstract class UserPoolBase extends Resource implements IUserPool { ...options, }); } + + public registerIdentityProvider(provider: IUserPoolIdentityProvider) { + this.identityProviders.push(provider); + } } /** diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index d3f83d76fcb5c..fee82c6b6c883 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -96,7 +96,9 @@ "exclude": [ "attribute-tag:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientName", "resource-attribute:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientClientSecret", - "props-physical-name:@aws-cdk/aws-cognito.UserPoolDomainProps" + "props-physical-name:@aws-cdk/aws-cognito.UserPoolDomainProps", + "props-physical-name:@aws-cdk/aws-cognito.UserPoolIdentityProviderFacebookProps", + "props-physical-name:@aws-cdk/aws-cognito.UserPoolIdentityProviderAmazonProps" ] }, "stability": "experimental", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.expected.json new file mode 100644 index 0000000000000..bbed1eca96f4c --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.expected.json @@ -0,0 +1,143 @@ +{ + "Resources": { + "poolsmsRole04048F13": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "integuserpoolidppoolAE0BD80C" + } + }, + "Effect": "Allow", + "Principal": { + "Service": "cognito-idp.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "sns-publish" + } + ] + } + }, + "pool056F3F7E": { + "Type": "AWS::Cognito::UserPool", + "Properties": { + "AdminCreateUserConfig": { + "AllowAdminCreateUserOnly": true + }, + "EmailVerificationMessage": "The verification code to your new account is {####}", + "EmailVerificationSubject": "Verify your new account", + "SmsConfiguration": { + "ExternalId": "integuserpoolidppoolAE0BD80C", + "SnsCallerArn": { + "Fn::GetAtt": [ + "poolsmsRole04048F13", + "Arn" + ] + } + }, + "SmsVerificationMessage": "The verification code to your new account is {####}", + "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 {####}" + } + } + }, + "poolclient2623294C": { + "Type": "AWS::Cognito::UserPoolClient", + "Properties": { + "UserPoolId": { + "Ref": "pool056F3F7E" + }, + "AllowedOAuthFlows": [ + "implicit", + "code" + ], + "AllowedOAuthScopes": [ + "profile", + "phone", + "email", + "openid", + "aws.cognito.signin.user.admin" + ], + "CallbackURLs": [ + "https://example.com" + ], + "SupportedIdentityProviders": [ + { + "Ref": "amazon2D32744A" + }, + "COGNITO" + ] + } + }, + "pooldomain430FA744": { + "Type": "AWS::Cognito::UserPoolDomain", + "Properties": { + "Domain": "nija-test-pool", + "UserPoolId": { + "Ref": "pool056F3F7E" + } + } + }, + "amazon2D32744A": { + "Type": "AWS::Cognito::UserPoolIdentityProvider", + "Properties": { + "ProviderName": "LoginWithAmazon", + "ProviderType": "LoginWithAmazon", + "UserPoolId": { + "Ref": "pool056F3F7E" + }, + "ProviderDetails": { + "client_id": "amzn-client-id", + "client_secret": "amzn-client-secret", + "authorize_scopes": "profile" + } + } + } + }, + "Outputs": { + "SignInLink": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "pooldomain430FA744" + }, + ".auth.", + { + "Ref": "AWS::Region" + }, + ".amazoncognito.com/login?client_id=", + { + "Ref": "poolclient2623294C" + }, + "&response_type=code&redirect_uri=https://example.com" + ] + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.ts new file mode 100644 index 0000000000000..e22b504cf8ad7 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.ts @@ -0,0 +1,32 @@ +import { App, CfnOutput, Stack } from '@aws-cdk/core'; +import { UserPool, UserPoolIdentityProviderAmazon } from '../lib'; + +/* + * Stack verification steps + * * Visit the URL provided by stack output 'SignInLink' in a browser, and verify the 'Login with Amazon' link shows up. + * * If you plug in valid 'Login with Amazon' credentials, the federated log in should work. + */ +const app = new App(); +const stack = new Stack(app, 'integ-user-pool-idp'); + +const userpool = new UserPool(stack, 'pool'); + +new UserPoolIdentityProviderAmazon(stack, 'amazon', { + userPool: userpool, + clientId: 'amzn-client-id', + clientSecret: 'amzn-client-secret', +}); + +const client = userpool.addClient('client'); + +const domain = userpool.addDomain('domain', { + cognitoDomain: { + domainPrefix: 'nija-test-pool', + }, +}); + +new CfnOutput(stack, 'SignInLink', { + value: domain.signInUrl(client, { + redirectUri: 'https://example.com', + }), +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts index 838584da1d25f..81b08dbec3750 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts @@ -1,7 +1,7 @@ import { ABSENT } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import { Stack } from '@aws-cdk/core'; -import { OAuthScope, UserPool, UserPoolClient } from '../lib'; +import { OAuthScope, UserPool, UserPoolClient, UserPoolClientIdentityProvider, UserPoolIdentityProvider } from '../lib'; describe('User Pool Client', () => { test('default setup', () => { @@ -365,4 +365,48 @@ describe('User Pool Client', () => { PreventUserExistenceErrors: ABSENT, }); }); + + test('default supportedIdentityProviders', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'Pool'); + + const idp = UserPoolIdentityProvider.fromProviderName(stack, 'imported', 'userpool-idp'); + pool.registerIdentityProvider(idp); + + // WHEN + new UserPoolClient(stack, 'Client', { + userPool: pool, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPoolClient', { + SupportedIdentityProviders: [ + 'userpool-idp', + 'COGNITO', + ], + }); + }); + + test('supportedIdentityProviders', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'Pool'); + + // WHEN + pool.addClient('AllEnabled', { + userPoolClientName: 'AllEnabled', + supportedIdentityProviders: [ + UserPoolClientIdentityProvider.COGNITO, + UserPoolClientIdentityProvider.FACEBOOK, + UserPoolClientIdentityProvider.AMAZON, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPoolClient', { + ClientName: 'AllEnabled', + SupportedIdentityProviders: [ 'COGNITO', 'Facebook', 'LoginWithAmazon' ], + }); + }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/amazon.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/amazon.test.ts new file mode 100644 index 0000000000000..78300c6b13e5f --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/amazon.test.ts @@ -0,0 +1,70 @@ +import '@aws-cdk/assert/jest'; +import { Stack } from '@aws-cdk/core'; +import { UserPool, UserPoolIdentityProviderAmazon } from '../../lib'; + +describe('UserPoolIdentityProvider', () => { + describe('amazon', () => { + test('defaults', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'userpool'); + + // WHEN + new UserPoolIdentityProviderAmazon(stack, 'userpoolidp', { + userPool: pool, + clientId: 'amzn-client-id', + clientSecret: 'amzn-client-secret', + }); + + expect(stack).toHaveResource('AWS::Cognito::UserPoolIdentityProvider', { + ProviderName: 'LoginWithAmazon', + ProviderType: 'LoginWithAmazon', + ProviderDetails: { + client_id: 'amzn-client-id', + client_secret: 'amzn-client-secret', + authorize_scopes: 'profile', + }, + }); + }); + + test('scopes', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'userpool'); + + // WHEN + new UserPoolIdentityProviderAmazon(stack, 'userpoolidp', { + userPool: pool, + clientId: 'amzn-client-id', + clientSecret: 'amzn-client-secret', + scopes: [ 'scope1', 'scope2' ], + }); + + expect(stack).toHaveResource('AWS::Cognito::UserPoolIdentityProvider', { + ProviderName: 'LoginWithAmazon', + ProviderType: 'LoginWithAmazon', + ProviderDetails: { + client_id: 'amzn-client-id', + client_secret: 'amzn-client-secret', + authorize_scopes: 'scope1 scope2', + }, + }); + }); + + test('registered with user pool', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'userpool'); + + // WHEN + const provider = new UserPoolIdentityProviderAmazon(stack, 'userpoolidp', { + userPool: pool, + clientId: 'amzn-client-id', + clientSecret: 'amzn-client-secret', + }); + + // THEN + expect(pool.identityProviders).toContain(provider); + }); + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-idps/facebook.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/facebook.test.ts new file mode 100644 index 0000000000000..40bc9287b5733 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-idps/facebook.test.ts @@ -0,0 +1,72 @@ +import '@aws-cdk/assert/jest'; +import { Stack } from '@aws-cdk/core'; +import { UserPool, UserPoolIdentityProviderFacebook } from '../../lib'; + +describe('UserPoolIdentityProvider', () => { + describe('facebook', () => { + test('defaults', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'userpool'); + + // WHEN + new UserPoolIdentityProviderFacebook(stack, 'userpoolidp', { + userPool: pool, + clientId: 'fb-client-id', + clientSecret: 'fb-client-secret', + }); + + expect(stack).toHaveResource('AWS::Cognito::UserPoolIdentityProvider', { + ProviderName: 'Facebook', + ProviderType: 'Facebook', + ProviderDetails: { + client_id: 'fb-client-id', + client_secret: 'fb-client-secret', + authorize_scopes: 'public_profile', + }, + }); + }); + + test('scopes & api_version', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'userpool'); + + // WHEN + new UserPoolIdentityProviderFacebook(stack, 'userpoolidp', { + userPool: pool, + clientId: 'fb-client-id', + clientSecret: 'fb-client-secret', + scopes: [ 'scope1', 'scope2' ], + apiVersion: 'version1', + }); + + expect(stack).toHaveResource('AWS::Cognito::UserPoolIdentityProvider', { + ProviderName: 'Facebook', + ProviderType: 'Facebook', + ProviderDetails: { + client_id: 'fb-client-id', + client_secret: 'fb-client-secret', + authorize_scopes: 'scope1,scope2', + api_version: 'version1', + }, + }); + }); + + test('registered with user pool', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'userpool'); + + // WHEN + const provider = new UserPoolIdentityProviderFacebook(stack, 'userpoolidp', { + userPool: pool, + clientId: 'fb-client-id', + clientSecret: 'fb-client-secret', + }); + + // THEN + expect(pool.identityProviders).toContain(provider); + }); + }); +}); \ No newline at end of file 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 83d4863b751c3..7472086d57fab 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -3,7 +3,7 @@ import { ABSENT } from '@aws-cdk/assert/lib/assertions/have-resource'; import { Role } from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { Construct, Duration, Stack, Tag } from '@aws-cdk/core'; -import { Mfa, NumberAttribute, StringAttribute, UserPool, UserPoolOperation, VerificationEmailStyle } from '../lib'; +import { Mfa, NumberAttribute, StringAttribute, UserPool, UserPoolIdentityProvider, UserPoolOperation, VerificationEmailStyle } from '../lib'; describe('User Pool', () => { test('default setup', () => { @@ -847,6 +847,21 @@ test('addDomain', () => { }); }); +test('registered identity providers', () => { + // GIVEN + const stack = new Stack(); + const userPool = new UserPool(stack, 'pool'); + const provider1 = UserPoolIdentityProvider.fromProviderName(stack, 'provider1', 'provider1'); + const provider2 = UserPoolIdentityProvider.fromProviderName(stack, 'provider2', 'provider2'); + + // WHEN + userPool.registerIdentityProvider(provider1); + userPool.registerIdentityProvider(provider2); + + // THEN + expect(userPool.identityProviders).toEqual([provider1, provider2]); +}); + function fooFunction(scope: Construct, name: string): lambda.IFunction { return new lambda.Function(scope, name, { functionName: name, diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 77e7e4ee0d1e1..2b06e10f822bc 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -65,7 +65,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/jest": "^25.2.3", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index 71b3591ed6fdf..22d4798ea7f36 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -358,3 +358,22 @@ scalableTarget.scaleOnMemoryUtilization('MemoryScaling', { targetUtilizationPercent: 50, }); ``` + +### Set deployment configuration on QueueProcessingService + +```ts +const queueProcessingFargateService = new QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + command: ["-c", "4", "amazon.com"], + enableLogging: false, + desiredTaskCount: 2, + environment: {}, + queue, + maxScalingCapacity: 5, + maxHealthyPercent: 200, + minHealthPercent: 66, +}); +``` + 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 6c43d4fd4aa6d..cd9e2f85f4633 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 @@ -147,6 +147,24 @@ export interface QueueProcessingServiceBaseProps { * @default - Automatically generated name. */ readonly family?: string; + + /** + * The maximum number of tasks, specified as a percentage of the Amazon ECS + * service's DesiredCount value, that can run in a service during a + * deployment. + * + * @default - default from underlying service. + */ + readonly maxHealthyPercent?: number; + + /** + * The minimum number of tasks, specified as a percentage of + * the Amazon ECS service's DesiredCount value, that must + * continue to run and remain healthy during a deployment. + * + * @default - default from underlying service. + */ + readonly minHealthyPercent?: number; } /** 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 0fb21d1f8263d..ff7cb0e905d98 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 @@ -96,6 +96,8 @@ export class QueueProcessingEc2Service extends QueueProcessingServiceBase { desiredCount: this.desiredCount, taskDefinition: this.taskDefinition, serviceName: props.serviceName, + minHealthyPercent: props.minHealthyPercent, + maxHealthyPercent: props.maxHealthyPercent, propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, }); 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 a7da98ed1fbfc..b0f92abab6f23 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 @@ -101,6 +101,8 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase { desiredCount: this.desiredCount, taskDefinition: this.taskDefinition, serviceName: props.serviceName, + minHealthyPercent: props.minHealthyPercent, + maxHealthyPercent: props.maxHealthyPercent, propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, platformVersion: props.platformVersion, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts index 3bd580cb93176..4bfa0732591cb 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts @@ -179,6 +179,8 @@ export = { }, queue, maxScalingCapacity: 5, + minHealthyPercent: 60, + maxHealthyPercent: 150, serviceName: 'ecs-test-service', family: 'ecs-task-family', }); @@ -186,6 +188,10 @@ export = { // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set. expect(stack).to(haveResource('AWS::ECS::Service', { DesiredCount: 2, + DeploymentConfiguration: { + MinimumHealthyPercent: 60, + MaximumPercent: 150, + }, LaunchType: 'EC2', ServiceName: 'ecs-test-service', })); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts index c37c7f349b496..4f0f434ef1f72 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts @@ -223,6 +223,8 @@ export = { }, queue, maxScalingCapacity: 5, + minHealthyPercent: 60, + maxHealthyPercent: 150, serviceName: 'fargate-test-service', family: 'fargate-task-family', platformVersion: ecs.FargatePlatformVersion.VERSION1_4, @@ -231,6 +233,10 @@ export = { // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. expect(stack).to(haveResource('AWS::ECS::Service', { DesiredCount: 2, + DeploymentConfiguration: { + MinimumHealthyPercent: 60, + MaximumPercent: 150, + }, LaunchType: 'FARGATE', ServiceName: 'fargate-test-service', PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index aa0b114f5de47..2aa311168dc6a 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index f51b406d5249f..4bdff4663018d 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -68,7 +68,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index b932a81975ee0..b415c57d92d9e 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -62,7 +62,7 @@ "@aws-cdk/assert": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 367e4dc8206d9..e6bcad26594e9 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -68,10 +68,10 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/aws-lambda": "^8.10.39", - "@types/lodash": "^4.14.153", + "@types/lodash": "^4.14.155", "@types/nodeunit": "^0.0.31", - "@types/sinon": "^9.0.3", - "aws-sdk": "^2.681.0", + "@types/sinon": "^9.0.4", + "aws-sdk": "^2.689.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 0496e2094d9f9..c99f3de12f7a1 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index ff1eb0933ce36..3aea5a8f58626 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -61,7 +61,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.31", - "@types/sinon": "^9.0.3", + "@types/sinon": "^9.0.4", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 84388336b33fa..ef28cad08a9ee 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -65,7 +65,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.31", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index c7cc3fe389099..c8482f9e57f09 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -216,6 +216,7 @@ The [SubmitJob](https://docs.aws.amazon.com/batch/latest/APIReference/API_Submit ```ts import * as batch from '@aws-cdk/aws-batch'; +import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; const batchQueue = new batch.JobQueue(this, 'JobQueue', { computeEnvironments: [ @@ -234,12 +235,10 @@ const batchJobDefinition = new batch.JobDefinition(this, 'JobDefinition', { }, }); -const task = new sfn.Task(this, 'Submit Job', { - task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, - jobName: 'MyJob', - jobQueue: batchQueue, - }), +const task = new tasks.BatchSubmitJob(this, 'Submit Job', { + jobDefinition: batchJobDefinition, + jobName: 'MyJob', + jobQueue: batchQueue, }); ``` @@ -728,15 +727,14 @@ const child = new sfn.StateMachine(stack, 'ChildStateMachine', { }); // Include the state machine in a Task state with callback pattern -const task = new sfn.Task(stack, 'ChildTask', { - task: new tasks.ExecuteStateMachine(child, { - integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, - input: { - token: sfn.Context.taskToken, - foo: 'bar' - }, - name: 'MyExecutionName' - }) +const task = new StepFunctionsStartExecution(stack, 'ChildTask', { + stateMachine: child, + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + input: sfn.TaskInput.fromObject({ + token: sfn.Context.taskToken, + foo: 'bar' + }), + name: 'MyExecutionName' }); // Define a second state machine with the Task state above diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/run-batch-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/run-batch-job.ts index 186d2da4ba5de..faeb7009b18eb 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/run-batch-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/run-batch-job.ts @@ -83,6 +83,8 @@ export interface JobDependency { /** * Properties for RunBatchJob + * + * @deprecated use `BatchSubmitJob` */ export interface RunBatchJobProps { /** @@ -170,6 +172,8 @@ export interface RunBatchJobProps { /** * A Step Functions Task to run AWS Batch + * + * @deprecated use `BatchSubmitJob` */ export class RunBatchJob implements sfn.IStepFunctionsTask { private readonly integrationPattern: sfn.ServiceIntegrationPattern; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts new file mode 100644 index 0000000000000..ee9577cbd6ac1 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/batch/submit-job.ts @@ -0,0 +1,311 @@ +import * as batch from '@aws-cdk/aws-batch'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Construct, Size, Stack, withResolved } from '@aws-cdk/core'; +import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; + +/** + * The overrides that should be sent to a container. + */ +export interface BatchContainerOverrides { + /** + * The command to send to the container that overrides + * the default command from the Docker image or the job definition. + * + * @default - No command overrides + */ + readonly command?: string[]; + + /** + * The environment variables to send to the container. + * You can add new environment variables, which are added to the container + * at launch, or you can override the existing environment variables from + * the Docker image or the job definition. + * + * @default - No environment overrides + */ + readonly environment?: { [key: string]: string }; + + /** + * The instance type to use for a multi-node parallel job. + * This parameter is not valid for single-node container jobs. + * + * @default - No instance type overrides + */ + readonly instanceType?: ec2.InstanceType; + + /** + * Memory reserved for the job. + * + * @default - No memory overrides. The memory supplied in the job definition will be used. + */ + readonly memory?: Size; + + /** + * The number of physical GPUs to reserve for the container. + * The number of GPUs reserved for all containers in a job + * should not exceed the number of available GPUs on the compute + * resource that the job is launched on. + * + * @default - No GPU reservation + */ + readonly gpuCount?: number; + + /** + * The number of vCPUs to reserve for the container. + * This value overrides the value set in the job definition. + * + * @default - No vCPUs overrides + */ + readonly vcpus?: number; +} + +/** + * An object representing an AWS Batch job dependency. + */ +export interface BatchJobDependency { + /** + * The job ID of the AWS Batch job associated with this dependency. + * + * @default - No jobId + */ + readonly jobId?: string; + + /** + * The type of the job dependency. + * + * @default - No type + */ + readonly type?: string; +} + +/** + * Properties for RunBatchJob + * + */ +export interface BatchSubmitJobProps extends sfn.TaskStateBaseProps { + /** + * The job definition used by this job. + */ + readonly jobDefinition: batch.IJobDefinition; + + /** + * The name of the job. + * The first character must be alphanumeric, and up to 128 letters (uppercase and lowercase), + * numbers, hyphens, and underscores are allowed. + */ + readonly jobName: string; + + /** + * The job queue into which the job is submitted. + */ + readonly jobQueue: batch.IJobQueue; + + /** + * The array size can be between 2 and 10,000. + * If you specify array properties for a job, it becomes an array job. + * For more information, see Array Jobs in the AWS Batch User Guide. + * + * @default - No array size + */ + readonly arraySize?: number; + + /** + * A list of container overrides in JSON format that specify the name of a container + * in the specified job definition and the overrides it should receive. + * + * @see https://docs.aws.amazon.com/batch/latest/APIReference/API_SubmitJob.html#Batch-SubmitJob-request-containerOverrides + * + * @default - No container overrides + */ + readonly containerOverrides?: BatchContainerOverrides; + + /** + * A list of dependencies for the job. + * A job can depend upon a maximum of 20 jobs. + * + * @see https://docs.aws.amazon.com/batch/latest/APIReference/API_SubmitJob.html#Batch-SubmitJob-request-dependsOn + * + * @default - No dependencies + */ + readonly dependsOn?: BatchJobDependency[]; + + /** + * The payload to be passed as parameters to the batch job + * + * @default - No parameters are passed + */ + readonly payload?: sfn.TaskInput; + + /** + * The number of times to move a job to the RUNNABLE status. + * You may specify between 1 and 10 attempts. + * If the value of attempts is greater than one, + * the job is retried on failure the same number of attempts as the value. + * + * @default 1 + */ + readonly attempts?: number; +} + +/** + * Task to submits an AWS Batch job from a job definition. + * + * @see https://docs.aws.amazon.com/step-functions/latest/dg/connect-batch.html + */ +export class BatchSubmitJob 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: BatchSubmitJobProps) { + super(scope, id, props); + + this.integrationPattern = props.integrationPattern ?? sfn.IntegrationPattern.RUN_JOB; + validatePatternSupported(this.integrationPattern, BatchSubmitJob.SUPPORTED_INTEGRATION_PATTERNS); + + // validate arraySize limits + withResolved(props.arraySize, (arraySize) => { + if (arraySize !== undefined && (arraySize < 2 || arraySize > 10_000)) { + throw new Error(`arraySize must be between 2 and 10,000. Received ${arraySize}.`); + } + }); + + // validate dependency size + if (props.dependsOn && props.dependsOn.length > 20) { + throw new Error(`dependencies must be 20 or less. Received ${props.dependsOn.length}.`); + } + + // validate attempts + withResolved(props.attempts, (attempts) => { + if (attempts !== undefined && (attempts < 1 || attempts > 10)) { + throw new Error(`attempts must be between 1 and 10. Received ${attempts}.`); + } + }); + + // validate timeout + // tslint:disable-next-line:no-unused-expression + props.timeout !== undefined && withResolved(props.timeout.toSeconds(), (timeout) => { + if (timeout < 60) { + throw new Error(`attempt duration must be greater than 60 seconds. Received ${timeout} seconds.`); + } + }); + + // This is required since environment variables must not start with AWS_BATCH; + // this naming convention is reserved for variables that are set by the AWS Batch service. + if (props.containerOverrides?.environment) { + Object.keys(props.containerOverrides.environment).forEach(key => { + if (key.match(/^AWS_BATCH/)) { + throw new Error( + `Invalid environment variable name: ${key}. Environment variable names starting with 'AWS_BATCH' are reserved.`, + ); + } + }); + } + + this.taskPolicies = this.configurePolicyStatements(); + } + + protected renderTask(): any { + return { + Resource: integrationResourceArn('batch', 'submitJob', this.integrationPattern), + Parameters: sfn.FieldUtils.renderObject({ + JobDefinition: this.props.jobDefinition.jobDefinitionArn, + JobName: this.props.jobName, + JobQueue: this.props.jobQueue.jobQueueArn, + Parameters: this.props.payload?.value, + ArrayProperties: + this.props.arraySize !== undefined + ? { Size: this.props.arraySize } + : undefined, + + ContainerOverrides: this.props.containerOverrides + ? this.configureContainerOverrides(this.props.containerOverrides) + : undefined, + + DependsOn: this.props.dependsOn + ? this.props.dependsOn.map(jobDependency => ({ + JobId: jobDependency.jobId, + Type: jobDependency.type, + })) + : undefined, + + RetryStrategy: + this.props.attempts !== undefined + ? { Attempts: this.props.attempts } + : undefined, + + Timeout: this.props.timeout + ? { AttemptDurationSeconds: this.props.timeout.toSeconds() } + : undefined, + }), + TimeoutSeconds: undefined, + }; + } + + private configurePolicyStatements(): iam.PolicyStatement[] { + return [ + // Resource level access control for job-definition requires revision which batch does not support yet + // Using the alternative permissions as mentioned here: + // https://docs.aws.amazon.com/batch/latest/userguide/batch-supported-iam-actions-resources.html + new iam.PolicyStatement({ + resources: [ + Stack.of(this).formatArn({ + service: 'batch', + resource: 'job-definition', + resourceName: '*', + }), + this.props.jobQueue.jobQueueArn, + ], + actions: ['batch:SubmitJob'], + }), + new iam.PolicyStatement({ + resources: [ + Stack.of(this).formatArn({ + service: 'events', + resource: 'rule/StepFunctionsGetEventsForBatchJobsRule', + }), + ], + actions: ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'], + }), + ]; + } + + private configureContainerOverrides(containerOverrides: BatchContainerOverrides) { + let environment; + if (containerOverrides.environment) { + environment = Object.entries(containerOverrides.environment).map( + ([key, value]) => ({ + Name: key, + Value: value, + }), + ); + } + + let resources; + if (containerOverrides.gpuCount) { + resources = [ + { + Type: 'GPU', + Value: `${containerOverrides.gpuCount}`, + }, + ]; + } + + return { + Command: containerOverrides.command, + Environment: environment, + InstanceType: containerOverrides.instanceType?.toString(), + Memory: containerOverrides.memory?.toMebibytes(), + ResourceRequirements: resources, + Vcpus: containerOverrides.vcpus, + }; + } +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts index 7b45086a4e48e..b9a5cd0a9f062 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/index.ts @@ -14,6 +14,7 @@ export * from './sagemaker/sagemaker-task-base-types'; export * from './sagemaker/sagemaker-train-task'; export * from './sagemaker/sagemaker-transform-task'; export * from './start-execution'; +export * from './stepfunctions/start-execution'; export * from './evaluate-expression'; export * from './emr/emr-create-cluster'; export * from './emr/emr-set-cluster-termination-protection'; @@ -25,4 +26,5 @@ export * from './emr/emr-modify-instance-group-by-name'; export * from './glue/run-glue-job-task'; export * from './glue/start-job-run'; export * from './batch/run-batch-job'; +export * from './batch/submit-job'; export * from './dynamodb/call-dynamodb'; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/start-execution.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/start-execution.ts index 049e558971206..9ec81c367e4df 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/start-execution.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/start-execution.ts @@ -5,6 +5,8 @@ import { getResourceArn } from './resource-arn-suffix'; /** * Properties for StartExecution + * + * @deprecated - use 'StepFunctionsStartExecution' */ export interface StartExecutionProps { /** @@ -39,6 +41,8 @@ export interface StartExecutionProps { * A Step Functions Task to call StartExecution on another state machine. * * It supports three service integration patterns: FIRE_AND_FORGET, SYNC and WAIT_FOR_TASK_TOKEN. + * + * @deprecated - use 'StepFunctionsStartExecution' */ export class StartExecution implements sfn.IStepFunctionsTask { private readonly integrationPattern: sfn.ServiceIntegrationPattern; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/stepfunctions/start-execution.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/stepfunctions/start-execution.ts new file mode 100644 index 0000000000000..5677d5d89021f --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/stepfunctions/start-execution.ts @@ -0,0 +1,129 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Construct, Stack } from '@aws-cdk/core'; +import { integrationResourceArn, validatePatternSupported } from '../private/task-utils'; + +/** + * Properties for StartExecution + */ +export interface StepFunctionsStartExecutionProps extends sfn.TaskStateBaseProps { + /** + * The Step Functions state machine to start the execution on. + */ + readonly stateMachine: sfn.IStateMachine; + + /** + * The JSON input for the execution, same as that of StartExecution. + * + * @see https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html + * + * @default - The state input (JSON path '$') + */ + readonly input?: sfn.TaskInput; + + /** + * The name of the execution, same as that of StartExecution. + * + * @see https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html + * + * @default - None + */ + readonly name?: string; +} + +/** + * A Step Functions Task to call StartExecution on another state machine. + * + * It supports three service integration patterns: FIRE_AND_FORGET, SYNC and WAIT_FOR_TASK_TOKEN. + */ +export class StepFunctionsStartExecution extends sfn.TaskStateBase { + private static readonly SUPPORTED_INTEGRATION_PATTERNS = [ + sfn.IntegrationPattern.REQUEST_RESPONSE, + sfn.IntegrationPattern.RUN_JOB, + sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + ]; + + protected readonly taskMetrics?: sfn.TaskMetricsConfig; + protected readonly taskPolicies?: iam.PolicyStatement[]; + + private readonly integrationPattern: sfn.IntegrationPattern; + + constructor(scope: Construct, id: string, private readonly props: StepFunctionsStartExecutionProps) { + super(scope, id, props); + + this.integrationPattern = props.integrationPattern || sfn.IntegrationPattern.REQUEST_RESPONSE; + validatePatternSupported(this.integrationPattern, StepFunctionsStartExecution.SUPPORTED_INTEGRATION_PATTERNS); + + if (this.integrationPattern === sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN && !sfn.FieldUtils.containsTaskToken(props.input)) { + throw new Error('Task Token is required in `input` for callback. Use Context.taskToken to set the token.'); + } + + this.taskPolicies = this.createScopedAccessPolicy(); + } + + protected renderTask(): any { + // suffix of ':2' indicates that the output of the nested state machine should be JSON + // suffix is only applicable when waiting for a nested state machine to complete (RUN_JOB) + // https://docs.aws.amazon.com/step-functions/latest/dg/connect-stepfunctions.html + const suffix = this.integrationPattern === sfn.IntegrationPattern.RUN_JOB ? ':2' : ''; + return { + Resource: `${integrationResourceArn('states', 'startExecution', this.integrationPattern)}${suffix}`, + Parameters: sfn.FieldUtils.renderObject({ + Input: this.props.input ? this.props.input.value : sfn.TaskInput.fromDataAt('$').value, + StateMachineArn: this.props.stateMachine.stateMachineArn, + Name: this.props.name, + }), + }; + } + + /** + * As StateMachineArn is extracted automatically from the state machine object included in the constructor, + * + * the scoped access policy should be generated accordingly. + * + * This means the action of StartExecution should be restricted on the given state machine, instead of being granted to all the resources (*). + */ + private createScopedAccessPolicy(): iam.PolicyStatement[] { + const stack = Stack.of(this); + + const policyStatements = [ + new iam.PolicyStatement({ + actions: ['states:StartExecution'], + resources: [this.props.stateMachine.stateMachineArn], + }), + ]; + + // Step Functions use Cloud Watch managed rules to deal with synchronous tasks. + if (this.integrationPattern === sfn.IntegrationPattern.RUN_JOB) { + policyStatements.push( + new iam.PolicyStatement({ + actions: ['states:DescribeExecution', 'states:StopExecution'], + // https://docs.aws.amazon.com/step-functions/latest/dg/concept-create-iam-advanced.html#concept-create-iam-advanced-execution + resources: [ + stack.formatArn({ + service: 'states', + resource: 'execution', + sep: ':', + resourceName: `${stack.parseArn(this.props.stateMachine.stateMachineArn, ':').resourceName}*`, + }), + ], + }), + ); + + policyStatements.push( + new iam.PolicyStatement({ + actions: ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'], + resources: [ + stack.formatArn({ + service: 'events', + resource: 'rule', + resourceName: 'StepFunctionsGetEventsForStepFunctionsExecutionRule', + }), + ], + }), + ); + } + + return policyStatements; + } +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.expected.json new file mode 100644 index 0000000000000..ba8874b8d44d0 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.expected.json @@ -0,0 +1,1036 @@ +{ + "Resources": { + "vpcA2121C38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc" + } + ] + } + }, + "vpcPublicSubnet1Subnet2E65531E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet1" + } + ] + } + }, + "vpcPublicSubnet1RouteTable48A2DF9B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet1" + } + ] + } + }, + "vpcPublicSubnet1RouteTableAssociation5D3F4579": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet1RouteTable48A2DF9B" + }, + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + } + } + }, + "vpcPublicSubnet1DefaultRoute10708846": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet1RouteTable48A2DF9B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + }, + "DependsOn": [ + "vpcVPCGW7984C166" + ] + }, + "vpcPublicSubnet1EIPDA49DCBE": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet1" + } + ] + } + }, + "vpcPublicSubnet1NATGateway9C16659E": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "vpcPublicSubnet1EIPDA49DCBE", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet1" + } + ] + } + }, + "vpcPublicSubnet2Subnet009B674F": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet2" + } + ] + } + }, + "vpcPublicSubnet2RouteTableEB40D4CB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet2" + } + ] + } + }, + "vpcPublicSubnet2RouteTableAssociation21F81B59": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet2RouteTableEB40D4CB" + }, + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + } + } + }, + "vpcPublicSubnet2DefaultRouteA1EC0F60": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet2RouteTableEB40D4CB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + }, + "DependsOn": [ + "vpcVPCGW7984C166" + ] + }, + "vpcPublicSubnet2EIP9B3743B1": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet2" + } + ] + } + }, + "vpcPublicSubnet2NATGateway9B8AE11A": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "vpcPublicSubnet2EIP9B3743B1", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet2" + } + ] + } + }, + "vpcPublicSubnet3Subnet11B92D7C": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet3" + } + ] + } + }, + "vpcPublicSubnet3RouteTableA3C00665": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet3" + } + ] + } + }, + "vpcPublicSubnet3RouteTableAssociationD102D1C4": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet3RouteTableA3C00665" + }, + "SubnetId": { + "Ref": "vpcPublicSubnet3Subnet11B92D7C" + } + } + }, + "vpcPublicSubnet3DefaultRoute3F356A11": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet3RouteTableA3C00665" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + }, + "DependsOn": [ + "vpcVPCGW7984C166" + ] + }, + "vpcPublicSubnet3EIP2C3B9D91": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet3" + } + ] + } + }, + "vpcPublicSubnet3NATGateway82F6CA9E": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "vpcPublicSubnet3EIP2C3B9D91", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "vpcPublicSubnet3Subnet11B92D7C" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PublicSubnet3" + } + ] + } + }, + "vpcPrivateSubnet1Subnet934893E8": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet1" + } + ] + } + }, + "vpcPrivateSubnet1RouteTableB41A48CC": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet1" + } + ] + } + }, + "vpcPrivateSubnet1RouteTableAssociation67945127": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet1RouteTableB41A48CC" + }, + "SubnetId": { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + } + } + }, + "vpcPrivateSubnet1DefaultRoute1AA8E2E5": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet1RouteTableB41A48CC" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "vpcPublicSubnet1NATGateway9C16659E" + } + } + }, + "vpcPrivateSubnet2Subnet7031C2BA": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet2" + } + ] + } + }, + "vpcPrivateSubnet2RouteTable7280F23E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet2" + } + ] + } + }, + "vpcPrivateSubnet2RouteTableAssociation007E94D3": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet2RouteTable7280F23E" + }, + "SubnetId": { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + } + } + }, + "vpcPrivateSubnet2DefaultRouteB0E07F99": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet2RouteTable7280F23E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "vpcPublicSubnet2NATGateway9B8AE11A" + } + } + }, + "vpcPrivateSubnet3Subnet985AC459": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet3" + } + ] + } + }, + "vpcPrivateSubnet3RouteTable24DA79A0": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc/PrivateSubnet3" + } + ] + } + }, + "vpcPrivateSubnet3RouteTableAssociationC58B3C2C": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet3RouteTable24DA79A0" + }, + "SubnetId": { + "Ref": "vpcPrivateSubnet3Subnet985AC459" + } + } + }, + "vpcPrivateSubnet3DefaultRoute30C45F47": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet3RouteTable24DA79A0" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "vpcPublicSubnet3NATGateway82F6CA9E" + } + } + }, + "vpcIGWE57CBDCA": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-stepfunctions-integ/vpc" + } + ] + } + }, + "vpcVPCGW7984C166": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "InternetGatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + } + }, + "ComputeEnvEcsInstanceRoleCFB290F9": { + "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/service-role/AmazonEC2ContainerServiceforEC2Role" + ] + ] + } + ] + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPrivateSubnet3DefaultRoute30C45F47", + "vpcPrivateSubnet3RouteTable24DA79A0", + "vpcPrivateSubnet3RouteTableAssociationC58B3C2C", + "vpcPrivateSubnet3Subnet985AC459", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcPublicSubnet3DefaultRoute3F356A11", + "vpcPublicSubnet3EIP2C3B9D91", + "vpcPublicSubnet3NATGateway82F6CA9E", + "vpcPublicSubnet3RouteTableA3C00665", + "vpcPublicSubnet3RouteTableAssociationD102D1C4", + "vpcPublicSubnet3Subnet11B92D7C", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "ComputeEnvInstanceProfile81AFCCF2": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "ComputeEnvEcsInstanceRoleCFB290F9" + } + ] + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPrivateSubnet3DefaultRoute30C45F47", + "vpcPrivateSubnet3RouteTable24DA79A0", + "vpcPrivateSubnet3RouteTableAssociationC58B3C2C", + "vpcPrivateSubnet3Subnet985AC459", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcPublicSubnet3DefaultRoute3F356A11", + "vpcPublicSubnet3EIP2C3B9D91", + "vpcPublicSubnet3NATGateway82F6CA9E", + "vpcPublicSubnet3RouteTableA3C00665", + "vpcPublicSubnet3RouteTableAssociationD102D1C4", + "vpcPublicSubnet3Subnet11B92D7C", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "ComputeEnvResourceSecurityGroupB84CF86B": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-stepfunctions-integ/ComputeEnv/Resource-Security-Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "vpcA2121C38" + } + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPrivateSubnet3DefaultRoute30C45F47", + "vpcPrivateSubnet3RouteTable24DA79A0", + "vpcPrivateSubnet3RouteTableAssociationC58B3C2C", + "vpcPrivateSubnet3Subnet985AC459", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcPublicSubnet3DefaultRoute3F356A11", + "vpcPublicSubnet3EIP2C3B9D91", + "vpcPublicSubnet3NATGateway82F6CA9E", + "vpcPublicSubnet3RouteTableA3C00665", + "vpcPublicSubnet3RouteTableAssociationD102D1C4", + "vpcPublicSubnet3Subnet11B92D7C", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "ComputeEnvResourceServiceInstanceRoleCF89E9E1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "batch.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSBatchServiceRole" + ] + ] + } + ] + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPrivateSubnet3DefaultRoute30C45F47", + "vpcPrivateSubnet3RouteTable24DA79A0", + "vpcPrivateSubnet3RouteTableAssociationC58B3C2C", + "vpcPrivateSubnet3Subnet985AC459", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcPublicSubnet3DefaultRoute3F356A11", + "vpcPublicSubnet3EIP2C3B9D91", + "vpcPublicSubnet3NATGateway82F6CA9E", + "vpcPublicSubnet3RouteTableA3C00665", + "vpcPublicSubnet3RouteTableAssociationD102D1C4", + "vpcPublicSubnet3Subnet11B92D7C", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "ComputeEnv2C40ACC2": { + "Type": "AWS::Batch::ComputeEnvironment", + "Properties": { + "ServiceRole": { + "Fn::GetAtt": [ + "ComputeEnvResourceServiceInstanceRoleCF89E9E1", + "Arn" + ] + }, + "Type": "MANAGED", + "ComputeResources": { + "AllocationStrategy": "BEST_FIT", + "InstanceRole": { + "Fn::GetAtt": [ + "ComputeEnvInstanceProfile81AFCCF2", + "Arn" + ] + }, + "InstanceTypes": [ + "optimal" + ], + "MaxvCpus": 256, + "MinvCpus": 0, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ComputeEnvResourceSecurityGroupB84CF86B", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + }, + { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + }, + { + "Ref": "vpcPrivateSubnet3Subnet985AC459" + } + ], + "Type": "EC2" + }, + "State": "ENABLED" + }, + "DependsOn": [ + "vpcIGWE57CBDCA", + "vpcPrivateSubnet1DefaultRoute1AA8E2E5", + "vpcPrivateSubnet1RouteTableB41A48CC", + "vpcPrivateSubnet1RouteTableAssociation67945127", + "vpcPrivateSubnet1Subnet934893E8", + "vpcPrivateSubnet2DefaultRouteB0E07F99", + "vpcPrivateSubnet2RouteTable7280F23E", + "vpcPrivateSubnet2RouteTableAssociation007E94D3", + "vpcPrivateSubnet2Subnet7031C2BA", + "vpcPrivateSubnet3DefaultRoute30C45F47", + "vpcPrivateSubnet3RouteTable24DA79A0", + "vpcPrivateSubnet3RouteTableAssociationC58B3C2C", + "vpcPrivateSubnet3Subnet985AC459", + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1EIPDA49DCBE", + "vpcPublicSubnet1NATGateway9C16659E", + "vpcPublicSubnet1RouteTable48A2DF9B", + "vpcPublicSubnet1RouteTableAssociation5D3F4579", + "vpcPublicSubnet1Subnet2E65531E", + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2EIP9B3743B1", + "vpcPublicSubnet2NATGateway9B8AE11A", + "vpcPublicSubnet2RouteTableEB40D4CB", + "vpcPublicSubnet2RouteTableAssociation21F81B59", + "vpcPublicSubnet2Subnet009B674F", + "vpcPublicSubnet3DefaultRoute3F356A11", + "vpcPublicSubnet3EIP2C3B9D91", + "vpcPublicSubnet3NATGateway82F6CA9E", + "vpcPublicSubnet3RouteTableA3C00665", + "vpcPublicSubnet3RouteTableAssociationD102D1C4", + "vpcPublicSubnet3Subnet11B92D7C", + "vpcA2121C38", + "vpcVPCGW7984C166" + ] + }, + "JobQueueEE3AD499": { + "Type": "AWS::Batch::JobQueue", + "Properties": { + "ComputeEnvironmentOrder": [ + { + "ComputeEnvironment": { + "Ref": "ComputeEnv2C40ACC2" + }, + "Order": 1 + } + ], + "Priority": 1, + "State": "ENABLED" + } + }, + "JobDefinition24FFE3ED": { + "Type": "AWS::Batch::JobDefinition", + "Properties": { + "Type": "container", + "ContainerProperties": { + "Image": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/aws-cdk/assets:4ba4a660dbcc1e71f0bf07105626a5bc65d95ae71724dc57bbb94c8e14202342" + ] + ] + }, + "Memory": 4, + "Privileged": false, + "ReadonlyRootFilesystem": false, + "Vcpus": 1 + }, + "RetryStrategy": { + "Attempts": 1 + }, + "Timeout": {} + } + }, + "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": "batch:SubmitJob", + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":batch:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":job-definition/*" + ] + ] + }, + { + "Ref": "JobQueueEE3AD499" + } + ] + }, + { + "Action": [ + "events:PutTargets", + "events:PutRule", + "events:DescribeRule" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":events:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":rule/StepFunctionsGetEventsForBatchJobsRule" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StateMachineRoleDefaultPolicyDF1E6607", + "Roles": [ + { + "Ref": "StateMachineRoleB840431D" + } + ] + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Start\",\"States\":{\"Start\":{\"Type\":\"Pass\",\"Result\":{\"bar\":\"SomeValue\"},\"Next\":\"Submit Job\"},\"Submit Job\":{\"End\":true,\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::batch:submitJob.sync\",\"Parameters\":{\"JobDefinition\":\"", + { + "Ref": "JobDefinition24FFE3ED" + }, + "\",\"JobName\":\"MyJob\",\"JobQueue\":\"", + { + "Ref": "JobQueueEE3AD499" + }, + "\",\"Parameters\":{\"foo.$\":\"$.bar\"},\"ContainerOverrides\":{\"Environment\":[{\"Name\":\"key\",\"Value\":\"value\"}],\"Memory\":256,\"Vcpus\":1},\"RetryStrategy\":{\"Attempts\":3},\"Timeout\":{\"AttemptDurationSeconds\":60}}}}}" + ] + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + } + }, + "DependsOn": [ + "StateMachineRoleDefaultPolicyDF1E6607", + "StateMachineRoleB840431D" + ] + } + }, + "Outputs": { + "JobQueueArn": { + "Value": { + "Ref": "JobQueueEE3AD499" + } + }, + "StateMachineArn": { + "Value": { + "Ref": "StateMachine2E01A3A5" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.ts new file mode 100644 index 0000000000000..86e891d4331ed --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/integ.submit-job.ts @@ -0,0 +1,78 @@ +import * as batch from '@aws-cdk/aws-batch'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as path from 'path'; +import { BatchSubmitJob } from '../../lib'; + +/* + * Stack verification steps: + * * aws stepfunctions start-execution --state-machine-arn : should return execution arn + * * aws batch list-jobs --job-queue --job-status RUNNABLE : should return jobs-list with size greater than 0 + * * + * * aws batch describe-jobs --jobs --query 'jobs[0].status': wait until the status is 'SUCCEEDED' + * * aws stepfunctions describe-execution --execution-arn --query 'status': should return status as SUCCEEDED + */ + +class RunBatchStack extends cdk.Stack { + constructor(scope: cdk.App, id: string, props: cdk.StackProps = {}) { + super(scope, id, props); + + const vpc = new ec2.Vpc(this, 'vpc'); + + const batchQueue = new batch.JobQueue(this, 'JobQueue', { + computeEnvironments: [ + { + order: 1, + computeEnvironment: new batch.ComputeEnvironment(this, 'ComputeEnv', { + computeResources: { vpc }, + }), + }, + ], + }); + + const batchJobDefinition = new batch.JobDefinition(this, 'JobDefinition', { + container: { + image: ecs.ContainerImage.fromAsset( + path.resolve(__dirname, 'batchjob-image'), + ), + }, + }); + + const submitJob = new BatchSubmitJob(this, 'Submit Job', { + jobDefinition: batchJobDefinition, + jobName: 'MyJob', + jobQueue: batchQueue, + containerOverrides: { + environment: { key: 'value' }, + memory: cdk.Size.mebibytes(256), + vcpus: 1, + }, + payload: sfn.TaskInput.fromObject({ + foo: sfn.Data.stringAt('$.bar'), + }), + attempts: 3, + timeout: cdk.Duration.seconds(60), + }); + + const definition = new sfn.Pass(this, 'Start', { + result: sfn.Result.fromObject({ bar: 'SomeValue' }), + }).next(submitJob); + + const stateMachine = new sfn.StateMachine(this, 'StateMachine', { + definition, + }); + + new cdk.CfnOutput(this, 'JobQueueArn', { + value: batchQueue.jobQueueArn, + }); + new cdk.CfnOutput(this, 'StateMachineArn', { + value: stateMachine.stateMachineArn, + }); + } +} + +const app = new cdk.App(); +new RunBatchStack(app, 'aws-stepfunctions-integ'); +app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts new file mode 100644 index 0000000000000..6538e8bc1733e --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/batch/submit-job.test.ts @@ -0,0 +1,311 @@ +import * as batch from '@aws-cdk/aws-batch'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as path from 'path'; +import { BatchSubmitJob } from '../../lib'; + +let stack: cdk.Stack; +let batchJobDefinition: batch.IJobDefinition; +let batchJobQueue: batch.IJobQueue; + +beforeEach(() => { + // GIVEN + stack = new cdk.Stack(); + + batchJobDefinition = new batch.JobDefinition(stack, 'JobDefinition', { + container: { + image: ecs.ContainerImage.fromAsset( + path.join(__dirname, 'batchjob-image'), + ), + }, + }); + + batchJobQueue = new batch.JobQueue(stack, 'JobQueue', { + computeEnvironments: [ + { + order: 1, + computeEnvironment: new batch.ComputeEnvironment(stack, 'ComputeEnv', { + computeResources: { vpc: new ec2.Vpc(stack, 'vpc') }, + }), + }, + ], + }); +}); + +test('Task with only the required parameters', () => { + // WHEN + const task = new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::batch:submitJob.sync', + ], + ], + }, + End: true, + Parameters: { + JobDefinition: { Ref: 'JobDefinition24FFE3ED' }, + JobName: 'JobName', + JobQueue: { Ref: 'JobQueueEE3AD499' }, + }, + }); +}); + +test('Task with all the parameters', () => { + // WHEN + const task = new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + arraySize: 15, + containerOverrides: { + command: ['sudo', 'rm'], + environment: { key: 'value' }, + instanceType: new ec2.InstanceType('MULTI'), + memory: cdk.Size.mebibytes(1024), + gpuCount: 1, + vcpus: 10, + }, + dependsOn: [{ jobId: '1234', type: 'some_type' }], + payload: sfn.TaskInput.fromObject({ + foo: sfn.Data.stringAt('$.bar'), + }), + attempts: 3, + timeout: cdk.Duration.seconds(60), + integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::batch:submitJob', + ], + ], + }, + End: true, + Parameters: { + JobDefinition: { Ref: 'JobDefinition24FFE3ED' }, + JobName: 'JobName', + JobQueue: { Ref: 'JobQueueEE3AD499' }, + ArrayProperties: { Size: 15 }, + ContainerOverrides: { + Command: ['sudo', 'rm'], + Environment: [{ Name: 'key', Value: 'value' }], + InstanceType: 'MULTI', + Memory: 1024, + ResourceRequirements: [{ Type: 'GPU', Value: '1' }], + Vcpus: 10, + }, + DependsOn: [{ JobId: '1234', Type: 'some_type' }], + Parameters: { 'foo.$': '$.bar' }, + RetryStrategy: { Attempts: 3 }, + Timeout: { AttemptDurationSeconds: 60 }, + }, + }); +}); + +test('supports tokens', () => { + // WHEN + const task = new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: sfn.Data.stringAt('$.jobName'), + jobQueue: batchJobQueue, + arraySize: sfn.Data.numberAt('$.arraySize'), + timeout: cdk.Duration.seconds(sfn.Data.numberAt('$.timeout')), + attempts: sfn.Data.numberAt('$.attempts'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::batch:submitJob.sync', + ], + ], + }, + End: true, + Parameters: { + 'JobDefinition': { Ref: 'JobDefinition24FFE3ED' }, + 'JobName.$': '$.jobName', + 'JobQueue': { Ref: 'JobQueueEE3AD499' }, + 'ArrayProperties': { + 'Size.$': '$.arraySize', + }, + 'RetryStrategy': { + 'Attempts.$': '$.attempts', + }, + 'Timeout': { + 'AttemptDurationSeconds.$': '$.timeout', + }, + }, + }); +}); + +test('supports passing task input into payload', () => { + // WHEN + const task = new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: sfn.Data.stringAt('$.jobName'), + jobQueue: batchJobQueue, + payload: sfn.TaskInput.fromDataAt('$.foo'), + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::batch:submitJob.sync', + ], + ], + }, + End: true, + Parameters: { + 'JobDefinition': { Ref: 'JobDefinition24FFE3ED' }, + 'JobName.$': '$.jobName', + 'JobQueue': { Ref: 'JobQueueEE3AD499' }, + 'Parameters.$': '$.foo', + }, + }); +}); + +test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration pattern', () => { + expect(() => { + new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + }); + }).toThrow( + /Unsupported service integration pattern. Supported Patterns: REQUEST_RESPONSE,RUN_JOB. Received: WAIT_FOR_TASK_TOKEN/, + ); +}); + +test('Task throws if environment in containerOverrides contain env with name starting with AWS_BATCH', () => { + expect(() => { + new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + containerOverrides: { + environment: { AWS_BATCH_MY_NAME: 'MY_VALUE' }, + }, + }); + }).toThrow( + /Invalid environment variable name: AWS_BATCH_MY_NAME. Environment variable names starting with 'AWS_BATCH' are reserved./, + ); +}); + +test('Task throws if arraySize is out of limits 2-10000', () => { + expect(() => { + new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + arraySize: 1, + }); + }).toThrow( + /arraySize must be between 2 and 10,000/, + ); + + expect(() => { + new BatchSubmitJob(stack, 'Task2', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + arraySize: 10001, + }); + }).toThrow( + /arraySize must be between 2 and 10,000/, + ); +}); + +test('Task throws if dependencies exceeds 20', () => { + expect(() => { + new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + dependsOn: [...Array(21).keys()].map(i => ({ + jobId: `${i}`, + type: `some_type-${i}`, + })), + }); + }).toThrow( + /dependencies must be 20 or less/, + ); +}); + +test('Task throws if attempts is out of limits 1-10', () => { + expect(() => { + new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + attempts: 0, + }); + }).toThrow( + /attempts must be between 1 and 10/, + ); + + expect(() => { + new BatchSubmitJob(stack, 'Task2', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + attempts: 11, + }); + }).toThrow( + /attempts must be between 1 and 10/, + ); +}); + +test('Task throws if attempt duration is less than 60 sec', () => { + expect(() => { + new BatchSubmitJob(stack, 'Task', { + jobDefinition: batchJobDefinition, + jobName: 'JobName', + jobQueue: batchJobQueue, + timeout: cdk.Duration.seconds(59), + }); + }).toThrow( + /attempt duration must be greater than 60 seconds./, + ); +}); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.expected.json new file mode 100644 index 0000000000000..7cd5dd9eed8f6 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.expected.json @@ -0,0 +1,187 @@ +{ + "Resources": { + "ChildRole1E3E0EF5": { + "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" + } + } + }, + "ChildDAB30558": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": "{\"StartAt\":\"Pass\",\"States\":{\"Pass\":{\"Type\":\"Pass\",\"End\":true}}}", + "RoleArn": { + "Fn::GetAtt": ["ChildRole1E3E0EF5", "Arn"] + } + }, + "DependsOn": ["ChildRole1E3E0EF5"] + }, + "ParentRole5F0C366C": { + "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" + } + } + }, + "ParentRoleDefaultPolicy9BDC56DC": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "ChildDAB30558" + } + }, + { + "Action": ["states:DescribeExecution", "states:StopExecution"], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":states:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":execution:", + { + "Fn::Select": [ + 6, + { + "Fn::Split": [ + ":", + { + "Ref": "ChildDAB30558" + } + ] + } + ] + }, + "*" + ] + ] + } + }, + { + "Action": ["events:PutTargets", "events:PutRule", "events:DescribeRule"], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":events:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":rule/StepFunctionsGetEventsForStepFunctionsExecutionRule" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ParentRoleDefaultPolicy9BDC56DC", + "Roles": [ + { + "Ref": "ParentRole5F0C366C" + } + ] + } + }, + "Parent8B210403": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"Task\",\"States\":{\"Task\":{\"End\":true,\"Type\":\"Task\",\"Resource\":\"arn:", + { + "Ref": "AWS::Partition" + }, + ":states:::states:startExecution.sync:2\",\"Parameters\":{\"Input\":{\"hello.$\":\"$.hello\"},\"StateMachineArn\":\"", + { + "Ref": "ChildDAB30558" + }, + "\"}}}}" + ] + ] + }, + "RoleArn": { + "Fn::GetAtt": ["ParentRole5F0C366C", "Arn"] + } + }, + "DependsOn": ["ParentRoleDefaultPolicy9BDC56DC", "ParentRole5F0C366C"] + } + }, + "Outputs": { + "StateMachineARN": { + "Value": { + "Ref": "Parent8B210403" + } + } + } +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.ts new file mode 100644 index 0000000000000..012189950cecd --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/integ.start-execution.ts @@ -0,0 +1,40 @@ +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { App, CfnOutput, Construct, Stack } from '@aws-cdk/core'; +import { StepFunctionsStartExecution } from '../../lib/stepfunctions/start-execution'; + +/* + * Stack verification steps: + * * aws stepfunctions start-execution --input '{"hello": "world"}' --state-machine-arn + * * aws stepfunctions describe-execution --execution-arn + * * The output here should contain `status: "SUCCEEDED"` and `output`: '"Output": { "hello": "world"},' + */ + +class TestStack extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const child = new sfn.StateMachine(this, 'Child', { + definition: new sfn.Pass(this, 'Pass'), + }); + + const parent = new sfn.StateMachine(this, 'Parent', { + definition: new StepFunctionsStartExecution(this, 'Task', { + stateMachine: child, + input: sfn.TaskInput.fromObject({ + hello: sfn.Data.stringAt('$.hello'), + }), + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + }), + }); + + new CfnOutput(this, 'StateMachineARN', { + value: parent.stateMachineArn, + }); + } +} + +const app = new App(); + +new TestStack(app, 'integ-sfn-start-execution'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/start-execution.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/start-execution.test.ts new file mode 100644 index 0000000000000..21d2546af8681 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/stepfunctions/start-execution.test.ts @@ -0,0 +1,217 @@ +import '@aws-cdk/assert/jest'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { Stack } from '@aws-cdk/core'; +import { StepFunctionsStartExecution } from '../../lib/stepfunctions/start-execution'; + +let stack: Stack; +let child: sfn.StateMachine; +beforeEach(() => { + stack = new Stack(); + child = new sfn.StateMachine(stack, 'ChildStateMachine', { + definition: sfn.Chain.start(new sfn.Pass(stack, 'PassState')), + }); +}); + +test('Execute State Machine - Default - Request Response', () => { + const task = new StepFunctionsStartExecution(stack, 'ChildTask', { + stateMachine: child, + input: sfn.TaskInput.fromObject({ + foo: 'bar', + }), + name: 'myExecutionName', + }); + + new sfn.StateMachine(stack, 'ParentStateMachine', { + definition: task, + }); + + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::states:startExecution', + ], + ], + }, + End: true, + Parameters: { + Input: { + foo: 'bar', + }, + Name: 'myExecutionName', + StateMachineArn: { + Ref: 'ChildStateMachine9133117F', + }, + }, + }); +}); + +test('Execute State Machine - Run Job', () => { + const task = new StepFunctionsStartExecution(stack, 'ChildTask', { + stateMachine: child, + integrationPattern: sfn.IntegrationPattern.RUN_JOB, + }); + + new sfn.StateMachine(stack, 'ParentStateMachine', { + definition: task, + }); + + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::states:startExecution.sync:2', + ], + ], + }, + End: true, + Parameters: { + 'Input.$': '$', + 'StateMachineArn': { + Ref: 'ChildStateMachine9133117F', + }, + }, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'states:StartExecution', + Effect: 'Allow', + Resource: { + Ref: 'ChildStateMachine9133117F', + }, + }, + { + Action: ['states:DescribeExecution', 'states:StopExecution'], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':execution:', + { + 'Fn::Select': [ + 6, + { + 'Fn::Split': [ + ':', + { + Ref: 'ChildStateMachine9133117F', + }, + ], + }, + ], + }, + '*', + ], + ], + }, + }, + { + Action: ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':events:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + ], + ], + }, + }, + ], + Version: '2012-10-17', + }, + Roles: [ + { + Ref: 'ParentStateMachineRoleE902D002', + }, + ], + }); +}); + +test('Execute State Machine - Wait For Task Token', () => { + const task = new StepFunctionsStartExecution(stack, 'ChildTask', { + stateMachine: child, + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + input: sfn.TaskInput.fromObject({ + token: sfn.Context.taskToken, + }), + }); + + new sfn.StateMachine(stack, 'ParentStateMachine', { + definition: task, + }); + + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':states:::states:startExecution.waitForTaskToken', + ], + ], + }, + End: true, + Parameters: { + Input: { + 'token.$': '$$.Task.Token', + }, + StateMachineArn: { + Ref: 'ChildStateMachine9133117F', + }, + }, + }); +}); + +test('Execute State Machine - Wait For Task Token - Missing Task Token', () => { + expect(() => { + new StepFunctionsStartExecution(stack, 'ChildTask', { + stateMachine: child, + integrationPattern: sfn.IntegrationPattern.WAIT_FOR_TASK_TOKEN, + }); + }).toThrow('Task Token is required in `input` for callback. Use Context.taskToken to set the token.'); +}); diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index c5eeee5a7b837..dc442ba4f5d9e 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -27,7 +27,7 @@ "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "fast-json-patch": "^2.2.1", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "json-diff": "^0.5.4", "nodeunit": "^0.11.3", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/core/lib/size.ts b/packages/@aws-cdk/core/lib/size.ts index cce9403009d2d..2cf445b16aab2 100644 --- a/packages/@aws-cdk/core/lib/size.ts +++ b/packages/@aws-cdk/core/lib/size.ts @@ -26,7 +26,7 @@ export class Size { } /** - * Create a Storage representing an amount mebibytes. + * Create a Storage representing an amount gibibytes. * 1 GiB = 1024 MiB */ public static gibibytes(amount: number): Size { @@ -97,7 +97,7 @@ export class Size { } /** - * Rouding behaviour when converting between units of `Size`. + * Rounding behaviour when converting between units of `Size`. */ export enum SizeRoundingBehavior { /** Fail the conversion if the result is not an integer. */ diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index a0927130ac58f..a654253f2d938 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -151,7 +151,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/lodash": "^4.14.153", + "@types/lodash": "^4.14.155", "@types/node": "^10.17.21", "@types/nodeunit": "^0.0.31", "@types/minimatch": "^3.0.3", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 65f8c90f0bcb9..82fba93c7691a 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -73,13 +73,13 @@ "@aws-cdk/aws-ssm": "0.0.0", "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", - "@types/sinon": "^9.0.3", - "aws-sdk": "^2.681.0", + "@types/sinon": "^9.0.4", + "aws-sdk": "^2.689.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "nock": "^12.0.3", "pkglint": "0.0.0", "sinon": "^9.0.2" diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index 4bfca87660b45..b15f9c8e7f3f7 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -55,7 +55,7 @@ "devDependencies": { "@types/fs-extra": "^8.1.0", "cdk-build-tools": "0.0.0", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "pkglint": "0.0.0" }, "repository": { diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 99b18c3136b9f..583e6dc3d6ee8 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -235,6 +235,17 @@ export async function deployStack(options: DeployStackOptions): Promise=3.0", diff --git a/packages/aws-cdk/test/integ/cli/app/app.js b/packages/aws-cdk/test/integ/cli/app/app.js index 396d13b248aaa..efd6acde64145 100644 --- a/packages/aws-cdk/test/integ/cli/app/app.js +++ b/packages/aws-cdk/test/integ/cli/app/app.js @@ -280,7 +280,7 @@ new StackWithNestedStack(app, `${stackPrefix}-with-nested-stack`); new StackWithNestedStackUsingParameters(app, `${stackPrefix}-with-nested-stack-using-parameters`); new YourStack(app, `${stackPrefix}-termination-protection`, { - terminationProtection: true, + terminationProtection: process.env.TERMINATION_PROTECTION !== 'FALSE' ? true : false, }); app.synth(); diff --git a/packages/aws-cdk/test/integ/cli/cli.integtest.ts b/packages/aws-cdk/test/integ/cli/cli.integtest.ts index 703dbda0a2aa0..47a7f9fe46ce3 100644 --- a/packages/aws-cdk/test/integ/cli/cli.integtest.ts +++ b/packages/aws-cdk/test/integ/cli/cli.integtest.ts @@ -39,15 +39,15 @@ test('Two ways of shoing the version', async () => { }); test('Termination protection', async () => { - await cdkDeploy('termination-protection'); + const stackName = 'termination-protection'; + await cdkDeploy(stackName); // Try a destroy that should fail - await expect(cdkDestroy('termination-protection')).rejects.toThrow('exited with error'); + await expect(cdkDestroy(stackName)).rejects.toThrow('exited with error'); - await cloudFormation('updateTerminationProtection', { - EnableTerminationProtection: false, - StackName: fullStackName('termination-protection'), - }); + // Can update termination protection even though the change set doesn't contain changes + await cdkDeploy(stackName, { modEnv: { TERMINATION_PROTECTION: 'FALSE' } }); + await cdkDestroy(stackName); }); test('cdk synth', async () => { @@ -437,15 +437,15 @@ test('IAM diff', async () => { // Roughly check for a table like this: // - // ┌───┬─────────────────┬────────┬────────────────┬────────────────────────────┬───────────┐ - // │ │ Resource │ Effect │ Action │ Principal │ Condition │ - // ├───┼─────────────────┼────────┼────────────────┼────────────────────────────┼───────────┤ - // │ + │ ${SomeRole.Arn} │ Allow │ sts:AssumeRole │ Service:ec2.amazonaws.com │ │ - // └───┴─────────────────┴────────┴────────────────┴────────────────────────────┴───────────┘ + // ┌───┬─────────────────┬────────┬────────────────┬────────────────────────────-──┬───────────┐ + // │ │ Resource │ Effect │ Action │ Principal │ Condition │ + // ├───┼─────────────────┼────────┼────────────────┼───────────────────────────────┼───────────┤ + // │ + │ ${SomeRole.Arn} │ Allow │ sts:AssumeRole │ Service:ec2.${AWS::URLSuffix} │ │ + // └───┴─────────────────┴────────┴────────────────┴───────────────────────────────┴───────────┘ expect(output).toContain('${SomeRole.Arn}'); expect(output).toContain('sts:AssumeRole'); - expect(output).toContain('ec2.amazonaws.com'); + expect(output).toContain('ec2.${AWS::URLSuffix}'); }); test('fast deploy', async () => { diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 30b5074892cba..043b55c56f2bd 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -48,7 +48,7 @@ "@aws-cdk/cdk-assets-schema": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "archiver": "^4.0.1", - "aws-sdk": "^2.681.0", + "aws-sdk": "^2.689.0", "glob": "^7.1.6", "yargs": "^15.3.1" }, diff --git a/packages/cdk-dasm/package.json b/packages/cdk-dasm/package.json index 3e2a90ad5fd31..67043c1b1f359 100644 --- a/packages/cdk-dasm/package.json +++ b/packages/cdk-dasm/package.json @@ -26,7 +26,7 @@ }, "license": "Apache-2.0", "dependencies": { - "codemaker": "^1.5.0", + "codemaker": "^1.6.0", "yaml": "1.10.0" }, "devDependencies": { diff --git a/packages/decdk/package.json b/packages/decdk/package.json index 46565cefab7cd..2efed31310e63 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -178,8 +178,8 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "constructs": "^3.0.2", - "fs-extra": "^8.1.0", - "jsii-reflect": "^1.5.0", + "fs-extra": "^9.0.1", + "jsii-reflect": "^1.6.0", "jsonschema": "^1.2.6", "yaml": "1.9.2", "yargs": "^15.3.1" @@ -190,7 +190,7 @@ "@types/yaml": "1.9.7", "@types/yargs": "^15.0.5", "jest": "^25.5.4", - "jsii": "^1.5.0" + "jsii": "^1.6.0" }, "keywords": [ "aws", diff --git a/packages/monocdk-experiment/package.json b/packages/monocdk-experiment/package.json index e8bec8325baea..6979ba08618d3 100644 --- a/packages/monocdk-experiment/package.json +++ b/packages/monocdk-experiment/package.json @@ -41,7 +41,8 @@ "exclude": [ "package-info/maturity", "jsii/java", - "jsii/python" + "jsii/python", + "jsii/dotnet" ] }, "jsii": { @@ -51,7 +52,7 @@ "outdir": "dist", "targets": { "dotnet": { - "namespace": "Amazon.CDK.MonoCDK.Experiment", + "namespace": "Amazon.CDK", "packageId": "Amazon.CDK.MonoCDK.Experiment", "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png", "versionSuffix": "-devpreview", @@ -59,7 +60,7 @@ "assemblyOriginatorKeyFile": "../../key.snk" }, "java": { - "package": "software.amazon.awscdk.monocdkexperiment", + "package": "software.amazon.awscdk.core", "maven": { "groupId": "software.amazon.awscdk", "artifactId": "monocdk-experiment", @@ -247,7 +248,7 @@ "@types/fs-extra": "^8.1.1", "@types/node": "^10.17.24", "cdk-build-tools": "0.0.0", - "fs-extra": "^9.0.0", + "fs-extra": "^9.0.1", "pkglint": "0.0.0", "ts-node": "^8.10.2", "typescript": "~3.8.3" diff --git a/tools/awslint/package.json b/tools/awslint/package.json index 9bb6507a893f8..959ba1f0a4697 100644 --- a/tools/awslint/package.json +++ b/tools/awslint/package.json @@ -16,11 +16,11 @@ "awslint": "bin/awslint" }, "dependencies": { - "@jsii/spec": "^1.5.0", + "@jsii/spec": "^1.6.0", "camelcase": "^6.0.0", "colors": "^1.4.0", - "fs-extra": "^8.1.0", - "jsii-reflect": "^1.5.0", + "fs-extra": "^9.0.1", + "jsii-reflect": "^1.6.0", "yargs": "^15.3.1" }, "devDependencies": { diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 42f531f06c53c..f66bf5459c3ea 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -47,10 +47,10 @@ "eslint-import-resolver-node": "^0.3.3", "eslint-import-resolver-typescript": "^2.0.0", "eslint-plugin-import": "^2.20.2", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "jest": "^25.5.4", - "jsii": "^1.5.0", - "jsii-pacmak": "^1.5.0", + "jsii": "^1.6.0", + "jsii-pacmak": "^1.6.0", "nodeunit": "^0.11.3", "nyc": "^15.0.1", "ts-jest": "^26.0.0", diff --git a/tools/cdk-integ-tools/package.json b/tools/cdk-integ-tools/package.json index b64577de5ad7f..9dfb2ad3eda96 100644 --- a/tools/cdk-integ-tools/package.json +++ b/tools/cdk-integ-tools/package.json @@ -38,7 +38,7 @@ "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "aws-cdk": "0.0.0", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "yargs": "^15.3.1" }, "keywords": [ diff --git a/tools/cfn2ts/package.json b/tools/cfn2ts/package.json index 9a5db7b2cf4f5..8a0dcf6e662a1 100644 --- a/tools/cfn2ts/package.json +++ b/tools/cfn2ts/package.json @@ -30,9 +30,9 @@ "license": "Apache-2.0", "dependencies": { "@aws-cdk/cfnspec": "0.0.0", - "codemaker": "^1.5.0", + "codemaker": "^1.6.0", "fast-json-patch": "^3.0.0-1", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "yargs": "^15.3.1" }, "devDependencies": { diff --git a/tools/pkglint/package.json b/tools/pkglint/package.json index 7a5d121594176..5ce02cb64d1df 100644 --- a/tools/pkglint/package.json +++ b/tools/pkglint/package.json @@ -42,7 +42,7 @@ "dependencies": { "case": "^1.6.3", "colors": "^1.4.0", - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "semver": "^7.2.2", "yargs": "^15.3.1" } diff --git a/tools/pkgtools/package.json b/tools/pkgtools/package.json index 7cfde15b5d3db..5a843fe0e5a6b 100644 --- a/tools/pkgtools/package.json +++ b/tools/pkgtools/package.json @@ -35,7 +35,7 @@ "pkglint": "0.0.0" }, "dependencies": { - "fs-extra": "^8.1.0", + "fs-extra": "^9.0.1", "yargs": "^15.3.1" }, "keywords": [ diff --git a/yarn.lock b/yarn.lock index b6c905333820d..4c56b7dbcbe35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -529,10 +529,10 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" -"@jsii/spec@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.5.0.tgz#55a6d7395862c287cff18cf6cf8d166b715d1e49" - integrity sha512-gmqCGiAuXd8XFwy2uqqwoA0VBhADbrPuuowK7Qfy44ZIzv2gm0txlSkKA5elwRFdqlYHCAl6GYcimZemm6x/rQ== +"@jsii/spec@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.6.0.tgz#a93fa8eb22684a2263f70c1ae2b7143e43548149" + integrity sha512-6S863f3YQCLG00236OOT29EOqZZRFQEQcfACZ5f3Ph1PApRRndeZLsELm23MS6cCktdgdptRzaYR0HCupajBHQ== dependencies: jsonschema "^1.2.6" @@ -670,10 +670,10 @@ is-ci "^2.0.0" npmlog "^4.1.2" -"@lerna/conventional-commits@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-3.18.5.tgz#08efd2e5b45acfaf3f151a53a3ec7ecade58a7bc" - integrity sha512-qcvXIEJ3qSgalxXnQ7Yxp5H9Ta5TVyai6vEor6AAEHc20WiO7UIdbLDCxBtiiHMdGdpH85dTYlsoYUwsCJu3HQ== +"@lerna/conventional-commits@3.22.0": + version "3.22.0" + resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-3.22.0.tgz#2798f4881ee2ef457bdae027ab7d0bf0af6f1e09" + integrity sha512-z4ZZk1e8Mhz7+IS8NxHr64wyklHctCJyWpJKEZZPJiLFJ8yKto/x38O80R10pIzC0rr8Sy/OsjSH4bl0TbbgqA== dependencies: "@lerna/validation-error" "3.13.0" conventional-changelog-angular "^5.0.3" @@ -696,10 +696,10 @@ fs-extra "^8.1.0" npmlog "^4.1.2" -"@lerna/create@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-3.21.0.tgz#e813832adf3488728b139e5a75c8b01b1372e62f" - integrity sha512-cRIopzKzE2vXJPmsiwCDMWo4Ct+KTmX3nvvkQLDoQNrrRK7w+3KQT3iiorbj1koD95RsVQA7mS2haWok9SIv0g== +"@lerna/create@3.22.0": + version "3.22.0" + resolved "https://registry.yarnpkg.com/@lerna/create/-/create-3.22.0.tgz#d6bbd037c3dc5b425fe5f6d1b817057c278f7619" + integrity sha512-MdiQQzCcB4E9fBF1TyMOaAEz9lUjIHp1Ju9H7f3lXze5JK6Fl5NYkouAvsLgY6YSIhXMY8AHW2zzXeBDY4yWkw== dependencies: "@evocateur/pacote" "^9.6.3" "@lerna/child-process" "3.16.5" @@ -787,13 +787,13 @@ ssri "^6.0.1" tar "^4.4.8" -"@lerna/github-client@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-3.16.5.tgz#2eb0235c3bf7a7e5d92d73e09b3761ab21f35c2e" - integrity sha512-rHQdn8Dv/CJrO3VouOP66zAcJzrHsm+wFuZ4uGAai2At2NkgKH+tpNhQy2H1PSC0Ezj9LxvdaHYrUzULqVK5Hw== +"@lerna/github-client@3.22.0": + version "3.22.0" + resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-3.22.0.tgz#5d816aa4f76747ed736ae64ff962b8f15c354d95" + integrity sha512-O/GwPW+Gzr3Eb5bk+nTzTJ3uv+jh5jGho9BOqKlajXaOkMYGBELEAqV5+uARNGWZFvYAiF4PgqHb6aCUu7XdXg== dependencies: "@lerna/child-process" "3.16.5" - "@octokit/plugin-enterprise-rest" "^3.6.1" + "@octokit/plugin-enterprise-rest" "^6.0.1" "@octokit/rest" "^16.28.4" git-url-parse "^11.1.2" npmlog "^4.1.2" @@ -820,10 +820,10 @@ "@lerna/child-process" "3.16.5" semver "^6.2.0" -"@lerna/import@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/import/-/import-3.21.0.tgz#87b08f2a2bfeeff7357c6fd8490e638d3cd5b32d" - integrity sha512-aISkL4XD0Dqf5asDaOZWu65jgj8fWUhuQseZWuQe3UfHxav69fTS2YLIngUfencaOSZVOcVCom28YCzp61YDxw== +"@lerna/import@3.22.0": + version "3.22.0" + resolved "https://registry.yarnpkg.com/@lerna/import/-/import-3.22.0.tgz#1a5f0394f38e23c4f642a123e5e1517e70d068d2" + integrity sha512-uWOlexasM5XR6tXi4YehODtH9Y3OZrFht3mGUFFT3OIl2s+V85xIGFfqFGMTipMPAGb2oF1UBLL48kR43hRsOg== dependencies: "@lerna/child-process" "3.16.5" "@lerna/command" "3.21.0" @@ -1042,10 +1042,10 @@ inquirer "^6.2.0" npmlog "^4.1.2" -"@lerna/publish@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.21.0.tgz#0112393125f000484c3f50caba71a547f91bd7f4" - integrity sha512-JZ+ehZB9UCQ9nqH8Ld/Yqc/If++aK/7XIubkrB9sQ5hf2GeIbmI/BrJpMgLW/e9T5bKrUBZPUvoUN3daVipA5A== +"@lerna/publish@3.22.0": + version "3.22.0" + resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.22.0.tgz#7a3fb61026d3b7425f3b9a1849421f67d795c55d" + integrity sha512-8LBeTLBN8NIrCrLGykRu+PKrfrCC16sGCVY0/bzq9TDioR7g6+cY0ZAw653Qt/0Kr7rg3J7XxVNdzj3fvevlwA== dependencies: "@evocateur/libnpmaccess" "^3.1.2" "@evocateur/npm-registry-fetch" "^4.0.0" @@ -1068,7 +1068,7 @@ "@lerna/run-lifecycle" "3.16.2" "@lerna/run-topologically" "3.18.5" "@lerna/validation-error" "3.13.0" - "@lerna/version" "3.21.0" + "@lerna/version" "3.22.0" figgy-pudding "^3.5.1" fs-extra "^8.1.0" npm-package-arg "^6.1.0" @@ -1181,17 +1181,17 @@ dependencies: npmlog "^4.1.2" -"@lerna/version@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.21.0.tgz#5bcc3d2de9eb8f4db18efb0d88973f9a509eccc3" - integrity sha512-nIT3u43fCNj6uSMN1dRxFnF4GhmIiOEqSTkGSjrMU+8kHKwzOqS/6X6TOzklBmCyEZOpF/fLlGqH3BZHnwLDzQ== +"@lerna/version@3.22.0": + version "3.22.0" + resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.22.0.tgz#67e1340c1904e9b339becd66429f32dd8ad65a55" + integrity sha512-6uhL6RL7/FeW6u1INEgyKjd5dwO8+IsbLfkfC682QuoVLS7VG6OOB+JmTpCvnuyYWI6fqGh1bRk9ww8kPsj+EA== dependencies: "@lerna/check-working-tree" "3.16.5" "@lerna/child-process" "3.16.5" "@lerna/collect-updates" "3.20.0" "@lerna/command" "3.21.0" - "@lerna/conventional-commits" "3.18.5" - "@lerna/github-client" "3.16.5" + "@lerna/conventional-commits" "3.22.0" + "@lerna/github-client" "3.22.0" "@lerna/gitlab-client" "3.15.0" "@lerna/output" "3.13.0" "@lerna/prerelease-id-from-version" "3.16.0" @@ -1250,10 +1250,10 @@ is-plain-object "^3.0.0" universal-user-agent "^5.0.0" -"@octokit/plugin-enterprise-rest@^3.6.1": - version "3.6.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-3.6.2.tgz#74de25bef21e0182b4fa03a8678cd00a4e67e561" - integrity sha512-3wF5eueS5OHQYuAEudkpN+xVeUsg8vYEMMenEzLphUZ7PRZ8OJtDcsreL3ad9zxXmBbaFWzLmFcdob5CLyZftA== +"@octokit/plugin-enterprise-rest@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" + integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== "@octokit/plugin-paginate-rest@^1.1.1": version "1.1.2" @@ -1507,10 +1507,10 @@ dependencies: jszip "*" -"@types/lodash@^4.14.153": - version "4.14.153" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.153.tgz#5cb7dded0649f1df97938ac5ffc4f134e9e9df98" - integrity sha512-lYniGRiRfZf2gGAR9cfRC3Pi5+Q1ziJCKqPmjZocigrSJUVPWf7st1BtSJ8JOeK0FLXVndQ1IjUjTco9CXGo/Q== +"@types/lodash@^4.14.155": + version "4.14.155" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.155.tgz#e2b4514f46a261fd11542e47519c20ebce7bc23a" + integrity sha512-vEcX7S7aPhsBCivxMwAANQburHBtfN9RdyXFk84IJmu2Z4Hkg1tOFgaslRiEqqvoLtbCBi6ika1EMspE+NZ9Lg== "@types/md5@^2.2.0": version "2.2.0" @@ -1595,10 +1595,10 @@ dependencies: "@types/node" "*" -"@types/sinon@^9.0.3": - version "9.0.3" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.3.tgz#c803f2ebf96db44230ce4e632235c279830edd45" - integrity sha512-NWVG++603tEDwmz5k0DwFR1hqP3iBmq5GYi6d+0KCQMQsfDEULF1D7xqZ+iXRJHeGwLVhM+Rv73uzIYuIUVlJQ== +"@types/sinon@^9.0.4": + version "9.0.4" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.4.tgz#e934f904606632287a6e7f7ab0ce3f08a0dad4b1" + integrity sha512-sJmb32asJZY6Z2u09bl0G2wglSxDlROlAejCjsnor+LzBMz17gu8IU7vKC/vWDnv9zEq2wqADHVXFjf4eE8Gdw== dependencies: "@types/sinonjs__fake-timers" "*" @@ -2134,12 +2134,12 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.681.0: - version "2.681.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.681.0.tgz#09eeedb5ca49813dfc637908abe408ae114a6824" - integrity sha512-/p8CDJ7LZvB1i4WrJrb32FUbbPdiZFZSN6FI2lv7s/scKypmuv/iJ9kpx6QWSWQZ72kJ3Njk/0o7GuVlw0jHXw== +aws-sdk@^2.637.0, aws-sdk@^2.689.0: + version "2.689.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.689.0.tgz#f8833031afd773bfc9503f8d6325186a985d019c" + integrity sha512-l9kbgZtIbR9dux4JHoxZ3vDWAfGtp34KpDDf5cwYHC5jDTTJoe6XhBBlEDSruwKh1+5DONpSZWNVhDZ6E02ojg== dependencies: - buffer "4.9.1" + buffer "4.9.2" events "1.1.1" ieee754 "1.1.13" jmespath "0.15.0" @@ -2350,10 +2350,10 @@ buffer-from@1.x, buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -buffer@4.9.1: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= +buffer@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -2689,10 +2689,10 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -codemaker@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.5.0.tgz#f0bf606e96dac89c8cf6d7641d344b3c46f11bc7" - integrity sha512-M3vtGs1koOa8OjpjaFX1T92LkcuXAWHAgArwYanAN7Ptu2mmbOJCtznubIr0GnXzetukpCFnRaf777CDgfUFIg== +codemaker@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.6.0.tgz#5fa6cf121bfb4476908666b46cf9ff34a72ef49a" + integrity sha512-B8FcGhBVMfQs+a8i8VnAWZLUgsM8IU3Q+V2hrLnBXd82Tlp/uUm5K5melOJeSKCoHHaTU8y1kNLaNo6qq47etw== dependencies: camelcase "^6.0.0" decamelize "^1.2.0" @@ -4418,10 +4418,10 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3" - integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g== +fs-extra@^9.0.0, fs-extra@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" + integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== dependencies: at-least-node "^1.0.0" graceful-fs "^4.2.0" @@ -4714,12 +4714,7 @@ globrex@^0.1.1: resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -graceful-fs@^4.2.4: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -5980,70 +5975,70 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsii-diff@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.5.0.tgz#a8400ea7ba69e619f8c44cc6a9677a2f71587fc2" - integrity sha512-6Z3ayLF1IMFLq9tSmfpozwF9F/JwEswEYSvKOhFb/vcULP5j743HbvEXoIzRNVX/xTKdpBbo7tXmFFECC3xDEw== +jsii-diff@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.6.0.tgz#a8b2cd56fd1fd77de37061c38a6434c70c235a41" + integrity sha512-m/xS549AtR/dK6crArmJeYHaJACwv+tj/koLsn2cKmPqfK2z6FcSgKjOnQH+Q2PlgsJWVUlyaVvhQlnj+W78kw== dependencies: - "@jsii/spec" "^1.5.0" + "@jsii/spec" "^1.6.0" fs-extra "^9.0.0" - jsii-reflect "^1.5.0" - log4js "^6.2.1" + jsii-reflect "^1.6.0" + log4js "^6.3.0" typescript "~3.8.3" yargs "^15.3.1" -jsii-pacmak@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.5.0.tgz#6de664237eb1f7669ed95d007f1c86a133015498" - integrity sha512-vtTi8640mCUko4cEcPA36zhLLz9IKZXRWtHhRjTH3pKk3PfKDId+jQSzHfCNFe4Gjt9SuJndIrwtvWt7dM+zQg== +jsii-pacmak@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.6.0.tgz#d25e162b16328b50e89c3927d996a277b6acb865" + integrity sha512-Ces8X36Ccyq5AZjzpznFUfV5wd0Ol0hiprJwtGHhs5vug5uJFLZxdS0hPFBFFPLiXQWwsEToWyM7PQ+xakTTpg== dependencies: - "@jsii/spec" "^1.5.0" + "@jsii/spec" "^1.6.0" clone "^2.1.2" - codemaker "^1.5.0" + codemaker "^1.6.0" commonmark "^0.29.1" escape-string-regexp "^4.0.0" fs-extra "^9.0.0" - jsii-reflect "^1.5.0" - jsii-rosetta "^1.5.0" + jsii-reflect "^1.6.0" + jsii-rosetta "^1.6.0" semver "^7.3.2" spdx-license-list "^6.2.0" xmlbuilder "^15.1.1" yargs "^15.3.1" -jsii-reflect@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.5.0.tgz#f6007bbb3b262832d93a1b5b87b1c8d570e5c2fc" - integrity sha512-+kDzb9ariTFrox1GaLfclU1Gxs1b40hr5BSBhVBzq03F+opMyTXp2gBPotsTm8Se44wcptDbTPwEmSx1ZxR+rQ== +jsii-reflect@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.6.0.tgz#dae9ea3aa04bc95a1c244051a4c4adf691849c01" + integrity sha512-JsVGJCcezNdnR4OukLNs7p6T6f3rKbGWNByE8Omvi7GfDf9c/YiVG4LggxEQaWyIZiYYqeEtBw6JtIKj3Qme5w== dependencies: - "@jsii/spec" "^1.5.0" + "@jsii/spec" "^1.6.0" colors "^1.4.0" fs-extra "^9.0.0" - oo-ascii-tree "^1.5.0" + oo-ascii-tree "^1.6.0" yargs "^15.3.1" -jsii-rosetta@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.5.0.tgz#158365c89fbc0022b821746f3500ececfc37fd21" - integrity sha512-ABR9FWLjuEMZJrY19hjec5JCwAS9k6aQMt6F2KXTh5chFwYjU/rHUMJ/IQ9kGNiiv5MDJeVokxH/CM2gERVOdA== +jsii-rosetta@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.6.0.tgz#49cf48328f29c0b88e2bec23372696b7c4eba006" + integrity sha512-eDaaIyvFcnB07j4aRS/xWBxenHE+OEW8gWLwSnv72+BsPifcS1QOkYcz/p/fTtPjNDyjtO8dcG5V4NUsy3QKdw== dependencies: - "@jsii/spec" "^1.5.0" + "@jsii/spec" "^1.6.0" commonmark "^0.29.1" fs-extra "^9.0.0" typescript "~3.8.3" xmldom "^0.3.0" yargs "^15.3.1" -jsii@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.5.0.tgz#dcf62a953bb765e0c55ba23b0711f25a349baafb" - integrity sha512-1dWN55Bttwx9zr58iSOxCkj9O99YKtzs/51FNwjGs20KNXvVfiY6ZBnUGhq57G5mSmb+NZosX71EFknoYrFoLA== +jsii@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.6.0.tgz#35a60fed491bb3e4fa2c35965f9f2bb8593f2165" + integrity sha512-g9L2xBnKCrzfMPkaioYSz8lYATYGt8SWimycq9HxfszaI0/QjKv+68E5pgTimy6EZil+2O/KguiYqlK9jNQE7A== dependencies: - "@jsii/spec" "^1.5.0" + "@jsii/spec" "^1.6.0" case "^1.6.3" colors "^1.4.0" deep-equal "^2.0.3" fs-extra "^9.0.0" - log4js "^6.2.1" + log4js "^6.3.0" semver "^7.3.2" semver-intersect "^1.4.0" sort-json "^2.0.0" @@ -6210,27 +6205,27 @@ lcov-parse@^1.0.0: resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0" integrity sha1-6w1GtUER68VhrLTECO+TY73I9+A= -lerna@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.21.0.tgz#c81a0f8df45c6b7c9d3fc9fdcd0f846aca2375c6" - integrity sha512-ux8yOwQEgIXOZVUfq+T8nVzPymL19vlIoPbysOP3YA4hcjKlqQIlsjI/1ugBe6b4MF7W4iV5vS3gH9cGqBBc1A== +lerna@^3.22.0: + version "3.22.0" + resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.22.0.tgz#da14d08f183ffe6eec566a4ef3f0e11afa621183" + integrity sha512-xWlHdAStcqK/IjKvjsSMHPZjPkBV1lS60PmsIeObU8rLljTepc4Sg/hncw4HWfQxPIewHAUTqhrxPIsqf9L2Eg== dependencies: "@lerna/add" "3.21.0" "@lerna/bootstrap" "3.21.0" "@lerna/changed" "3.21.0" "@lerna/clean" "3.21.0" "@lerna/cli" "3.18.5" - "@lerna/create" "3.21.0" + "@lerna/create" "3.22.0" "@lerna/diff" "3.21.0" "@lerna/exec" "3.21.0" - "@lerna/import" "3.21.0" + "@lerna/import" "3.22.0" "@lerna/info" "3.21.0" "@lerna/init" "3.21.0" "@lerna/link" "3.21.0" "@lerna/list" "3.21.0" - "@lerna/publish" "3.21.0" + "@lerna/publish" "3.22.0" "@lerna/run" "3.21.0" - "@lerna/version" "3.21.0" + "@lerna/version" "3.22.0" import-local "^2.0.0" npmlog "^4.1.2" @@ -6424,10 +6419,10 @@ log-driver@^1.2.7: resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== -log4js@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.2.1.tgz#fc23a3bf287f40f5b48259958e5e0ed30d558eeb" - integrity sha512-7n+Oqxxz7VcQJhIlqhcYZBTpbcQ7XsR0MUIfJkx/n3VUjkAS4iUr+4UJlhxf28RvP9PMGQXbgTUhLApnu0XXgA== +log4js@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb" + integrity sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw== dependencies: date-format "^3.0.0" debug "^4.1.1" @@ -7300,10 +7295,10 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -oo-ascii-tree@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.5.0.tgz#e462474b98910dd33fec6518629358c74845ce1a" - integrity sha512-6s+nBxOutQeDvForKX5oFUchFSDpD2KGFIkqyv4VDX0FZl79iCx8E9R4Y/7o2umjTjuK9CrBJzO0kFKNKWbZQA== +oo-ascii-tree@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.6.0.tgz#afc53c12d9bc33e658bfd3a4b128f8aeb2c97196" + integrity sha512-3JNvbe7r+qHPHbJhnQ8R8GzgSdF5sAA49gNKnJDWD/bQ9cZzSKG8qtbGPBBnwQ2wX/YCaJ4rUTs1c2Rz2sx1+w== opener@^1.5.1: version "1.5.1"