From fa0e2fa846d68a17d613533260e7f6eb1a4e491b Mon Sep 17 00:00:00 2001 From: Hitendra Nishar Date: Mon, 20 Jul 2020 16:31:03 -0400 Subject: [PATCH] Update to version v1.52.0 --- CHANGELOG.md | 8 + 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/package.json | 20 +- .../aws-lambda-sns/package.json | 24 +- .../aws-lambda-sqs/.eslintignore | 5 + .../aws-lambda-sqs/.gitignore | 15 + .../aws-lambda-sqs/.npmignore | 21 + .../aws-lambda-sqs/README.md | 92 ++ .../aws-lambda-sqs/architecture.png | Bin 0 -> 129307 bytes .../aws-lambda-sqs/lib/index.ts | 128 +++ .../aws-lambda-sqs/package.json | 78 ++ .../__snapshots__/lambda-sqs.test.js.snap | 994 ++++++++++++++++++ .../test/integ.deployFunction.expected.json | 194 ++++ .../test/integ.deployFunction.ts | 36 + .../test/integ.existingFunction.expected.json | 194 ++++ .../test/integ.existingFunction.ts | 41 + .../aws-lambda-sqs/test/lambda-sqs.test.ts | 149 +++ .../aws-lambda-sqs/test/lambda/index.js | 31 + .../aws-lambda-step-function/package.json | 24 +- .../aws-s3-lambda/package.json | 32 +- .../test/__snapshots__/s3-lambda.test.js.snap | 2 +- .../integ.existing-s3-bucket.expected.json | 2 +- .../test/integ.no-arguments.expected.json | 2 +- .../aws-s3-step-function/package.json | 48 +- .../aws-sns-lambda/package.json | 32 +- .../aws-sqs-lambda/README.md | 1 + .../aws-sqs-lambda/lib/index.ts | 9 +- .../aws-sqs-lambda/package.json | 28 +- .../test.sqs-lambda.test.js.snap | 194 ++++ .../test/test.sqs-lambda.test.ts | 24 + .../core/lib/sqs-helper.ts | 62 +- .../core/package.json | 88 +- .../__snapshots__/sqs-helper.test.js.snap | 102 ++ .../core/test/sqs-helper.test.ts | 49 +- 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 +- 58 files changed, 2877 insertions(+), 496 deletions(-) create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.eslintignore create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.gitignore create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.npmignore create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/architecture.png create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/package.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/__snapshots__/lambda-sqs.test.js.snap create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.expected.json create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.ts create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.expected.json create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.ts create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda-sqs.test.ts create mode 100755 source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda/index.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b7a56d16..52cc1850e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ 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.52.0] - 2020-07-20 + +### Added +- aws-lambda-sqs pattern added + +### Changed +- Upgraded all patterns to CDK v1.52.0 + ## [1.51.0] - 2020-07-13 ### Changed diff --git a/source/lerna.json b/source/lerna.json index 08af7fac8..7f680378a 100644 --- a/source/lerna.json +++ b/source/lerna.json @@ -6,5 +6,5 @@ "./patterns/@aws-solutions-constructs/*" ], "rejectCycles": "true", - "version": "1.51.0" + "version": "1.52.0" } diff --git a/source/package.json b/source/package.json index e5c82e63f..924a51fb6 100644 --- a/source/package.json +++ b/source/package.json @@ -1,6 +1,6 @@ { "name": "aws-solutions-constructs", - "version": "1.51.0", + "version": "1.52.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 dc390a78f..eb8223b8b 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 af53ad141..998112fa3 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 518ef324c..b5e0a56f2 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-sqs": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-sqs": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-sqs": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-sqs": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 a1d29c696..08a29f09d 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-solutions-constructs/aws-cloudfront-apigateway": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-solutions-constructs/aws-cloudfront-apigateway": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-solutions-constructs/aws-cloudfront-apigateway": "~1.51.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-solutions-constructs/aws-cloudfront-apigateway": "~1.52.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 1d3681e93..64ec55ab6 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.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 ee94e6bff..1fdc4c2d5 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +70,10 @@ ] }, "peerDependencies": { - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 76e93ccda..cfca80e7c 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 0e71c7509..c42593ec1 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-elasticsearch": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-dynamodb-stream-lambda": "~1.51.0", - "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-elasticsearch": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-dynamodb-stream-lambda": "~1.52.0", + "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -76,16 +76,16 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-elasticsearch": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-dynamodb-stream-lambda": "~1.51.0", - "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-elasticsearch": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-dynamodb-stream-lambda": "~1.52.0", + "@aws-solutions-constructs/aws-lambda-elasticsearch-kibana": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.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 2ab174c99..edeeb7825 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.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 b3db29d75..b86e3347f 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-events": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-events": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-events": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-events": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 ba8b40815..85fb3ee46 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-stepfunctions-tasks": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-events": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-stepfunctions": "~1.52.0", + "@aws-cdk/aws-stepfunctions-tasks": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-events": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -74,14 +74,14 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-stepfunctions": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-events": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-stepfunctions": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-events": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-cdk/aws-stepfunctions-tasks": "~1.51.0" + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-cdk/aws-stepfunctions-tasks": "~1.52.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 f23027464..237129d69 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-kinesisfirehose": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-iot": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.51.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kinesisfirehose": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-iot": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,13 +72,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-kinesisfirehose": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-iot": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.51.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kinesisfirehose": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-iot": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.52.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 6003e78c6..fa8d41588 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-iot": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-iot-lambda": "~1.51.0", - "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.51.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-iot": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-iot-lambda": "~1.52.0", + "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-iot": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-iot-lambda": "~1.51.0", - "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.51.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-iot": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-iot-lambda": "~1.52.0", + "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.52.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 4b57ec662..c02e1f63b 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-iot": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,11 +71,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iot": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", + "@aws-cdk/aws-iot": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.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 c9796c8bf..e229bc0c9 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-kinesis": "~1.51.0", - "@aws-cdk/aws-kinesisanalytics": "~1.51.0", - "@aws-cdk/aws-kinesisfirehose": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.51.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kinesis": "~1.52.0", + "@aws-cdk/aws-kinesisanalytics": "~1.52.0", + "@aws-cdk/aws-kinesisfirehose": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,14 +73,14 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-kinesis": "~1.51.0", - "@aws-cdk/aws-kinesisanalytics": "~1.51.0", - "@aws-cdk/aws-kinesisfirehose": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.51.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kinesis": "~1.52.0", + "@aws-cdk/aws-kinesisanalytics": "~1.52.0", + "@aws-cdk/aws-kinesisfirehose": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-kinesisfirehose-s3": "~1.52.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 215e30cf8..1a77c125c 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-kinesisfirehose": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kinesisfirehose": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -71,12 +71,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-kinesisfirehose": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kinesisfirehose": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 c95878c0a..5b7fda2a8 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-kinesis": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kinesis": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-kinesis": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kinesis": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 d8e676ef1..cb1e3d666 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,10 +70,10 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 672f57177..2c7ac4261 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-elasticsearch": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-elasticsearch": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-elasticsearch": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-elasticsearch": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", "constructs": "^3.0.2" } } 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 5d2582c2e..33e4f0380 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -69,10 +69,10 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.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 b27c7e112..e1988c2c2 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-sns": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-sns": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -70,11 +70,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-sns": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-sns": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.eslintignore b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.eslintignore new file mode 100755 index 000000000..0819e2e65 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.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-sqs/.gitignore b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.gitignore new file mode 100755 index 000000000..6773cabd2 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.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-sqs/.npmignore b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.npmignore new file mode 100755 index 000000000..f66791629 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/.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-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md new file mode 100755 index 000000000..53646d03a --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md @@ -0,0 +1,92 @@ +# aws-lambda-sqs 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_sqs`| +|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-lambda-sqs`| +|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.lambdasqs`| + +This AWS Solutions Construct implements an AWS Lambda function connected to an Amazon SQS queue. + +Here is a minimal deployable pattern definition: + +``` javascript +const { LambdaToSqs } = require('@aws-solutions-constructs/aws-lambda-sqs'); + +new LambdaToSqs(stack, 'LambdaToSqsPattern', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + } +}); + +``` + +## Initializer + +``` text +new LambdaToSqs(scope: Construct, id: string, props: LambdaToSqsProps); +``` + +_Parameters_ + +* scope [`Construct`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Construct.html) +* id `string` +* props [`LambdaToSqsProps`](#pattern-construct-props) + +## Pattern Construct Props + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +|existingLambdaObj?|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|An optional, existing Lambda function to be used instead of the default function. If an existing function is provided, the `lambdaFunctionProps` property will be ignored.| +|lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|Optional user-provided properties to override the default properties for the Lambda function. Ignored if an `existingLambdaObj` is provided. | +|existingQueueObj?|[`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.Queue.html)|An optional, existing SQS queue to be used instead of the default queue. If an existing queue is provided, the `queueProps` property will be ignored.| +|queueProps?|[`sqs.QueueProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.QueueProps.html)|Optional user-provided properties to override the default properties for the SQS queue. Ignored if an `existingQueueObj` is provided. | +|enableQueuePurging?|`boolean`|Whether to grant additional permissions to the Lambda function enabling it to purge the SQS queue. Defaults to `false`.| +|deployDeadLetterQueue?|`boolean`|Whether to create a secondary queue to be used as a dead letter queue. Defaults to `true`.| +|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 queue. Only used if the `deployDeadLetterQueue` property is set 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`.| + +## 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.| +|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 | undefined`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.Queue.html)|Returns an instance of the dead letter queue created by the pattern, if one is deployed.| + +## 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. +* Allow the function to send messages only to the queue (purging can be enabled using the `enableQueuePurge` property). + +### Amazon SQS Queue +* Deploy SQS dead-letter queue for the source SQS Queue. +* Enable server-side encryption for source SQS Queue using AWS Managed KMS Key. + +## Architecture +![Architecture Diagram](architecture.png) + +*** +© Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/architecture.png b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..1f81293b54a22ebc09c02b127c3a49f0cd2ce660 GIT binary patch literal 129307 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
a7&Fe5I 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 H-2eXryn3gg literal 0 HcmV?d00001 diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts new file mode 100755 index 000000000..0435e772d --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts @@ -0,0 +1,128 @@ +/** + * 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 defaults from '@aws-solutions-constructs/core'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as sqs from '@aws-cdk/aws-sqs'; +import { Construct } from '@aws-cdk/core'; + +/** + * @summary The properties for the LambdaToSqs class. + */ +export interface LambdaToSqsProps { + /** + * Existing instance of Lambda Function object, if this is set then the lambdaFunctionProps is ignored. + * + * @default - None + */ + readonly existingLambdaObj?: lambda.Function, + /** + * User provided props to override the default props for the Lambda function. + * + * @default - Default properties are used. + */ + readonly lambdaFunctionProps?: lambda.FunctionProps, + /** + * Existing instance of SQS queue object, if this is set then queueProps is ignored. + * + * @default - Default props are used + */ + readonly existingQueueObj?: sqs.Queue, + /** + * Optional user-provided props to override the default props for the SQS queue. + * + * @default - Default props are used + */ + readonly queueProps?: sqs.QueueProps, + /** + * Whether to grant additional permissions to the Lambda function enabling it to purge the SQS queue. + * + * @default - "false", disabled by default. + */ + readonly enableQueuePurging?: boolean, + /** + * 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. + * + * @default - true. + */ + readonly deployDeadLetterQueue?: boolean, + /** + * The number of times a message can be unsuccessfully dequeued before being moved to the dead-letter queue. + * + * @default - required field if deployDeadLetterQueue=true. + */ + readonly maxReceiveCount?: number +} + +/** + * @summary The LambdaToSqs class. + */ +export class LambdaToSqs extends Construct { + public readonly lambdaFunction: lambda.Function; + public readonly sqsQueue: sqs.Queue; + public readonly deadLetterQueue: sqs.DeadLetterQueue | undefined; + + /** + * @summary Constructs a new instance of the LambdaToSqs class. + * @param {cdk.App} scope - represents the scope for all the resources. + * @param {string} id - this is a a scope-unique id. + * @param {LambdaToSqsProps} props - user provided props for the construct. + * @since 1.49.0 + * @access public + */ + constructor(scope: Construct, id: string, props: LambdaToSqsProps) { + super(scope, id); + + // Setup the Lambda function + this.lambdaFunction = defaults.buildLambdaFunction(this, { + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps + }); + + // Setup a dead letter queue, if applicable + if (props.deployDeadLetterQueue || props.deployDeadLetterQueue === undefined) { + const dlq: sqs.Queue = defaults.buildQueue(this, 'deadLetterQueue', { + queueProps: props.deadLetterQueueProps + }); + this.deadLetterQueue = defaults.buildDeadLetterQueue({ + deadLetterQueue: dlq, + maxReceiveCount: props.maxReceiveCount + }); + } + + // Setup the queue + this.sqsQueue = defaults.buildQueue(this, 'queue', { + existingQueueObj: props.existingQueueObj, + queueProps: props.queueProps, + deadLetterQueue: this.deadLetterQueue + }); + + // Configure environment variables + this.lambdaFunction.addEnvironment('SQS_QUEUE_URL', this.sqsQueue.queueUrl); + + // Enable queue purging permissions for the Lambda function, if enabled + if (props.enableQueuePurging) { + this.sqsQueue.grantPurge(this.lambdaFunction); + } + + // Enable message send permissions for the Lambda function by default + this.sqsQueue.grantSendMessages(this.lambdaFunction); + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/package.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/package.json new file mode 100755 index 000000000..87a82552d --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/package.json @@ -0,0 +1,78 @@ +{ + "name": "@aws-solutions-constructs/aws-lambda-sqs", + "version": "1.52.0", + "description": "CDK constructs for defining an interaction between an AWS Lambda function and an Amazon SQS queue.", + "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-sqs" + }, + "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", + "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.lambdasqs", + "maven": { + "groupId": "software.amazon.awsconstructs", + "artifactId": "lambdasqs" + } + }, + "dotnet": { + "namespace": "Amazon.Constructs.AWS.LambdaSqs", + "packageId": "Amazon.Constructs.AWS.LambdaSqs", + "signAssembly": true, + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-solutions-constructs.aws-lambda-sqs", + "module": "aws_solutions_constructs.aws_lambda_sqs" + } + } + }, + "dependencies": { + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-sqs": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "constructs": "^3.0.2" + }, + "devDependencies": { + "@aws-cdk/assert": "~1.52.0", + "@types/jest": "^24.0.23", + "@types/node": "^10.3.0" + }, + "jest": { + "moduleFileExtensions": [ + "js" + ] + }, + "peerDependencies": { + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-sqs": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "constructs": "^3.0.2" + } +} diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/__snapshots__/lambda-sqs.test.js.snap b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/__snapshots__/lambda-sqs.test.js.snap new file mode 100644 index 000000000..56544223c --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/__snapshots__/lambda-sqs.test.js.snap @@ -0,0 +1,994 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Test deployment w/ DLQ and purging enabled 1`] = ` +Object { + "Parameters": Object { + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913ArtifactHash452EF11C": Object { + "Description": "Artifact hash for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72": Object { + "Description": "S3 bucket for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3": Object { + "Description": "S3 key for asset version \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + }, + "Resources": Object { + "lambdatosqsstackLambdaFunctionDAB62CB1": Object { + "DependsOn": Array [ + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + ], + "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": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": Object { + "Ref": "lambdatosqsstackqueueFDDEE3DB", + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF": 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", + }, + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "sqs:PurgeQueue", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackqueueFDDEE3DB", + "Arn", + ], + }, + }, + Object { + "Action": Array [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackqueueFDDEE3DB", + "Arn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "Roles": Array [ + Object { + "Ref": "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "lambdatosqsstackdeadLetterQueueEAF9B078": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + }, + "Type": "AWS::SQS::Queue", + }, + "lambdatosqsstackqueueFDDEE3DB": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + "RedrivePolicy": Object { + "deadLetterTargetArn": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackdeadLetterQueueEAF9B078", + "Arn", + ], + }, + "maxReceiveCount": 15, + }, + }, + "Type": "AWS::SQS::Queue", + }, + }, +} +`; + +exports[`Test deployment w/ DLQ disabled 1`] = ` +Object { + "Parameters": Object { + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913ArtifactHash452EF11C": Object { + "Description": "Artifact hash for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72": Object { + "Description": "S3 bucket for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3": Object { + "Description": "S3 key for asset version \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + }, + "Resources": Object { + "lambdatosqsstackLambdaFunctionDAB62CB1": Object { + "DependsOn": Array [ + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + ], + "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": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": Object { + "Ref": "lambdatosqsstackqueueFDDEE3DB", + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF": 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", + }, + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "sqs:PurgeQueue", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackqueueFDDEE3DB", + "Arn", + ], + }, + }, + Object { + "Action": Array [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackqueueFDDEE3DB", + "Arn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "Roles": Array [ + Object { + "Ref": "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "lambdatosqsstackqueueFDDEE3DB": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + "QueueName": "queue-with-dlq-disabled", + }, + "Type": "AWS::SQS::Queue", + }, + }, +} +`; + +exports[`Test deployment w/ existing queue 1`] = ` +Object { + "Parameters": Object { + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913ArtifactHash452EF11C": Object { + "Description": "Artifact hash for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72": Object { + "Description": "S3 bucket for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3": Object { + "Description": "S3 key for asset version \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + }, + "Resources": Object { + "existingqueueobjF8AF0ED1": Object { + "Properties": Object { + "QueueName": "existing-queue-obj", + }, + "Type": "AWS::SQS::Queue", + }, + "lambdatosqsstackLambdaFunctionDAB62CB1": Object { + "DependsOn": Array [ + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + ], + "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": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": Object { + "Ref": "existingqueueobjF8AF0ED1", + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF": 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", + }, + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "sqs:PurgeQueue", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "existingqueueobjF8AF0ED1", + "Arn", + ], + }, + }, + Object { + "Action": Array [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "existingqueueobjF8AF0ED1", + "Arn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "Roles": Array [ + Object { + "Ref": "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + }, +} +`; + +exports[`Test deployment w/ purging disabled 1`] = ` +Object { + "Parameters": Object { + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913ArtifactHash452EF11C": Object { + "Description": "Artifact hash for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72": Object { + "Description": "S3 bucket for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3": Object { + "Description": "S3 key for asset version \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + }, + "Resources": Object { + "lambdatosqsstackLambdaFunctionDAB62CB1": Object { + "DependsOn": Array [ + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + ], + "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": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": Object { + "Ref": "lambdatosqsstackqueueFDDEE3DB", + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF": 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", + }, + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackqueueFDDEE3DB", + "Arn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "Roles": Array [ + Object { + "Ref": "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "lambdatosqsstackdeadLetterQueueEAF9B078": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + }, + "Type": "AWS::SQS::Queue", + }, + "lambdatosqsstackqueueFDDEE3DB": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + "RedrivePolicy": Object { + "deadLetterTargetArn": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackdeadLetterQueueEAF9B078", + "Arn", + ], + }, + "maxReceiveCount": 15, + }, + }, + "Type": "AWS::SQS::Queue", + }, + }, +} +`; + +exports[`Test minimal deployment with new Lambda function 1`] = ` +Object { + "Parameters": Object { + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913ArtifactHash452EF11C": Object { + "Description": "Artifact hash for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72": Object { + "Description": "S3 bucket for asset \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3": Object { + "Description": "S3 key for asset version \\"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\\"", + "Type": "String", + }, + }, + "Resources": Object { + "lambdatosqsstackLambdaFunctionDAB62CB1": Object { + "DependsOn": Array [ + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + ], + "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": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": Object { + "Ref": "lambdatosqsstackqueueFDDEE3DB", + }, + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF": 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", + }, + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackqueueFDDEE3DB", + "Arn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "Roles": Array [ + Object { + "Ref": "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "lambdatosqsstackdeadLetterQueueEAF9B078": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + }, + "Type": "AWS::SQS::Queue", + }, + "lambdatosqsstackqueueFDDEE3DB": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + "RedrivePolicy": Object { + "deadLetterTargetArn": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackdeadLetterQueueEAF9B078", + "Arn", + ], + }, + "maxReceiveCount": 15, + }, + }, + "Type": "AWS::SQS::Queue", + }, + }, +} +`; diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.expected.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.expected.json new file mode 100755 index 000000000..8794ca0e9 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.expected.json @@ -0,0 +1,194 @@ +{ + "Description": "Integration Test for aws-lambda-sqs", + "Resources": { + "testlambdasqsLambdaFunctionServiceRoleC0430CA8": { + "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" + } + ] + } + }, + "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D", + "Roles": [ + { + "Ref": "testlambdasqsLambdaFunctionServiceRoleC0430CA8" + } + ] + } + }, + "testlambdasqsLambdaFunction28E890A1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testlambdasqsLambdaFunctionServiceRoleC0430CA8", + "Arn" + ] + }, + "Runtime": "nodejs10.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": { + "Ref": "testlambdasqsqueueDD178B7C" + } + } + } + }, + "DependsOn": [ + "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D", + "testlambdasqsLambdaFunctionServiceRoleC0430CA8" + ], + "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." + } + ] + } + } + }, + "testlambdasqsdeadLetterQueueC34BC0BD": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": "alias/aws/sqs" + } + }, + "testlambdasqsqueueDD178B7C": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": "alias/aws/sqs", + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "maxReceiveCount": 15 + } + } + } + }, + "Parameters": { + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72": { + "Type": "String", + "Description": "S3 bucket for asset \"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\"" + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3": { + "Type": "String", + "Description": "S3 key for asset version \"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\"" + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913ArtifactHash452EF11C": { + "Type": "String", + "Description": "Artifact hash for asset \"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\"" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.ts new file mode 100755 index 000000000..3460cd190 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.ts @@ -0,0 +1,36 @@ +/** + * 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 { LambdaToSqs, LambdaToSqsProps } from "../lib"; +import * as lambda from '@aws-cdk/aws-lambda'; + +// Setup +const app = new App(); +const stack = new Stack(app, 'test-lambda-sqs'); +stack.templateOptions.description = 'Integration Test for aws-lambda-sqs'; + +// Definitions +const props: LambdaToSqsProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + } +}; + +new LambdaToSqs(stack, 'test-lambda-sqs', props); + +// Synth +app.synth(); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.expected.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.expected.json new file mode 100755 index 000000000..d39fb6f9e --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.expected.json @@ -0,0 +1,194 @@ +{ + "Description": "Integration Test for aws-lambda-sqs", + "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": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRoleDefaultPolicy126C8897", + "Roles": [ + { + "Ref": "LambdaFunctionServiceRole0C4CDE0B" + } + ] + } + }, + "LambdaFunctionBF21E41F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "LambdaFunctionServiceRole0C4CDE0B", + "Arn" + ] + }, + "Runtime": "nodejs10.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": { + "Ref": "testlambdasqsqueueDD178B7C" + } + } + } + }, + "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." + } + ] + } + } + }, + "testlambdasqsdeadLetterQueueC34BC0BD": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": "alias/aws/sqs" + } + }, + "testlambdasqsqueueDD178B7C": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": "alias/aws/sqs", + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "maxReceiveCount": 15 + } + } + } + }, + "Parameters": { + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3Bucket642A6F72": { + "Type": "String", + "Description": "S3 bucket for asset \"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\"" + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913S3VersionKeyDBE0BAD3": { + "Type": "String", + "Description": "S3 key for asset version \"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\"" + }, + "AssetParameters0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913ArtifactHash452EF11C": { + "Type": "String", + "Description": "Artifact hash for asset \"0a8a28cfd21b2481ab3395199806266e35521d7d2bd264025d6c9b7198460913\"" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.ts new file mode 100755 index 000000000..f253beca9 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.ts @@ -0,0 +1,41 @@ +/** + * 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 { LambdaToSqs, LambdaToSqsProps } from "../lib"; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as defaults from '@aws-solutions-constructs/core'; + +// Setup +const app = new App(); +const stack = new Stack(app, 'test-lambda-sqs'); +stack.templateOptions.description = 'Integration Test for aws-lambda-sqs'; + +// Definitions +const lambdaFunctionProps = { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) +}; + +const func = defaults.deployLambdaFunction(stack, lambdaFunctionProps); + +const props: LambdaToSqsProps = { + existingLambdaObj: func +}; + +new LambdaToSqs(stack, 'test-lambda-sqs', props); + +// Synth +app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda-sqs.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda-sqs.test.ts new file mode 100755 index 000000000..0858f629d --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda-sqs.test.ts @@ -0,0 +1,149 @@ +/** + * 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 sqs from "@aws-cdk/aws-sqs"; +import { LambdaToSqs } from '../lib'; +import { SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; + +// -------------------------------------------------------------- +// Test minimal deployment with new Lambda function +// -------------------------------------------------------------- +test('Test minimal deployment with new Lambda function', () => { + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToSqs(stack, 'lambda-to-sqs-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); +}); + +// -------------------------------------------------------------- +// Test deployment w/ DLQ and purging explicitly enabled +// -------------------------------------------------------------- +test('Test deployment w/ DLQ and purging enabled', () => { + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToSqs(stack, 'lambda-to-sqs-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + enableQueuePurging: true, + deployDeadLetterQueue: true + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); +}); + +// -------------------------------------------------------------- +// Test deployment w/ purging explicitly disabled +// -------------------------------------------------------------- +test('Test deployment w/ purging disabled', () => { + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToSqs(stack, 'lambda-to-sqs-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + enableQueuePurging: false + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); +}); + +// -------------------------------------------------------------- +// Test the getter methods +// -------------------------------------------------------------- +test('Test the properties', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const pattern = new LambdaToSqs(stack, 'lambda-to-sqs-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + }); + // Assertion 1 + const func = pattern.lambdaFunction; + expect(func !== null); + // Assertion 2 + const queue = pattern.sqsQueue; + expect(queue !== null); + // Assertion 3 + const dlq = pattern.deadLetterQueue; + expect(dlq !== null); +}); + +// -------------------------------------------------------------- +// Test deployment w/ DLQ disabled +// -------------------------------------------------------------- +test('Test deployment w/ DLQ disabled', () => { + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToSqs(stack, 'lambda-to-sqs-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + enableQueuePurging: true, + deployDeadLetterQueue: false, + queueProps: { + queueName: 'queue-with-dlq-disabled' + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); +}); + +// -------------------------------------------------------------- +// Test deployment w/ existing queue +// -------------------------------------------------------------- +test('Test deployment w/ existing queue', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const queue = new sqs.Queue(stack, 'existing-queue-obj', { + queueName: 'existing-queue-obj' + }); + new LambdaToSqs(stack, 'lambda-to-sqs-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + enableQueuePurging: true, + deployDeadLetterQueue: false, + existingQueueObj: queue + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); +}); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda/index.js b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda/index.js new file mode 100755 index 000000000..5f6dd811f --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda/index.js @@ -0,0 +1,31 @@ +/** + * 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. + */ + +const aws = require('aws-sdk'); + +console.log('Loading function'); + +exports.handler = () => { + const params = { + MessageBody: 'sample-message-body', + QueueUrl: process.env.SQS_QUEUE_URL + }; + const sqs = new aws.SQS(); + sqs.sendMessage(params, function (err, data) { + if (err) { + throw Error('An error occurred sending the message.'); + } else { + console.log('Message was successfully sent.'); + } + }) +}; \ 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 index 5c93a5003..d8d375487 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/package.json @@ -1,6 +1,6 @@ { "name": "@aws-solutions-constructs/aws-lambda-step-function", - "version": "1.51.0", + "version": "1.52.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", @@ -53,15 +53,15 @@ } }, "dependencies": { - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-stepfunctions": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-stepfunctions": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0", "eslint-plugin-import": "^2.22.0" @@ -72,11 +72,11 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-stepfunctions": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-stepfunctions": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" } } 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 45410dd2c..fd9e7fca3 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-s3-notifications": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/aws-s3-notifications": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-s3-notifications": "~1.51.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-s3-notifications": "~1.52.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/__snapshots__/s3-lambda.test.js.snap b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/__snapshots__/s3-lambda.test.js.snap index 407a3d45f..289ba31eb 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/__snapshots__/s3-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/__snapshots__/s3-lambda.test.js.snap @@ -62,7 +62,7 @@ Object { function log(obj) { console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj); } - // tslint:disable-next-line:max-line-length + // eslint-disable-next-line max-len // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule // to allow sending an error messge as a reason. function submitResponse(responseStatus, reason) { diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.existing-s3-bucket.expected.json b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.existing-s3-bucket.expected.json index a2201787e..29aa21a2c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.existing-s3-bucket.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.existing-s3-bucket.expected.json @@ -321,7 +321,7 @@ "Properties": { "Description": "AWS CloudFormation handler for \"Custom::S3BucketNotifications\" resources (@aws-cdk/aws-s3)", "Code": { - "ZipFile": "exports.handler = (event, context) => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies\n const s3 = new (require('aws-sdk').S3)();\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const https = require('https');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const url = require('url');\n log(JSON.stringify(event, undefined, 2));\n const props = event.ResourceProperties;\n if (event.RequestType === 'Delete') {\n props.NotificationConfiguration = {}; // this is how you clean out notifications\n }\n const req = {\n Bucket: props.BucketName,\n NotificationConfiguration: props.NotificationConfiguration,\n };\n return s3.putBucketNotificationConfiguration(req, (err, data) => {\n log({ err, data });\n if (err) {\n return submitResponse('FAILED', err.message + `\\nMore information in CloudWatch Log Stream: ${context.logStreamName}`);\n }\n else {\n return submitResponse('SUCCESS');\n }\n });\n function log(obj) {\n console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj);\n }\n // tslint:disable-next-line:max-line-length\n // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule\n // to allow sending an error messge as a reason.\n function submitResponse(responseStatus, reason) {\n const responseBody = JSON.stringify({\n Status: responseStatus,\n Reason: reason || 'See the details in CloudWatch Log Stream: ' + context.logStreamName,\n PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,\n StackId: event.StackId,\n RequestId: event.RequestId,\n LogicalResourceId: event.LogicalResourceId,\n NoEcho: false,\n });\n log({ responseBody });\n const parsedUrl = url.parse(event.ResponseURL);\n const options = {\n hostname: parsedUrl.hostname,\n port: 443,\n path: parsedUrl.path,\n method: 'PUT',\n headers: {\n 'content-type': '',\n 'content-length': responseBody.length,\n },\n };\n const request = https.request(options, (r) => {\n log({ statusCode: r.statusCode, statusMessage: r.statusMessage });\n context.done();\n });\n request.on('error', (error) => {\n log({ sendError: error });\n context.done();\n });\n request.write(responseBody);\n request.end();\n }\n};" + "ZipFile": "exports.handler = (event, context) => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies\n const s3 = new (require('aws-sdk').S3)();\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const https = require('https');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const url = require('url');\n log(JSON.stringify(event, undefined, 2));\n const props = event.ResourceProperties;\n if (event.RequestType === 'Delete') {\n props.NotificationConfiguration = {}; // this is how you clean out notifications\n }\n const req = {\n Bucket: props.BucketName,\n NotificationConfiguration: props.NotificationConfiguration,\n };\n return s3.putBucketNotificationConfiguration(req, (err, data) => {\n log({ err, data });\n if (err) {\n return submitResponse('FAILED', err.message + `\\nMore information in CloudWatch Log Stream: ${context.logStreamName}`);\n }\n else {\n return submitResponse('SUCCESS');\n }\n });\n function log(obj) {\n console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj);\n }\n // eslint-disable-next-line max-len\n // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule\n // to allow sending an error messge as a reason.\n function submitResponse(responseStatus, reason) {\n const responseBody = JSON.stringify({\n Status: responseStatus,\n Reason: reason || 'See the details in CloudWatch Log Stream: ' + context.logStreamName,\n PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,\n StackId: event.StackId,\n RequestId: event.RequestId,\n LogicalResourceId: event.LogicalResourceId,\n NoEcho: false,\n });\n log({ responseBody });\n const parsedUrl = url.parse(event.ResponseURL);\n const options = {\n hostname: parsedUrl.hostname,\n port: 443,\n path: parsedUrl.path,\n method: 'PUT',\n headers: {\n 'content-type': '',\n 'content-length': responseBody.length,\n },\n };\n const request = https.request(options, (r) => {\n log({ statusCode: r.statusCode, statusMessage: r.statusMessage });\n context.done();\n });\n request.on('error', (error) => {\n log({ sendError: error });\n context.done();\n });\n request.write(responseBody);\n request.end();\n }\n};" }, "Handler": "index.handler", "Role": { diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.no-arguments.expected.json b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.no-arguments.expected.json index 0a6f102aa..c5d30e6de 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.no-arguments.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.no-arguments.expected.json @@ -321,7 +321,7 @@ "Properties": { "Description": "AWS CloudFormation handler for \"Custom::S3BucketNotifications\" resources (@aws-cdk/aws-s3)", "Code": { - "ZipFile": "exports.handler = (event, context) => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies\n const s3 = new (require('aws-sdk').S3)();\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const https = require('https');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const url = require('url');\n log(JSON.stringify(event, undefined, 2));\n const props = event.ResourceProperties;\n if (event.RequestType === 'Delete') {\n props.NotificationConfiguration = {}; // this is how you clean out notifications\n }\n const req = {\n Bucket: props.BucketName,\n NotificationConfiguration: props.NotificationConfiguration,\n };\n return s3.putBucketNotificationConfiguration(req, (err, data) => {\n log({ err, data });\n if (err) {\n return submitResponse('FAILED', err.message + `\\nMore information in CloudWatch Log Stream: ${context.logStreamName}`);\n }\n else {\n return submitResponse('SUCCESS');\n }\n });\n function log(obj) {\n console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj);\n }\n // tslint:disable-next-line:max-line-length\n // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule\n // to allow sending an error messge as a reason.\n function submitResponse(responseStatus, reason) {\n const responseBody = JSON.stringify({\n Status: responseStatus,\n Reason: reason || 'See the details in CloudWatch Log Stream: ' + context.logStreamName,\n PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,\n StackId: event.StackId,\n RequestId: event.RequestId,\n LogicalResourceId: event.LogicalResourceId,\n NoEcho: false,\n });\n log({ responseBody });\n const parsedUrl = url.parse(event.ResponseURL);\n const options = {\n hostname: parsedUrl.hostname,\n port: 443,\n path: parsedUrl.path,\n method: 'PUT',\n headers: {\n 'content-type': '',\n 'content-length': responseBody.length,\n },\n };\n const request = https.request(options, (r) => {\n log({ statusCode: r.statusCode, statusMessage: r.statusMessage });\n context.done();\n });\n request.on('error', (error) => {\n log({ sendError: error });\n context.done();\n });\n request.write(responseBody);\n request.end();\n }\n};" + "ZipFile": "exports.handler = (event, context) => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies\n const s3 = new (require('aws-sdk').S3)();\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const https = require('https');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const url = require('url');\n log(JSON.stringify(event, undefined, 2));\n const props = event.ResourceProperties;\n if (event.RequestType === 'Delete') {\n props.NotificationConfiguration = {}; // this is how you clean out notifications\n }\n const req = {\n Bucket: props.BucketName,\n NotificationConfiguration: props.NotificationConfiguration,\n };\n return s3.putBucketNotificationConfiguration(req, (err, data) => {\n log({ err, data });\n if (err) {\n return submitResponse('FAILED', err.message + `\\nMore information in CloudWatch Log Stream: ${context.logStreamName}`);\n }\n else {\n return submitResponse('SUCCESS');\n }\n });\n function log(obj) {\n console.error(event.RequestId, event.StackId, event.LogicalResourceId, obj);\n }\n // eslint-disable-next-line max-len\n // adapted from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-cfnresponsemodule\n // to allow sending an error messge as a reason.\n function submitResponse(responseStatus, reason) {\n const responseBody = JSON.stringify({\n Status: responseStatus,\n Reason: reason || 'See the details in CloudWatch Log Stream: ' + context.logStreamName,\n PhysicalResourceId: event.PhysicalResourceId || event.LogicalResourceId,\n StackId: event.StackId,\n RequestId: event.RequestId,\n LogicalResourceId: event.LogicalResourceId,\n NoEcho: false,\n });\n log({ responseBody });\n const parsedUrl = url.parse(event.ResponseURL);\n const options = {\n hostname: parsedUrl.hostname,\n port: 443,\n path: parsedUrl.path,\n method: 'PUT',\n headers: {\n 'content-type': '',\n 'content-length': responseBody.length,\n },\n };\n const request = https.request(options, (r) => {\n log({ statusCode: r.statusCode, statusMessage: r.statusMessage });\n context.done();\n });\n request.on('error', (error) => {\n log({ sendError: error });\n context.done();\n });\n request.write(responseBody);\n request.end();\n }\n};" }, "Handler": "index.handler", "Role": { 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 b26a89dbf..45d88ef5e 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-stepfunctions-tasks": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-cdk/aws-cloudtrail": "~1.51.0", - "@aws-cdk/aws-events": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-events-rule-step-function": "~1.51.0", + "@aws-cdk/aws-stepfunctions": "~1.52.0", + "@aws-cdk/aws-stepfunctions-tasks": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-cdk/aws-cloudtrail": "~1.52.0", + "@aws-cdk/aws-events": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-events-rule-step-function": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -77,17 +77,17 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-stepfunctions": "~1.51.0", - "@aws-cdk/aws-stepfunctions-tasks": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-cdk/aws-cloudtrail": "~1.51.0", - "@aws-cdk/aws-events": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-solutions-constructs/aws-events-rule-step-function": "~1.51.0", + "@aws-cdk/aws-stepfunctions": "~1.52.0", + "@aws-cdk/aws-stepfunctions-tasks": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-cdk/aws-cloudtrail": "~1.52.0", + "@aws-cdk/aws-events": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-solutions-constructs/aws-events-rule-step-function": "~1.52.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 db88c24eb..df18f88a7 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-sns": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -73,13 +73,13 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-sns": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", + "@aws-cdk/aws-sns": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.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 e466e649c..07cee7599 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/README.md @@ -57,6 +57,7 @@ _Parameters_ |:-------------|:----------------|-----------------| |existingLambdaObj?|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Existing instance of Lambda Function object, if this is set then the lambdaFunctionProps is ignored.| |lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|User provided props to override the default props for the Lambda function.| +|existingQueueObj?|[`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.Queue.html)|An optional, existing SQS queue to be used instead of the default queue. If an existing queue is provided, the `queueProps` property will be ignored.| |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.| 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 026b61165..bf62b09be 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 @@ -33,7 +33,13 @@ export interface SqsToLambdaProps { * * @default - Default properties are used. */ - readonly lambdaFunctionProps?: lambda.FunctionProps + readonly lambdaFunctionProps?: lambda.FunctionProps, + /** + * Existing instance of SQS queue object, if this is set then queueProps is ignored. + * + * @default - Default props are used + */ + readonly existingQueueObj?: sqs.Queue, /** * Optional user provided properties * @@ -98,6 +104,7 @@ export class SqsToLambda extends Construct { // Setup the queue this.sqsQueue = defaults.buildQueue(this, 'queue', { + existingQueueObj: props.existingQueueObj, queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue }); 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 fa959155d..d3f44cb1b 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-sqs": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-sqs": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -72,12 +72,12 @@ ] }, "peerDependencies": { - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-sqs": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-sqs": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "constructs": "^3.0.2" } } diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/__snapshots__/test.sqs-lambda.test.js.snap b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/__snapshots__/test.sqs-lambda.test.js.snap index 47e41e820..ab9628e45 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/__snapshots__/test.sqs-lambda.test.js.snap +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/__snapshots__/test.sqs-lambda.test.js.snap @@ -367,3 +367,197 @@ Object { }, } `; + +exports[`Test deployment w/ existing queue 1`] = ` +Object { + "Parameters": Object { + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420ArtifactHashA71E92AD": Object { + "Description": "Artifact hash for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458": Object { + "Description": "S3 bucket for asset \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D": Object { + "Description": "S3 key for asset version \\"8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420\\"", + "Type": "String", + }, + }, + "Resources": Object { + "existingqueueobjF8AF0ED1": Object { + "Properties": Object { + "QueueName": "existing-queue-obj", + }, + "Type": "AWS::SQS::Queue", + }, + "lambdatosqsstackLambdaFunctionDAB62CB1": Object { + "DependsOn": Array [ + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + ], + "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": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3Bucket749AC458", + }, + "S3Key": Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D", + }, + ], + }, + ], + }, + Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::Split": Array [ + "||", + Object { + "Ref": "AssetParameters8efd3dd9643a4d64a128ad582cab718a1e464bcc719bbbcf0e7b0481188a0420S3VersionKeyFF5CC16D", + }, + ], + }, + ], + }, + ], + ], + }, + }, + "Environment": Object { + "Variables": Object { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + }, + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + "Arn", + ], + }, + "Runtime": "nodejs10.x", + }, + "Type": "AWS::Lambda::Function", + }, + "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF": 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", + }, + "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "sqs:ReceiveMessage", + "sqs:ChangeMessageVisibility", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "existingqueueobjF8AF0ED1", + "Arn", + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "lambdatosqsstackLambdaFunctionServiceRoleDefaultPolicy467E145A", + "Roles": Array [ + Object { + "Ref": "lambdatosqsstackLambdaFunctionServiceRole0AD9DDDF", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + "lambdatosqsstackLambdaFunctionSqsEventSourceexistingqueueobj3C4A9AF1": Object { + "Properties": Object { + "EventSourceArn": Object { + "Fn::GetAtt": Array [ + "existingqueueobjF8AF0ED1", + "Arn", + ], + }, + "FunctionName": Object { + "Ref": "lambdatosqsstackLambdaFunctionDAB62CB1", + }, + }, + "Type": "AWS::Lambda::EventSourceMapping", + }, + }, +} +`; 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 c76541ae4..363ec12c2 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 @@ -15,6 +15,7 @@ import { Stack } from "@aws-cdk/core"; import { SqsToLambda, SqsToLambdaProps } from "../lib"; import * as lambda from '@aws-cdk/aws-lambda'; +import * as sqs from '@aws-cdk/aws-sqs'; import { SynthUtils } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; @@ -147,4 +148,27 @@ test('Test error handling for new Lambda function w/o required properties', () = expect(() => { new SqsToLambda(stack, 'test-sqs-lambda', props); }).toThrowError(); +}); + +// -------------------------------------------------------------- +// Test deployment w/ existing queue +// -------------------------------------------------------------- +test('Test deployment w/ existing queue', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const queue = new sqs.Queue(stack, 'existing-queue-obj', { + queueName: 'existing-queue-obj' + }); + new SqsToLambda(stack, 'lambda-to-sqs-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.asset(`${__dirname}/lambda`) + }, + deployDeadLetterQueue: false, + existingQueueObj: queue + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts index bdf5da2bb..eb0228a3d 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts @@ -18,12 +18,18 @@ import * as cdk from '@aws-cdk/core'; import { overrideProps } from './utils'; export interface BuildQueueProps { + /** + * Existing instance of SQS queue object, if this is set then the queueProps is ignored. + * + * @default - None. + */ + readonly existingQueueObj?: sqs.Queue, /** * Optional user provided props to override the default props for the primary queue. * * @default - Default props are used. */ - readonly queueProps?: sqs.QueueProps | any + readonly queueProps?: sqs.QueueProps /** * Optional dead letter queue to pass bad requests to after the max receive count is reached. * @@ -33,23 +39,38 @@ export interface BuildQueueProps { } export function buildQueue(scope: cdk.Construct, id: string, props?: BuildQueueProps): sqs.Queue { - // If props is undefined, define it - props = (props === undefined) ? {} : props; - // Setup the queue - let queueProps; - if (props.queueProps) { - // If property overrides have been provided, incorporate them and deploy - queueProps = overrideProps(defaults.DefaultQueueProps(), props.queueProps); - } else { - // If no property overrides, deploy using the default configuration - queueProps = defaults.DefaultQueueProps(); - } - // Determine whether a DLQ property should be added - if (props.deadLetterQueue) { - queueProps.deadLetterQueue = props.deadLetterQueue; - } - // Return the queue - return new sqs.Queue(scope, id, queueProps); + // If props is undefined, define it + props = (props === undefined) ? {} : props; + // Conditional queue creation + // If an existingQueueObj is not specified + if (!props.existingQueueObj) { + // Deploy the queue + return deployQueue(scope, id, props.queueProps, props.deadLetterQueue); + // If an existingQueueObj is specified, return that object as the queue to be used + } else { + return props.existingQueueObj; + } +} + +export function deployQueue(scope: cdk.Construct, + id: string, + queuePropsParam?: sqs.QueueProps, + deadLetterQueueParam?: sqs.DeadLetterQueue): sqs.Queue { + // Setup the queue + let queueProps; + if (queuePropsParam) { + // If property overrides have been provided, incorporate them and deploy + queueProps = overrideProps(defaults.DefaultQueueProps(), queuePropsParam); + } else { + // If no property overrides, deploy using the default configuration + queueProps = defaults.DefaultQueueProps(); + } + // Determine whether a DLQ property should be added + if (deadLetterQueueParam) { + queueProps.deadLetterQueue = deadLetterQueueParam; + } + // Return the queue + return new sqs.Queue(scope, id, queueProps); } export interface BuildDeadLetterQueueProps { @@ -60,7 +81,7 @@ export interface BuildDeadLetterQueueProps { */ readonly deadLetterQueue: sqs.Queue /** - * The number of times a message can be unsuccessfully dequeued before being moved to the dead-letter queue. + * The number of times a message can be unsuccessfully dequeued before being moved to the dead letter queue. * * @default - Default props are used */ @@ -69,10 +90,11 @@ export interface BuildDeadLetterQueueProps { export function buildDeadLetterQueue(props: BuildDeadLetterQueueProps): sqs.DeadLetterQueue { const mrc = (props.maxReceiveCount) ? props.maxReceiveCount : defaults.defaultMaxReceiveCount; - // Setup the queue interface and return + // Setup the queue interface const dlq: sqs.DeadLetterQueue = { maxReceiveCount: mrc, queue: props.deadLetterQueue }; + // Return the dead letter queue return dlq; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/package.json b/source/patterns/@aws-solutions-constructs/core/package.json index f4f7cd41c..674360ee2 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.51.0", + "version": "1.52.0", "description": "Core CDK Construct for patterns library", "main": "index.js", "types": "index.ts", @@ -52,27 +52,27 @@ } }, "dependencies": { - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/aws-iot": "~1.51.0", - "@aws-cdk/aws-kinesis": "~1.51.0", - "@aws-cdk/aws-kinesisanalytics": "~1.51.0", - "@aws-cdk/aws-kinesisfirehose": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/aws-sns": "~1.51.0", - "@aws-cdk/aws-sqs": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/aws-events": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-elasticsearch": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-cdk/aws-stepfunctions": "~1.51.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/aws-iot": "~1.52.0", + "@aws-cdk/aws-kinesis": "~1.52.0", + "@aws-cdk/aws-kinesisanalytics": "~1.52.0", + "@aws-cdk/aws-kinesisfirehose": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/aws-sns": "~1.52.0", + "@aws-cdk/aws-sqs": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/aws-events": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-elasticsearch": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-cdk/aws-stepfunctions": "~1.52.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.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -97,26 +97,26 @@ "@types/deep-diff" ], "peerDependencies": { - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-cdk/aws-iot": "~1.51.0", - "@aws-cdk/aws-kinesis": "~1.51.0", - "@aws-cdk/aws-kinesisanalytics": "~1.51.0", - "@aws-cdk/aws-kinesisfirehose": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-lambda-event-sources": "~1.51.0", - "@aws-cdk/aws-logs": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/aws-sns": "~1.51.0", - "@aws-cdk/aws-sqs": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-kms": "~1.51.0", - "@aws-cdk/aws-events": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-elasticsearch": "~1.51.0", - "@aws-cdk/aws-cloudwatch": "~1.51.0", - "@aws-cdk/aws-stepfunctions": "~1.51.0" + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-cdk/aws-iot": "~1.52.0", + "@aws-cdk/aws-kinesis": "~1.52.0", + "@aws-cdk/aws-kinesisanalytics": "~1.52.0", + "@aws-cdk/aws-kinesisfirehose": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-lambda-event-sources": "~1.52.0", + "@aws-cdk/aws-logs": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/aws-sns": "~1.52.0", + "@aws-cdk/aws-sqs": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-kms": "~1.52.0", + "@aws-cdk/aws-events": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-elasticsearch": "~1.52.0", + "@aws-cdk/aws-cloudwatch": "~1.52.0", + "@aws-cdk/aws-stepfunctions": "~1.52.0" } } diff --git a/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/sqs-helper.test.js.snap b/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/sqs-helper.test.js.snap index 36e4ae13d..e275a6209 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/sqs-helper.test.js.snap +++ b/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/sqs-helper.test.js.snap @@ -69,6 +69,7 @@ Object { "Arn", ], }, + "QueueName": "not-the-dead-letter-queue-props", "RedrivePolicy": Object { "deadLetterTargetArn": Object { "Fn::GetAtt": Array [ @@ -85,6 +86,92 @@ Object { } `; +exports[`Test dead letter queue deployment/configuration w/o mrc 1`] = ` +Object { + "Resources": Object { + "EncryptionKey1B843E66": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "EnableKeyRotation": true, + "KeyPolicy": Object { + "Statement": Array [ + Object { + "Action": Array [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource", + ], + "Effect": "Allow", + "Principal": Object { + "AWS": Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":iam::", + Object { + "Ref": "AWS::AccountId", + }, + ":root", + ], + ], + }, + }, + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + }, + "Type": "AWS::KMS::Key", + "UpdateReplacePolicy": "Retain", + }, + "deadletterqueueD1EEB012": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + }, + "Type": "AWS::SQS::Queue", + }, + "primaryqueue045A5712": Object { + "Properties": Object { + "KmsMasterKeyId": Object { + "Fn::GetAtt": Array [ + "EncryptionKey1B843E66", + "Arn", + ], + }, + "QueueName": "not-the-dead-letter-queue-props", + "RedrivePolicy": Object { + "deadLetterTargetArn": Object { + "Fn::GetAtt": Array [ + "deadletterqueueD1EEB012", + "Arn", + ], + }, + "maxReceiveCount": 15, + }, + }, + "Type": "AWS::SQS::Queue", + }, + }, +} +`; + exports[`Test deployment w/ custom properties 1`] = ` Object { "Resources": Object { @@ -148,6 +235,21 @@ Object { "Arn", ], }, + "QueueName": "custom-queue-props", + }, + "Type": "AWS::SQS::Queue", + }, + }, +} +`; + +exports[`Test existingQueueObj 1`] = ` +Object { + "Resources": Object { + "existingqueue03D57A53": Object { + "Properties": Object { + "KmsMasterKeyId": "alias/aws/sqs", + "QueueName": "existing-queue", }, "Type": "AWS::SQS::Queue", }, diff --git a/source/patterns/@aws-solutions-constructs/core/test/sqs-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/sqs-helper.test.ts index f53f596ff..dd343e7e1 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/sqs-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/sqs-helper.test.ts @@ -41,7 +41,7 @@ test('Test deployment w/ custom properties', () => { // Helper declaration defaults.buildQueue(stack, 'primary-queue', { queueProps: { - description: "custom-queue-props", + queueName: "custom-queue-props", encryption: sqs.QueueEncryption.KMS, encryptionMasterKey: encKey } @@ -66,7 +66,7 @@ test('Test dead letter queue deployment/configuration', () => { // Helper declaration defaults.buildQueue(stack, 'primary-queue', { queueProps: { - description: "not-the-dead-letter-queue-props", + queueName: "not-the-dead-letter-queue-props", encryption: sqs.QueueEncryption.KMS, encryptionMasterKey: encKey }, @@ -74,4 +74,49 @@ test('Test dead letter queue deployment/configuration', () => { }); // Assertion 1 expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); +}); + +// -------------------------------------------------------------- +// Test dead letter queue deployment/configuration w/o mrc +// -------------------------------------------------------------- +test('Test dead letter queue deployment/configuration w/o mrc', () => { + // Stack + const stack = new Stack(); + // Helper setup + const encKey = defaults.buildEncryptionKey(stack); + const dlq = defaults.buildQueue(stack, 'dead-letter-queue'); + const dlqi = defaults.buildDeadLetterQueue({ + deadLetterQueue: dlq + }); + // Helper declaration + defaults.buildQueue(stack, 'primary-queue', { + queueProps: { + queueName: "not-the-dead-letter-queue-props", + encryption: sqs.QueueEncryption.KMS, + encryptionMasterKey: encKey + }, + deadLetterQueue: dlqi + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); +}); + +// -------------------------------------------------------------- +// Test existingQueueObj +// -------------------------------------------------------------- +test('Test existingQueueObj', () => { + // Stack + const stack = new Stack(); + // Helper setup + const existingQueue = defaults.buildQueue(stack, 'existing-queue', { + queueProps: { + queueName: 'existing-queue' + } + }); + // Helper declaration + defaults.buildQueue(stack, 'primary-queue', { + existingQueueObj: existingQueue + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); \ No newline at end of file diff --git a/source/tools/cdk-integ-tools/package.json b/source/tools/cdk-integ-tools/package.json index 2f5bc0b3d..8dd6dba8d 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.51.0", - "@aws-cdk/cx-api": "~1.51.0", - "aws-cdk": "~1.51.0", + "@aws-cdk/cloudformation-diff": "~1.52.0", + "@aws-cdk/cx-api": "~1.52.0", + "aws-cdk": "~1.52.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 74a41da42..ba9f47b52 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/custom-resources": "~1.51.0", - "@aws-cdk/aws-cloudformation": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-solutions-constructs/aws-cloudfront-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/custom-resources": "~1.52.0", + "@aws-cdk/aws-cloudformation": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "source-map-support": "^0.5.16" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.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 7051f792b..7ac369001 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.51.0", + "version": "1.52.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.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda": "~1.51.0", - "@aws-solutions-constructs/aws-lambda-s3": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0" + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda": "~1.52.0", + "@aws-solutions-constructs/aws-lambda-s3": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" }, @@ -74,14 +74,14 @@ ] }, "peerDependencies": { - "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda": "~1.51.0", - "@aws-solutions-constructs/aws-lambda-s3": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0" + "@aws-solutions-constructs/aws-cloudfront-apigateway-lambda": "~1.52.0", + "@aws-solutions-constructs/aws-lambda-s3": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0" } } diff --git a/source/use_cases/aws-serverless-web-app/package.json b/source/use_cases/aws-serverless-web-app/package.json index 03a8b3e3d..d359d966d 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.51.0", + "version": "1.52.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.51.0", - "@aws-solutions-constructs/aws-cognito-apigateway-lambda": "~1.51.0", - "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.51.0", - "@aws-cdk/core": "~1.51.0", - "@aws-cdk/aws-lambda": "~1.51.0", - "@aws-cdk/aws-cloudfront": "~1.51.0", - "@aws-cdk/aws-s3": "~1.51.0", - "@aws-cdk/custom-resources": "~1.51.0", - "@aws-cdk/aws-cloudformation": "~1.51.0", - "@aws-cdk/aws-iam": "~1.51.0", - "@aws-cdk/aws-cognito": "~1.51.0", - "@aws-cdk/aws-apigateway": "~1.51.0", - "@aws-cdk/aws-dynamodb": "~1.51.0", - "@aws-solutions-constructs/core": "~1.51.0", + "@aws-solutions-constructs/aws-cloudfront-s3": "~1.52.0", + "@aws-solutions-constructs/aws-cognito-apigateway-lambda": "~1.52.0", + "@aws-solutions-constructs/aws-lambda-dynamodb": "~1.52.0", + "@aws-cdk/core": "~1.52.0", + "@aws-cdk/aws-lambda": "~1.52.0", + "@aws-cdk/aws-cloudfront": "~1.52.0", + "@aws-cdk/aws-s3": "~1.52.0", + "@aws-cdk/custom-resources": "~1.52.0", + "@aws-cdk/aws-cloudformation": "~1.52.0", + "@aws-cdk/aws-iam": "~1.52.0", + "@aws-cdk/aws-cognito": "~1.52.0", + "@aws-cdk/aws-apigateway": "~1.52.0", + "@aws-cdk/aws-dynamodb": "~1.52.0", + "@aws-solutions-constructs/core": "~1.52.0", "source-map-support": "^0.5.16" }, "devDependencies": { - "@aws-cdk/assert": "~1.51.0", + "@aws-cdk/assert": "~1.52.0", "@types/jest": "^24.0.23", "@types/node": "^10.3.0" },