From 89924d3d6c4e61d2d1ca67abeca7e893928b7dcc Mon Sep 17 00:00:00 2001 From: Hitendra Nishar Date: Mon, 6 Jul 2020 17:17:06 -0400 Subject: [PATCH] Update to version v1.48.0 --- CHANGELOG.md | 10 + CONTRIBUTING.md | 4 +- README.md | 2 + deployment/build-patterns.sh | 4 - source/lerna.json | 2 +- source/package.json | 2 +- .../aws-apigateway-dynamodb/package.json | 24 +- .../aws-apigateway-lambda/package.json | 24 +- .../aws-apigateway-sqs/package.json | 28 +- .../package.json | 32 +- .../aws-cloudfront-apigateway/package.json | 28 +- .../aws-cloudfront-s3/package.json | 20 +- .../package.json | 24 +- .../package.json | 44 +- .../aws-dynamodb-stream-lambda/package.json | 24 +- .../aws-events-rule-lambda/package.json | 24 +- .../package.json | 36 +- .../aws-iot-kinesisfirehose-s3/package.json | 32 +- .../aws-iot-lambda-dynamodb/package.json | 32 +- .../aws-iot-lambda/package.json | 24 +- .../package.json | 36 +- .../aws-kinesisfirehose-s3/package.json | 28 +- .../aws-kinesisstreams-lambda/package.json | 28 +- .../aws-lambda-dynamodb/package.json | 20 +- .../package.json | 32 +- .../aws-lambda-s3/README.md | 2 + .../aws-lambda-s3/package.json | 20 +- .../aws-lambda-sns/package.json | 24 +- .../aws-lambda-step-function/.eslintignore | 5 + .../aws-lambda-step-function/.gitignore | 15 + .../aws-lambda-step-function/.npmignore | 21 + .../aws-lambda-step-function/README.md | 91 +++ .../aws-lambda-step-function/architecture.png | Bin 0 -> 57090 bytes .../aws-lambda-step-function/lib/index.ts | 92 +++ .../aws-lambda-step-function/package.json | 82 ++ .../lambda-step-function.test.js.snap | 715 ++++++++++++++++++ .../test/integ.deploy-lambda.expected.json | 353 +++++++++ .../test/integ.deploy-lambda.ts | 44 ++ .../integ.existing-function.expected.json | 353 +++++++++ .../test/integ.existing-function.ts | 51 ++ .../test/lambda-step-function.test.ts | 163 ++++ .../test/lambda/index.js | 18 + .../aws-s3-lambda/package.json | 32 +- .../aws-s3-step-function/package.json | 48 +- .../aws-sns-lambda/package.json | 32 +- .../aws-sqs-lambda/README.md | 2 + .../aws-sqs-lambda/lib/index.ts | 18 +- .../aws-sqs-lambda/package.json | 28 +- .../test/integ.deployFifoQueue.expected.json | 211 ++++++ .../test/integ.deployFifoQueue.ts | 45 ++ .../test/test.sqs-lambda.test.ts | 4 +- .../core/package.json | 88 +-- source/tools/cdk-integ-tools/package.json | 6 +- .../aws-s3-static-website/package.json | 22 +- .../aws-serverless-image-handler/package.json | 40 +- .../aws-serverless-web-app/package.json | 32 +- 56 files changed, 2751 insertions(+), 470 deletions(-) create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.eslintignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.gitignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.npmignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/README.md create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/architecture.png create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/lib/index.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/package.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/__snapshots__/lambda-step-function.test.js.snap create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda-step-function.test.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda/index.js create mode 100644 source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index de495ac3c..ca7263e04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.48.0] - 2020-07-06 + +### Added +- Upgraded all patterns to CDK v1.48.0 +- aws-lambda-step-function pattern added + +### Changed +- Fix for aws-sqs-lambda pattern bug when using FIFO queue ([#13](https://github.com/awslabs/aws-solutions-constructs/pull/13)) +- Minor updates to CONTRIBUTING.md and deployment/build-patterns.sh + ## [1.47.0] - 2020-06-25 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec5bae250..61ed1f146 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -182,7 +182,9 @@ First run a clean Full Build before doing the partial build. ```console $ cd $ docker run --rm --net=host -it -v $PWD:$PWD -w $PWD jsii/superchain -docker$ cd source/patterns/@aws-solutions-constructs/my-module +docker$ cd source +docker$ export PATH=$(npm bin):$PATH +docker$ cd patterns/@aws-solutions-constructs/my-module docker$ npm run build+lint+test docker$ exit ``` diff --git a/README.md b/README.md index e06a5ab9d..8a22b83cf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # AWS Solutions Constructs +| **Browse Library**:| https://aws.amazon.com/solutions/constructs/patterns/| +|:-------------|:-------------| | **Reference Documentation**:| https://docs.aws.amazon.com/solutions/latest/constructs/| |:-------------|:-------------|
diff --git a/deployment/build-patterns.sh b/deployment/build-patterns.sh index 60008d7ac..07b1857fb 100755 --- a/deployment/build-patterns.sh +++ b/deployment/build-patterns.sh @@ -25,7 +25,3 @@ yarn install --frozen-lockfile echo "=============================================================================================" echo "building..." time lerna run $bail --stream $runtarget || fail - -echo "=============================================================================================" -echo "packaging..." -time lerna run $bail --stream jsii-pacmak || fail diff --git a/source/lerna.json b/source/lerna.json index ab48db195..b035adc59 100644 --- a/source/lerna.json +++ b/source/lerna.json @@ -6,5 +6,5 @@ "./patterns/@aws-solutions-constructs/*" ], "rejectCycles": "true", - "version": "1.47.0" + "version": "1.48.0" } diff --git a/source/package.json b/source/package.json index d71da7ec0..04b18916e 100644 --- a/source/package.json +++ b/source/package.json @@ -1,6 +1,6 @@ { "name": "aws-solutions-constructs", - "version": "1.47.0", + "version": "1.48.0", "description": "AWS Solutions Constructs Library", "repository": { "type": "git", diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/package.json b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/package.json index 1165b8485..63c88cd85 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-apigateway-dynamodb", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS API Gateway and Amazon DynamoDB integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,15 +53,15 @@ } }, "dependencies": { - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/package.json index 7884e2877..d080b490e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-apigateway-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK constructs for defining an interaction between an API Gateway and a Lambda function.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,15 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/package.json b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/package.json index 7877e7ba8..f3a16fd5c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-apigateway-sqs", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK constructs for defining an interaction between an AWS Lambda function and an Amazon S3 bucket.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,16 @@ } }, "dependencies": { - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-sqs": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-sqs": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-sqs": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-sqs": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/package.json index 941f6c121..75d179733 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS Cloudfront to AWS API Gateway to AWS Lambda integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,17 +53,17 @@ } }, "dependencies": { - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-solutions-constructs/aws-cloudfront-apigateway": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-solutions-constructs/aws-cloudfront-apigateway": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-solutions-constructs/aws-cloudfront-apigateway": "~1.47.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-solutions-constructs/aws-cloudfront-apigateway": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/package.json b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/package.json index 749cf2710..aa0d992ab 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-cloudfront-apigateway", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS Cloudfront to AWS API Gateway integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,16 @@ } }, "dependencies": { - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/package.json b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/package.json index c8872f812..6d81037bc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-cloudfront-s3", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS Cloudfront to AWS S3 integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,14 +53,14 @@ } }, "dependencies": { - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +70,10 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/package.json index a32f23169..31566faca 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-cognito-apigateway-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS Cognito to AWS API Gateway to AWS Lambda integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,15 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/package.json b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/package.json index 6433af6da..b3dfac38a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for Amazon Dynamodb stream to AWS Lambda to AWS Elasticsearch with Kibana integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,20 +53,20 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-elasticsearch": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-dynamodb-stream-lambda": "~1.47.0", - "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-elasticsearch": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-dynamodb-stream-lambda": "~1.48.0", + "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -76,16 +76,16 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-elasticsearch": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-dynamodb-stream-lambda": "~1.47.0", - "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-elasticsearch": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-dynamodb-stream-lambda": "~1.48.0", + "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/package.json index cc96f7cd5..6754f4f99 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-dynamodb-stream-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS DynamoDB Stream to AWS Lambda integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,15 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/package.json index d9dda6d26..c1393a1db 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-events-rule-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for deploying AWS Events Rule that inveokes AWS Lambda", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,15 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-events": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-events": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-events": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-events": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/package.json b/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/package.json index 4f6346cf4..1014bcd0f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-events-rule-step-function", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for deploying AWS Events Rule that invokes AWS Step Function", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,18 +53,18 @@ } }, "dependencies": { - "@aws-cdk/aws-stepfunctions": "~1.47.0", - "@aws-cdk/aws-stepfunctions-tasks": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-events": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-stepfunctions": "~1.48.0", + "@aws-cdk/aws-stepfunctions-tasks": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-events": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -74,14 +74,14 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-stepfunctions": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-events": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-stepfunctions": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-events": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-cdk/aws-stepfunctions-tasks": "~1.47.0" + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-cdk/aws-stepfunctions-tasks": "~1.48.0" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/package.json b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/package.json index 602f1b473..bb69fe79d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-iot-kinesisfirehose-s3", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS IoT to AWS Kinesis Firehose to AWS S3 integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,17 +52,17 @@ } }, "dependencies": { - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kinesisfirehose": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-iot": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.47.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kinesisfirehose": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-iot": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,13 +72,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kinesisfirehose": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-iot": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.47.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kinesisfirehose": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-iot": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/package.json b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/package.json index 32d5de693..7c9e2a544 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-iot-lambda-dynamodb", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS IoT to AWS Lambda to AWS DyanmoDB integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,17 +53,17 @@ } }, "dependencies": { - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-iot": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-iot-lambda": "~1.47.0", - "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.47.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-iot": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-iot-lambda": "~1.48.0", + "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-iot": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-iot-lambda": "~1.47.0", - "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.47.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-iot": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-iot-lambda": "~1.48.0", + "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/package.json index 663bbccc6..1197eab90 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-iot-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS IoT to AWS Lambda integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,15 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-iot": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-iot": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iot": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", + "@aws-cdk/aws-iot": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/package.json b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/package.json index 2833acf9d..a67674cfc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK constructs for defining an interaction between an Amazon Kinesis Data Firehose delivery stream and (1) an Amazon S3 bucket, and (2) an Amazon Kinesis Data Analytics application.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,18 +52,18 @@ } }, "dependencies": { - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kinesis": "~1.47.0", - "@aws-cdk/aws-kinesisanalytics": "~1.47.0", - "@aws-cdk/aws-kinesisfirehose": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.47.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kinesis": "~1.48.0", + "@aws-cdk/aws-kinesisanalytics": "~1.48.0", + "@aws-cdk/aws-kinesisfirehose": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,14 +73,14 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kinesis": "~1.47.0", - "@aws-cdk/aws-kinesisanalytics": "~1.47.0", - "@aws-cdk/aws-kinesisfirehose": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.47.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kinesis": "~1.48.0", + "@aws-cdk/aws-kinesisanalytics": "~1.48.0", + "@aws-cdk/aws-kinesisfirehose": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/package.json b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/package.json index 6671faed4..2c70a3076 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-kinesisfirehose-s3", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK constructs for defining an interaction between an Amazon Kinesis Data Firehose delivery stream and an Amazon S3 bucket.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,16 +52,16 @@ } }, "dependencies": { - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kinesisfirehose": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kinesisfirehose": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,12 +71,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kinesisfirehose": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kinesisfirehose": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/package.json index b332f38b0..4c357c76f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-kinesisstreams-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK constructs for defining an interaction between an Amazon Kinesis Data Stream and an AWS Lambda function.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,16 @@ } }, "dependencies": { - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kinesis": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kinesis": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kinesis": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kinesis": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/package.json b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/package.json index 5e61feda2..76ab71f0f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-lambda-dynamodb", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS Lambda to AWS DynamoDB integration.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,14 +53,14 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +70,10 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/package.json b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/package.json index a37ec91ce..b5f5b573d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS Lambda to AWS Elasticsearch with Kibana integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,17 +53,17 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-elasticsearch": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-elasticsearch": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-elasticsearch": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-elasticsearch": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/README.md index 5cde61ea5..2fe5df36e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/README.md @@ -66,6 +66,8 @@ _Parameters_ ## Pattern Properties +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| |lambdaFunction|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of the Lambda function created by the pattern.| |s3Bucket|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of the S3 bucket created by the pattern.| diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/package.json b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/package.json index 9c8d6845e..74e375747 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-lambda-s3", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK constructs for defining an interaction between an AWS Lambda function and an Amazon S3 bucket.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,14 +52,14 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -69,10 +69,10 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/package.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/package.json index e4d71ab36..cccdc31f5 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-lambda-sns", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK constructs for defining an interaction between an AWS Lambda function and an Amazon SNS topic.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -52,15 +52,15 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-sns": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-sns": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,11 +70,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-sns": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-sns": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.eslintignore b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.eslintignore new file mode 100644 index 000000000..0819e2e65 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.eslintignore @@ -0,0 +1,5 @@ +lib/*.js +test/*.js +*.d.ts +coverage +test/lambda/index.js \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.gitignore b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.gitignore new file mode 100644 index 000000000..6773cabd2 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.gitignore @@ -0,0 +1,15 @@ +lib/*.js +test/*.js +*.js.map +*.d.ts +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.npmignore b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.npmignore new file mode 100644 index 000000000..f66791629 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/.npmignore @@ -0,0 +1,21 @@ +# Exclude typescript source and config +*.ts +tsconfig.json +coverage +.nyc_output +*.tgz +*.snk +*.tsbuildinfo + +# Include javascript files and typescript declarations +!*.js +!*.d.ts + +# Exclude jsii outdir +dist + +# Include .jsii +!.jsii + +# Include .jsii +!.jsii \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/README.md new file mode 100644 index 000000000..bfbb7c6ea --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/README.md @@ -0,0 +1,91 @@ +# aws-lambda-step-function module + + +--- + +![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) + +> All classes are under active development and subject to non-backward compatible changes or removal in any +> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. +> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +| **Reference Documentation**:| https://docs.aws.amazon.com/solutions/latest/constructs/| +|:-------------|:-------------| +
+ +| **Language** | **Package** | +|:-------------|-----------------| +|![Python Logo](https://docs.aws.amazon.com/cdk/api/latest/img/python32.png) Python|`aws_solutions_constructs.aws_lambda_step_function`| +|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-lambda-step-function`| +|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.lambdastepfunction`| + +This AWS Solutions Construct implements an AWS Lambda function connected to an AWS Step Function. + +Here is a minimal deployable pattern definition: + +``` javascript +const { LambdaToStepFunction } = require('@aws-solutions-constructs/aws-lambda-step-function'); + +new LambdaToStepFunction(stack, 'LambdaToStepFunctionPattern', { + deployLambda: true, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + stateMachineProps: { + definition: startState + } +}); + +``` + +## Initializer + +``` text +new LambdaToStepFunction(scope: Construct, id: string, props: LambdaToStepFunctionProps); +``` + +_Parameters_ + +* scope [`Construct`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Construct.html) +* id `string` +* props [`LambdaToStepFunctionProps`](#pattern-construct-props) + +## Pattern Construct Props + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +|deployLambda|`boolean`|Whether to create a new Lambda function or use an existing Lambda function.| +|existingLambdaObj?|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|An optional, existing Lambda function.| +|lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|Optional user-provided props to override the default props for the Lambda function.| +|stateMachineProps|[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|User provided props for the sfn.StateMachine.| + +## Pattern Properties + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +|lambdaFunction|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of the Lambda function created by the pattern.| +|stateMachine|[`sfn.StateMachine`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachine.html)|Returns an instance of StateMachine created by the construct.| +|cloudwatchAlarms|[`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of alarms created by the construct. + +## Default settings + +Out of the box implementation of the Construct without any override will set the following defaults: + +### AWS Lambda Function +* Configure least privilege access IAM role for Lambda function +* Enable reusing connections with Keep-Alive for NodeJs Lambda function + +### AWS Step Function +* Enable CloudWatch logging for API Gateway +* Deploy best practices CloudWatch Alarms for the Step Function + +## Architecture +![Architecture Diagram](architecture.png) + +*** +© Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/architecture.png b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..fbb8a0e402de580bd1c38ab72c29d3ddb0928f35 GIT binary patch literal 57090 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 Kb6Mw<&;$Up&!^G= literal 0 HcmV?d00001 diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/lib/index.ts new file mode 100644 index 000000000..9bf9f0326 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/lib/index.ts @@ -0,0 +1,92 @@ +/** + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// Imports +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as defaults from '@aws-solutions-constructs/core'; +import { Construct } from '@aws-cdk/core'; + +/** + * @summary Properties for the LambdaToStepFunction class. + */ +export interface LambdaToStepFunctionProps { + /** + * Whether to create a new Lambda function or use an existing Lambda function. + * If set to false, you must provide an existing function for the `existingLambdaObj` property. + * + * @default - true + */ + readonly deployLambda: boolean, + /** + * Existing instance of Lambda Function object. + * If `deploy` is set to false only then this property is required + * + * @default - None + */ + readonly existingLambdaObj?: lambda.Function, + /** + * Optional user provided properties to override the default properties for the Lambda function. + * If `deploy` is set to true only then this property is required. + * + * @default - Default properties are used. + */ + readonly lambdaFunctionProps?: lambda.FunctionProps + /** + * User provided StateMachineProps to override the defaults + * + * @default - None + */ + readonly stateMachineProps: sfn.StateMachineProps +} + +/** + * @summary The LambdaToStepFunctionProps class. + */ +export class LambdaToStepFunction extends Construct { + public readonly lambdaFunction: lambda.Function; + public readonly stateMachine: sfn.StateMachine; + public readonly cloudwatchAlarms: cloudwatch.Alarm[]; + + /** + * @summary Constructs a new instance of the LambdaToStepFunctionProps class. + * @param {cdk.App} scope - represents the scope for all the resources. + * @param {string} id - this is a a scope-unique id. + * @param {LambdaToStepFunctionProps} props - user provided props for the construct. + * @since 0.8.0 + * @access public + */ + constructor(scope: Construct, id: string, props: LambdaToStepFunctionProps) { + super(scope, id); + + // Setup the state machine + this.stateMachine = defaults.buildStateMachine(this, props.stateMachineProps); + + // Setup the Lambda function + this.lambdaFunction = defaults.buildLambdaFunction(this, { + deployLambda: props.deployLambda, + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps, + }); + + // Assign the state machine ARN as an environment variable + this.lambdaFunction.addEnvironment('STATE_MACHINE_ARN', this.stateMachine.stateMachineArn); + + // Grant the start execution permission to the Lambda function + this.stateMachine.grantStartExecution(this.lambdaFunction); + + // Deploy best-practice CloudWatch Alarm for state machine + this.cloudwatchAlarms = defaults.buildStepFunctionCWAlarms(this, this.stateMachine); + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/package.json b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/package.json new file mode 100644 index 000000000..3575fad89 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/package.json @@ -0,0 +1,82 @@ +{ + "name": "@aws-solutions-constructs/aws-lambda-step-function", + "version": "1.48.0", + "description": "CDK constructs for defining an interaction between an AWS Lambda function and an AWS Step Function.", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/awslabs/aws-solutions-constructs.git", + "directory": "source/patterns/@aws-solutions-constructs/aws-lambda-step-function" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "scripts": { + "build": "tsc -b .", + "lint": "eslint -c ../eslintrc.yml --ext=.js,.ts . && tslint --project .", + "lint-fix": "eslint -c ../eslintrc.yml --ext=.js,.ts --fix .", + "test": "jest --coverage", + "clean": "tsc -b --clean", + "watch": "tsc -b -w", + "integ": "cdk-integ", + "integ-assert": "cdk-integ-assert", + "integ-no-clean": "cdk-integ --no-clean", + "jsii": "jsii", + "jsii-pacmak": "jsii-pacmak", + "build+lint+test": "npm run jsii && npm run lint && npm test && npm run integ-assert", + "snapshot-update": "npm run jsii && npm test -- -u && npm run integ-assert" + }, + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awsconstructs.services.lambdastepfunction", + "maven": { + "groupId": "software.amazon.awsconstructs", + "artifactId": "lambdastepfunction" + } + }, + "dotnet": { + "namespace": "Amazon.Constructs.AWS.LambdaStepFunction", + "packageId": "Amazon.Constructs.AWS.LambdaStepFunction", + "signAssembly": true, + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-solutions-constructs.aws-lambda-step-function", + "module": "aws_solutions_constructs.aws_lambda_step_function" + } + } + }, + "dependencies": { + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-stepfunctions": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "constructs": "^3.0.2" + }, + "devDependencies": { + "@aws-cdk/assert": "~1.48.0", + "@types/jest": "^24.0.23", + "@types/node": "^10.3.0", + "eslint-plugin-import": "^2.22.0" + }, + "jest": { + "moduleFileExtensions": [ + "js" + ] + }, + "peerDependencies": { + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-stepfunctions": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "constructs": "^3.0.2" + } +} diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/__snapshots__/lambda-step-function.test.js.snap b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/__snapshots__/lambda-step-function.test.js.snap new file mode 100644 index 000000000..761b9582f --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/__snapshots__/lambda-step-function.test.js.snap @@ -0,0 +1,715 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Test deployment with existing Lambda function 1`] = ` +Object { + "Parameters": Object { + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93ArtifactHashC69F2EC4": Object { + "Description": "Artifact hash for asset \\"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\\"", + "Type": "String", + }, + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3Bucket0DF3E8CF": Object { + "Description": "S3 bucket for asset \\"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\\"", + "Type": "String", + }, + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528": Object { + "Description": "S3 key for asset version \\"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\\"", + "Type": "String", + }, + }, + "Resources": Object { + "LambdaFunctionBF21E41F": Object { + "DependsOn": Array [ + "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "LambdaFunctionServiceRole0C4CDE0B", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "S3Bucket": Object { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3Bucket0DF3E8CF", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "LAMBDA_NAME": "existing-function", + "STATE_MACHINE_ARN": Object { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9", + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "LambdaFunctionServiceRole0C4CDE0B", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "LambdaFunctionServiceRole0C4CDE0B": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "LambdaFunctionServiceRoleDefaultPolicy126C8897": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": Object { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9", + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "Roles": Array [ + Object { + "Ref": "LambdaFunctionServiceRole0C4CDE0B", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "testlambdastepfunctionstackExecutionAbortedAlarmFF10BB21": Object { + "Properties": Object { + "AlarmDescription": "Alarm for the number of executions that aborted exceeded the threshold of 1. ", + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "Dimensions": Array [ + Object { + "Name": "StateMachineArn", + "Value": Object { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9", + }, + }, + ], + "EvaluationPeriods": 1, + "MetricName": "ExecutionsAborted", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 1, + }, + "Type": "AWS::CloudWatch::Alarm", + }, + "testlambdastepfunctionstackExecutionFailedAlarm15D73A68": Object { + "Properties": Object { + "AlarmDescription": "Alarm for the number of executions that failed exceeded the threshold of 1. ", + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "Dimensions": Array [ + Object { + "Name": "StateMachineArn", + "Value": Object { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9", + }, + }, + ], + "EvaluationPeriods": 1, + "MetricName": "ExecutionsFailed", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1, + }, + "Type": "AWS::CloudWatch::Alarm", + }, + "testlambdastepfunctionstackExecutionThrottledAlarmB7EC1213": Object { + "Properties": Object { + "AlarmDescription": "Alarm for the number of executions that throttled exceeded the threshold of 1. ", + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "Dimensions": Array [ + Object { + "Name": "StateMachineArn", + "Value": Object { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9", + }, + }, + ], + "EvaluationPeriods": 1, + "MetricName": "ExecutionThrottled", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1, + }, + "Type": "AWS::CloudWatch::Alarm", + }, + "testlambdastepfunctionstackStateMachine373C0BB9": Object { + "DependsOn": Array [ + "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1", + "testlambdastepfunctionstackStateMachineRoleF5EE1C78", + ], + "Properties": Object { + "DefinitionString": "{\\"StartAt\\":\\"StartState\\",\\"States\\":{\\"StartState\\":{\\"Type\\":\\"Pass\\",\\"End\\":true}}}", + "LoggingConfiguration": Object { + "Destinations": Array [ + Object { + "CloudWatchLogsLogGroup": Object { + "LogGroupArn": Object { + "Fn::GetAtt": Array [ + "testlambdastepfunctionstackStateMachineLogGroup42D53E65", + "Arn", + ], + }, + }, + }, + ], + "Level": "ERROR", + }, + "RoleArn": Object { + "Fn::GetAtt": Array [ + "testlambdastepfunctionstackStateMachineRoleF5EE1C78", + "Arn", + ], + }, + }, + "Type": "AWS::StepFunctions::StateMachine", + }, + "testlambdastepfunctionstackStateMachineLogGroup42D53E65": Object { + "DeletionPolicy": "Retain", + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + }, + "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W12", + "reason": "The 'LogDelivery' actions do not support resource-level authorizations", + }, + ], + }, + }, + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + ], + "Effect": "Allow", + "Resource": "*", + }, + Object { + "Action": Array [ + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1", + "Roles": Array [ + Object { + "Ref": "testlambdastepfunctionstackStateMachineRoleF5EE1C78", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "testlambdastepfunctionstackStateMachineRoleF5EE1C78": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": Object { + "Fn::Join": Array [ + "", + Array [ + "states.", + Object { + "Ref": "AWS::Region", + }, + ".amazonaws.com", + ], + ], + }, + }, + }, + ], + "Version": "2012-10-17", + }, + }, + "Type": "AWS::IAM::Role", + }, + }, +} +`; + +exports[`Test deployment with new Lambda function 1`] = ` +Object { + "Parameters": Object { + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93ArtifactHashC69F2EC4": Object { + "Description": "Artifact hash for asset \\"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\\"", + "Type": "String", + }, + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3Bucket0DF3E8CF": Object { + "Description": "S3 bucket for asset \\"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\\"", + "Type": "String", + }, + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528": Object { + "Description": "S3 key for asset version \\"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\\"", + "Type": "String", + }, + }, + "Resources": Object { + "lambdatostepfunctionstackExecutionAbortedAlarmB59542AF": Object { + "Properties": Object { + "AlarmDescription": "Alarm for the number of executions that aborted exceeded the threshold of 1. ", + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "Dimensions": Array [ + Object { + "Name": "StateMachineArn", + "Value": Object { + "Ref": "lambdatostepfunctionstackStateMachine98EE8EFB", + }, + }, + ], + "EvaluationPeriods": 1, + "MetricName": "ExecutionsAborted", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 1, + }, + "Type": "AWS::CloudWatch::Alarm", + }, + "lambdatostepfunctionstackExecutionFailedAlarmED41CA91": Object { + "Properties": Object { + "AlarmDescription": "Alarm for the number of executions that failed exceeded the threshold of 1. ", + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "Dimensions": Array [ + Object { + "Name": "StateMachineArn", + "Value": Object { + "Ref": "lambdatostepfunctionstackStateMachine98EE8EFB", + }, + }, + ], + "EvaluationPeriods": 1, + "MetricName": "ExecutionsFailed", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1, + }, + "Type": "AWS::CloudWatch::Alarm", + }, + "lambdatostepfunctionstackExecutionThrottledAlarm2DEE538A": Object { + "Properties": Object { + "AlarmDescription": "Alarm for the number of executions that throttled exceeded the threshold of 1. ", + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "Dimensions": Array [ + Object { + "Name": "StateMachineArn", + "Value": Object { + "Ref": "lambdatostepfunctionstackStateMachine98EE8EFB", + }, + }, + ], + "EvaluationPeriods": 1, + "MetricName": "ExecutionThrottled", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1, + }, + "Type": "AWS::CloudWatch::Alarm", + }, + "lambdatostepfunctionstackLambdaFunction2C7FCAC4": Object { + "DependsOn": Array [ + "lambdatostepfunctionstackLambdaFunctionServiceRoleDefaultPolicyFF90D87F", + "lambdatostepfunctionstackLambdaFunctionServiceRole98A7C47A", + ], + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.", + }, + ], + }, + }, + "Properties": Object { + "Code": Object { + "S3Bucket": Object { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3Bucket0DF3E8CF", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "LAMBDA_NAME": "deploy-function", + "STATE_MACHINE_ARN": Object { + "Ref": "lambdatostepfunctionstackStateMachine98EE8EFB", + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "lambdatostepfunctionstackLambdaFunctionServiceRole98A7C47A", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "lambdatostepfunctionstackLambdaFunctionServiceRole98A7C47A": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "Policies": Array [ + Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":log-group:/aws/lambda/*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "LambdaFunctionServiceRolePolicy", + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "lambdatostepfunctionstackLambdaFunctionServiceRoleDefaultPolicyFF90D87F": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": Object { + "Ref": "lambdatostepfunctionstackStateMachine98EE8EFB", + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "lambdatostepfunctionstackLambdaFunctionServiceRoleDefaultPolicyFF90D87F", + "Roles": Array [ + Object { + "Ref": "lambdatostepfunctionstackLambdaFunctionServiceRole98A7C47A", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "lambdatostepfunctionstackStateMachine98EE8EFB": Object { + "DependsOn": Array [ + "lambdatostepfunctionstackStateMachineRoleDefaultPolicy6657ED67", + "lambdatostepfunctionstackStateMachineRole707B037B", + ], + "Properties": Object { + "DefinitionString": "{\\"StartAt\\":\\"StartState\\",\\"States\\":{\\"StartState\\":{\\"Type\\":\\"Pass\\",\\"End\\":true}}}", + "LoggingConfiguration": Object { + "Destinations": Array [ + Object { + "CloudWatchLogsLogGroup": Object { + "LogGroupArn": Object { + "Fn::GetAtt": Array [ + "lambdatostepfunctionstackStateMachineLogGroupEAD4854E", + "Arn", + ], + }, + }, + }, + ], + "Level": "ERROR", + }, + "RoleArn": Object { + "Fn::GetAtt": Array [ + "lambdatostepfunctionstackStateMachineRole707B037B", + "Arn", + ], + }, + }, + "Type": "AWS::StepFunctions::StateMachine", + }, + "lambdatostepfunctionstackStateMachineLogGroupEAD4854E": Object { + "DeletionPolicy": "Retain", + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + }, + "lambdatostepfunctionstackStateMachineRole707B037B": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": Object { + "Fn::Join": Array [ + "", + Array [ + "states.", + Object { + "Ref": "AWS::Region", + }, + ".amazonaws.com", + ], + ], + }, + }, + }, + ], + "Version": "2012-10-17", + }, + }, + "Type": "AWS::IAM::Role", + }, + "lambdatostepfunctionstackStateMachineRoleDefaultPolicy6657ED67": Object { + "Metadata": Object { + "cfn_nag": Object { + "rules_to_suppress": Array [ + Object { + "id": "W12", + "reason": "The 'LogDelivery' actions do not support resource-level authorizations", + }, + ], + }, + }, + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + ], + "Effect": "Allow", + "Resource": "*", + }, + Object { + "Action": Array [ + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:aws:logs:", + Object { + "Ref": "AWS::Region", + }, + ":", + Object { + "Ref": "AWS::AccountId", + }, + ":*", + ], + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "lambdatostepfunctionstackStateMachineRoleDefaultPolicy6657ED67", + "Roles": Array [ + Object { + "Ref": "lambdatostepfunctionstackStateMachineRole707B037B", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + }, +} +`; diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.expected.json b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.expected.json new file mode 100644 index 000000000..51894432f --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.expected.json @@ -0,0 +1,353 @@ +{ + "Resources": { + "testlambdastepfunctionstackStateMachineLogGroup42D53E65": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testlambdastepfunctionstackStateMachineRoleF5EE1C78": { + "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" + } + } + }, + "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1", + "Roles": [ + { + "Ref": "testlambdastepfunctionstackStateMachineRoleF5EE1C78" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W12", + "reason": "The 'LogDelivery' actions do not support resource-level authorizations" + } + ] + } + } + }, + "testlambdastepfunctionstackStateMachine373C0BB9": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "testlambdastepfunctionstackStateMachineRoleF5EE1C78", + "Arn" + ] + }, + "DefinitionString": "{\"StartAt\":\"StartState\",\"States\":{\"StartState\":{\"Type\":\"Pass\",\"End\":true}}}", + "LoggingConfiguration": { + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "testlambdastepfunctionstackStateMachineLogGroup42D53E65", + "Arn" + ] + } + } + } + ], + "Level": "ERROR" + } + }, + "DependsOn": [ + "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1", + "testlambdastepfunctionstackStateMachineRoleF5EE1C78" + ] + }, + "testlambdastepfunctionstackLambdaFunctionServiceRoleA27C24DF": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testlambdastepfunctionstackLambdaFunctionServiceRoleDefaultPolicy0CE366B0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testlambdastepfunctionstackLambdaFunctionServiceRoleDefaultPolicy0CE366B0", + "Roles": [ + { + "Ref": "testlambdastepfunctionstackLambdaFunctionServiceRoleA27C24DF" + } + ] + } + }, + "testlambdastepfunctionstackLambdaFunctionF3ADF992": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3Bucket0DF3E8CF" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testlambdastepfunctionstackLambdaFunctionServiceRoleA27C24DF", + "Arn" + ] + }, + "Runtime": "nodejs10.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "STATE_MACHINE_ARN": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + } + }, + "DependsOn": [ + "testlambdastepfunctionstackLambdaFunctionServiceRoleDefaultPolicy0CE366B0", + "testlambdastepfunctionstackLambdaFunctionServiceRoleA27C24DF" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testlambdastepfunctionstackExecutionFailedAlarm15D73A68": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that failed exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + ], + "MetricName": "ExecutionsFailed", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1 + } + }, + "testlambdastepfunctionstackExecutionThrottledAlarmB7EC1213": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that throttled exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + ], + "MetricName": "ExecutionThrottled", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1 + } + }, + "testlambdastepfunctionstackExecutionAbortedAlarmFF10BB21": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that aborted exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + ], + "MetricName": "ExecutionsAborted", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 1 + } + } + }, + "Parameters": { + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3Bucket0DF3E8CF": { + "Type": "String", + "Description": "S3 bucket for asset \"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\"" + }, + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528": { + "Type": "String", + "Description": "S3 key for asset version \"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\"" + }, + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93ArtifactHashC69F2EC4": { + "Type": "String", + "Description": "Artifact hash for asset \"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\"" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.ts new file mode 100644 index 000000000..abb5143b3 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.ts @@ -0,0 +1,44 @@ +/** + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +/// !cdk-integ * +import { App, Stack } from "@aws-cdk/core"; +import { LambdaToStepFunction, LambdaToStepFunctionProps } from "../lib"; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; + +// Setup the app and stack +const app = new App(); +const stack = new Stack(app, 'test-lambda-step-function-stack'); + +// Create a start state for the state machine +const startState = new stepfunctions.Pass(stack, 'StartState'); + +// Setup the pattern props +const props: LambdaToStepFunctionProps = { + deployLambda: true, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + stateMachineProps: { + definition: startState + } +}; + +// Add the pattern +new LambdaToStepFunction(stack, 'test-lambda-step-function-stack', props); + +// Synth the app +app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.expected.json b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.expected.json new file mode 100644 index 000000000..2fdf9793d --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.expected.json @@ -0,0 +1,353 @@ +{ + "Resources": { + "LambdaFunctionServiceRole0C4CDE0B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "LambdaFunctionServiceRoleDefaultPolicy126C8897": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "Roles": [ + { + "Ref": "LambdaFunctionServiceRole0C4CDE0B" + } + ] + } + }, + "LambdaFunctionBF21E41F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3Bucket0DF3E8CF" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "LambdaFunctionServiceRole0C4CDE0B", + "Arn" + ] + }, + "Runtime": "nodejs10.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "STATE_MACHINE_ARN": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + } + }, + "DependsOn": [ + "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "LambdaFunctionServiceRole0C4CDE0B" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testlambdastepfunctionstackStateMachineLogGroup42D53E65": { + "Type": "AWS::Logs::LogGroup", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "testlambdastepfunctionstackStateMachineRoleF5EE1C78": { + "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" + } + } + }, + "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1", + "Roles": [ + { + "Ref": "testlambdastepfunctionstackStateMachineRoleF5EE1C78" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W12", + "reason": "The 'LogDelivery' actions do not support resource-level authorizations" + } + ] + } + } + }, + "testlambdastepfunctionstackStateMachine373C0BB9": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "testlambdastepfunctionstackStateMachineRoleF5EE1C78", + "Arn" + ] + }, + "DefinitionString": "{\"StartAt\":\"StartState\",\"States\":{\"StartState\":{\"Type\":\"Pass\",\"End\":true}}}", + "LoggingConfiguration": { + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "testlambdastepfunctionstackStateMachineLogGroup42D53E65", + "Arn" + ] + } + } + } + ], + "Level": "ERROR" + } + }, + "DependsOn": [ + "testlambdastepfunctionstackStateMachineRoleDefaultPolicy1FFD5CB1", + "testlambdastepfunctionstackStateMachineRoleF5EE1C78" + ] + }, + "testlambdastepfunctionstackExecutionFailedAlarm15D73A68": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that failed exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + ], + "MetricName": "ExecutionsFailed", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1 + } + }, + "testlambdastepfunctionstackExecutionThrottledAlarmB7EC1213": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that throttled exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + ], + "MetricName": "ExecutionThrottled", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1 + } + }, + "testlambdastepfunctionstackExecutionAbortedAlarmFF10BB21": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that aborted exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testlambdastepfunctionstackStateMachine373C0BB9" + } + } + ], + "MetricName": "ExecutionsAborted", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 1 + } + } + }, + "Parameters": { + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3Bucket0DF3E8CF": { + "Type": "String", + "Description": "S3 bucket for asset \"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\"" + }, + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93S3VersionKeyE124A528": { + "Type": "String", + "Description": "S3 key for asset version \"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\"" + }, + "AssetParametersfd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93ArtifactHashC69F2EC4": { + "Type": "String", + "Description": "Artifact hash for asset \"fd7a741674eeef7951675d2a57f0459376e046d88e5bee9aab601d8f5a704c93\"" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.ts new file mode 100644 index 000000000..4ad258925 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.ts @@ -0,0 +1,51 @@ +/** + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +/// !cdk-integ * +import { App, Stack } from "@aws-cdk/core"; +import { LambdaToStepFunction, LambdaToStepFunctionProps } from "../lib"; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; +import * as defaults from '@aws-solutions-constructs/core'; + +// Setup the app and stack +const app = new App(); +const stack = new Stack(app, 'test-lambda-step-function-stack'); + +// Create a start state for the state machine +const startState = new stepfunctions.Pass(stack, 'StartState'); + +// Setup the "existing" Lambda function props +const lambdaFunctionProps = { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) +}; + +// Setup the "existing" Lambda function +const fn = defaults.deployLambdaFunction(stack, lambdaFunctionProps); + +// Setup the pattern props +const props: LambdaToStepFunctionProps = { + deployLambda: false, + existingLambdaObj: fn, + stateMachineProps: { + definition: startState + } +}; + +// Add the pattern +new LambdaToStepFunction(stack, 'test-lambda-step-function-stack', props); + +// Synth the app +app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda-step-function.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda-step-function.test.ts new file mode 100644 index 000000000..f57534a71 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda-step-function.test.ts @@ -0,0 +1,163 @@ +/** + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// Imports +import { Stack } from "@aws-cdk/core"; +import * as lambda from "@aws-cdk/aws-lambda"; +import * as defaults from '@aws-solutions-constructs/core'; +import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; +import { LambdaToStepFunction } from '../lib'; +import { SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; + +// -------------------------------------------------------------- +// Test deployment with new Lambda function +// -------------------------------------------------------------- +test('Test deployment with new Lambda function', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const startState = new stepfunctions.Pass(stack, 'StartState'); + new LambdaToStepFunction(stack, 'lambda-to-step-function-stack', { + deployLambda: true, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`), + environment: { + LAMBDA_NAME: 'deploy-function' + } + }, + stateMachineProps: { + definition: startState + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResourceLike("AWS::Lambda::Function", { + Environment: { + Variables: { + LAMBDA_NAME: 'deploy-function' + } + } + }); +}); + +// -------------------------------------------------------------- +// Test deployment with existing Lambda function +// -------------------------------------------------------------- +test('Test deployment with existing Lambda function', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const startState = new stepfunctions.Pass(stack, 'StartState'); + const lambdaFunctionProps = { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`), + environment: { + LAMBDA_NAME: 'existing-function' + } + }; + const fn = defaults.deployLambdaFunction(stack, lambdaFunctionProps); + // Add the pattern + new LambdaToStepFunction(stack, 'test-lambda-step-function-stack', { + deployLambda: false, + existingLambdaObj: fn, + stateMachineProps: { + definition: startState + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResourceLike("AWS::Lambda::Function", { + Environment: { + Variables: { + LAMBDA_NAME: 'existing-function' + } + } + }); +}); + +// -------------------------------------------------------------- +// Test invocation permissions +// -------------------------------------------------------------- +test('Test invocation permissions', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const startState = new stepfunctions.Pass(stack, 'StartState'); + const lambdaFunctionProps = { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`), + environment: { + LAMBDA_NAME: 'existing-function' + } + }; + const fn = defaults.deployLambdaFunction(stack, lambdaFunctionProps); + // Add the pattern + new LambdaToStepFunction(stack, 'test-lambda-step-function-stack', { + deployLambda: false, + existingLambdaObj: fn, + stateMachineProps: { + definition: startState + } + }); + // Assertion 1 + expect(stack).toHaveResourceLike("AWS::IAM::Policy", { + PolicyDocument: { + Statement: [ + { + Action: "states:StartExecution", + Effect: "Allow" + } + ] + } + }); +}); + +// -------------------------------------------------------------- +// Test the getter methods +// -------------------------------------------------------------- +test('Test the properties', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const startState = new stepfunctions.Pass(stack, 'StartState'); + const pattern = new LambdaToStepFunction(stack, 'lambda-to-step-function-stack', { + deployLambda: true, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`), + environment: { + LAMBDA_NAME: 'existing-function' + } + }, + stateMachineProps: { + definition: startState + } + }); + // Assertion 1 + const func = pattern.lambdaFunction; + expect(func !== null); + // Assertion 2 + const stateMachine = pattern.stateMachine; + expect(stateMachine !== null); + // Assertion 3 + const cwAlarm = pattern.cloudwatchAlarms; + expect(cwAlarm !== null); +}); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda/index.js b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda/index.js new file mode 100644 index 000000000..2a786d862 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda/index.js @@ -0,0 +1,18 @@ +const aws = require('aws-sdk'); + +console.log('Loading function'); + +exports.handler = () => { + const params = { + stateMachineArn: process.env.STATE_MACHINE_ARN, + input: JSON.stringify({}) + }; + const stepFunction = new aws.StepFunctions(); + stepFunction.startExecution(params, function (err, data) { + if (err) { + throw Error('An error occurred executing the step function.'); + } else { + console.log('Step function was successfully executed.'); + } + }) +}; \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/package.json index 2be8ad947..af465fd2d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-s3-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS S3 to AWS Lambda integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,17 +53,17 @@ } }, "dependencies": { - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/aws-s3-notifications": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/aws-s3-notifications": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-s3-notifications": "~1.47.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-s3-notifications": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/package.json b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/package.json index c8339a1a4..ce534c81d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-s3-step-function", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS S3 to AWS Step Function integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,21 +53,21 @@ } }, "dependencies": { - "@aws-cdk/aws-stepfunctions": "~1.47.0", - "@aws-cdk/aws-stepfunctions-tasks": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-cdk/aws-cloudtrail": "~1.47.0", - "@aws-cdk/aws-events": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-events-rule-step-function": "~1.47.0", + "@aws-cdk/aws-stepfunctions": "~1.48.0", + "@aws-cdk/aws-stepfunctions-tasks": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-cdk/aws-cloudtrail": "~1.48.0", + "@aws-cdk/aws-events": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-events-rule-step-function": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -77,17 +77,17 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-stepfunctions": "~1.47.0", - "@aws-cdk/aws-stepfunctions-tasks": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-cdk/aws-cloudtrail": "~1.47.0", - "@aws-cdk/aws-events": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-solutions-constructs/aws-events-rule-step-function": "~1.47.0", + "@aws-cdk/aws-stepfunctions": "~1.48.0", + "@aws-cdk/aws-stepfunctions-tasks": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-cdk/aws-cloudtrail": "~1.48.0", + "@aws-cdk/aws-events": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-solutions-constructs/aws-events-rule-step-function": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/package.json index 17e9a6f43..609e194c0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-sns-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK Constructs for AWS SNS to AWS Lambda integration", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,17 +53,17 @@ } }, "dependencies": { - "@aws-cdk/aws-sns": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-sns": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-sns": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", + "@aws-cdk/aws-sns": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/README.md index 505ba9453..86d317508 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/README.md @@ -60,6 +60,7 @@ _Parameters_ |existingLambdaObj?|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|An optional, existing Lambda function.| |lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|Optional user-provided props to override the default props for the Lambda function.| |queueProps?|[`sqs.QueueProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.QueueProps.html)|Optional user-provided props to override the default props for the SQS queue.| +|deadLetterQueueProps?|[`sqs.QueueProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.QueueProps.html)|Optional user-provided props to override the default props for the dead letter SQS queue.| |deployDeadLetterQueue?|`boolean`|Whether to create a secondary queue to be used as a dead letter queue. Defaults to true.| |maxReceiveCount?|`number`|The number of times a message can be unsuccessfully dequeued before being moved to the dead letter queue. Defaults to 15.| @@ -69,6 +70,7 @@ _Parameters_ |:-------------|:----------------|-----------------| |lambdaFunction|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of the Lambda function created by the pattern.| |sqsQueue|[`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.Queue.html)|Returns an instance of the SQS queue created by the pattern.| +|deadLetterQueue|[`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.Queue.html)|Returns an instance of the dead-letter SQS queue created by the pattern.| ## Default settings diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts index e5feec38a..c0d1d09b4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts @@ -42,13 +42,19 @@ export interface SqsToLambdaProps { * * @default - Default properties are used. */ - readonly lambdaFunctionProps?: lambda.FunctionProps | any + readonly lambdaFunctionProps?: lambda.FunctionProps /** * Optional user provided properties * * @default - Default props are used */ - readonly queueProps?: sqs.QueueProps | any + readonly queueProps?: sqs.QueueProps, + /** + * Optional user provided properties for the dead letter queue + * + * @default - Default props are used + */ + readonly deadLetterQueueProps?: sqs.QueueProps, /** * Whether to deploy a secondary queue to be used as a dead letter queue. * @@ -68,6 +74,7 @@ export interface SqsToLambdaProps { */ export class SqsToLambda extends Construct { public readonly sqsQueue: sqs.Queue; + public readonly deadLetterQueue: sqs.DeadLetterQueue | undefined; public readonly lambdaFunction: lambda.Function; /** @@ -89,12 +96,11 @@ export class SqsToLambda extends Construct { }); // Setup the dead letter queue, if applicable - let dlqi: sqs.DeadLetterQueue | undefined; if (props.deployDeadLetterQueue || props.deployDeadLetterQueue === undefined) { const dlq: sqs.Queue = defaults.buildQueue(this, 'deadLetterQueue', { - queueProps: props.queueProps + queueProps: props.deadLetterQueueProps }); - dlqi = defaults.buildDeadLetterQueue({ + this.deadLetterQueue = defaults.buildDeadLetterQueue({ deadLetterQueue: dlq, maxReceiveCount: props.maxReceiveCount }); @@ -103,7 +109,7 @@ export class SqsToLambda extends Construct { // Setup the queue this.sqsQueue = defaults.buildQueue(this, 'queue', { queueProps: props.queueProps, - deadLetterQueue: dlqi + deadLetterQueue: this.deadLetterQueue }); // Setup the event source mapping diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/package.json b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/package.json index c363997c5..0a59d6d34 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-sqs-lambda", - "version": "1.47.0", + "version": "1.48.0", "description": "CDK constructs for defining an interaction between an Amazon SQS queue and an AWS Lambda function.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,16 +53,16 @@ } }, "dependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-sqs": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-sqs": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-sqs": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-sqs": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.expected.json b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.expected.json new file mode 100644 index 000000000..5dd4645b8 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.expected.json @@ -0,0 +1,211 @@ +{ + "Description": "Integration Test for aws-sqs-lambda with FIFO Queue", + "Resources": { + "testsqslambdafifoLambdaFunctionServiceRole74463822": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testsqslambdafifoLambdaFunctionServiceRoleDefaultPolicy016B538E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:ReceiveMessage", + "sqs:ChangeMessageVisibility", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "testsqslambdafifoqueue45DD24D7", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testsqslambdafifoLambdaFunctionServiceRoleDefaultPolicy016B538E", + "Roles": [ + { + "Ref": "testsqslambdafifoLambdaFunctionServiceRole74463822" + } + ] + } + }, + "testsqslambdafifoLambdaFunction0F3AE705": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testsqslambdafifoLambdaFunctionServiceRole74463822", + "Arn" + ] + }, + "Runtime": "nodejs10.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" + } + } + }, + "DependsOn": [ + "testsqslambdafifoLambdaFunctionServiceRoleDefaultPolicy016B538E", + "testsqslambdafifoLambdaFunctionServiceRole74463822" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testsqslambdafifoLambdaFunctionSqsEventSourcetestsqslambdafifoqueue2EDECAD03B39CEA5": { + "Type": "AWS::Lambda::EventSourceMapping", + "Properties": { + "EventSourceArn": { + "Fn::GetAtt": [ + "testsqslambdafifoqueue45DD24D7", + "Arn" + ] + }, + "FunctionName": { + "Ref": "testsqslambdafifoLambdaFunction0F3AE705" + } + } + }, + "testsqslambdafifodeadLetterQueue99A41920": { + "Type": "AWS::SQS::Queue", + "Properties": { + "FifoQueue": true, + "KmsMasterKeyId": "alias/aws/sqs", + "QueueName": "myDLQueue.fifo" + } + }, + "testsqslambdafifoqueue45DD24D7": { + "Type": "AWS::SQS::Queue", + "Properties": { + "FifoQueue": true, + "KmsMasterKeyId": "alias/aws/sqs", + "QueueName": "myQueue.fifo", + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "testsqslambdafifodeadLetterQueue99A41920", + "Arn" + ] + }, + "maxReceiveCount": 15 + } + } + } + }, + "Parameters": { + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": { + "Type": "String", + "Description": "S3 bucket for asset \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": { + "Type": "String", + "Description": "S3 key for asset version \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": { + "Type": "String", + "Description": "Artifact hash for asset \"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\"" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.ts new file mode 100644 index 000000000..7f698ba86 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.ts @@ -0,0 +1,45 @@ +/** + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// Imports +import { App, Stack } from "@aws-cdk/core"; +import { SqsToLambda, SqsToLambdaProps } from "../lib"; +import * as lambda from '@aws-cdk/aws-lambda'; + +// Setup +const app = new App(); +const stack = new Stack(app, 'test-sqs-lambda-fifo'); +stack.templateOptions.description = 'Integration Test for aws-sqs-lambda with FIFO Queue'; + +// Definitions +const props: SqsToLambdaProps = { + deployLambda: true, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + queueProps: { + queueName: `myQueue.fifo`, + fifo: true, + }, + deadLetterQueueProps: { + queueName: `myDLQueue.fifo`, + fifo: true, + }, +}; + +new SqsToLambda(stack, 'test-sqs-lambda-fifo', props); + +// Synth +app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/test.sqs-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/test.sqs-lambda.test.ts index ddcb5fe64..0e2de60cf 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/test.sqs-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/test.sqs-lambda.test.ts @@ -104,7 +104,7 @@ test('Test getter methods', () => { handler: 'index.handler', code: lambda.Code.asset(`${__dirname}/lambda`) }, - deployDeadLetterQueue: false, + deployDeadLetterQueue: true, maxReceiveCount: 0, queueProps: {} }; @@ -113,6 +113,8 @@ test('Test getter methods', () => { expect(app.lambdaFunction !== null); // Assertion 2 expect(app.sqsQueue !== null); + // Assertion 3 + expect(app.deadLetterQueue !== null); }); // -------------------------------------------------------------- diff --git a/source/patterns/@aws-solutions-constructs/core/package.json b/source/patterns/@aws-solutions-constructs/core/package.json index 57d682e0e..08560410a 100644 --- a/source/patterns/@aws-solutions-constructs/core/package.json +++ b/source/patterns/@aws-solutions-constructs/core/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/core", - "version": "1.47.0", + "version": "1.48.0", "description": "Core CDK Construct for patterns library", "main": "index.js", "types": "index.ts", @@ -52,27 +52,27 @@ } }, "dependencies": { - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/aws-iot": "~1.47.0", - "@aws-cdk/aws-kinesis": "~1.47.0", - "@aws-cdk/aws-kinesisanalytics": "~1.47.0", - "@aws-cdk/aws-kinesisfirehose": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/aws-sns": "~1.47.0", - "@aws-cdk/aws-sqs": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/aws-events": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-elasticsearch": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-cdk/aws-stepfunctions": "~1.47.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/aws-iot": "~1.48.0", + "@aws-cdk/aws-kinesis": "~1.48.0", + "@aws-cdk/aws-kinesisanalytics": "~1.48.0", + "@aws-cdk/aws-kinesisfirehose": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/aws-sns": "~1.48.0", + "@aws-cdk/aws-sqs": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/aws-events": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-elasticsearch": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-cdk/aws-stepfunctions": "~1.48.0", "@types/deep-diff": "^1.0.0", "@types/npmlog": "^4.1.2", "deep-diff": "^1.0.2", @@ -80,7 +80,7 @@ "npmlog": "^4.1.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -97,26 +97,26 @@ "@types/deep-diff" ], "peerDependencies": { - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-cdk/aws-iot": "~1.47.0", - "@aws-cdk/aws-kinesis": "~1.47.0", - "@aws-cdk/aws-kinesisanalytics": "~1.47.0", - "@aws-cdk/aws-kinesisfirehose": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-lambda-event-sources": "~1.47.0", - "@aws-cdk/aws-logs": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/aws-sns": "~1.47.0", - "@aws-cdk/aws-sqs": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-kms": "~1.47.0", - "@aws-cdk/aws-events": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-elasticsearch": "~1.47.0", - "@aws-cdk/aws-cloudwatch": "~1.47.0", - "@aws-cdk/aws-stepfunctions": "~1.47.0" + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-cdk/aws-iot": "~1.48.0", + "@aws-cdk/aws-kinesis": "~1.48.0", + "@aws-cdk/aws-kinesisanalytics": "~1.48.0", + "@aws-cdk/aws-kinesisfirehose": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-lambda-event-sources": "~1.48.0", + "@aws-cdk/aws-logs": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/aws-sns": "~1.48.0", + "@aws-cdk/aws-sqs": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-kms": "~1.48.0", + "@aws-cdk/aws-events": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-elasticsearch": "~1.48.0", + "@aws-cdk/aws-cloudwatch": "~1.48.0", + "@aws-cdk/aws-stepfunctions": "~1.48.0" } } diff --git a/source/tools/cdk-integ-tools/package.json b/source/tools/cdk-integ-tools/package.json index eed7f5c4f..160f04ff4 100644 --- a/source/tools/cdk-integ-tools/package.json +++ b/source/tools/cdk-integ-tools/package.json @@ -31,9 +31,9 @@ "typescript": "~3.7.4" }, "dependencies": { - "@aws-cdk/cloudformation-diff": "~1.47.0", - "@aws-cdk/cx-api": "~1.47.0", - "aws-cdk": "~1.47.0", + "@aws-cdk/cloudformation-diff": "~1.48.0", + "@aws-cdk/cx-api": "~1.48.0", + "aws-cdk": "~1.48.0", "fs-extra": "^8.1.0", "yargs": "^15.1.0" }, diff --git a/source/use_cases/aws-s3-static-website/package.json b/source/use_cases/aws-s3-static-website/package.json index 9f92a6bd9..5a77cb415 100644 --- a/source/use_cases/aws-s3-static-website/package.json +++ b/source/use_cases/aws-s3-static-website/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-s3-static-website", - "version": "1.47.0", + "version": "1.48.0", "description": "Use case pattern for deploying a S3 static website.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -28,19 +28,19 @@ "build+lint+test": "npm run build && npm run lint && npm test && npm run integ-assert" }, "dependencies": { - "@aws-solutions-constructs/aws-cloudfront-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/custom-resources": "~1.47.0", - "@aws-cdk/aws-cloudformation": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-solutions-constructs/aws-cloudfront-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/custom-resources": "~1.48.0", + "@aws-cdk/aws-cloudformation": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "source-map-support": "^0.5.16" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, diff --git a/source/use_cases/aws-serverless-image-handler/package.json b/source/use_cases/aws-serverless-image-handler/package.json index 37c4469c4..1b038ffb0 100644 --- a/source/use_cases/aws-serverless-image-handler/package.json +++ b/source/use_cases/aws-serverless-image-handler/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-serverless-image-handler", - "version": "1.47.0", + "version": "1.48.0", "description": "Use case pattern for deploying a serverless image handler API.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -53,18 +53,18 @@ } }, "dependencies": { - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda": "~1.47.0", - "@aws-solutions-constructs/aws-lambda-s3": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0" + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda": "~1.48.0", + "@aws-solutions-constructs/aws-lambda-s3": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -74,14 +74,14 @@ ] }, "peerDependencies": { - "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda": "~1.47.0", - "@aws-solutions-constructs/aws-lambda-s3": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0" + "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda": "~1.48.0", + "@aws-solutions-constructs/aws-lambda-s3": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0" } } diff --git a/source/use_cases/aws-serverless-web-app/package.json b/source/use_cases/aws-serverless-web-app/package.json index 694a2ab6c..28c00b8ad 100644 --- a/source/use_cases/aws-serverless-web-app/package.json +++ b/source/use_cases/aws-serverless-web-app/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-serverless-web-app", - "version": "1.47.0", + "version": "1.48.0", "description": "Use case pattern for deploying a serverless web app.", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -28,24 +28,24 @@ "build+lint+test": "npm run build && npm run lint && npm test && npm run integ-assert" }, "dependencies": { - "@aws-solutions-constructs/aws-cloudfront-s3": "~1.47.0", - "@aws-solutions-constructs/aws-cognito-apigateway-lambda": "~1.47.0", - "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.47.0", - "@aws-cdk/core": "~1.47.0", - "@aws-cdk/aws-lambda": "~1.47.0", - "@aws-cdk/aws-cloudfront": "~1.47.0", - "@aws-cdk/aws-s3": "~1.47.0", - "@aws-cdk/custom-resources": "~1.47.0", - "@aws-cdk/aws-cloudformation": "~1.47.0", - "@aws-cdk/aws-iam": "~1.47.0", - "@aws-cdk/aws-cognito": "~1.47.0", - "@aws-cdk/aws-apigateway": "~1.47.0", - "@aws-cdk/aws-dynamodb": "~1.47.0", - "@aws-solutions-constructs/core": "~1.47.0", + "@aws-solutions-constructs/aws-cloudfront-s3": "~1.48.0", + "@aws-solutions-constructs/aws-cognito-apigateway-lambda": "~1.48.0", + "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.48.0", + "@aws-cdk/core": "~1.48.0", + "@aws-cdk/aws-lambda": "~1.48.0", + "@aws-cdk/aws-cloudfront": "~1.48.0", + "@aws-cdk/aws-s3": "~1.48.0", + "@aws-cdk/custom-resources": "~1.48.0", + "@aws-cdk/aws-cloudformation": "~1.48.0", + "@aws-cdk/aws-iam": "~1.48.0", + "@aws-cdk/aws-cognito": "~1.48.0", + "@aws-cdk/aws-apigateway": "~1.48.0", + "@aws-cdk/aws-dynamodb": "~1.48.0", + "@aws-solutions-constructs/core": "~1.48.0", "source-map-support": "^0.5.16" }, "devDependencies": { - "@aws-cdk/assert": "~1.47.0", + "@aws-cdk/assert": "~1.48.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" },