From d920b191b9ac86e5b56d519714e3d9d7720daea2 Mon Sep 17 00:00:00 2001 From: AWS Solutions Constructs Team <67720492+aws-solutions-constructs-team@users.noreply.github.com> Date: Fri, 13 May 2022 16:25:10 -0400 Subject: [PATCH 1/2] chore(release): 1.155.0 (#699) * chore(release): 2.7.0 * chore(changelog): Updated CHANGELOG.v2.md * feat(aws-fargate-stepfunctions): new construct (#677) * created README.md * removed arn env var prop and fixed state machine doc comments * made createCloudWatchAlarms prop optional * created new construct * fixed README typo * refactored test to single concept design * updated default for vpcProps * Update copyright year to 2022 (#693) Skipping review, only copyright messages have been changed. * fix(Test Coverage): Improve test coverage of 2 core files (#691) * Added additional tests * More coverage based on review * chore(Improve documentation): Environment Variable descriptions (#692) * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update Environment Variable documenation/comments * Results of self-review * Response to review * Review 2 * Review 3 * Update DESIGN_GUIDELINES.md * Pin @types/prettier 2.6.0 til 2.6.1 issue resolved (#698) No one is available to review and this is time sensitive. The nature of the change makes any review rather perfunctory as it a single line added to the package.json file * chore(release): 1.155.0 * chore(changelog): Updated CHANGELOG.md * chore(changelog): Updated CHANGELOG.md * Refresh to accomodate CDK changes * Align CDK V2 version * Align CDK Versions * Align CDK Versions Co-authored-by: biffgaut <78155736+biffgaut@users.noreply.github.com> Co-authored-by: mickychetta <45010053+mickychetta@users.noreply.github.com> --- CHANGELOG.md | 13 + CHANGELOG.v2.md | 5 + DESIGN_GUIDELINES.md | 8 +- NOTICE.txt | 2 +- README.md | 2 +- deployment/v2/align-version.js | 2 +- source/lerna.json | 2 +- source/lerna.v2.json | 2 +- source/package.json | 3 +- .../aws-alb-lambda/README.md | 2 +- ....privateApiExistingResources.expected.json | 16 +- ...integ.privateApiNewResources.expected.json | 10 +- ...g.publicApiExistingResources.expected.json | 16 +- .../integ.publicApiNewResources.expected.json | 16 +- .../test/integ.twoTargets.expected.json | 20 +- .../aws-apigateway-dynamodb/README.md | 2 +- .../aws-apigateway-iot/README.md | 2 +- .../aws-apigateway-kinesisstreams/README.md | 2 +- .../aws-apigateway-lambda/README.md | 2 +- .../README.md | 2 +- .../aws-apigateway-sqs/README.md | 2 +- .../README.md | 2 +- .../aws-cloudfront-apigateway/README.md | 2 +- .../aws-cloudfront-mediastore/README.md | 2 +- .../aws-cloudfront-s3/README.md | 2 +- .../aws-cognito-apigateway-lambda/README.md | 2 +- .../README.md | 2 +- .../aws-dynamodb-stream-lambda/README.md | 2 +- .../README.md | 2 +- .../aws-dynamodbstreams-lambda/README.md | 2 +- .../README.md | 2 +- .../aws-eventbridge-kinesisstreams/README.md | 2 +- .../aws-eventbridge-lambda/README.md | 2 +- .../aws-eventbridge-sns/README.md | 2 +- .../aws-eventbridge-sqs/README.md | 2 +- .../aws-eventbridge-stepfunctions/README.md | 2 +- .../README.md | 2 +- .../aws-events-rule-kinesisstreams/README.md | 2 +- .../aws-events-rule-lambda/README.md | 2 +- .../aws-events-rule-sns/README.md | 2 +- .../aws-events-rule-sqs/README.md | 2 +- .../aws-events-rule-step-function/README.md | 2 +- .../aws-fargate-dynamodb/README.md | 4 +- .../aws-fargate-dynamodb/lib/index.ts | 8 +- .../aws-fargate-s3/README.md | 4 +- .../aws-fargate-s3/lib/index.ts | 8 +- .../aws-fargate-secretsmanager/README.md | 2 +- .../aws-fargate-secretsmanager/lib/index.ts | 2 +- .../aws-fargate-sns/README.md | 4 +- .../aws-fargate-sns/lib/index.ts | 8 +- .../aws-fargate-sqs/README.md | 3 +- .../aws-fargate-sqs/lib/index.ts | 8 +- .../aws-fargate-ssmstringparameter/README.md | 2 +- .../lib/index.ts | 4 +- .../aws-fargate-stepfunctions/.eslintignore | 4 + .../aws-fargate-stepfunctions/.gitignore | 15 + .../aws-fargate-stepfunctions/.npmignore | 21 + .../aws-fargate-stepfunctions/README.md | 141 ++ .../architecture.png | Bin 0 -> 187339 bytes .../aws-fargate-stepfunctions/lib/index.ts | 187 +++ .../aws-fargate-stepfunctions/package.json | 110 ++ .../test/fargate-stepfunctions.test.ts | 313 ++++ .../test/integ.new-resources.expected.json | 1355 +++++++++++++++++ .../test/integ.new-resources.ts | 59 + .../integ.no-cloudwatch-alarms.expected.json | 1292 ++++++++++++++++ .../test/integ.no-cloudwatch-alarms.ts | 59 + .../aws-iot-kinesisfirehose-s3/README.md | 2 +- .../aws-iot-kinesisstreams/README.md | 2 +- .../aws-iot-lambda-dynamodb/README.md | 2 +- .../aws-iot-lambda/README.md | 2 +- .../aws-iot-s3/README.md | 2 +- .../aws-iot-sqs/README.md | 2 +- .../README.md | 2 +- .../aws-kinesisfirehose-s3/README.md | 2 +- .../aws-kinesisstreams-gluejob/README.md | 2 +- .../aws-kinesisstreams-gluejob/lib/index.ts | 2 +- .../README.md | 2 +- .../aws-kinesisstreams-lambda/README.md | 2 +- .../aws-lambda-dynamodb/README.md | 4 +- .../aws-lambda-dynamodb/lib/index.ts | 4 +- .../aws-lambda-elasticachememcached/README.md | 4 +- .../lib/index.ts | 2 +- .../package.json | 2 +- .../aws-lambda-elasticsearch-kibana/README.md | 4 +- .../lib/index.ts | 4 +- .../aws-lambda-eventbridge/README.md | 4 +- .../aws-lambda-eventbridge/lib/index.ts | 4 +- .../aws-lambda-s3/README.md | 4 +- .../aws-lambda-s3/lib/index.ts | 4 +- .../aws-lambda-sagemakerendpoint/README.md | 32 +- .../aws-lambda-sagemakerendpoint/lib/index.ts | 18 +- .../aws-lambda-secretsmanager/README.md | 4 +- .../aws-lambda-secretsmanager/lib/index.ts | 2 +- .../aws-lambda-sns/README.md | 6 +- .../aws-lambda-sns/lib/index.ts | 8 +- .../aws-lambda-sqs-lambda/README.md | 4 +- .../aws-lambda-sqs-lambda/lib/index.ts | 4 +- .../aws-lambda-sqs/README.md | 4 +- .../aws-lambda-sqs/lib/index.ts | 4 +- .../aws-lambda-ssmstringparameter/README.md | 4 +- .../lib/index.ts | 2 +- .../aws-lambda-step-function/README.md | 4 +- .../aws-lambda-step-function/lib/index.ts | 4 +- .../aws-lambda-stepfunctions/README.md | 4 +- .../aws-lambda-stepfunctions/lib/index.ts | 4 +- .../aws-route53-alb/README.md | 2 +- .../aws-s3-lambda/README.md | 2 +- .../aws-s3-sqs/README.md | 2 +- .../aws-s3-step-function/README.md | 2 +- .../aws-s3-stepfunctions/README.md | 2 +- .../aws-sns-lambda/README.md | 2 +- .../aws-sns-sqs/README.md | 2 +- .../aws-sqs-lambda/README.md | 2 +- .../aws-wafwebacl-alb/README.md | 2 +- .../aws-wafwebacl-apigateway/README.md | 2 +- .../aws-wafwebacl-cloudfront/README.md | 2 +- .../core/test/kinesis-analytics.test.ts | 177 ++- .../core/test/sqs-helper.test.ts | 121 ++ source/tools/cdk-integ-tools/LICENSE | 2 +- source/tools/cdk-integ-tools/NOTICE | 2 +- .../stream-producer/generate_data.py | 2 +- .../aws-restaurant-management-demo/README.md | 2 +- .../SAMPLE_REQUESTS.md | 2 +- .../kitchen-staff/complete-order/index.js | 2 +- .../kitchen-staff/get-open-orders/index.js | 2 +- .../lib/lambda/layer/db-access.js | 2 +- .../lambda/manager/archive-orders/index.js | 2 +- .../lambda/manager/calculate-tips/index.js | 2 +- .../lambda/manager/check-late-orders/index.js | 2 +- .../lambda/manager/close-out-service/index.js | 2 +- .../lib/lambda/manager/create-report/index.js | 2 +- .../lambda/manager/get-all-orders/index.js | 2 +- .../lib/lambda/manager/get-report/index.js | 2 +- .../service-staff/create-order/index.js | 2 +- .../service-staff/process-payment/index.js | 2 +- .../use_cases/aws-s3-static-website/README.md | 2 +- .../aws-serverless-image-handler/README.md | 2 +- .../lib/lambda/image-handler/image-handler.js | 2 +- .../lib/lambda/image-handler/image-request.js | 2 +- .../lib/lambda/image-handler/index.js | 2 +- .../image-handler/test/test-image-handler.js | 2 +- .../image-handler/test/test-image-request.js | 2 +- .../test/test-thumbor-mapping.js | 2 +- .../lambda/image-handler/thumbor-mapping.js | 2 +- .../aws-serverless-web-app/README.md | 2 +- 145 files changed, 4083 insertions(+), 249 deletions(-) create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.eslintignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.gitignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.npmignore create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/README.md create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/architecture.png create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/package.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/fargate-stepfunctions.test.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.ts create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.expected.json create mode 100644 source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a5e35c3c..9ece77b38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.155.0](https://github.com/awslabs/aws-solutions-constructs/compare/v2.7.0...v1.155.0) (2022-05-13) + +* Upgraded all patterns to CDK v1.155.0 + +### Features + +* **aws-fargate-stepfunctions:** new construct ([#677](https://github.com/awslabs/aws-solutions-constructs/issues/677)) ([f4829ba](https://github.com/awslabs/aws-solutions-constructs/commit/f4829ba1af3643a8b42bb74af9dfa8207d383da3)) + +### Bug Fixes + +* **Test Coverage:** Improve test coverage of 2 core files ([#691](https://github.com/awslabs/aws-solutions-constructs/issues/691)) ([0ea1743](https://github.com/awslabs/aws-solutions-constructs/commit/0ea1743ca1de577ab02ecd3ad0ef67fa56e51a90)) +* **@types/prettier** Pin library to version 2.6.0 of @types/prettier + ## [1.154.0](https://github.com/awslabs/aws-solutions-constructs/compare/v2.6.0...v1.154.0) (2022-05-08) * Upgraded all patterns to CDK v1.154.0 diff --git a/CHANGELOG.v2.md b/CHANGELOG.v2.md index 289d58acf..3e5392a87 100644 --- a/CHANGELOG.v2.md +++ b/CHANGELOG.v2.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.7.0](https://github.com/awslabs/aws-solutions-constructs/compare/v2.6.0...v2.7.0) (2022-05-09) + +* Includes all functionality of V1.154.0 +* Built upon underlying CDK version V2.15.0 + ## [2.6.0](https://github.com/awslabs/aws-solutions-constructs/compare/v2.5.0...v2.6.0) (2022-05-07) * Includes all functionality of V1.153.1 diff --git a/DESIGN_GUIDELINES.md b/DESIGN_GUIDELINES.md index 8985fd9b7..a7ebe215c 100644 --- a/DESIGN_GUIDELINES.md +++ b/DESIGN_GUIDELINES.md @@ -184,7 +184,7 @@ Existing Inconsistencies would not be published, that’s for our internal use | Name | Type | Description | Notes | | --- | --- | --- | --- | -| eventsRule | [`events.Rule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-events.Rule.html)|Returns an instance of `events.Rule` created by the construct. | +| eventsRule | [`events.Rule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-events.Rule.html)|Returns an instance of `events.Rule` created by the construct. Only exposed when EventBridge is the soure of events, not exposed when other services (Lambda, Fargate) are triggering events. | | eventBus? | [`events.IEventBus`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-events.IEventBus.html)|Returns the instance of `events.IEventBus` used by the construct| Required only for non-default Event Buses.| ## Fargate @@ -347,14 +347,14 @@ Existing Inconsistencies would not be published, that’s for our internal use | Name | Type | Description | Notes | | --- | --- | --- |--- | | stateMachineProps |[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|Optional user provided props to override the default props for `sfn.StateMachine`| -| createCloudWatchAlarms | `boolean`|Whether to create recommended CloudWatch alarms.| +| createCloudWatchAlarms? | `boolean`|Whether to create recommended CloudWatch alarms.| **Required Construct Properties** | Name | Type | Description | Notes | | --- | --- | --- |--- | | stateMachine| [`sfn.StateMachine`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachine.html)|Returns an instance of `sfn.StateMachine` created by the construct.| -| stateMachineLoggingGroup|[`logs.ILogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.ILogGroup.html)|Returns an instance of the `logs.ILogGroup` created by the construct for StateMachine.| +| stateMachineLogGroup|[`logs.ILogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.ILogGroup.html)|Returns an instance of the `logs.ILogGroup` created by the construct for StateMachine.| | cloudwatchAlarms? | [`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of `cloudwatch.Alarm` created by the construct.| ## VPC @@ -384,4 +384,4 @@ Existing Inconsistencies would not be published, that’s for our internal use | Name | Type | Description | Notes | | --- | --- | --- |--- | -| webacl| [`waf.CfnWebACL`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-wafv2.CfnWebACL.html)|Returns an instance of the `waf.CfnWebACL` created by the construct.| \ No newline at end of file +| webacl| [`waf.CfnWebACL`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-wafv2.CfnWebACL.html)|Returns an instance of the `waf.CfnWebACL` created by the construct.| diff --git a/NOTICE.txt b/NOTICE.txt index 0b6b7d801..ef2dc699f 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ AWS Solutions Constructs -Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright 2022 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/ or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, diff --git a/README.md b/README.md index ebadacf6c..0161c690d 100644 --- a/README.md +++ b/README.md @@ -49,4 +49,4 @@ containing a central DynamoDB table for managing orders, as well as a Lambda lay * Use case pattern: https://github.com/awslabs/aws-solutions-constructs/tree/master/source/use_cases/aws-restaurant-management-demo *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/deployment/v2/align-version.js b/deployment/v2/align-version.js index 76f72e1ab..430b2420b 100755 --- a/deployment/v2/align-version.js +++ b/deployment/v2/align-version.js @@ -10,7 +10,7 @@ const findVersion = process.argv[2]; const replaceVersion = process.argv[3]; // these versions need to be sourced from a config file -const awsCdkLibVersion = '2.20.0'; +const awsCdkLibVersion = '2.23.0'; const constructsVersion = '10.0.0'; const MODULE_EXEMPTIONS = new Set([ '@aws-cdk/cloudformation-diff', diff --git a/source/lerna.json b/source/lerna.json index f5d93886c..403b443c1 100644 --- a/source/lerna.json +++ b/source/lerna.json @@ -6,5 +6,5 @@ "./patterns/@aws-solutions-constructs/*" ], "rejectCycles": "true", - "version": "1.154.0" + "version": "1.155.0" } diff --git a/source/lerna.v2.json b/source/lerna.v2.json index a98a00f23..991e76351 100644 --- a/source/lerna.v2.json +++ b/source/lerna.v2.json @@ -6,5 +6,5 @@ "./patterns/@aws-solutions-constructs/*" ], "rejectCycles": "true", - "version": "2.6.0" + "version": "2.7.0" } diff --git a/source/package.json b/source/package.json index 6d1525fa0..58f731898 100644 --- a/source/package.json +++ b/source/package.json @@ -30,7 +30,8 @@ "aws-cdk-migration": "^1.135.0" }, "devDependencies": { - "lerna": "^3.22.1" + "lerna": "^3.22.1", + "@types/prettier": "2.6.0" }, "workspaces": { "packages": [ diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/README.md index 98b723ca7..165a9f32c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/README.md @@ -177,4 +177,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.privateApiExistingResources.expected.json b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.privateApiExistingResources.expected.json index 2af9f1483..9ee9fe97b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.privateApiExistingResources.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.privateApiExistingResources.expected.json @@ -19,11 +19,11 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.0.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "172.168.0.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -126,11 +126,11 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.32.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "172.168.32.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -233,11 +233,11 @@ "VpcPublicSubnet3SubnetBE12F0B6": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.64.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "172.168.64.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -340,11 +340,11 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.96.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "172.168.96.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -402,11 +402,11 @@ "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.128.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "172.168.128.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -464,11 +464,11 @@ "VpcPrivateSubnet3SubnetF258B56E": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.160.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "172.168.160.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -856,7 +856,7 @@ } } }, - "LambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom842E1595": { + "LambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HYAD69E89D": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -1324,7 +1324,7 @@ "TargetType": "lambda" }, "DependsOn": [ - "LambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom842E1595" + "LambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HYAD69E89D" ] } }, diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.privateApiNewResources.expected.json b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.privateApiNewResources.expected.json index 6d44cdb71..1b5814b41 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.privateApiNewResources.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.privateApiNewResources.expected.json @@ -533,7 +533,7 @@ } } }, - "testoneLambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom776E5E70": { + "testoneLambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY508A8518": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -593,7 +593,7 @@ "TargetType": "lambda" }, "DependsOn": [ - "testoneLambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom776E5E70" + "testoneLambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY508A8518" ] }, "Vpc8378EB38": { @@ -614,11 +614,11 @@ "VpcisolatedSubnet1SubnetE62B1B9B": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.0.0/18", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.0.0/18", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -664,11 +664,11 @@ "VpcisolatedSubnet2Subnet39217055": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.64.0/18", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.64.0/18", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -714,11 +714,11 @@ "VpcisolatedSubnet3Subnet44F2537D": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.128.0/18", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.128.0/18", "MapPublicIpOnLaunch": false, "Tags": [ { diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.publicApiExistingResources.expected.json b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.publicApiExistingResources.expected.json index 86df2546e..de6bd6a3b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.publicApiExistingResources.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.publicApiExistingResources.expected.json @@ -19,11 +19,11 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.0.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "172.168.0.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -126,11 +126,11 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.32.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "172.168.32.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -233,11 +233,11 @@ "VpcPublicSubnet3SubnetBE12F0B6": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.64.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "172.168.64.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -340,11 +340,11 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.96.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "172.168.96.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -402,11 +402,11 @@ "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.128.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "172.168.128.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -464,11 +464,11 @@ "VpcPrivateSubnet3SubnetF258B56E": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "172.168.160.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "172.168.160.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -856,7 +856,7 @@ } } }, - "LambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom842E1595": { + "LambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HYAD69E89D": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -1324,7 +1324,7 @@ "TargetType": "lambda" }, "DependsOn": [ - "LambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom842E1595" + "LambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HYAD69E89D" ] } }, diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.publicApiNewResources.expected.json b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.publicApiNewResources.expected.json index 394f3d1f1..82e882102 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.publicApiNewResources.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.publicApiNewResources.expected.json @@ -536,7 +536,7 @@ } } }, - "testoneLambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom776E5E70": { + "testoneLambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY508A8518": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -596,7 +596,7 @@ "TargetType": "lambda" }, "DependsOn": [ - "testoneLambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom776E5E70" + "testoneLambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY508A8518" ] }, "Vpc8378EB38": { @@ -617,11 +617,11 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.0.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.0.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -724,11 +724,11 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.32.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.32.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -831,11 +831,11 @@ "VpcPublicSubnet3SubnetBE12F0B6": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.64.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.64.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -938,11 +938,11 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.96.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.96.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -1000,11 +1000,11 @@ "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.128.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.128.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -1062,11 +1062,11 @@ "VpcPrivateSubnet3SubnetF258B56E": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.160.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.160.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.twoTargets.expected.json b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.twoTargets.expected.json index 649baec20..f8db680d3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.twoTargets.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-alb-lambda/test/integ.twoTargets.expected.json @@ -536,7 +536,7 @@ } } }, - "testoneLambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom776E5E70": { + "testoneLambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY508A8518": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -623,7 +623,7 @@ "TargetType": "lambda" }, "DependsOn": [ - "testoneLambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom776E5E70" + "testoneLambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY508A8518" ] }, "Vpc8378EB38": { @@ -644,11 +644,11 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.0.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.0.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -751,11 +751,11 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.32.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.32.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -858,11 +858,11 @@ "VpcPublicSubnet3SubnetBE12F0B6": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.64.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.64.0/19", "MapPublicIpOnLaunch": true, "Tags": [ { @@ -965,11 +965,11 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.96.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.96.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -1027,11 +1027,11 @@ "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.128.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.128.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -1089,11 +1089,11 @@ "VpcPrivateSubnet3SubnetF258B56E": { "Type": "AWS::EC2::Subnet", "Properties": { - "CidrBlock": "10.0.160.0/19", "VpcId": { "Ref": "Vpc8378EB38" }, "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.160.0/19", "MapPublicIpOnLaunch": false, "Tags": [ { @@ -1559,7 +1559,7 @@ } } }, - "testtwoLambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom1048E788": { + "testtwoLambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY068D8D47": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -1588,7 +1588,7 @@ "TargetType": "lambda" }, "DependsOn": [ - "testtwoLambdaFunctionInvokeServicePrincipalelasticloadbalancingamazonawscom1048E788" + "testtwoLambdaFunctionInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HY068D8D47" ] } }, diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/README.md b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/README.md index 237ba4334..d3c9480a1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/README.md @@ -107,4 +107,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/README.md b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/README.md index 655f457ab..caa2e7413 100755 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/README.md @@ -159,4 +159,4 @@ curl -XPOST https://.execute-api..amazonaws.com/prod/message/d *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/README.md b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/README.md index ecd0ca06c..f4834c396 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/README.md @@ -106,4 +106,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/README.md index 0ff4e1c86..a52c76104 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/README.md @@ -118,4 +118,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/README.md b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/README.md index 526e30937..7feb5a552 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/README.md @@ -159,4 +159,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/README.md index 5b6ddd7c2..3e46d615d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/README.md @@ -109,4 +109,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/README.md index 08112642c..6fde41040 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/README.md @@ -127,4 +127,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/README.md b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/README.md index c4b0dfb1b..d37e9672d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/README.md @@ -148,4 +148,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/README.md b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/README.md index 70de0638d..436bddb3c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/README.md @@ -98,4 +98,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/README.md index d4c9bbbea..1c0a0bae7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/README.md @@ -98,4 +98,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/README.md index de4d94ef6..2c08e3724 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/README.md @@ -225,4 +225,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/README.md b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/README.md index 574713cc8..dcdd4fdd7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/README.md @@ -156,4 +156,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/README.md index a61f5c89f..041e2c7f8 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/README.md @@ -126,4 +126,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda-elasticsearch-kibana/README.md b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda-elasticsearch-kibana/README.md index 538b96d2c..809866148 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda-elasticsearch-kibana/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda-elasticsearch-kibana/README.md @@ -157,4 +157,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/README.md index daf24e552..028fd7429 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/README.md @@ -125,4 +125,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/README.md index ad6e38788..73b13c300 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisfirehose-s3/README.md @@ -123,4 +123,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/README.md b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/README.md index 625b4e54e..8e4f5ec64 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-kinesisstreams/README.md @@ -110,4 +110,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/README.md index e30afa303..1af1c7fd1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-lambda/README.md @@ -128,4 +128,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/README.md b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/README.md index 94fe8880c..df1f513ce 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/README.md @@ -145,4 +145,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/README.md index 3c6830f4c..4eff6a5da 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/README.md @@ -150,4 +150,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/README.md b/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/README.md index 70d177844..f617f309a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/README.md @@ -128,4 +128,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/README.md index ae83d3809..19660caa4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/README.md @@ -128,4 +128,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/README.md b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/README.md index 7f6309c74..b4a52c7c7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/README.md @@ -111,4 +111,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/README.md index 3c0087832..ed9a3ebf4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/README.md @@ -130,4 +130,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/README.md b/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/README.md index 81e0a0d32..74fa0393f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/README.md @@ -147,4 +147,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/README.md index 6ea791e66..84aaf4862 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/README.md @@ -152,4 +152,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/README.md b/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/README.md index 9436187c9..83127617a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/README.md @@ -132,4 +132,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/README.md b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/README.md index 6744b8c7b..4b14c2d61 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/README.md @@ -85,8 +85,8 @@ new FargateToDynamoDB(this, "test-construct", new FargateToDynamoDBProps.Builder | dynamoTableProps? | [`dynamodb.TableProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.TableProps.html)|Optional user provided props to override the default props for DynamoDB Table.| |existingTableInterface?|[`dynamodb.ITable`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.ITable.html)|Existing instance of DynamoDB table object or interface, providing both this and `dynamoTableProps` will cause an error.| | tablePermissions? |`string`|Optional table permissions to grant to the Fargate service. One of the following may be specified: `All`, `Read`, `ReadWrite`, `Write`.| -|tableArnEnvironmentVariableName?|`string`|Optional Name for the DynamoDB table arn environment variable set for the container.| -|tableEnvironmentVariableName?|`string`|Optional Name for the DynamoDB table name environment variable set for the container.| +|tableArnEnvironmentVariableName?|`string`|Optional Name for the container environment variable set to the ARN for the DynamoDB table. Default: DYNAMODB_TABLE_ARN | +|tableEnvironmentVariableName?|`string`|Optional Name for the container environment variable set to the DynamoDB table name. Default: DYNAMODB_TABLE_NAME | ## Pattern Properties diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts index 016db217f..f5d0be56b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts @@ -120,15 +120,15 @@ export interface FargateToDynamoDBProps { */ readonly tablePermissions?: string /** - * Optional Name for the DynamoDB table arn environment variable set for the container. + * Optional Name for the container environment variable set to the ARN for the DynamoDB table. * - * @default - None + * @default - DYNAMODB_TABLE_ARN */ readonly tableArnEnvironmentVariableName?: string; /** - * Optional Name for the DynamoDB table name environment variable set for the container. + * Optional Name for the container environment variable set to the name of the DynamoDB table. * - * @default - None + * @default - DYNAMODB_TABLE_NAME */ readonly tableEnvironmentVariableName?: string; } diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/README.md index 3d94bc761..2f2b5b313 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/README.md @@ -86,8 +86,8 @@ new FargateToS3(this, "test_construct", new FargateToS3Props.Builder() |loggingBucketProps?|[`s3.BucketProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.BucketProps.html)|Optional user provided props to override the default props for the S3 Logging Bucket.| |logS3AccessLogs?| boolean|Whether to turn on Access Logging for the S3 bucket. Creates an S3 bucket with associated storage costs for the logs. Enabling Access Logging is a best practice. default - true| |bucketPermissions?|`string[]`|Optional bucket permissions to grant to the Fargate service. One or more of the following may be specified: `Delete`, `Read`, and `Write`. Default is ["Read", "Write"] which includes `[s3:GetObject*, s3:GetBucket*, s3:List*, s3:DeleteObject*, s3:PutObject*, s3:Abort*]`.| -|bucketArnEnvironmentVariableName?|string|Optional Name for the S3 bucket arn environment variable set for the container.| -|bucketEnvironmentVariableName?|string|Optional Name for the S3 bucket name environment variable set for the container.| +|bucketArnEnvironmentVariableName?|string|Optional Name for the container environment variable set to the bucket ARN. Default: S3_BUCKET_ARN | +|bucketEnvironmentVariableName?|string|Optional Optional Name for the container environment variable set to the bucket name. Default: S3_BUCKET_NAME | ## Pattern Properties diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts index e27d11b6c..5d46f08a2 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts @@ -128,15 +128,15 @@ export interface FargateToS3Props { */ readonly bucketPermissions?: string[]; /** - * Optional Name for the S3 bucket arn environment variable set for the container. + * Optional Name for the container environment variable set to the bucket ARN. * - * @default - None + * @default - S3_BUCKET_ARN */ readonly bucketArnEnvironmentVariableName?: string; /** - * Optional Name for the S3 bucket name environment variable set for the container. + * Optional Name for the container environment variable set to the bucket name. * - * @default - None + * @default - S3_BUCKET_NAME */ readonly bucketEnvironmentVariableName?: string; /* diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/README.md b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/README.md index 7b0707c86..15b76b37f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/README.md @@ -85,7 +85,7 @@ new FargateToSecretsmanager(this, "test-construct", new FargateToSecretsmanagerP |secretProps?|[`secretsmanager.SecretProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.SecretProps.html)|Optional user provided props to override the default props for Secrets Manager| |existingSecretObj?|[`secretsmanager.Secret`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.Secret.html)|Existing instance of Secrets Manager Secret object, If this is set then the secretProps is ignored| |grantWriteAccess?|`boolean`|Optional write access to the Secret for the Fargate service (Read-Only by default) -|secretEnvironmentVariableName?|`string`|Optional Name for the Secrets Manager secret environment variable set for the Fargate service.| +|secretEnvironmentVariableName?|`string`|Optional Name for the container environment variable set to the ARN of the secret. Default: SECRET_ARN | ## Pattern Properties diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts index 15b828614..a37b6c249 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts @@ -121,7 +121,7 @@ export interface FargateToSecretsmanagerProps { */ readonly grantWriteAccess?: string /** - * Optional Name for container environment variable containing the ARN of the secret. + * Optional Name for the container environment variable set to the ARN of the secret. * * @default - SECRET_ARN */ diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/README.md b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/README.md index cd0b685c1..c08884e5c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/README.md @@ -84,8 +84,8 @@ new FargateToSns(this, "test_construct", new FargateToSnsProps.Builder() | existingContainerDefinitionObject? | [ecs.ContainerDefinition](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ContainerDefinition.html) | A container definition already instantiated as part of a Fargate service. This must be the container in the existingFargateServiceObject | |existingTopicObj?|[sns.Topic](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-sns.Topic.html)|Existing instance of SNS Topic object, providing both this and `topicProps` will cause an error.| |topicProps?|[sns.TopicProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sns.TopicProps.html)|Optional user provided properties to override the default properties for the SNS topic.| -|topicArnEnvironmentVariableName?|string|Optional Name for the SNS topic arn environment variable set for the container.| -|topicNameEnvironmentVariableName?|string|Optional Name for the SNS topic name environment variable set for the container.| +|topicArnEnvironmentVariableName?|string|Optional Name for the container environment variable set to the ARN of the topic. Default: SNS_TOPIC_ARN | +|topicNameEnvironmentVariableName?|string|Optional Name for the container environment variable set to the name of the topic. Default: SNS_TOPIC_NAME | ## Pattern Properties diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts index c507202b4..07521d81f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts @@ -107,15 +107,15 @@ export interface FargateToSnsProps { */ readonly topicProps?: sns.TopicProps; /** - * Optional Name for the SNS topic arn environment variable set for the container. + * Optional Name for the container environment variable set to the ARN of the topic. * - * @default - None + * @default - SNS_TOPIC_ARN */ readonly topicArnEnvironmentVariableName?: string; /** - * Optional Name for the SNS topic name environment variable set for the container. + * Optional Name for the container environment variable set to the name of the topic. * - * @default - None + * @default - SNS_TOPIC_NAME */ readonly topicNameEnvironmentVariableName?: string; /* diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/README.md index e2e56737b..de78588c1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/README.md @@ -87,7 +87,8 @@ new FargateToSqs(this, "test_construct", new FargateToSqsProps.Builder() |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?|integer|The number of times a message can be unsuccessfully dequeued before being moved to the dead letter queue. Defaults to `15`.| -|queueUrlEnvironmentVariableName?|string|Optional Name for the SQS queue name environment variable set for the container.| +|queueUrlEnvironmentVariableName?|string|Optional Name for the container environment variable set to the URL of the queue. Default: SQS_QUEUE_URL | +|queueArnEnvironmentVariableName?|string|Optional Name for the container environment variable set to the arn of the queue. Default: SQS_QUEUE_ARN | |queuePermissions?|`string[]`|Optional queue permissions to grant to the Fargate service. One or more of the following may be specified: `Read`,`Write`. Default is `Write`| diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts index e68739238..6792dcf29 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts @@ -132,15 +132,15 @@ export interface FargateToSqsProps { */ readonly maxReceiveCount?: number; /** - * Optional Name for the SQS queue ARN environment variable to set for the container. + * Optional Name for the container environment variable set to the arn of the queue. * - * @default - None + * @default - SQS_QUEUE_ARN */ readonly queueArnEnvironmentVariableName?: string; /** - * Optional Name for the SQS queue name environment variable to set for the container. + * Optional Name for the container environment variable set to the URL of the queue. * - * @default - None + * @default - SQS_QUEUE_URL */ readonly queueUrlEnvironmentVariableName?: string; /** diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/README.md b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/README.md index 155aba9bb..5b7dd985b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/README.md @@ -93,7 +93,7 @@ new FargateToSsmstringparameter(this, "test-construct", new FargateToSsmstringpa |existingStringParameterObj?|[`ssm.StringParameter`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ssm.StringParameter.html)|Existing instance of SSM String parameter object, providing both this and `stringParameterProps` will cause an error| |stringParameterProps?|[`ssm.StringParameterProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ssm.StringParameterProps.html)|Optional user provided props to override the default props for SSM String parameter. If existingStringParameterObj is not set stringParameterProps is required. The only supported [`ssm.StringParameterProps.type`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ssm.StringParameterProps.html#type) is [`STRING`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ssm.ParameterType.html#string) if a different value is provided it will be overridden.| |stringParameterPermissions?|`string`|Optional SSM String parameter permissions to grant to the Fargate service. One of the following may be specified: "Read", "ReadWrite". -|stringParameterEnvironmentVariableName?|`string`|Optional Name for the SSM parameter name environment variable set for the container.| +|stringParameterEnvironmentVariableName?|`string`|Optional Name for the container environment variable set to the SSM parameter name. Default: SSM_STRING_PARAMETER_NAME | ## Pattern Properties diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts index 2130389d1..8300cea46 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts @@ -120,9 +120,9 @@ export interface FargateToSsmstringparameterProps { */ readonly stringParameterPermissions?: string /** - * Optional Name for the SSM parameter name environment variable set for the container. + * Optional Name for the container environment variable set to the SSM parameter name. * - * @default - None + * @default - SSM_STRING_PARAMETER_NAME */ readonly stringParameterEnvironmentVariableName?: string; } diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.eslintignore b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.eslintignore new file mode 100644 index 000000000..e6f7801ea --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.eslintignore @@ -0,0 +1,4 @@ +lib/*.js +test/*.js +*.d.ts +coverage diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.gitignore b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.gitignore new file mode 100644 index 000000000..6773cabd2 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.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-fargate-stepfunctions/.npmignore b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.npmignore new file mode 100644 index 000000000..f66791629 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/.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-fargate-stepfunctions/README.md b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/README.md new file mode 100644 index 000000000..4e0ac3a04 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/README.md @@ -0,0 +1,141 @@ +# aws-fargate-stepfunctions 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_fargate_stepfunctions`| +|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-fargate-stepfunctions`| +|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.fargatestepfunctions`| + +This AWS Solutions Construct implements an AWS Fargate service that can execute an AWS Step Functions state machine + +Here is a minimal deployable pattern definition: + +Typescript +``` typescript +import { Construct } from 'constructs'; +import { Stack, StackProps } from 'aws-cdk-lib'; +import { FargateToStepfunctions, FargateToStepfunctionsProps } from '@aws-solutions-constructs/aws-fargate-stepfunctions'; +import * as stepfunctions from 'aws-cdk-lib/aws-stepfunctions'; + +const startState = new stepfunctions.Pass(this, 'StartState'); + +const constructProps: FargateToStepfunctionsProps = { + publicApi: true, + ecrRepositoryArn: "arn:aws:ecr:us-east-1:123456789012:repository/your-ecr-repo", + stateMachineProps: { + definition: startState + } +}; + +new FargateToStepfunctions(this, 'test-construct', constructProps); +``` + +Python +``` python +from aws_solutions_constructs.aws_fargate_stepfunctions import FargateToStepfunctions, FargateToStepfunctionsProps +from aws_cdk import ( + aws_stepfunctions as stepfunctions, + Stack +) +from constructs import Construct + +start_state = stepfunctions.Pass(self, 'start_state') + +FargateToStepfunctions(self, 'test_construct', + public_api=True, + ecr_repository_arn="arn:aws:ecr:us-east-1:123456789012:repository/your-ecr-repo", + state_machine_props=stepfunctions.StateMachineProps( + definition=start_state)) +``` + +Java +``` java +import software.constructs.Construct; + +import software.amazon.awscdk.Stack; +import software.amazon.awscdk.StackProps; +import software.amazon.awsconstructs.services.fargatestepfunctions.*; +import software.amazon.awscdk.services.stepfunctions.*; + +start_state = stepfunctions.Pass(self, 'start_state') + +new FargateToStepfunctions(this, "test-construct", new FargateToStepfunctionsProps.Builder() + .publicApi(true) + .ecrRepositoryArn("arn:aws:ecr:us-east-1:123456789012:repository/your-ecr-repo") + .stateMachineProps(new StateMachineProps.Builder() + .definition(startState) + .build() + .build()); +``` + +## Pattern Construct Props + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +| publicApi | `boolean` | Whether the construct is deploying a private or public API. This has implications for the VPC. | +| vpcProps? | [`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html) | Optional custom properties for a VPC the construct will create. This VPC will be used by any Private Hosted Zone the construct creates (that's why loadBalancerProps and privateHostedZoneProps can't include a VPC). Providing both this and existingVpc is an error. | +| existingVpc? | [`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html) | An existing VPC in which to deploy the construct. Providing both this and vpcProps is an error. If the client provides an existing load balancer and/or existing Private Hosted Zone, those constructs must exist in this VPC. | +| clusterProps? | [`ecs.ClusterProps`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ClusterProps.html) | Optional properties to create a new ECS cluster. To provide an existing cluster, use the cluster attribute of fargateServiceProps. | +| ecrRepositoryArn? | `string` | The arn of an ECR Repository containing the image to use to generate the containers. Either this or the image property of containerDefinitionProps must be provided. format: arn:aws:ecr:*region*:*account number*:repository/*Repository Name* | +| ecrImageVersion? | `string` | The version of the image to use from the repository. Defaults to 'Latest' | +| containerDefinitionProps? | [`ecs.ContainerDefinitionProps \| any`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ContainerDefinitionProps.html) | Optional props to define the container created for the Fargate Service (defaults found in fargate-defaults.ts) | +| fargateTaskDefinitionProps? | [`ecs.FargateTaskDefinitionProps \| any`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateTaskDefinitionProps.html) | Optional props to define the Fargate Task Definition for this construct (defaults found in fargate-defaults.ts) | +| fargateServiceProps? | [`ecs.FargateServiceProps \| any`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateServiceProps.html) | Optional values to override default Fargate Task definition properties (fargate-defaults.ts). The construct will default to launching the service is the most isolated subnets available (precedence: Isolated, Private and Public). Override those and other defaults here. | +|existingFargateServiceObject? | [`ecs.FargateService`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateService.html) | A Fargate Service already instantiated (probably by another Solutions Construct). If this is specified, then no props defining a new service can be provided, including: ecrImageVersion, containerDefinitionProps, fargateTaskDefinitionProps, ecrRepositoryArn, fargateServiceProps, clusterProps | +|existingContainerDefinitionObject? | [`ecs.ContainerDefinition`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ContainerDefinition.html) | A container definition already instantiated as part of a Fargate service. This must be the container in the existingFargateServiceObject | +|stateMachineProps|[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|User provided props to override the default props for sfn.StateMachine.| +| createCloudWatchAlarms? | `boolean`|Whether to create recommended CloudWatch alarms. Default is true.| +|logGroupProps?|[`logs.LogGroupProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.LogGroupProps.html)|Optional user provided props to override the default props for for the CloudWatchLogs LogGroup.| +|stateMachineEnvironmentVariableName?|`string`|Optional Name for the container environment variable set to the ARN of the state machine. Default: STATE_MACHINE_ARN | + +## Pattern Properties + +| **Name** | **Type** | **Description** | +|:-------------|:----------------|-----------------| +| vpc | [`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html) | The VPC used by the construct (whether created by the construct or provided by the client) | +| service | [`ecs.FargateService`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateService.html) | The AWS Fargate service used by this construct (whether created by this construct or passed to this construct at initialization) | +| container | [`ecs.ContainerDefinition`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ContainerDefinition.html) | The container associated with the AWS Fargate service in the service property. | +| stateMachine| [`sfn.StateMachine`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachine.html)|Returns an instance of `sfn.StateMachine` created by the construct.| +| stateMachineLogGroup|[`logs.ILogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.ILogGroup.html)|Returns an instance of the `logs.ILogGroup` created by the construct for StateMachine.| +| cloudwatchAlarms? | [`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of `cloudwatch.Alarm` created by the construct.| + +## Default settings + +Out of the box implementation of the Construct without any override will set the following defaults: + +### AWS Fargate Service +* Sets up an AWS Fargate service + * Uses the existing service if provided + * Creates a new service if none provided. + * Service will run in isolated subnets if available, then private subnets if available and finally public subnets +* Adds an environment variable to the container containing the ARN of the state machine + * Default name is `STATE_MACHINE_ARN` +* Add permissions to the container IAM role allowing it to start the execution of a state machine + +### AWS Step Functions +* Sets up an AWS Step Functions state machine + * Uses an existing state machine if one is provided, otherwise creates a new one +* Adds an Interface Endpoint to the VPC for Step Functions (the service by default runs in Isolated or Private subnets) +* Enables CloudWatch logging + +## Architecture +![Architecture Diagram](architecture.png) + +*** +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/architecture.png b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..091cbd81be8f55e527da54048f6bf52ca16892a8 GIT binary patch literal 187339 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
  • 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

    iloZ#ixK6_Z0%N5Z>e3UOvRdal?_^$K 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 z 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 NtFC(sdDH6Y{{e00XAA%U literal 0 HcmV?d00001 diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts new file mode 100644 index 000000000..2f653d715 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts @@ -0,0 +1,187 @@ +/** + * Copyright 2022 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. + */ + +// Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate +import { Construct } from "@aws-cdk/core"; +import * as defaults from "@aws-solutions-constructs/core"; +import * as ecs from "@aws-cdk/aws-ecs"; +import * as ec2 from "@aws-cdk/aws-ec2"; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as logs from '@aws-cdk/aws-logs'; +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; + +export interface FargateToStepfunctionsProps { + /** + * Whether the construct is deploying a private or public API. This has implications for the VPC deployed + * by this construct. + * + * @default - none + */ + readonly publicApi: boolean; + /** + * Optional custom properties for a VPC the construct will create. This VPC will + * be used by the new Fargate service the construct creates (that's + * why targetGroupProps can't include a VPC). Providing + * both this and existingVpc is an error. A Step Functions Interface + * endpoint will be included in this VPC. + * + * @default - A set of defaults from vpc-defaults.ts: DefaultPublicPrivateVpcProps() for public APIs + * and DefaultIsolatedVpcProps() for private APIs. + */ + readonly vpcProps?: ec2.VpcProps; + /** + * An existing VPC in which to deploy the construct. Providing both this and + * vpcProps is an error. If the client provides an existing Fargate service, + * this value must be the VPC where the service is running. A Step Functions Interface + * endpoint will be added to this VPC. + * + * @default - none + */ + readonly existingVpc?: ec2.IVpc; + /** + * Optional properties to create a new ECS cluster + */ + readonly clusterProps?: ecs.ClusterProps; + /** + * The arn of an ECR Repository containing the image to use + * to generate the containers + * + * format: + * arn:aws:ecr:[region]:[account number]:repository/[Repository Name] + */ + readonly ecrRepositoryArn?: string; + /** + * The version of the image to use from the repository + * + * @default - 'latest' + */ + readonly ecrImageVersion?: string; + /* + * Optional props to define the container created for the Fargate Service + * + * defaults - fargate-defaults.ts + */ + readonly containerDefinitionProps?: ecs.ContainerDefinitionProps | any; + /* + * Optional props to define the Fargate Task Definition for this construct + * + * defaults - fargate-defaults.ts + */ + readonly fargateTaskDefinitionProps?: ecs.FargateTaskDefinitionProps | any; + /** + * Optional values to override default Fargate Task definition properties + * (fargate-defaults.ts). The construct will default to launching the service + * is the most isolated subnets available (precedence: Isolated, Private and + * Public). Override those and other defaults here. + * + * defaults - fargate-defaults.ts + */ + readonly fargateServiceProps?: ecs.FargateServiceProps | any; + /** + * A Fargate Service already instantiated (probably by another Solutions Construct). If + * this is specified, then no props defining a new service can be provided, including: + * existingImageObject, ecrImageVersion, containerDefintionProps, fargateTaskDefinitionProps, + * ecrRepositoryArn, fargateServiceProps, clusterProps, existingClusterInterface. If this value + * is provided, then existingContainerDefinitionObject must be provided as well. + * + * @default - none + */ + readonly existingFargateServiceObject?: ecs.FargateService; + /* + * A container definition already instantiated as part of a Fargate service. This must + * be the container in the existingFargateServiceObject. + * + * @default - None + */ + readonly existingContainerDefinitionObject?: ecs.ContainerDefinition; + /** + * User provided StateMachineProps to override the defaults + * + * @default - None + */ + readonly stateMachineProps: sfn.StateMachineProps; + /** + * Whether to create recommended CloudWatch alarms + * + * @default - true + */ + readonly createCloudWatchAlarms?: boolean; + /** + * User provided props to override the default props for the CloudWatchLogs LogGroup. + * + * @default - Default props are used + */ + readonly logGroupProps?: logs.LogGroupProps; + /** + * Optional Name for the container environment variable set to the ARN of the state machine. + * + * @default - STATE_MACHINE_ARN + */ + readonly stateMachineEnvironmentVariableName?: string; +} + +export class FargateToStepfunctions extends Construct { + public readonly vpc: ec2.IVpc; + public readonly service: ecs.FargateService; + public readonly container: ecs.ContainerDefinition; + public readonly stateMachine: sfn.StateMachine; + public readonly stateMachineLogGroup: logs.ILogGroup; + public readonly cloudwatchAlarms?: cloudwatch.Alarm[]; + + constructor(scope: Construct, id: string, props: FargateToStepfunctionsProps) { + super(scope, id); + defaults.CheckProps(props); + defaults.CheckFargateProps(props); + + this.vpc = defaults.buildVpc(scope, { + existingVpc: props.existingVpc, + defaultVpcProps: props.publicApi ? defaults.DefaultPublicPrivateVpcProps() : defaults.DefaultIsolatedVpcProps(), + userVpcProps: props.vpcProps, + constructVpcProps: { enableDnsHostnames: true, enableDnsSupport: true } + }); + + defaults.AddAwsServiceEndpoint(scope, this.vpc, defaults.ServiceEndpointTypes.STEP_FUNCTIONS); + + if (props.existingFargateServiceObject) { + this.service = props.existingFargateServiceObject; + // CheckFargateProps confirms that the container is provided + this.container = props.existingContainerDefinitionObject!; + } else { + [this.service, this.container] = defaults.CreateFargateService( + scope, + id, + this.vpc, + props.clusterProps, + props.ecrRepositoryArn, + props.ecrImageVersion, + props.fargateTaskDefinitionProps, + props.containerDefinitionProps, + props.fargateServiceProps + ); + } + + [this.stateMachine, this.stateMachineLogGroup] = defaults.buildStateMachine(this, props.stateMachineProps, + props.logGroupProps); + + this.stateMachine.grantStartExecution(this.service.taskDefinition.taskRole); + + if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { + // Deploy best-practice CloudWatch Alarm for state machine + this.cloudwatchAlarms = defaults.buildStepFunctionCWAlarms(this, this.stateMachine); + } + + // Add environment variable + const stateMachineEnvironmentVariableName = props.stateMachineEnvironmentVariableName || 'STATE_MACHINE_ARN'; + this.container.addEnvironment(stateMachineEnvironmentVariableName, this.stateMachine.stateMachineArn); + } +} diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/package.json b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/package.json new file mode 100644 index 000000000..afa446f43 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/package.json @@ -0,0 +1,110 @@ +{ + "name": "@aws-solutions-constructs/aws-fargate-stepfunctions", + "version": "0.0.0", + "description": "CDK Constructs for AWS Fargate to Amazon Step Functions integration", + "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-fargate-stepfunctions" + }, + "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-no-clean": "cdk-integ --no-clean", + "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.fargatestepfunctions", + "maven": { + "groupId": "software.amazon.awsconstructs", + "artifactId": "fargatestepfunctions" + } + }, + "dotnet": { + "namespace": "Amazon.SolutionsConstructs.AWS.FargateStepfunctions", + "packageId": "Amazon.SolutionsConstructs.AWS.FargateStepfunctions", + "signAssembly": true, + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-solutions-constructs.aws-fargate-stepfunctions", + "module": "aws_solutions_constructs.aws_fargate_stepfunctions" + } + } + }, + "dependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", + "@aws-solutions-constructs/core": "0.0.0", + "constructs": "^3.2.0" + }, + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", + "@aws-solutions-constructs/core": "0.0.0", + "@types/jest": "^26.0.22", + "@types/node": "^10.3.0", + "constructs": "3.2.0" + }, + "jest": { + "moduleFileExtensions": [ + "js" + ], + "coverageReporters": [ + "text", + [ + "lcov", + { + "projectRoot": "../../../../" + } + ] + ] + }, + "peerDependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", + "@aws-solutions-constructs/core": "0.0.0", + "constructs": "^3.2.0" + }, + "keywords": [ + "aws", + "cdk", + "awscdk", + "AWS Solutions Constructs", + "Amazon Step Functions", + "AWS Fargate" + ] +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/fargate-stepfunctions.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/fargate-stepfunctions.test.ts new file mode 100644 index 000000000..330a4b131 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/fargate-stepfunctions.test.ts @@ -0,0 +1,313 @@ +/** + * Copyright 2022 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. + */ + +import '@aws-cdk/assert/jest'; +import * as defaults from '@aws-solutions-constructs/core'; +import * as cdk from "@aws-cdk/core"; +import { FargateToStepfunctions } from "../lib"; +import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; +import * as ecs from '@aws-cdk/aws-ecs'; + +const clusterName = "custom-cluster-name"; +const containerName = "custom-container-name"; +const serviceName = "custom-service-name"; +const familyName = "family-name"; +const testCidr = "172.0.0.0/16"; + +test('Check for construct properties', () => { + const stack = new cdk.Stack(); + const publicApi = true; + + const construct = createFargateConstructWithNewResources(stack, publicApi); + + expect(construct.vpc).toBeDefined(); + expect(construct.service).toBeDefined(); + expect(construct.container).toBeDefined(); + expect(construct.stateMachine).toBeDefined(); + expect(construct.stateMachineLogGroup).toBeDefined(); + expect(construct.cloudwatchAlarms).toBeDefined(); +}); + +test('Check for new service', () => { + const stack = new cdk.Stack(); + const publicApi = false; + + createFargateConstructWithNewResources(stack, publicApi); + + expect(stack).toHaveResourceLike("AWS::ECS::Service", { + ServiceName: serviceName, + LaunchType: 'FARGATE', + DesiredCount: 2, + DeploymentConfiguration: { + MaximumPercent: 150, + MinimumHealthyPercent: 75 + }, + PlatformVersion: ecs.FargatePlatformVersion.LATEST, + }); +}); + +test('Check for an existing service', () => { + const stack = new cdk.Stack(); + const publicApi = true; + + const existingVpc = defaults.getTestVpc(stack); + + const [testService, testContainer] = defaults.CreateFargateService(stack, + 'test', + existingVpc, + { clusterName }, + defaults.fakeEcrRepoArn, + undefined, + { family: familyName }, + { containerName }, + { serviceName }); + + new FargateToStepfunctions(stack, 'test-construct', { + publicApi, + existingFargateServiceObject: testService, + existingContainerDefinitionObject: testContainer, + existingVpc, + stateMachineProps: testStateMachineProps(stack) + }); + + expect(stack).toHaveResourceLike("AWS::ECS::Service", { + ServiceName: serviceName, + LaunchType: 'FARGATE', + DesiredCount: 2, + DeploymentConfiguration: { + MaximumPercent: 150, + MinimumHealthyPercent: 75 + }, + PlatformVersion: ecs.FargatePlatformVersion.LATEST, + }); +}); + +test('Check for IAM startExecution policy', () => { + const stack = new cdk.Stack(); + const publicApi = false; + + createFargateConstructWithNewResources(stack, publicApi); + + expect(stack).toHaveResourceLike("AWS::IAM::Policy", { + PolicyDocument: { + Statement: [ + { + Action: "states:StartExecution", + Effect: "Allow", + Resource: { + Ref: "testconstructStateMachine3333AAA9" + } + } + ], + Version: "2012-10-17" + }, + PolicyName: "testconstructtaskdefTaskRoleDefaultPolicyF34A1535", + Roles: [ + { + Ref: "testconstructtaskdefTaskRoleC60414C4" + } + ] + }); +}); + +test('Check for public/private VPC', () => { + const stack = new cdk.Stack(); + const publicApi = true; + + createFargateConstructWithNewResources(stack, publicApi); + + expect(stack).toHaveResourceLike("AWS::EC2::VPC", { + CidrBlock: testCidr + }); + + expect(stack).toHaveResourceLike('AWS::EC2::InternetGateway', {}); + expect(stack).toCountResources('AWS::EC2::VPC', 1); + expect(stack).toCountResources('AWS::StepFunctions::StateMachine', 1); + expect(stack).toCountResources('AWS::ECS::Service', 1); +}); + +test('Check for isolated VPC', () => { + const stack = new cdk.Stack(); + const publicApi = false; + + createFargateConstructWithNewResources(stack, publicApi); + + expect(stack).toHaveResourceLike("AWS::EC2::VPC", { + CidrBlock: testCidr + }); + + expect(stack).not.toHaveResourceLike('AWS::EC2::InternetGateway', {}); + expect(stack).toCountResources('AWS::EC2::VPC', 1); + expect(stack).toCountResources('AWS::StepFunctions::StateMachine', 1); + expect(stack).toCountResources('AWS::ECS::Service', 1); +}); + +test('Check for an existing VPC', () => { + const stack = new cdk.Stack(); + const publicApi = false; + + const existingVpc = defaults.getTestVpc(stack, publicApi); + + new FargateToStepfunctions(stack, 'test-construct', { + publicApi, + ecrRepositoryArn: defaults.fakeEcrRepoArn, + clusterProps: { clusterName }, + containerDefinitionProps: { containerName }, + fargateTaskDefinitionProps: { family: familyName }, + fargateServiceProps: { serviceName }, + existingVpc, + stateMachineProps: testStateMachineProps(stack) + }); + + expect(stack).toHaveResourceLike("AWS::EC2::VPC", { + CidrBlock: "172.168.0.0/16" + }); + + expect(stack).toCountResources("AWS::EC2::VPC", 1); +}); + +test('Check for custom ARN resource', () => { + const stack = new cdk.Stack(); + const publicApi = true; + const customEnvName = "TEST_CUSTOM_ARN"; + + new FargateToStepfunctions(stack, 'test-construct', { + publicApi, + ecrRepositoryArn: defaults.fakeEcrRepoArn, + vpcProps: { cidr: testCidr }, + clusterProps: { clusterName }, + containerDefinitionProps: { containerName }, + fargateTaskDefinitionProps: { family: familyName }, + fargateServiceProps: { serviceName }, + stateMachineProps: testStateMachineProps(stack), + stateMachineEnvironmentVariableName: customEnvName + }); + + expect(stack).toHaveResourceLike("AWS::ECS::TaskDefinition", { + Family: familyName, + ContainerDefinitions: [ + { + Environment: [ + { + Name: customEnvName, + Value: { + Ref: "testconstructStateMachine3333AAA9" + } + } + ], + Essential: true, + Image: { + "Fn::Join": [ + "", + [ + "123456789012.dkr.ecr.us-east-1.", + { + Ref: "AWS::URLSuffix" + }, + "/fake-repo:latest" + ] + ] + }, + MemoryReservation: 512, + Name: containerName, + PortMappings: [ + { + ContainerPort: 8080, + Protocol: "tcp" + } + ] + } + ] + }); +}); + +test('Check for no cloudwatch creation', () => { + const stack = new cdk.Stack(); + const publicApi = true; + + const construct = new FargateToStepfunctions(stack, 'test-construct', { + publicApi, + ecrRepositoryArn: defaults.fakeEcrRepoArn, + vpcProps: { cidr: testCidr }, + clusterProps: { clusterName }, + containerDefinitionProps: { containerName }, + fargateTaskDefinitionProps: { family: familyName }, + fargateServiceProps: { serviceName }, + stateMachineProps: testStateMachineProps(stack), + createCloudWatchAlarms: false + }); + + expect(construct.cloudwatchAlarms).not.toBeDefined(); + expect(stack).not.toHaveResource("AWS::CloudWatch::Alarm", { + ComparisonOperator: "GreaterThanOrEqualToThreshold", + EvaluationPeriods: 1, + AlarmDescription: "Alarm for the number of executions that aborted exceeded the threshold of 1. ", + Dimensions: [ + { + Name: "StateMachineArn", + Value: { + Ref: "testconstructStateMachine3333AAA9" + } + } + ], + MetricName: "ExecutionsAborted", + Namespace: "AWS/States", + Period: 300, + Statistic: "Maximum", + Threshold: 1 + }); +}); + +test('Check for custom log group props', () => { + const stack = new cdk.Stack(); + const publicApi = true; + const logGroupName = "custom-log-group"; + + new FargateToStepfunctions(stack, 'test-construct', { + publicApi, + ecrRepositoryArn: defaults.fakeEcrRepoArn, + vpcProps: { cidr: testCidr }, + clusterProps: { clusterName }, + containerDefinitionProps: { containerName }, + fargateTaskDefinitionProps: { family: familyName }, + fargateServiceProps: { serviceName }, + stateMachineProps: testStateMachineProps(stack), + logGroupProps: { + logGroupName + } + }); + + expect(stack).toHaveResourceLike("AWS::Logs::LogGroup", { + LogGroupName: logGroupName + }); +}); + +function createFargateConstructWithNewResources(stack: cdk.Stack, publicApi: boolean) { + return new FargateToStepfunctions(stack, 'test-construct', { + publicApi, + ecrRepositoryArn: defaults.fakeEcrRepoArn, + vpcProps: { cidr: testCidr }, + clusterProps: { clusterName }, + containerDefinitionProps: { containerName }, + fargateTaskDefinitionProps: { family: familyName }, + fargateServiceProps: { serviceName }, + stateMachineProps: testStateMachineProps(stack), + }); +} + +function testStateMachineProps(stack: cdk.Stack, userProps?: stepfunctions.StateMachineProps): + stepfunctions.StateMachineProps { + const defaultTestProp = { definition: new stepfunctions.Pass(stack, 'StartState') }; + + return defaults.consolidateProps(defaultTestProp, userProps); +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.expected.json b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.expected.json new file mode 100644 index 000000000..ba5c88912 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.expected.json @@ -0,0 +1,1355 @@ +{ + "Description": "Integration Test with new VPC, Service and a state machine", + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "172.168.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "CidrBlock": "172.168.0.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet1" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W33", + "reason": "Allow Public Subnets to have MapPublicIpOnLaunch set to true" + } + ] + } + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "CidrBlock": "172.168.32.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet2" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W33", + "reason": "Allow Public Subnets to have MapPublicIpOnLaunch set to true" + } + ] + } + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet3SubnetBE12F0B6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "CidrBlock": "172.168.64.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet3" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W33", + "reason": "Allow Public Subnets to have MapPublicIpOnLaunch set to true" + } + ] + } + } + }, + "VpcPublicSubnet3RouteTable93458DBB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTableAssociation1F1EDF02": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + } + } + }, + "VpcPublicSubnet3DefaultRoute4697774F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet3EIP3A666A23": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3NATGateway7640CD1D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet3EIP3A666A23", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "CidrBlock": "172.168.96.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "new-resources/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "CidrBlock": "172.168.128.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "new-resources/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcPrivateSubnet3SubnetF258B56E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "CidrBlock": "172.168.160.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "new-resources/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableD98824C7": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableAssociation16BDDC43": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + } + }, + "VpcPrivateSubnet3DefaultRoute94B74F0D": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet3NATGateway7640CD1D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "VpcFlowLogIAMRole6A475D41": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "vpc-flow-logs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc" + } + ] + } + }, + "VpcFlowLogIAMRoleDefaultPolicy406FB995": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:DescribeLogStreams" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "VpcFlowLogLogGroup7B5C56B9", + "Arn" + ] + } + }, + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "VpcFlowLogIAMRole6A475D41", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "VpcFlowLogIAMRoleDefaultPolicy406FB995", + "Roles": [ + { + "Ref": "VpcFlowLogIAMRole6A475D41" + } + ] + } + }, + "VpcFlowLogLogGroup7B5C56B9": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc" + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W84", + "reason": "By default CloudWatchLogs LogGroups data is encrypted using the CloudWatch server-side encryption keys (AWS Managed Keys)" + } + ] + } + } + }, + "VpcFlowLog8FF33A73": { + "Type": "AWS::EC2::FlowLog", + "Properties": { + "ResourceId": { + "Ref": "Vpc8378EB38" + }, + "ResourceType": "VPC", + "TrafficType": "ALL", + "DeliverLogsPermissionArn": { + "Fn::GetAtt": [ + "VpcFlowLogIAMRole6A475D41", + "Arn" + ] + }, + "LogDestinationType": "cloud-watch-logs", + "LogGroupName": { + "Ref": "VpcFlowLogLogGroup7B5C56B9" + }, + "Tags": [ + { + "Key": "Name", + "Value": "new-resources/Vpc" + } + ] + } + }, + "VpcECRAPI9A3B6A2B": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": "com.amazonaws.us-east-1.ecr.api", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "newresourcesECRAPIsecuritygroupE52BAE3F", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VpcECRDKR604E039F": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": "com.amazonaws.us-east-1.ecr.dkr", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "newresourcesECRDKRsecuritygroupBA34F94F", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VpcS3A5408339": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".s3" + ] + ] + }, + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "RouteTableIds": [ + { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + } + ], + "VpcEndpointType": "Gateway" + } + }, + "VpcSTEPFUNCTIONS550F8CB6": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": "com.amazonaws.us-east-1.states", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "newresourcesSTEPFUNCTIONSsecuritygroupFB5E4F76", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ], + "VpcEndpointType": "Interface" + } + }, + "newresourcesECRAPIsecuritygroupE52BAE3F": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "new-resources/new-resources-ECR_API-security-group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W5", + "reason": "Egress of 0.0.0.0/0 is default and generally considered OK" + }, + { + "id": "W40", + "reason": "Egress IPProtocol of -1 is default and generally considered OK" + } + ] + } + } + }, + "newresourcesECRDKRsecuritygroupBA34F94F": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "new-resources/new-resources-ECR_DKR-security-group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W5", + "reason": "Egress of 0.0.0.0/0 is default and generally considered OK" + }, + { + "id": "W40", + "reason": "Egress IPProtocol of -1 is default and generally considered OK" + } + ] + } + } + }, + "testclusterDF8B0D19": { + "Type": "AWS::ECS::Cluster" + }, + "testtaskdefTaskRoleB2DEF113": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "testtaskdefTaskRoleDefaultPolicy5D591D1C": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "testconstructStateMachine3333AAA9" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testtaskdefTaskRoleDefaultPolicy5D591D1C", + "Roles": [ + { + "Ref": "testtaskdefTaskRoleB2DEF113" + } + ] + } + }, + "testtaskdefF924AD58": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Environment": [ + { + "Name": "CUSTOM_NAME", + "Value": { + "Ref": "testconstructStateMachine3333AAA9" + } + } + ], + "Essential": true, + "Image": "nginx", + "MemoryReservation": 512, + "Name": "test-container", + "PortMappings": [ + { + "ContainerPort": 8080, + "Protocol": "tcp" + } + ] + } + ], + "Cpu": "256", + "Family": "newresourcestesttaskdef75720C83", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "testtaskdefTaskRoleB2DEF113", + "Arn" + ] + } + } + }, + "testsg872EB48A": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Construct created security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W5", + "reason": "Egress of 0.0.0.0/0 is default and generally considered OK" + }, + { + "id": "W40", + "reason": "Egress IPProtocol of -1 is default and generally considered OK" + } + ] + } + } + }, + "testserviceService2730C249": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "testclusterDF8B0D19" + }, + "DeploymentConfiguration": { + "MaximumPercent": 150, + "MinimumHealthyPercent": 75 + }, + "DesiredCount": 2, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "testsg872EB48A", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ] + } + }, + "PlatformVersion": "LATEST", + "TaskDefinition": { + "Ref": "testtaskdefF924AD58" + } + } + }, + "testconstructStateMachineLogGroup2EB4F48B": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/vendedlogs/states/newresourcestestconstructstatemachinelog63b3cb15f80b" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W86", + "reason": "Retention period for CloudWatchLogs LogGroups are set to 'Never Expire' to preserve customer data indefinitely" + }, + { + "id": "W84", + "reason": "By default CloudWatchLogs LogGroups data is encrypted using the CloudWatch server-side encryption keys (AWS Managed Keys)" + } + ] + } + } + }, + "testconstructStateMachineRoleA396E5D3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "states.us-east-1.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "testconstructStateMachineRoleDefaultPolicyF10A684E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testconstructStateMachineRoleDefaultPolicyF10A684E", + "Roles": [ + { + "Ref": "testconstructStateMachineRoleA396E5D3" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W12", + "reason": "The 'LogDelivery' actions do not support resource-level authorizations" + } + ] + } + } + }, + "testconstructStateMachine3333AAA9": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "testconstructStateMachineRoleA396E5D3", + "Arn" + ] + }, + "DefinitionString": "{\"StartAt\":\"StartState\",\"States\":{\"StartState\":{\"Type\":\"Pass\",\"End\":true}}}", + "LoggingConfiguration": { + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "testconstructStateMachineLogGroup2EB4F48B", + "Arn" + ] + } + } + } + ], + "Level": "ERROR" + } + }, + "DependsOn": [ + "testconstructStateMachineRoleDefaultPolicyF10A684E", + "testconstructStateMachineRoleA396E5D3" + ] + }, + "testconstructExecutionFailedAlarmE9CEA29E": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that failed exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testconstructStateMachine3333AAA9" + } + } + ], + "MetricName": "ExecutionsFailed", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1 + } + }, + "testconstructExecutionThrottledAlarmEE993A2A": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that throttled exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testconstructStateMachine3333AAA9" + } + } + ], + "MetricName": "ExecutionThrottled", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Sum", + "Threshold": 1 + } + }, + "testconstructExecutionAbortedAlarm2BC3DDB8": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 1, + "AlarmDescription": "Alarm for the number of executions that aborted exceeded the threshold of 1. ", + "Dimensions": [ + { + "Name": "StateMachineArn", + "Value": { + "Ref": "testconstructStateMachine3333AAA9" + } + } + ], + "MetricName": "ExecutionsAborted", + "Namespace": "AWS/States", + "Period": 300, + "Statistic": "Maximum", + "Threshold": 1 + } + }, + "newresourcesSTEPFUNCTIONSsecuritygroupFB5E4F76": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "new-resources/new-resources-STEP_FUNCTIONS-security-group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W5", + "reason": "Egress of 0.0.0.0/0 is default and generally considered OK" + }, + { + "id": "W40", + "reason": "Egress IPProtocol of -1 is default and generally considered OK" + } + ] + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.ts new file mode 100644 index 000000000..68cdedc3e --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.ts @@ -0,0 +1,59 @@ +/** + * Copyright 2022 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 { Aws, App, Stack, RemovalPolicy } from "@aws-cdk/core"; +import { FargateToStepfunctions, FargateToStepfunctionsProps } from "../lib"; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as defaults from '@aws-solutions-constructs/core'; +import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; + +// Setup +const app = new App(); +const stack = new Stack(app, defaults.generateIntegStackName(__filename), { + env: { account: Aws.ACCOUNT_ID, region: 'us-east-1' }, +}); +stack.templateOptions.description = 'Integration Test with new VPC, Service and a state machine'; + +const existingVpc = defaults.getTestVpc(stack); +const startState = new stepfunctions.Pass(stack, 'StartState'); +const image = ecs.ContainerImage.fromRegistry('nginx'); + +const [testService, testContainer] = defaults.CreateFargateService(stack, + 'test', + existingVpc, + undefined, + undefined, + undefined, + undefined, + { image }, +); + +const constructProps: FargateToStepfunctionsProps = { + publicApi: true, + existingVpc, + stateMachineProps: { + definition: startState + }, + existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: testService, + stateMachineEnvironmentVariableName: 'CUSTOM_NAME', + logGroupProps: { + removalPolicy: RemovalPolicy.DESTROY + } +}; + +new FargateToStepfunctions(stack, 'test-construct', constructProps); + +// Synth +app.synth(); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.expected.json b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.expected.json new file mode 100644 index 000000000..1eb6a03a8 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.expected.json @@ -0,0 +1,1292 @@ +{ + "Description": "Integration Test with new VPC, Service and a state machine with no CloudWatch alarms", + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "172.168.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "CidrBlock": "172.168.0.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet1" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W33", + "reason": "Allow Public Subnets to have MapPublicIpOnLaunch set to true" + } + ] + } + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "CidrBlock": "172.168.32.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet2" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W33", + "reason": "Allow Public Subnets to have MapPublicIpOnLaunch set to true" + } + ] + } + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet3SubnetBE12F0B6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "CidrBlock": "172.168.64.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet3" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W33", + "reason": "Allow Public Subnets to have MapPublicIpOnLaunch set to true" + } + ] + } + } + }, + "VpcPublicSubnet3RouteTable93458DBB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTableAssociation1F1EDF02": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + } + } + }, + "VpcPublicSubnet3DefaultRoute4697774F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet3EIP3A666A23": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3NATGateway7640CD1D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet3EIP3A666A23", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "CidrBlock": "172.168.96.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "CidrBlock": "172.168.128.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcPrivateSubnet3SubnetF258B56E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "CidrBlock": "172.168.160.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableD98824C7": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableAssociation16BDDC43": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + } + }, + "VpcPrivateSubnet3DefaultRoute94B74F0D": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet3NATGateway7640CD1D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "VpcFlowLogIAMRole6A475D41": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "vpc-flow-logs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc" + } + ] + } + }, + "VpcFlowLogIAMRoleDefaultPolicy406FB995": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:DescribeLogStreams" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "VpcFlowLogLogGroup7B5C56B9", + "Arn" + ] + } + }, + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "VpcFlowLogIAMRole6A475D41", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "VpcFlowLogIAMRoleDefaultPolicy406FB995", + "Roles": [ + { + "Ref": "VpcFlowLogIAMRole6A475D41" + } + ] + } + }, + "VpcFlowLogLogGroup7B5C56B9": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc" + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W84", + "reason": "By default CloudWatchLogs LogGroups data is encrypted using the CloudWatch server-side encryption keys (AWS Managed Keys)" + } + ] + } + } + }, + "VpcFlowLog8FF33A73": { + "Type": "AWS::EC2::FlowLog", + "Properties": { + "ResourceId": { + "Ref": "Vpc8378EB38" + }, + "ResourceType": "VPC", + "TrafficType": "ALL", + "DeliverLogsPermissionArn": { + "Fn::GetAtt": [ + "VpcFlowLogIAMRole6A475D41", + "Arn" + ] + }, + "LogDestinationType": "cloud-watch-logs", + "LogGroupName": { + "Ref": "VpcFlowLogLogGroup7B5C56B9" + }, + "Tags": [ + { + "Key": "Name", + "Value": "no-cloudwatch-alarms/Vpc" + } + ] + } + }, + "VpcECRAPI9A3B6A2B": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": "com.amazonaws.us-east-1.ecr.api", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "nocloudwatchalarmsECRAPIsecuritygroupA72029F8", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VpcECRDKR604E039F": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": "com.amazonaws.us-east-1.ecr.dkr", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "nocloudwatchalarmsECRDKRsecuritygroup11863825", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ], + "VpcEndpointType": "Interface" + } + }, + "VpcS3A5408339": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".s3" + ] + ] + }, + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "RouteTableIds": [ + { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + } + ], + "VpcEndpointType": "Gateway" + } + }, + "VpcSTEPFUNCTIONS550F8CB6": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": "com.amazonaws.us-east-1.states", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "nocloudwatchalarmsSTEPFUNCTIONSsecuritygroupE67433DC", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ], + "VpcEndpointType": "Interface" + } + }, + "nocloudwatchalarmsECRAPIsecuritygroupA72029F8": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "no-cloudwatch-alarms/no-cloudwatch-alarms-ECR_API-security-group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W5", + "reason": "Egress of 0.0.0.0/0 is default and generally considered OK" + }, + { + "id": "W40", + "reason": "Egress IPProtocol of -1 is default and generally considered OK" + } + ] + } + } + }, + "nocloudwatchalarmsECRDKRsecuritygroup11863825": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "no-cloudwatch-alarms/no-cloudwatch-alarms-ECR_DKR-security-group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W5", + "reason": "Egress of 0.0.0.0/0 is default and generally considered OK" + }, + { + "id": "W40", + "reason": "Egress IPProtocol of -1 is default and generally considered OK" + } + ] + } + } + }, + "testclusterDF8B0D19": { + "Type": "AWS::ECS::Cluster" + }, + "testtaskdefTaskRoleB2DEF113": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "testtaskdefTaskRoleDefaultPolicy5D591D1C": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "testconstructStateMachine3333AAA9" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testtaskdefTaskRoleDefaultPolicy5D591D1C", + "Roles": [ + { + "Ref": "testtaskdefTaskRoleB2DEF113" + } + ] + } + }, + "testtaskdefF924AD58": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Environment": [ + { + "Name": "STATE_MACHINE_ARN", + "Value": { + "Ref": "testconstructStateMachine3333AAA9" + } + } + ], + "Essential": true, + "Image": "nginx", + "MemoryReservation": 512, + "Name": "test-container", + "PortMappings": [ + { + "ContainerPort": 8080, + "Protocol": "tcp" + } + ] + } + ], + "Cpu": "256", + "Family": "nocloudwatchalarmstesttaskdef18D90B7C", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "testtaskdefTaskRoleB2DEF113", + "Arn" + ] + } + } + }, + "testsg872EB48A": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Construct created security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W5", + "reason": "Egress of 0.0.0.0/0 is default and generally considered OK" + }, + { + "id": "W40", + "reason": "Egress IPProtocol of -1 is default and generally considered OK" + } + ] + } + } + }, + "testserviceService2730C249": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "testclusterDF8B0D19" + }, + "DeploymentConfiguration": { + "MaximumPercent": 150, + "MinimumHealthyPercent": 75 + }, + "DesiredCount": 2, + "EnableECSManagedTags": false, + "LaunchType": "FARGATE", + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "testsg872EB48A", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + }, + { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + ] + } + }, + "PlatformVersion": "LATEST", + "TaskDefinition": { + "Ref": "testtaskdefF924AD58" + } + } + }, + "testconstructStateMachineLogGroup2EB4F48B": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/vendedlogs/states/nocloudwatchalarmstestconstructstatemachinelogdbb9902b27ea" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete", + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W86", + "reason": "Retention period for CloudWatchLogs LogGroups are set to 'Never Expire' to preserve customer data indefinitely" + }, + { + "id": "W84", + "reason": "By default CloudWatchLogs LogGroups data is encrypted using the CloudWatch server-side encryption keys (AWS Managed Keys)" + } + ] + } + } + }, + "testconstructStateMachineRoleA396E5D3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "states.us-east-1.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "testconstructStateMachineRoleDefaultPolicyF10A684E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testconstructStateMachineRoleDefaultPolicyF10A684E", + "Roles": [ + { + "Ref": "testconstructStateMachineRoleA396E5D3" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W12", + "reason": "The 'LogDelivery' actions do not support resource-level authorizations" + } + ] + } + } + }, + "testconstructStateMachine3333AAA9": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "testconstructStateMachineRoleA396E5D3", + "Arn" + ] + }, + "DefinitionString": "{\"StartAt\":\"StartState\",\"States\":{\"StartState\":{\"Type\":\"Pass\",\"End\":true}}}", + "LoggingConfiguration": { + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "testconstructStateMachineLogGroup2EB4F48B", + "Arn" + ] + } + } + } + ], + "Level": "ERROR" + } + }, + "DependsOn": [ + "testconstructStateMachineRoleDefaultPolicyF10A684E", + "testconstructStateMachineRoleA396E5D3" + ] + }, + "nocloudwatchalarmsSTEPFUNCTIONSsecuritygroupE67433DC": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "no-cloudwatch-alarms/no-cloudwatch-alarms-STEP_FUNCTIONS-security-group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "SecurityGroupIngress": [ + { + "CidrIp": { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + ":443" + ] + ] + }, + "FromPort": 443, + "IpProtocol": "tcp", + "ToPort": 443 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W5", + "reason": "Egress of 0.0.0.0/0 is default and generally considered OK" + }, + { + "id": "W40", + "reason": "Egress IPProtocol of -1 is default and generally considered OK" + } + ] + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.ts new file mode 100644 index 000000000..1f8081f64 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.ts @@ -0,0 +1,59 @@ +/** + * Copyright 2022 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 { Aws, App, Stack, RemovalPolicy } from "@aws-cdk/core"; +import { FargateToStepfunctions, FargateToStepfunctionsProps } from "../lib"; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as defaults from '@aws-solutions-constructs/core'; +import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; + +// Setup +const app = new App(); +const stack = new Stack(app, defaults.generateIntegStackName(__filename), { + env: { account: Aws.ACCOUNT_ID, region: 'us-east-1' }, +}); +stack.templateOptions.description = 'Integration Test with new VPC, Service and a state machine with no CloudWatch alarms'; + +const existingVpc = defaults.getTestVpc(stack); +const startState = new stepfunctions.Pass(stack, 'StartState'); +const image = ecs.ContainerImage.fromRegistry('nginx'); + +const [testService, testContainer] = defaults.CreateFargateService(stack, + 'test', + existingVpc, + undefined, + undefined, + undefined, + undefined, + { image }, +); + +const constructProps: FargateToStepfunctionsProps = { + publicApi: true, + existingVpc, + stateMachineProps: { + definition: startState + }, + existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: testService, + createCloudWatchAlarms: false, + logGroupProps: { + removalPolicy: RemovalPolicy.DESTROY + } +}; + +new FargateToStepfunctions(stack, 'test-construct', constructProps); + +// Synth +app.synth(); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/README.md index 90726a44e..efb44c707 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/README.md @@ -139,4 +139,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/README.md b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/README.md index d907934bd..d793feaa0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisstreams/README.md @@ -125,4 +125,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/README.md b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/README.md index e6312b6c7..3692e6d33 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/README.md @@ -151,4 +151,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/README.md index 60eb219c0..ac19990b3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/README.md @@ -140,4 +140,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-iot-s3/README.md index db0733821..1f571cc42 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-iot-s3/README.md @@ -137,4 +137,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) --- -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-iot-sqs/README.md index 78157133a..798a4a203 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-iot-sqs/README.md @@ -133,4 +133,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/README.md b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/README.md index 6008416ba..1968f21ca 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/README.md @@ -201,4 +201,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/README.md index 9916fc726..3eef7a484 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/README.md @@ -96,4 +96,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/README.md b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/README.md index 4459f0a84..3e7c64a21 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/README.md @@ -161,4 +161,4 @@ Out of the box implementation of the Construct without any override will set the A sample use case which uses this pattern is available under [`use_cases/aws-custom-glue-etl`](https://github.com/awslabs/aws-solutions-constructs/tree/master/source/use_cases/aws-custom-glue-etl). -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts index cd47f538f..0f649792c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts @@ -50,7 +50,7 @@ export interface KinesisstreamsToGluejobProps { * The ETL script can be provided either under glue.CfnJob.JobCommandProperty or set as an Asset instance under * @KinesisstreamsToGluejobProps.etlCodeAsset. * - * If an S3 location is know and exists, provide the S3 url in the `scriptLocation` attribute in glue.CfnJob.JobCommandProperty as an + * If an S3 location is know and exists, provide the S3 URL in the `scriptLocation` attribute in glue.CfnJob.JobCommandProperty as an * S3 format URL (example: `s3://bucketname/keyprefix.py`) * * If the ETL script exists as a local files or directories, create an instance of the Asset (aws-cdk-lib » aws_s3_assets) class diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/README.md index d7ca78e01..1683c4f99 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/README.md @@ -107,4 +107,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/README.md index 431477afa..731b79b37 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/README.md @@ -133,4 +133,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/README.md index 64292598a..cdb4fa529 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/README.md @@ -86,7 +86,7 @@ new LambdaToDynamoDB(this, "test_lambda_dynamodb_stack", new LambdaToDynamoDBPro |dynamoTableProps?|[`dynamodb.TableProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.TableProps.html)|Optional user provided props to override the default props for DynamoDB Table| |existingTableObj?|[`dynamodb.Table`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html)|Existing instance of DynamoDB table object, providing both this and `dynamoTableProps` will cause an error.| |tablePermissions?|`string`|Optional table permissions to grant to the Lambda function. One of the following may be specified: `All`, `Read`, `ReadWrite`, `Write`.| -|tableEnvironmentVariableName?|`string`|Optional Name for the DynamoDB table environment variable set for the Lambda function.| +|tableEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the name of the DynamoDB table. Default: DDB_TABLE_NAME | |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and a Gateway Endpoint will be created in the VPC for Amazon DynamoDB. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:

    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| @@ -122,4 +122,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/lib/index.ts index f18e349d1..d15d96ed8 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/lib/index.ts @@ -54,9 +54,9 @@ export interface LambdaToDynamoDBProps { */ readonly tablePermissions?: string; /** - * Optional Name for the DynamoDB table environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the name of the DynamoDB table. * - * @default - None + * @default - DDB_TABLE_NAME */ readonly tableEnvironmentVariableName?: string; /** diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/README.md index 889dd024d..458e86e06 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/README.md @@ -83,7 +83,7 @@ new LambdaToElasticachememcached(this, "LambdaToCachePattern", new LambdaToElast |lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|Optional user provided props to override the default props for the Lambda function.| |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for Amazon SQS. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user provided properties to override the default properties for the new VPC. `subnetConfiguration` is set by the pattern, so any values for those properties supplied here will be overrriden. | -| cacheEndpointEnvironmentVariableName?| string | Lambda function environment variable name for the cache Endpoint. Defaults to CACHE_ENDPOINT | +| cacheEndpointEnvironmentVariableName?| string | Optional Name for the Lambda function environment variable set to the cache endpoint. Default: CACHE_ENDPOINT | | cacheProps? | [`cache.CfnCacheClusterProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_elasticache.CfnCacheClusterProps.html) | Optional user provided props to override the default props for the Elasticache Cluster. Providing both this and `existingCache` will cause an error. | | existingCache? | [`cache.CfnCacheCluster`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_elasticache.CfnCacheCluster.html#attrconfigurationendpointport) | Existing instance of Elasticache Cluster object, providing both this and `cacheProps` will cause an error. If you provide this, you must provide the associated VPC in existingVpc. | @@ -117,4 +117,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/lib/index.ts index 3dfa6cafe..bf938c3cc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/lib/index.ts @@ -50,7 +50,7 @@ export interface LambdaToElasticachememcachedProps { */ readonly vpcProps?: ec2.VpcProps; /** - * Optional Name for the Elasticache Endpoint environment variable + * Optional Name for the Lambda function environment variable set to the cache endpoint. * * @default - CACHE_ENDPOINT */ diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/package.json b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/package.json index 9696fb652..db8da8a48 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticachememcached/package.json @@ -94,4 +94,4 @@ "Amazon Elasticache", "AWS Lambda" ] -} +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/README.md index 464891b08..89d36ca21 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/README.md @@ -104,7 +104,7 @@ new LambdaToElasticSearchAndKibana(this, "sample", |domainName|`string`|Domain name for the Cognito and the Elasticsearch Service| |cognitoDomainName?|`string`|Optional Cognito Domain Name, if provided it will be used for Cognito Domain, and domainName will be used for the Elasticsearch Domain| |createCloudWatchAlarms|`boolean`|Whether to create recommended CloudWatch alarms| -|domainEndpointEnvironmentVariableName?|`string`|Optional Name for the ElasticSearch domain endpoint environment variable set for the Lambda function.| +|domainEndpointEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the domain endpoint. Default: DOMAIN_ENDPOINT | ## Pattern Properties @@ -149,4 +149,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/lib/index.ts index a9596d13b..60ee7c346 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/lib/index.ts @@ -62,9 +62,9 @@ export interface LambdaToElasticSearchAndKibanaProps { */ readonly createCloudWatchAlarms?: boolean; /** - * Optional Name for the ElasticSearch domain endpoint environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the domain endpoint. * - * @default - None + * @default - DOMAIN_ENDPOINT */ readonly domainEndpointEnvironmentVariableName?: string; } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/README.md index 2c4cf9200..bcc5858e5 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/README.md @@ -89,7 +89,7 @@ new LambdaToEventbridge(this, "LambdaToEventbridgePattern", new LambdaToEventbri |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for Amazon EventBridge. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| -|eventBusEnvironmentVariableName?|`string`|Optional Name for the EventBus's name environment variable set for the Lambda function.| +|eventBusEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the name of the Event bus. Default: EVENTBUS_NAME | ## Pattern Properties @@ -116,4 +116,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/lib/index.ts index 5692e1a90..a0be73f43 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-eventbridge/lib/index.ts @@ -61,9 +61,9 @@ export interface LambdaToEventbridgeProps { */ readonly deployVpc?: boolean; /** - * Optional Name for the EventBus's name environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the name of the Event bus. * - * @default - EVENTBUS_NAME is used + * @default - EVENTBUS_NAME */ readonly eventBusEnvironmentVariableName?: string; } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/README.md index aceff41ff..d8f59097f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/README.md @@ -87,7 +87,7 @@ new LambdaToS3(this, "LambdaToS3Pattern", new LambdaToS3Props.Builder() |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for Amazon SQS. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| -|bucketEnvironmentVariableName?|`string`|Optional name for the S3 bucket environment variable set for the Lambda function.| +|bucketEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the name of the bucket. Default: S3_BUCKET_NAME | |loggingBucketProps?|[`s3.BucketProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.BucketProps.html)|Optional user provided props to override the default props for the S3 Logging Bucket.| |logS3AccessLogs?| boolean|Whether to turn on Access Logging for the S3 bucket. Creates an S3 bucket with associated storage costs for the logs. Enabling Access Logging is a best practice. default - true| @@ -126,4 +126,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/lib/index.ts index 6fc7a36a7..dc41fe321 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/lib/index.ts @@ -69,9 +69,9 @@ export interface LambdaToS3Props { */ readonly deployVpc?: boolean; /** - * Optional name for the S3 bucket environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the name of the bucket. * - * @default - None + * @default - S3_BUCKET_NAME */ readonly bucketEnvironmentVariableName?: string; /** diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/README.md index 14a65b251..e35a58a45 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/README.md @@ -122,23 +122,23 @@ new LambdaToSagemakerEndpoint(this, "LambdaToSagemakerEndpointPattern", |:-------------|:----------------|-----------------| |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. Providing both this and `lambdaFunctionProps` will cause an error.| |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.| -|existingSagemakerEndpointObj?|[`sagemaker.CfnEndpoint`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpoint.html)|An optional, existing Sagemaker Enpoint to be used. Providing both this and `endpointProps?` will cause an error.| -|modelProps?|[`sagemaker.CfnModelProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnModelProps.html) \| `any`|User-provided properties to override the default properties for the Sagemaker Model. At least `modelProps?.primaryContainer` must be provided to create a model. By default, the pattern will create a role with the minimum required permissions, but the client can provide a custom role with additional capabilities using `modelProps?.executionRoleArn`.| -|endpointConfigProps?|[`sagemaker.CfnEndpointConfigProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpointConfigProps.html)|Optional user-provided properties to override the default properties for the Sagemaker Endpoint Config. | -|endpointProps?|[`sagemaker.CfnEndpointProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpointProps.html)| Optional user-provided properties to override the default properties for the Sagemaker Endpoint Config. | -|existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this construct should be deployed. When deployed in a VPC, the Lambda function and Sagemaker Endpoint will use ENIs in the VPC to access network resources. An Interface Endpoint will be created in the VPC for Amazon Sagemaker Runtime, and Amazon S3 VPC Endpoint. If an existing VPC is provided, the `deployVpc?` property cannot be `true`.| +|existingSagemakerEndpointObj?|[`sagemaker.CfnEndpoint`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpoint.html)|An optional, existing SageMaker Enpoint to be used. Providing both this and `endpointProps?` will cause an error.| +|modelProps?|[`sagemaker.CfnModelProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnModelProps.html) \| `any`|User-provided properties to override the default properties for the SageMaker Model. At least `modelProps?.primaryContainer` must be provided to create a model. By default, the pattern will create a role with the minimum required permissions, but the client can provide a custom role with additional capabilities using `modelProps?.executionRoleArn`.| +|endpointConfigProps?|[`sagemaker.CfnEndpointConfigProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpointConfigProps.html)|Optional user-provided properties to override the default properties for the SageMaker Endpoint Config. | +|endpointProps?|[`sagemaker.CfnEndpointProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpointProps.html)| Optional user-provided properties to override the default properties for the SageMaker Endpoint Config. | +|existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this construct should be deployed. When deployed in a VPC, the Lambda function and Sagemaker Endpoint will use ENIs in the VPC to access network resources. An Interface Endpoint will be created in the VPC for Amazon SageMaker Runtime, and Amazon S3 VPC Endpoint. If an existing VPC is provided, the `deployVpc?` property cannot be `true`.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the Construct, so any values for those properties supplied here will be overrriden. If `deployVpc?` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| -|sagemakerEnvironmentVariableName?|`string`|Optional Name for the SageMaker endpoint environment variable set for the Lambda function.| +|sagemakerEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the name of the SageMaker endpoint. Default: SAGEMAKER_ENDPOINT_NAME | ## 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. | -| sagemakerEndpoint | [`sagemaker.CfnEndpoint`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpoint.html) | Returns an instance of the Sagemaker Endpoint created by the pattern. | +| sagemakerEndpoint | [`sagemaker.CfnEndpoint`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpoint.html) | Returns an instance of the SageMaker Endpoint created by the pattern. | | sagemakerEndpointConfig? | [`sagemaker.CfnEndpointConfig`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnEndpointConfig.html) | Returns an instance of the SageMaker EndpointConfig created by the pattern, if `existingSagemakerEndpointObj?` is not provided. | -| sagemakerModel? | [`sagemaker.CfnModel`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnModel.html) | Returns an instance of the Sagemaker Model created by the pattern, if `existingSagemakerEndpointObj?` is not provided. | +| sagemakerModel? | [`sagemaker.CfnModel`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sagemaker.CfnModel.html) | Returns an instance of the SageMaker Model created by the pattern, if `existingSagemakerEndpointObj?` is not provided. | | vpc? | `ec2.IVpc` | Returns an instance of the VPC created by the pattern, if `deployVpc?` is `true`, or `existingVpc?` is provided. | ## Default settings @@ -149,19 +149,19 @@ Out of the box implementation of the Construct without any override will set the - Configure limited privilege access IAM role for Lambda function - Enable reusing connections with Keep-Alive for NodeJs Lambda function -- Allow the function to invoke the Sagemaker endpoint for Inferences -- Configure the function to access resources in the VPC, where the Sagemaker endpoint is deployed +- Allow the function to invoke the SageMaker endpoint for Inferences +- Configure the function to access resources in the VPC, where the SageMaker endpoint is deployed - Enable X-Ray Tracing - Set environment variables: - (default) SAGEMAKER_ENDPOINT_NAME - AWS_NODEJS_CONNECTION_REUSE_ENABLED (for Node 10.x and higher functions). -### Amazon Sagemaker Endpoint +### Amazon SageMaker Endpoint -- Configure limited privilege to create Sagemaker resources -- Deploy Sagemaker model, endpointConfig, and endpoint -- Configure the Sagemaker endpoint to be deployed in a VPC -- Deploy S3 VPC Endpoint and Sagemaker Runtime VPC Interface +- Configure limited privilege to create SageMaker resources +- Deploy SageMaker model, endpointConfig, and endpoint +- Configure the SageMaker endpoint to be deployed in a VPC +- Deploy S3 VPC Endpoint and SageMaker Runtime VPC Interface ## Architecture @@ -169,4 +169,4 @@ Out of the box implementation of the Construct without any override will set the --- -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts index 7e34e31e3..ed6dd967b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts @@ -36,25 +36,25 @@ export interface LambdaToSagemakerEndpointProps { */ readonly lambdaFunctionProps?: lambda.FunctionProps; /** - * Existing Sagemaker Enpoint object, providing both this and endpointProps will cause an error. + * Existing SageMaker Enpoint object, providing both this and endpointProps will cause an error. * * @default - None */ readonly existingSagemakerEndpointObj?: sagemaker.CfnEndpoint; /** - * User provided props to create Sagemaker Model + * User provided props to create SageMaker Model * * @default - None */ readonly modelProps?: sagemaker.CfnModelProps | any; /** - * User provided props to create Sagemaker Endpoint Configuration + * User provided props to create SageMaker Endpoint Configuration * * @default - Default props are used */ readonly endpointConfigProps?: sagemaker.CfnEndpointConfigProps; /** - * User provided props to create Sagemaker Endpoint + * User provided props to create SageMaker Endpoint * * @default - Default props are used */ @@ -78,9 +78,9 @@ export interface LambdaToSagemakerEndpointProps { */ readonly deployVpc?: boolean; /** - * Optional Name for the SageMaker endpoint environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the name of the SageMaker endpoint. * - * @default - None + * @default - SAGEMAKER_ENDPOINT_NAME */ readonly sagemakerEnvironmentVariableName?: string; } @@ -123,13 +123,13 @@ export class LambdaToSagemakerEndpoint extends Construct { }, }); - // Add S3 VPC Gateway Endpoint, required by Sagemaker to access Models artifacts via AWS private network + // Add S3 VPC Gateway Endpoint, required by SageMaker to access Models artifacts via AWS private network defaults.AddAwsServiceEndpoint(scope, this.vpc, defaults.ServiceEndpointTypes.S3); - // Add SAGEMAKER_RUNTIME VPC Interface Endpoint, required by the lambda function to invoke the Sagemaker endpoint + // Add SAGEMAKER_RUNTIME VPC Interface Endpoint, required by the lambda function to invoke the SageMaker endpoint defaults.AddAwsServiceEndpoint(scope, this.vpc, defaults.ServiceEndpointTypes.SAGEMAKER_RUNTIME); } - // Build Sagemaker Endpoint (inclduing Sagemaker's Endpoint Configuration and Model) + // Build SageMaker Endpoint (inclduing SageMaker's Endpoint Configuration and Model) [this.sagemakerEndpoint, this.sagemakerEndpointConfig, this.sagemakerModel] = defaults.BuildSagemakerEndpoint( this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/README.md index bacb326c1..98f67e6f5 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/README.md @@ -91,7 +91,7 @@ new LambdaToSecretsmanager(this, "test-lambda-secretsmanager-stack", new LambdaT |secretProps?|[`secretsmanager.SecretProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.SecretProps.html)|Optional user provided props to override the default props for Secrets Manager| |existingSecretObj?|[`secretsmanager.Secret`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.Secret.html)|Existing instance of Secrets Manager Secret object, If this is set then the secretProps is ignored| |grantWriteAccess?|`string`|Optional Access granted to the Lambda function for the secret. 'Read' or 'ReadWrite". Default is "Read" -|secretEnvironmentVariableName?|`string`|Optional Name for Lambda function environment variable containing the ARN of the secret. Default is SECRET_ARN. | +|secretEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the ARN of the secret. Default: SECRET_ARN. | |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for AWS Secrets Manager. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| @@ -127,4 +127,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/lib/index.ts index 40a738466..30cf3e9dd 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/lib/index.ts @@ -61,7 +61,7 @@ export interface LambdaToSecretsmanagerProps { */ readonly deployVpc?: boolean; /** - * Optional Name for Lambda function environment variable containing the ARN of the secret. + * Optional Name for the Lambda function environment variable set to the ARN of the secret. * * @default - SECRET_ARN */ diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/README.md index a6d11356e..abb4ce6f9 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/README.md @@ -87,8 +87,8 @@ new LambdaToSns(this, "test-lambda-sns-stack", new LambdaToSnsProps.Builder() |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for Amazon SQS. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| -|topicArnEnvironmentVariableName?|`string`|Optional Name for the SNS topic arn environment variable set for the Lambda function.| -|topicNameEnvironmentVariableName?|`string`|Optional Name for the SNS topic name environment variable set for the Lambda function.| +|topicArnEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the arn of the topic. Default: SNS_TOPIC_ARN | +|topicNameEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the name of the topic. Default: SNS_TOPIC_NAME | ## Pattern Properties @@ -120,4 +120,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/lib/index.ts index 62d2d9820..afd583a6c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/lib/index.ts @@ -62,15 +62,15 @@ export interface LambdaToSnsProps { */ readonly deployVpc?: boolean; /** - * Optional Name for the SNS topic arn environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the arn of the Topic. * - * @default - None + * @default - SNS_TOPIC_ARN */ readonly topicArnEnvironmentVariableName?: string; /** - * Optional Name for the SNS topic name environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the name of the Topic. * - * @default - None + * @default - SNS_TOPIC_NAME */ readonly topicNameEnvironmentVariableName?: string; } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/README.md index ea019928d..d97e41676 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/README.md @@ -107,7 +107,7 @@ new LambdaToSqsToLambda(this, "LambdaToSqsToLambdaPattern", new LambdaToSqsToLam |maxReceiveCount?|`number`|The number of times a message can be unsuccessfully dequeued before being moved to the dead letter queue. Defaults to `15`.| |existingConsumerLambdaObj?|[`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 for receiving/consuming messages from the queue. Providing both this and `consumerLambdaFunctionProps` will cause an error. | |consumerLambdaFunctionProps?|[`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 consumer Lambda function.| -|queueEnvironmentVariableName?|`string`|Optional Name for the SQS queue URL environment variable set for the producer Lambda function.| +|queueEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the URL of the queue. Default: SQS_QUEUE_URL | |sqsEventSourceProps?| [`SqsEventSourceProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda-event-sources.SqsEventSourceProps.html)|Optional user provided properties for the queue event source.| |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for Amazon SQS. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| @@ -143,4 +143,4 @@ Out-of-the-box implementation of this Construct (without any overridden properti ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/lib/index.ts index 85d185870..795d0da36 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/lib/index.ts @@ -85,9 +85,9 @@ export interface LambdaToSqsToLambdaProps { */ readonly consumerLambdaFunctionProps?: lambda.FunctionProps; /** - * Optional Name for the SQS queue URL environment variable set for the producer Lambda function. + * Optional Name for the Lambda function environment variable set to the URL of the queue. * - * @default - None + * @default - SQS_QUEUE_URL */ readonly queueEnvironmentVariableName?: string; /** diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md index 25836880a..7acee2a8c 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md @@ -91,7 +91,7 @@ new LambdaToSqs(this, "test-lambda-sqs-stack", new LambdaToSqsProps.Builder() |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for Amazon SQS. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| -|queueEnvironmentVariableName?|`string`|Optional Name for the SQS queue URL environment variable set for the Lambda function.| +|queueEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the URL of the queue. Default: SQS_QUEUE_URL | ## Pattern Properties @@ -124,4 +124,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 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 index eec0ea029..6653c1810 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.ts @@ -85,9 +85,9 @@ export interface LambdaToSqsProps { */ readonly deployVpc?: boolean; /** - * Optional Name for the SQS queue URL environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the URL of the queue. * - * @default - None + * @default - SQS_QUEUE_URL */ readonly queueEnvironmentVariableName?: string; } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/README.md index 5d97fa9b7..3fe9882cf 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/README.md @@ -99,7 +99,7 @@ new LambdaToSsmstringparameter(this, "test-lambda-ssmstringparameter-stack", |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.| |existingStringParameterObj?|[`ssm.StringParameter`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ssm.StringParameter.html)|Existing instance of SSM String parameter object, providing both this and `stringParameterProps` will cause an error| |stringParameterProps?|[`ssm.StringParameterProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ssm.StringParameterProps.html)|Optional user provided props to override the default props for SSM String parameter. If existingStringParameterObj is not set stringParameterProps is required. The only supported [`ssm.StringParameterProps.type`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ssm.StringParameterProps.html#type) is [`STRING`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ssm.ParameterType.html#string) if a different value is provided it will be overridden.| -|stringParameterEnvironmentVariableName?|`string`|Optional Name for the SSM String parameter environment variable set for the Lambda function.| +|stringParameterEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the name of the parameter. Default: SSM_STRING_PARAMETER_NAME | |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for AWS Systems Manager Parameter. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| @@ -134,4 +134,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/lib/index.ts index 20d849282..2f64765a7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-ssmstringparameter/lib/index.ts @@ -62,7 +62,7 @@ export interface LambdaToSsmstringparameterProps { */ readonly deployVpc?: boolean; /** - * Optional Name for the SSM String parameter environment variable set for the Lambda function. + * Optional Name for the Lambda function environment variable set to the name of the parameter. * * @default - SSM_STRING_PARAMETER_NAME */ diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/README.md index 61c43c397..764c2b459 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/README.md @@ -108,7 +108,7 @@ new LambdaToStepFunction(this, "test-lambda-stepfunctions-stack", |stateMachineProps|[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|User provided props for the sfn.StateMachine.| |createCloudWatchAlarms|`boolean`|Whether to create recommended CloudWatch alarms| |logGroupProps?|[`logs.LogGroupProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.LogGroupProps.html)|User provided props to override the default props for for the CloudWatchLogs LogGroup.| -|stateMachineEnvironmentVariableName?|`string`|Optional Name for the Step Functions state machine environment variable set for the producer Lambda function.| +|stateMachineEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the ARN of the state machine. Default: STATE_MACHINE_ARN | |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for Amazon Step Functions. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| @@ -143,4 +143,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/lib/index.ts index 6bbc18385..d5eb396cb 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/lib/index.ts @@ -56,9 +56,9 @@ export interface LambdaToStepFunctionProps { */ readonly logGroupProps?: logs.LogGroupProps; /** - * Optional Name for the Step Functions state machine environment variable set for the producer Lambda function. + * Optional Name for the Lambda function environment variable set to the ARN of the state machine. * - * @default - None + * @default - STATE_MACHINE_ARN */ readonly stateMachineEnvironmentVariableName?: string; /** diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/README.md b/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/README.md index 594c34904..768e491f3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/README.md @@ -103,7 +103,7 @@ new LambdaToStepfunctions(this, "test-lambda-stepfunctions-stack", |stateMachineProps|[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|User provided props for the sfn.StateMachine.| |createCloudWatchAlarms|`boolean`|Whether to create recommended CloudWatch alarms| |logGroupProps?|[`logs.LogGroupProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.LogGroupProps.html)|User provided props to override the default props for for the CloudWatchLogs LogGroup.| -|stateMachineEnvironmentVariableName?|`string`|Optional Name for the Step Functions state machine environment variable set for the producer Lambda function.| +|stateMachineEnvironmentVariableName?|`string`|Optional Name for the Lambda function environment variable set to the ARN of the state machine. Default: STATE_MACHINE_ARN | |existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for Amazon Step Functions. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.| |vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.| |deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:
    • One isolated subnet in each Availability Zone used by the CDK program
    • `enableDnsHostnames` and `enableDnsSupport` will both be set to true
    If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.| @@ -139,4 +139,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts index d718d9210..cbda2e486 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts @@ -56,9 +56,9 @@ export interface LambdaToStepfunctionsProps { */ readonly logGroupProps?: logs.LogGroupProps; /** - * Optional Name for the Step Functions state machine environment variable set for the producer Lambda function. + * Optional Name for the Lambda function environment variable set to the ARN of the state machine. * - * @default - None + * @default - STATE_MACHINE_ARN */ readonly stateMachineEnvironmentVariableName?: string; /** diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-alb/README.md b/source/patterns/@aws-solutions-constructs/aws-route53-alb/README.md index d2f3e1736..cbb1e580e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-route53-alb/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-route53-alb/README.md @@ -133,4 +133,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/README.md index 9a7928c7f..4fd13dd4c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/README.md @@ -121,6 +121,6 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/README.md index cccfd13f5..2b8c97b7d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/README.md @@ -110,4 +110,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/README.md b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/README.md index 97f7416d3..4cedd21ff 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/README.md @@ -142,4 +142,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/README.md b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/README.md index c03af2bb7..385bded5f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/README.md @@ -141,4 +141,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/README.md b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/README.md index 014e6e901..92109f537 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/README.md @@ -110,4 +110,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/README.md b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/README.md index 8b851ad28..bfd8d37a3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/README.md @@ -135,4 +135,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 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 26b0c177f..3ab131e22 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/README.md @@ -117,4 +117,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/README.md b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/README.md index 615d2924d..49c8c35e5 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-alb/README.md @@ -138,4 +138,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/README.md b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/README.md index 023b166a1..1ea462209 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-apigateway/README.md @@ -143,4 +143,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/README.md b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/README.md index 2da02e312..053f27f11 100644 --- a/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-wafwebacl-cloudfront/README.md @@ -116,4 +116,4 @@ Out of the box implementation of the Construct without any override will set the ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics.test.ts b/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics.test.ts index be21dd4fe..db1f9be73 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics.test.ts @@ -11,32 +11,38 @@ * and limitations under the License. */ -import { Stack } from '@aws-cdk/core'; -import * as kinesisanalytics from '@aws-cdk/aws-kinesisanalytics'; -import * as defaults from '../index'; -import { overrideProps } from '../lib/utils'; -import '@aws-cdk/assert/jest'; +import { Stack, RemovalPolicy } from "@aws-cdk/core"; +import * as cdk from "@aws-cdk/core"; +import * as kinesisanalytics from "@aws-cdk/aws-kinesisanalytics"; +import * as kinesisFirehose from "@aws-cdk/aws-kinesisfirehose"; +import * as iam from "@aws-cdk/aws-iam"; +import * as kms from "@aws-cdk/aws-kms"; +import * as logs from "@aws-cdk/aws-logs"; +import * as defaults from "../index"; +import { overrideProps } from "../lib/utils"; +import "@aws-cdk/assert/jest"; -test('test kinesisanalytics override inputProperty', () => { +test("test kinesisanalytics override inputProperty", () => { const stack = new Stack(); const inputProperty: kinesisanalytics.CfnApplication.InputProperty = { inputSchema: { - recordColumns: [{name: 'x', sqlType: 'y'}], - recordFormat: { recordFormatType: 'csv' } + recordColumns: [{ name: "x", sqlType: "y" }], + recordFormat: { recordFormatType: "csv" }, }, - namePrefix: 'zzz' + namePrefix: "zzz", }; - const defaultProps: kinesisanalytics.CfnApplicationProps = defaults.DefaultCfnApplicationProps; + const defaultProps: kinesisanalytics.CfnApplicationProps = + defaults.DefaultCfnApplicationProps; const inProps: kinesisanalytics.CfnApplicationProps = { - inputs: [inputProperty] + inputs: [inputProperty], }; const outProps = overrideProps(defaultProps, inProps); - new kinesisanalytics.CfnApplication(stack, 'KinesisAnalytics', outProps); + new kinesisanalytics.CfnApplication(stack, "KinesisAnalytics", outProps); expect(stack).toHaveResource("AWS::KinesisAnalytics::Application", { Inputs: [ @@ -45,15 +51,146 @@ test('test kinesisanalytics override inputProperty', () => { RecordColumns: [ { Name: "x", - SqlType: "y" - } + SqlType: "y", + }, ], RecordFormat: { - RecordFormatType: "csv" - } + RecordFormatType: "csv", + }, }, - NamePrefix: "zzz" - } - ] + NamePrefix: "zzz", + }, + ], }); -}); \ No newline at end of file +}); + +test("Test default implementation", () => { + const stack = new Stack(); + + const newFirehose = CreateFirehose(stack); + const kinesisProps: defaults.BuildKinesisAnalyticsAppProps = { + kinesisFirehose: newFirehose, + kinesisAnalyticsProps: { + inputs: [{ + inputSchema: { + recordColumns: [{ + name: 'ts', + sqlType: 'TIMESTAMP', + mapping: '$.timestamp' + }, { + name: 'trip_id', + sqlType: 'VARCHAR(64)', + mapping: '$.trip_id' + }], + recordFormat: { + recordFormatType: 'JSON' + }, + recordEncoding: 'UTF-8' + }, + namePrefix: 'SOURCE_SQL_STREAM' + }] + }, + }; + + defaults.buildKinesisAnalyticsApp(stack, kinesisProps); + + expect(stack).toHaveResourceLike("AWS::KinesisAnalytics::Application", { + Inputs: [{ + InputSchema: { + RecordColumns: [{ + Name: 'ts', + SqlType: 'TIMESTAMP', + Mapping: '$.timestamp' + }, { + Name: 'trip_id', + SqlType: 'VARCHAR(64)', + Mapping: '$.trip_id' + }], + RecordFormat: { + RecordFormatType: 'JSON' + }, + RecordEncoding: 'UTF-8' + }, + NamePrefix: 'SOURCE_SQL_STREAM' + }] + }); +}); + +// test('Test for customer overrides', { +// test('Check policy created', { + +function CreateFirehose(stack: Stack): kinesisFirehose.CfnDeliveryStream { + // Creating the Firehose is kind of a big deal. FirehoseToS3 is not readily available here in core, + // so this routine pretty much replicates it. If this function ceases to work correctly, look at + // FirehoseToS3 and see if that changed. + const destinationBucket = defaults.CreateScrapBucket(stack, { + removalPolicy: RemovalPolicy.DESTROY, + autoDeleteObjects: true, + }); + + const kinesisFirehoseLogGroup = defaults.buildLogGroup( + stack, + "firehose-log-group", + {} + ); + + const cwLogStream: logs.LogStream = kinesisFirehoseLogGroup.addStream( + "firehose-log-stream" + ); + + const firehoseRole = new iam.Role(stack, "test-role", { + assumedBy: new iam.ServicePrincipal("firehose.amazonaws.com"), + }); + + // Setup the IAM policy for Kinesis Firehose + const firehosePolicy = new iam.Policy(stack, "KinesisFirehosePolicy", { + statements: [ + new iam.PolicyStatement({ + actions: [ + "s3:AbortMultipartUpload", + "s3:GetBucketLocation", + "s3:GetObject", + "s3:ListBucket", + "s3:ListBucketMultipartUploads", + "s3:PutObject", + ], + resources: [ + `${destinationBucket.bucketArn}`, + `${destinationBucket.bucketArn}/*`, + ], + }), + new iam.PolicyStatement({ + actions: ["logs:PutLogEvents"], + resources: [ + `arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:${kinesisFirehoseLogGroup.logGroupName}:log-stream:${cwLogStream.logStreamName}`, + ], + }), + ], + }); + + // Attach policy to role + firehosePolicy.attachToRole(firehoseRole); + + const awsManagedKey: kms.IKey = kms.Alias.fromAliasName( + stack, + "aws-managed-key", + "alias/aws/s3" + ); + + const defaultKinesisFirehoseProps: kinesisFirehose.CfnDeliveryStreamProps = defaults.DefaultCfnDeliveryStreamProps( + destinationBucket.bucketArn, + firehoseRole.roleArn, + kinesisFirehoseLogGroup.logGroupName, + cwLogStream.logStreamName, + awsManagedKey + ); + + destinationBucket.grantPut(firehoseRole); + + const firehose = new kinesisFirehose.CfnDeliveryStream( + stack, + "KinesisFirehose", + defaultKinesisFirehoseProps + ); + return firehose; +} 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 d28d2add4..9e9799038 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 @@ -13,8 +13,10 @@ // Imports import { Stack } from "@aws-cdk/core"; +import * as sqs from '@aws-cdk/aws-sqs'; import * as defaults from '../'; import '@aws-cdk/assert/jest'; +import { buildDeadLetterQueue, buildQueue } from "../lib/sqs-helper"; // -------------------------------------------------------------- // Test deployment w/ imported encryption key @@ -57,3 +59,122 @@ test('Test deployment without imported encryption key', () => { KmsMasterKeyId: "alias/aws/sqs" }); }); + +// -------------------------------------------------------------- +// Test deployment w/ construct created encryption key +// -------------------------------------------------------------- +test('Test deployment w/ construct created encryption key', () => { + // Stack + const stack = new Stack(); + // Helper declaration + const [queue, key] = defaults.buildQueue(stack, 'existing-queue', { + queueProps: { + queueName: 'existing-queue' + }, + enableEncryptionWithCustomerManagedKey: true, + }); + + expect(stack).toHaveResource("AWS::SQS::Queue", { + QueueName: "existing-queue" + }); + expect(stack).toHaveResource("AWS::KMS::Key", { + EnableKeyRotation: true + }); + expect(queue).toBeDefined(); + expect(key).toBeDefined(); +}); + +test('Test DLQ when existing Queue Provided', () => { + const stack = new Stack(); + + const existingQueue = new sqs.Queue(stack, 'test-queue'); + const buildDlqProps: defaults.BuildDeadLetterQueueProps = { + existingQueueObj: existingQueue, + }; + + const returnedQueueu = defaults.buildDeadLetterQueue(stack, buildDlqProps); + + expect(returnedQueueu).toBeUndefined(); + expect(stack).toCountResources("AWS::SQS::Queue", 1); +}); + +test('Test DLQ with all defaults', () => { + const stack = new Stack(); + + buildDeadLetterQueue(stack, {}); + expect(stack).toHaveResourceLike("AWS::SQS::Queue", { + KmsMasterKeyId: "alias/aws/sqs" + }); +}); + +test("Test DLQ with a provided properties", () => { + const stack = new Stack(); + const testQueueName = "test-unique252"; + + const returnedQueue = buildDeadLetterQueue(stack, { + deadLetterQueueProps: { + queueName: testQueueName, + }, + }); + expect(stack).toHaveResourceLike("AWS::SQS::Queue", { + QueueName: testQueueName, + }); + expect(returnedQueue).toBeDefined(); +}); + +test('Test DLQ with a provided maxReceiveCount', () => { + const stack = new Stack(); + const testMaxReceiveCount = 31; + + const dlqInterface = buildDeadLetterQueue(stack, { + maxReceiveCount: testMaxReceiveCount + }); + expect(dlqInterface?.maxReceiveCount).toEqual(testMaxReceiveCount); +}); + +test('Test returning an existing Queue', () => { + const stack = new Stack(); + const testQueueName = 'existing-queue'; + + const existingQueue = new sqs.Queue(stack, 'test-queue', { + queueName: testQueueName + }); + + const [returnedQueue] = defaults.buildQueue(stack, 'newQueue', { + existingQueueObj: existingQueue + }); + + expect(stack).toHaveResourceLike("AWS::SQS::Queue", { + QueueName: testQueueName, + }); + expect(existingQueue.queueName).toEqual(returnedQueue.queueName); +}); + +test('Test creating a queue with a DLQ', () => { + const stack = new Stack(); + + const dlqInterface = buildDeadLetterQueue(stack, {}); + + const [newQueue] = buildQueue(stack, 'new-queue', { + deadLetterQueue: dlqInterface + }); + + expect(stack).toCountResources("AWS::SQS::Queue", 2); + expect(newQueue).toBeDefined(); + expect(newQueue.deadLetterQueue).toBeDefined(); +}); + +test('Test creating a FIFO queue', () => { + const stack = new Stack(); + + const [newFifoQueue] = buildQueue(stack, 'new-queue', { + queueProps: { + fifo: true + } + }); + + expect(stack).toHaveResourceLike("AWS::SQS::Queue", { + FifoQueue: true + }); + expect(newFifoQueue.fifo).toBe(true); +}); diff --git a/source/tools/cdk-integ-tools/LICENSE b/source/tools/cdk-integ-tools/LICENSE index 28e4bdcec..82ad00bb0 100644 --- a/source/tools/cdk-integ-tools/LICENSE +++ b/source/tools/cdk-integ-tools/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + Copyright 2018-2022 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. diff --git a/source/tools/cdk-integ-tools/NOTICE b/source/tools/cdk-integ-tools/NOTICE index 5fc382692..1b7adbb89 100644 --- a/source/tools/cdk-integ-tools/NOTICE +++ b/source/tools/cdk-integ-tools/NOTICE @@ -1,2 +1,2 @@ AWS Cloud Development Kit (AWS CDK) -Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/source/use_cases/aws-custom-glue-etl/stream-producer/generate_data.py b/source/use_cases/aws-custom-glue-etl/stream-producer/generate_data.py index 8ecfb3b1d..2a4054587 100644 --- a/source/use_cases/aws-custom-glue-etl/stream-producer/generate_data.py +++ b/source/use_cases/aws-custom-glue-etl/stream-producer/generate_data.py @@ -1,5 +1,5 @@ """ - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/README.md b/source/use_cases/aws-restaurant-management-demo/README.md index fa5801303..b6ed8f932 100644 --- a/source/use_cases/aws-restaurant-management-demo/README.md +++ b/source/use_cases/aws-restaurant-management-demo/README.md @@ -128,4 +128,4 @@ The `cdk.json` file tells the CDK Toolkit how to execute your app. ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/use_cases/aws-restaurant-management-demo/SAMPLE_REQUESTS.md b/source/use_cases/aws-restaurant-management-demo/SAMPLE_REQUESTS.md index ebbf24bc3..70d9fac37 100644 --- a/source/use_cases/aws-restaurant-management-demo/SAMPLE_REQUESTS.md +++ b/source/use_cases/aws-restaurant-management-demo/SAMPLE_REQUESTS.md @@ -64,4 +64,4 @@ for calculating tips, archiving orders, and creating end-of-day reports. *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/kitchen-staff/complete-order/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/kitchen-staff/complete-order/index.js index 8f09ff1a4..5ac4c2e31 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/kitchen-staff/complete-order/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/kitchen-staff/complete-order/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/kitchen-staff/get-open-orders/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/kitchen-staff/get-open-orders/index.js index 7a8867f8f..38a519fd6 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/kitchen-staff/get-open-orders/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/kitchen-staff/get-open-orders/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/layer/db-access.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/layer/db-access.js index 1995ed5e9..87b01b560 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/layer/db-access.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/layer/db-access.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/archive-orders/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/archive-orders/index.js index 3e8eca6e1..9d3113539 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/archive-orders/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/archive-orders/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/calculate-tips/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/calculate-tips/index.js index faeec6acd..a19491975 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/calculate-tips/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/calculate-tips/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/check-late-orders/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/check-late-orders/index.js index a49859f3a..22b9d25bf 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/check-late-orders/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/check-late-orders/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/close-out-service/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/close-out-service/index.js index f95eb3a4f..28777cf8e 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/close-out-service/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/close-out-service/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/create-report/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/create-report/index.js index ddd64d8a2..8661e987d 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/create-report/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/create-report/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/get-all-orders/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/get-all-orders/index.js index 707e6a1af..94bb4c96f 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/get-all-orders/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/get-all-orders/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/get-report/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/get-report/index.js index 5babf8a96..dd5d58aef 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/get-report/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/manager/get-report/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/service-staff/create-order/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/service-staff/create-order/index.js index 0136818f4..d1d10a763 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/service-staff/create-order/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/service-staff/create-order/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-restaurant-management-demo/lib/lambda/service-staff/process-payment/index.js b/source/use_cases/aws-restaurant-management-demo/lib/lambda/service-staff/process-payment/index.js index e077fb9ca..78ed8fbca 100644 --- a/source/use_cases/aws-restaurant-management-demo/lib/lambda/service-staff/process-payment/index.js +++ b/source/use_cases/aws-restaurant-management-demo/lib/lambda/service-staff/process-payment/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2022 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 diff --git a/source/use_cases/aws-s3-static-website/README.md b/source/use_cases/aws-s3-static-website/README.md index 809b29aaf..9b0af136d 100644 --- a/source/use_cases/aws-s3-static-website/README.md +++ b/source/use_cases/aws-s3-static-website/README.md @@ -32,4 +32,4 @@ cdk deploy After the stack is deployed successfully, go to the Outputs tab in AWS Cloudformation console, it should show the 'websiteURL', click on the link and enjoy the Wile Rydes Unicorn website. *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/use_cases/aws-serverless-image-handler/README.md b/source/use_cases/aws-serverless-image-handler/README.md index 1101f0d0a..148402371 100644 --- a/source/use_cases/aws-serverless-image-handler/README.md +++ b/source/use_cases/aws-serverless-image-handler/README.md @@ -54,4 +54,4 @@ new ServerlessImageHandler(this, 'ServerlessImageHandlerPattern', { ![Architecture Diagram](architecture.png) *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/image-handler.js b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/image-handler.js index 3d5d2f0ca..d75bc010c 100755 --- a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/image-handler.js +++ b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/image-handler.js @@ -1,5 +1,5 @@ /********************************************************************************************************************* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * Copyright 2022 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 * diff --git a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/image-request.js b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/image-request.js index 216408faf..06d26e8e6 100755 --- a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/image-request.js +++ b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/image-request.js @@ -1,5 +1,5 @@ /********************************************************************************************************************* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * Copyright 2022 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 * diff --git a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/index.js b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/index.js index b67403c4e..e8ae14c5d 100755 --- a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/index.js +++ b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/index.js @@ -1,5 +1,5 @@ /********************************************************************************************************************* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * Copyright 2022 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 * diff --git a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-image-handler.js b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-image-handler.js index 569a8607e..d2094ea5c 100755 --- a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-image-handler.js +++ b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-image-handler.js @@ -1,5 +1,5 @@ /********************************************************************************************************************* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * Copyright 2022 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 * diff --git a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-image-request.js b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-image-request.js index 80da813f4..d870bfdf7 100755 --- a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-image-request.js +++ b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-image-request.js @@ -1,5 +1,5 @@ /********************************************************************************************************************* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * Copyright 2022 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 * diff --git a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-thumbor-mapping.js b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-thumbor-mapping.js index 52a15b250..72f0dead2 100755 --- a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-thumbor-mapping.js +++ b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/test/test-thumbor-mapping.js @@ -1,5 +1,5 @@ /********************************************************************************************************************* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * Copyright 2022 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 * diff --git a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/thumbor-mapping.js b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/thumbor-mapping.js index 924c8760d..b1e7271da 100755 --- a/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/thumbor-mapping.js +++ b/source/use_cases/aws-serverless-image-handler/lib/lambda/image-handler/thumbor-mapping.js @@ -1,5 +1,5 @@ /********************************************************************************************************************* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * Copyright 2022 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 * diff --git a/source/use_cases/aws-serverless-web-app/README.md b/source/use_cases/aws-serverless-web-app/README.md index a1674e870..7a79c5325 100644 --- a/source/use_cases/aws-serverless-web-app/README.md +++ b/source/use_cases/aws-serverless-web-app/README.md @@ -45,4 +45,4 @@ After the stack is deployed successfully, go to the Outputs tab in AWS Cloudform *** -© Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file +© Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file From c3b0dbab1f9625eadea5510a6279cc65fb2ce6e5 Mon Sep 17 00:00:00 2001 From: AWS Solutions Constructs Team <67720492+aws-solutions-constructs-team@users.noreply.github.com> Date: Fri, 13 May 2022 20:01:10 -0400 Subject: [PATCH 2/2] chore(release): 1.156.0 (#704) * chore(release): 2.7.0 * chore(changelog): Updated CHANGELOG.v2.md * feat(aws-fargate-stepfunctions): new construct (#677) * created README.md * removed arn env var prop and fixed state machine doc comments * made createCloudWatchAlarms prop optional * created new construct * fixed README typo * refactored test to single concept design * updated default for vpcProps * Update copyright year to 2022 (#693) Skipping review, only copyright messages have been changed. * fix(Test Coverage): Improve test coverage of 2 core files (#691) * Added additional tests * More coverage based on review * chore(Improve documentation): Environment Variable descriptions (#692) * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update Environment Variable documenation/comments * Results of self-review * Response to review * Review 2 * Review 3 * Update DESIGN_GUIDELINES.md * Pin @types/prettier 2.6.0 til 2.6.1 issue resolved (#698) No one is available to review and this is time sensitive. The nature of the change makes any review rather perfunctory as it a single line added to the package.json file * chore(release): 1.155.0 (#699) (#701) * chore(release): 2.7.0 * chore(changelog): Updated CHANGELOG.v2.md * feat(aws-fargate-stepfunctions): new construct (#677) * created README.md * removed arn env var prop and fixed state machine doc comments * made createCloudWatchAlarms prop optional * created new construct * fixed README typo * refactored test to single concept design * updated default for vpcProps * Update copyright year to 2022 (#693) Skipping review, only copyright messages have been changed. * fix(Test Coverage): Improve test coverage of 2 core files (#691) * Added additional tests * More coverage based on review * chore(Improve documentation): Environment Variable descriptions (#692) * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update Environment Variable documenation/comments * Results of self-review * Response to review * Review 2 * Review 3 * Update DESIGN_GUIDELINES.md * Pin @types/prettier 2.6.0 til 2.6.1 issue resolved (#698) No one is available to review and this is time sensitive. The nature of the change makes any review rather perfunctory as it a single line added to the package.json file * chore(release): 1.155.0 * chore(changelog): Updated CHANGELOG.md * chore(changelog): Updated CHANGELOG.md * Refresh to accomodate CDK changes * Align CDK V2 version * Align CDK Versions * Align CDK Versions Co-authored-by: biffgaut <78155736+biffgaut@users.noreply.github.com> Co-authored-by: mickychetta <45010053+mickychetta@users.noreply.github.com> Co-authored-by: biffgaut <78155736+biffgaut@users.noreply.github.com> Co-authored-by: mickychetta <45010053+mickychetta@users.noreply.github.com> * Expedited update to address @types/prettier versioning issue. * chore(release): 1.156.0 * chore(changelog): Updated CHANGELOG.md Co-authored-by: biffgaut <78155736+biffgaut@users.noreply.github.com> Co-authored-by: mickychetta <45010053+mickychetta@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ source/lerna.json | 2 +- .../patterns/@aws-solutions-constructs/core/package.json | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ece77b38..ae16501b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.156.0](https://github.com/awslabs/aws-solutions-constructs/compare/v2.7.0...v1.156.0) (2022-05-13) + +### Features + +* Upgraded all patterns to CDK v1.156.0 +* Pinned @types/prettier to 2.6.0 in core + ## [1.155.0](https://github.com/awslabs/aws-solutions-constructs/compare/v2.7.0...v1.155.0) (2022-05-13) * Upgraded all patterns to CDK v1.155.0 diff --git a/source/lerna.json b/source/lerna.json index 403b443c1..96faf8afb 100644 --- a/source/lerna.json +++ b/source/lerna.json @@ -6,5 +6,5 @@ "./patterns/@aws-solutions-constructs/*" ], "rejectCycles": "true", - "version": "1.155.0" + "version": "1.156.0" } diff --git a/source/patterns/@aws-solutions-constructs/core/package.json b/source/patterns/@aws-solutions-constructs/core/package.json index 55c416e5e..c5117c973 100644 --- a/source/patterns/@aws-solutions-constructs/core/package.json +++ b/source/patterns/@aws-solutions-constructs/core/package.json @@ -97,6 +97,7 @@ "@types/deep-diff": "^1.0.0", "@types/npmlog": "^4.1.2", "@aws-cdk/assert": "0.0.0", + "@types/prettier": "2.6.0", "@types/jest": "^27.4.0", "@types/node": "^10.3.0" }, @@ -153,4 +154,4 @@ "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/aws-wafv2": "0.0.0" } -} \ No newline at end of file +}