diff --git a/.viperlightignore b/.viperlightignore index d1c37730c..d1f0f81f1 100644 --- a/.viperlightignore +++ b/.viperlightignore @@ -19,7 +19,7 @@ source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.apigatew source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.expected.json:179 source/tools/cdk-integ-tools/package-lock.json:373 source/patterns/@aws-solutions-constructs/core/test/step-function-helper.test.js:115 -source/patterns/@aws-solutions-constructs/core/test/lambda-func.test.ts:277 +source/patterns/@aws-solutions-constructs/core/test/lambda-helper.test.ts:296 source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts:102 source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts:219 source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts:185 diff --git a/CHANGELOG.md b/CHANGELOG.md index 98c9532f4..8d37043e0 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.76.0 (2020-12-14) + +### Changed +- Upgraded all patterns to CDK v1.76.0 +- Added ESLint rule to enfore 2 space indentation +- Updated `aws-lambda-sqs` to support for VPC + ## 1.75.0 (2020-12-03) ### Changed diff --git a/source/lerna.json b/source/lerna.json index cea7caf3a..a728d3683 100644 --- a/source/lerna.json +++ b/source/lerna.json @@ -6,5 +6,5 @@ "./patterns/@aws-solutions-constructs/*" ], "rejectCycles": "true", - "version": "1.75.0" + "version": "1.76.0" } diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/apigateway-dynamodb.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/apigateway-dynamodb.test.ts index 0df171b1d..cb80f970e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/apigateway-dynamodb.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/apigateway-dynamodb.test.ts @@ -20,208 +20,208 @@ import { AttributeType } from "@aws-cdk/aws-dynamodb"; import * as api from "@aws-cdk/aws-apigateway"; test('snapshot test ApiGatewayToDynamoDB default params', () => { - const stack = new Stack(); - const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = {}; - new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb-default', apiGatewayToDynamoDBProps); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = {}; + new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb-default', apiGatewayToDynamoDBProps); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); test('check properties', () => { - const stack = new Stack(); - const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = {}; - const construct = new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb-default', apiGatewayToDynamoDBProps); - - expect(construct.dynamoTable !== null); - expect(construct.apiGateway !== null); - expect(construct.apiGatewayRole !== null); - expect(construct.apiGatewayCloudWatchRole !== null); - expect(construct.apiGatewayLogGroup !== null); + const stack = new Stack(); + const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = {}; + const construct = new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb-default', apiGatewayToDynamoDBProps); + + expect(construct.dynamoTable !== null); + expect(construct.apiGateway !== null); + expect(construct.apiGatewayRole !== null); + expect(construct.apiGatewayCloudWatchRole !== null); + expect(construct.apiGatewayLogGroup !== null); }); test('check allow CRUD operations', () => { - const stack = new Stack(); - const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = { - allowReadOperation: true, - allowCreateOperation: true, - createRequestTemplate: "{}", - allowDeleteOperation: true, - allowUpdateOperation: true, - updateRequestTemplate: "{}" - }; - new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', apiGatewayToDynamoDBProps); - - expect(stack).toHaveResource("AWS::IAM::Policy", { - PolicyDocument: { - Statement: [ - { - Action: "dynamodb:PutItem", - Effect: "Allow", - Resource: { - "Fn::GetAtt": [ - "testapigatewaydynamodbDynamoTableEEE3F463", - "Arn" - ] - } - }, - { - Action: "dynamodb:Query", - Effect: "Allow", - Resource: { - "Fn::GetAtt": [ - "testapigatewaydynamodbDynamoTableEEE3F463", - "Arn" - ] - } - }, - { - Action: "dynamodb:UpdateItem", - Effect: "Allow", - Resource: { - "Fn::GetAtt": [ - "testapigatewaydynamodbDynamoTableEEE3F463", - "Arn" - ] - } - }, - { - Action: "dynamodb:DeleteItem", - Effect: "Allow", - Resource: { - "Fn::GetAtt": [ - "testapigatewaydynamodbDynamoTableEEE3F463", - "Arn" - ] - } - } - ], - Version: "2012-10-17" + const stack = new Stack(); + const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = { + allowReadOperation: true, + allowCreateOperation: true, + createRequestTemplate: "{}", + allowDeleteOperation: true, + allowUpdateOperation: true, + updateRequestTemplate: "{}" + }; + new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', apiGatewayToDynamoDBProps); + + expect(stack).toHaveResource("AWS::IAM::Policy", { + PolicyDocument: { + Statement: [ + { + Action: "dynamodb:PutItem", + Effect: "Allow", + Resource: { + "Fn::GetAtt": [ + "testapigatewaydynamodbDynamoTableEEE3F463", + "Arn" + ] + } }, - PolicyName: "testapigatewaydynamodbapigatewayroleDefaultPolicy43AC565D", - Roles: [ - { - Ref: "testapigatewaydynamodbapigatewayrole961B19C4" - } - ] - }); - - expect(stack).toHaveResource("AWS::ApiGateway::Method", { - HttpMethod: "GET", - AuthorizationType: "AWS_IAM" - }); - - expect(stack).toHaveResource("AWS::ApiGateway::Method", { - HttpMethod: "POST", - AuthorizationType: "AWS_IAM" - }); - - expect(stack).toHaveResource("AWS::ApiGateway::Method", { - HttpMethod: "PUT", - AuthorizationType: "AWS_IAM" - }); - - expect(stack).toHaveResource("AWS::ApiGateway::Method", { - HttpMethod: "DELETE", - AuthorizationType: "AWS_IAM" - }); - - expect(stack).toHaveResource("AWS::ApiGateway::Resource", { - PathPart: "{id}", - }); + { + Action: "dynamodb:Query", + Effect: "Allow", + Resource: { + "Fn::GetAtt": [ + "testapigatewaydynamodbDynamoTableEEE3F463", + "Arn" + ] + } + }, + { + Action: "dynamodb:UpdateItem", + Effect: "Allow", + Resource: { + "Fn::GetAtt": [ + "testapigatewaydynamodbDynamoTableEEE3F463", + "Arn" + ] + } + }, + { + Action: "dynamodb:DeleteItem", + Effect: "Allow", + Resource: { + "Fn::GetAtt": [ + "testapigatewaydynamodbDynamoTableEEE3F463", + "Arn" + ] + } + } + ], + Version: "2012-10-17" + }, + PolicyName: "testapigatewaydynamodbapigatewayroleDefaultPolicy43AC565D", + Roles: [ + { + Ref: "testapigatewaydynamodbapigatewayrole961B19C4" + } + ] + }); + + expect(stack).toHaveResource("AWS::ApiGateway::Method", { + HttpMethod: "GET", + AuthorizationType: "AWS_IAM" + }); + + expect(stack).toHaveResource("AWS::ApiGateway::Method", { + HttpMethod: "POST", + AuthorizationType: "AWS_IAM" + }); + + expect(stack).toHaveResource("AWS::ApiGateway::Method", { + HttpMethod: "PUT", + AuthorizationType: "AWS_IAM" + }); + + expect(stack).toHaveResource("AWS::ApiGateway::Method", { + HttpMethod: "DELETE", + AuthorizationType: "AWS_IAM" + }); + + expect(stack).toHaveResource("AWS::ApiGateway::Resource", { + PathPart: "{id}", + }); }); test('check allow read and update only', () => { - const stack = new Stack(); - const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = { - allowUpdateOperation: true, - updateRequestTemplate: "{}" - }; - new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', apiGatewayToDynamoDBProps); - - expect(stack).toHaveResource("AWS::IAM::Policy", { - PolicyDocument: { - Statement: [ - { - Action: "dynamodb:Query", - Effect: "Allow", - Resource: { - "Fn::GetAtt": [ - "testapigatewaydynamodbDynamoTableEEE3F463", - "Arn" - ] - } - }, - { - Action: "dynamodb:UpdateItem", - Effect: "Allow", - Resource: { - "Fn::GetAtt": [ - "testapigatewaydynamodbDynamoTableEEE3F463", - "Arn" - ] - } - } - ], - Version: "2012-10-17" + const stack = new Stack(); + const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = { + allowUpdateOperation: true, + updateRequestTemplate: "{}" + }; + new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', apiGatewayToDynamoDBProps); + + expect(stack).toHaveResource("AWS::IAM::Policy", { + PolicyDocument: { + Statement: [ + { + Action: "dynamodb:Query", + Effect: "Allow", + Resource: { + "Fn::GetAtt": [ + "testapigatewaydynamodbDynamoTableEEE3F463", + "Arn" + ] + } }, - PolicyName: "testapigatewaydynamodbapigatewayroleDefaultPolicy43AC565D", - Roles: [ - { - Ref: "testapigatewaydynamodbapigatewayrole961B19C4" - } - ] - }); - - expect(stack).toHaveResource("AWS::ApiGateway::Method", { - HttpMethod: "GET", - AuthorizationType: "AWS_IAM" - }); + { + Action: "dynamodb:UpdateItem", + Effect: "Allow", + Resource: { + "Fn::GetAtt": [ + "testapigatewaydynamodbDynamoTableEEE3F463", + "Arn" + ] + } + } + ], + Version: "2012-10-17" + }, + PolicyName: "testapigatewaydynamodbapigatewayroleDefaultPolicy43AC565D", + Roles: [ + { + Ref: "testapigatewaydynamodbapigatewayrole961B19C4" + } + ] + }); + + expect(stack).toHaveResource("AWS::ApiGateway::Method", { + HttpMethod: "GET", + AuthorizationType: "AWS_IAM" + }); }); test('check using custom partition key for dynamodb', () => { - const stack = new Stack(); - const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = { - dynamoTableProps: { - partitionKey: { - name: 'page_id', - type: AttributeType.STRING - } - } - }; - new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', apiGatewayToDynamoDBProps); - - expect(stack).toHaveResource("AWS::ApiGateway::Resource", { - PathPart: "{page_id}", - }); + const stack = new Stack(); + const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = { + dynamoTableProps: { + partitionKey: { + name: 'page_id', + type: AttributeType.STRING + } + } + }; + new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', apiGatewayToDynamoDBProps); + + expect(stack).toHaveResource("AWS::ApiGateway::Resource", { + PathPart: "{page_id}", + }); }); test('override apiGatewayProps for api gateway', () => { - const stack = new Stack(); - const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = { - apiGatewayProps: { - description: 'This is a sample description for api gateway' - } - }; - new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', apiGatewayToDynamoDBProps); - - expect(stack).toHaveResource("AWS::ApiGateway::RestApi", { - Description: "This is a sample description for api gateway" - }); + const stack = new Stack(); + const apiGatewayToDynamoDBProps: ApiGatewayToDynamoDBProps = { + apiGatewayProps: { + description: 'This is a sample description for api gateway' + } + }; + new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', apiGatewayToDynamoDBProps); + + expect(stack).toHaveResource("AWS::ApiGateway::RestApi", { + Description: "This is a sample description for api gateway" + }); }); test('Test deployment ApiGateway AuthorizationType override', () => { - const stack = new Stack(); - new ApiGatewayToDynamoDB(stack, 'api-gateway-dynamodb', { - apiGatewayProps: { - defaultMethodOptions: { - authorizationType: api.AuthorizationType.NONE - } - } - }); - - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "GET", - AuthorizationType: "NONE" - }); - }); \ No newline at end of file + const stack = new Stack(); + new ApiGatewayToDynamoDB(stack, 'api-gateway-dynamodb', { + apiGatewayProps: { + defaultMethodOptions: { + authorizationType: api.AuthorizationType.NONE + } + } + }); + + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "GET", + AuthorizationType: "NONE" + }); +}); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/integ.apigateway-dynamodb-CRUD.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/integ.apigateway-dynamodb-CRUD.ts index 3ed061504..532ee869e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/integ.apigateway-dynamodb-CRUD.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/test/integ.apigateway-dynamodb-CRUD.ts @@ -22,12 +22,12 @@ stack.templateOptions.description = 'Integration Test for aws-apigateway-dynamod // Definitions const props: ApiGatewayToDynamoDBProps = { - allowReadOperation: true, - allowCreateOperation: true, - allowDeleteOperation: true, - allowUpdateOperation: true, - createRequestTemplate: "{\r\n \"TableName\": \"${Table}\",\r\n \"Item\": {\r\n \"id\": {\r\n \"S\": \"$input.path('$.id')\"\r\n },\r\n \"EventCount\": {\r\n \"N\": \"$input.path('$.EventCount')\"\r\n },\r\n \"Message\": {\r\n \"S\": \"$input.path('$.Message')\"\r\n }\r\n }\r\n}", - updateRequestTemplate: "{\r\n \"TableName\": \"${Table}\",\r\n \"Key\": {\r\n \"id\": {\r\n \"S\": \"$input.path('$.id')\"\r\n }\r\n },\r\n \"ExpressionAttributeValues\": {\r\n \":event_count\": {\r\n \"N\": \"$input.path('$.EventCount')\"\r\n },\r\n \":message\": {\r\n \"S\": \"$input.path('$.Message')\"\r\n }\r\n },\r\n \"UpdateExpression\": \"ADD EventCount :event_count SET Message = :message\",\r\n \"ReturnValues\": \"ALL_NEW\"\r\n}" + allowReadOperation: true, + allowCreateOperation: true, + allowDeleteOperation: true, + allowUpdateOperation: true, + createRequestTemplate: "{\r\n \"TableName\": \"${Table}\",\r\n \"Item\": {\r\n \"id\": {\r\n \"S\": \"$input.path('$.id')\"\r\n },\r\n \"EventCount\": {\r\n \"N\": \"$input.path('$.EventCount')\"\r\n },\r\n \"Message\": {\r\n \"S\": \"$input.path('$.Message')\"\r\n }\r\n }\r\n}", + updateRequestTemplate: "{\r\n \"TableName\": \"${Table}\",\r\n \"Key\": {\r\n \"id\": {\r\n \"S\": \"$input.path('$.id')\"\r\n }\r\n },\r\n \"ExpressionAttributeValues\": {\r\n \":event_count\": {\r\n \"N\": \"$input.path('$.EventCount')\"\r\n },\r\n \":message\": {\r\n \"S\": \"$input.path('$.Message')\"\r\n }\r\n },\r\n \"UpdateExpression\": \"ADD EventCount :event_count SET Message = :message\",\r\n \"ReturnValues\": \"ALL_NEW\"\r\n}" }; new ApiGatewayToDynamoDB(stack, 'test-api-gateway-dynamodb', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/lib/index.ts index 66812e0fe..024c12087 100755 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/lib/index.ts @@ -73,121 +73,121 @@ export class ApiGatewayToIot extends Construct { * @access public */ constructor(scope: Construct, id: string, props: ApiGatewayToIotProps) { - super(scope, id); + super(scope, id); - // Assignment to local member variables to make these available to all member methods of the class. - // (Split the string just in case user supplies fully qualified endpoint eg. ab123cdefghij4l-ats.iot.ap-south-1.amazonaws.com) - this.iotEndpoint = props.iotEndpoint.trim().split('.')[0]; + // Assignment to local member variables to make these available to all member methods of the class. + // (Split the string just in case user supplies fully qualified endpoint eg. ab123cdefghij4l-ats.iot.ap-south-1.amazonaws.com) + this.iotEndpoint = props.iotEndpoint.trim().split('.')[0]; - // Mandatory params check - if (!this.iotEndpoint || this.iotEndpoint.length < 0) { - throw new Error('specify a valid iotEndpoint'); - } - - // Add additional params to the apiGatewayProps - let extraApiGwProps = { - binaryMediaTypes: ['application/octet-stream'], - defaultMethodOptions: { - apiKeyRequired: props.apiGatewayCreateApiKey - } - }; + // Mandatory params check + if (!this.iotEndpoint || this.iotEndpoint.length < 0) { + throw new Error('specify a valid iotEndpoint'); + } - // If apiGatewayProps are specified override the extra Api Gateway properties - if (props.apiGatewayProps) { - extraApiGwProps = defaults.overrideProps(props.apiGatewayProps, extraApiGwProps); + // Add additional params to the apiGatewayProps + let extraApiGwProps = { + binaryMediaTypes: ['application/octet-stream'], + defaultMethodOptions: { + apiKeyRequired: props.apiGatewayCreateApiKey } + }; + + // If apiGatewayProps are specified override the extra Api Gateway properties + if (props.apiGatewayProps) { + extraApiGwProps = defaults.overrideProps(props.apiGatewayProps, extraApiGwProps); + } - // Check whether an API Gateway execution role is specified? - if (props.apiGatewayExecutionRole) { - this.apiGatewayRole = props.apiGatewayExecutionRole; - } else { - // JSON that will be used for policy document - const policyJSON = { - Version: "2012-10-17", - Statement: [ - { - Action: [ - "iot:UpdateThingShadow" - ], - Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:thing/*`, - Effect: "Allow" - }, - { - Action: [ - "iot:Publish" - ], - Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/*`, - Effect: "Allow" - } - ] - }; + // Check whether an API Gateway execution role is specified? + if (props.apiGatewayExecutionRole) { + this.apiGatewayRole = props.apiGatewayExecutionRole; + } else { + // JSON that will be used for policy document + const policyJSON = { + Version: "2012-10-17", + Statement: [ + { + Action: [ + "iot:UpdateThingShadow" + ], + Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:thing/*`, + Effect: "Allow" + }, + { + Action: [ + "iot:Publish" + ], + Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/*`, + Effect: "Allow" + } + ] + }; - // Create a policy document - const policyDocument: iam.PolicyDocument = iam.PolicyDocument.fromJson(policyJSON); + // Create a policy document + const policyDocument: iam.PolicyDocument = iam.PolicyDocument.fromJson(policyJSON); - // Props for IAM Role - const iamRoleProps: iam.RoleProps = { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), - path: '/', - inlinePolicies: {awsapigatewayiotpolicy: policyDocument} - }; + // Props for IAM Role + const iamRoleProps: iam.RoleProps = { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + path: '/', + inlinePolicies: {awsapigatewayiotpolicy: policyDocument} + }; // Create a policy that overrides the default policy that gets created with the construct - this.apiGatewayRole = new iam.Role(this, 'apigateway-iot-role', iamRoleProps); - } + this.apiGatewayRole = new iam.Role(this, 'apigateway-iot-role', iamRoleProps); + } - // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, - this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, extraApiGwProps); + // Setup the API Gateway + [this.apiGateway, this.apiGatewayCloudWatchRole, + this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, extraApiGwProps); - // Validate the Query Params - const requestValidatorProps: api.RequestValidatorProps = { - restApi: this.apiGateway, - validateRequestBody: false, - validateRequestParameters: true - }; - this.requestValidator = new api.RequestValidator(this, `aws-apigateway-iot-req-val`, requestValidatorProps); + // Validate the Query Params + const requestValidatorProps: api.RequestValidatorProps = { + restApi: this.apiGateway, + validateRequestBody: false, + validateRequestParameters: true + }; + this.requestValidator = new api.RequestValidator(this, `aws-apigateway-iot-req-val`, requestValidatorProps); - // Create a resource for messages '/message' - const msgResource: api.IResource = this.apiGateway.root.addResource('message'); + // Create a resource for messages '/message' + const msgResource: api.IResource = this.apiGateway.root.addResource('message'); - // Create resources from '/message/{topic-level-1}' through '/message/{topic-level-1}/..../{topic-level-7}' - let topicPath = 'topics'; - let parentNode = msgResource; - let integParams = {}; - let methodParams = {}; - for (let pathLevel = 1; pathLevel <= this.topicNestingLevel; pathLevel++) { - const topicName = `topic-level-${pathLevel}`; - const topicResource: api.IResource = parentNode.addResource(`{${topicName}}`); - const integReqParam = JSON.parse(`{"integration.request.path.${topicName}": "method.request.path.${topicName}"}`); - const methodReqParam = JSON.parse(`{"method.request.path.${topicName}": true}`); - topicPath = `${topicPath}/{${topicName}}`; - integParams = Object.assign(integParams, integReqParam); - methodParams = Object.assign(methodParams, methodReqParam); - this.addResourceMethod(topicResource, props, topicPath, integParams, methodParams); - parentNode = topicResource; - } + // Create resources from '/message/{topic-level-1}' through '/message/{topic-level-1}/..../{topic-level-7}' + let topicPath = 'topics'; + let parentNode = msgResource; + let integParams = {}; + let methodParams = {}; + for (let pathLevel = 1; pathLevel <= this.topicNestingLevel; pathLevel++) { + const topicName = `topic-level-${pathLevel}`; + const topicResource: api.IResource = parentNode.addResource(`{${topicName}}`); + const integReqParam = JSON.parse(`{"integration.request.path.${topicName}": "method.request.path.${topicName}"}`); + const methodReqParam = JSON.parse(`{"method.request.path.${topicName}": true}`); + topicPath = `${topicPath}/{${topicName}}`; + integParams = Object.assign(integParams, integReqParam); + methodParams = Object.assign(methodParams, methodReqParam); + this.addResourceMethod(topicResource, props, topicPath, integParams, methodParams); + parentNode = topicResource; + } - // Create a resource for shadow updates '/shadow' - const shadowResource: api.IResource = this.apiGateway.root.addResource('shadow'); + // Create a resource for shadow updates '/shadow' + const shadowResource: api.IResource = this.apiGateway.root.addResource('shadow'); - // Create resource '/shadow/{thingName}' - const defaultShadowResource: api.IResource = shadowResource.addResource('{thingName}'); - const shadowReqParams = {'integration.request.path.thingName': 'method.request.path.thingName'}; - const methodShadowReqParams = {'method.request.path.thingName': true}; - this.addResourceMethod(defaultShadowResource, props, 'things/{thingName}/shadow', - shadowReqParams, methodShadowReqParams); + // Create resource '/shadow/{thingName}' + const defaultShadowResource: api.IResource = shadowResource.addResource('{thingName}'); + const shadowReqParams = {'integration.request.path.thingName': 'method.request.path.thingName'}; + const methodShadowReqParams = {'method.request.path.thingName': true}; + this.addResourceMethod(defaultShadowResource, props, 'things/{thingName}/shadow', + shadowReqParams, methodShadowReqParams); - // Create resource '/shadow/{thingName}/{shadowName}' - const namedShadowResource: api.IResource = defaultShadowResource.addResource('{shadowName}'); - const namedShadowReqParams = Object.assign({ - 'integration.request.path.shadowName': 'method.request.path.shadowName'}, - shadowReqParams); - const methodNamedShadowReqParams = Object.assign({ - 'method.request.path.shadowName': true}, methodShadowReqParams); + // Create resource '/shadow/{thingName}/{shadowName}' + const namedShadowResource: api.IResource = defaultShadowResource.addResource('{shadowName}'); + const namedShadowReqParams = Object.assign({ + 'integration.request.path.shadowName': 'method.request.path.shadowName'}, + shadowReqParams); + const methodNamedShadowReqParams = Object.assign({ + 'method.request.path.shadowName': true}, methodShadowReqParams); // For some reason path mapping to 'things/{thingName}/shadow/name/{shadowName}' results in 403 error, hence this shortcut - this.addResourceMethod(namedShadowResource, props, 'topics/$aws/things/{thingName}/shadow/name/{shadowName}/update', - namedShadowReqParams, methodNamedShadowReqParams); + this.addResourceMethod(namedShadowResource, props, 'topics/$aws/things/{thingName}/shadow/name/{shadowName}/update', + namedShadowReqParams, methodNamedShadowReqParams); } /** @@ -198,8 +198,8 @@ export class ApiGatewayToIot extends Construct { * @param methodReqParams request parameters at Method level */ private addResourceMethod(resource: api.IResource, props: ApiGatewayToIotProps, resourcePath: string, - integReqParams: {[key: string]: string}, - methodReqParams: {[key: string]: boolean}) { + integReqParams: {[key: string]: string}, + methodReqParams: {[key: string]: boolean}) { const integResp: api.IntegrationResponse[] = [ { statusCode: "200", @@ -271,10 +271,10 @@ export class ApiGatewayToIot extends Construct { const cfnMethod = apiMethod.node.findChild('Resource') as api.CfnMethod; cfnMethod.cfnOptions.metadata = { cfn_nag: { - rules_to_suppress: [{ - id: 'W59', - reason: 'When ApiKey is being created, we also set apikeyRequired to true, so techincally apiGateway still looks for apiKey even though user specified AuthorizationType to NONE' - }] + rules_to_suppress: [{ + id: 'W59', + reason: 'When ApiKey is being created, we also set apikeyRequired to true, so techincally apiGateway still looks for apiKey even though user specified AuthorizationType to NONE' + }] } }; } diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.defaultParams.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.defaultParams.ts index 914216712..bd591445a 100755 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.defaultParams.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.defaultParams.ts @@ -22,7 +22,7 @@ stack.templateOptions.description = 'Integration Test for aws-apigateway-iot wit // Definitions const props: ApiGatewayToIotProps = { - iotEndpoint: 'a1234567890123-ats', + iotEndpoint: 'a1234567890123-ats', }; new ApiGatewayToIot(stack, 'test-apigateway-iot', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.overrideParams.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.overrideParams.ts index b681ad3d2..401076b4f 100755 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.overrideParams.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.overrideParams.ts @@ -23,39 +23,39 @@ const stack = new cdk.Stack(app, 'test-apigateway-iot-overriden-params'); stack.templateOptions.description = 'Integration Test for aws-apigateway-iot with overriden params'; const apiGatewayProps = { - restApiName: 'RestApi-Regional', - description: 'Description for the Regional Rest Api', - endpointConfiguration: {types: [api.EndpointType.REGIONAL]}, - apiKeySourceType: api.ApiKeySourceType.HEADER, - defaultMethodOptions: { - authorizationType: api.AuthorizationType.NONE, - } + restApiName: 'RestApi-Regional', + description: 'Description for the Regional Rest Api', + endpointConfiguration: {types: [api.EndpointType.REGIONAL]}, + apiKeySourceType: api.ApiKeySourceType.HEADER, + defaultMethodOptions: { + authorizationType: api.AuthorizationType.NONE, + } }; const policyJSON = { - Version: "2012-10-17", - Statement: [ - { - Action: [ - "iot:UpdateThingShadow" - ], - Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:thing/*`, - Effect: "Allow" - }, - { - Action: [ - "iot:Publish" - ], - Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/*`, - Effect: "Allow" - } - ] + Version: "2012-10-17", + Statement: [ + { + Action: [ + "iot:UpdateThingShadow" + ], + Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:thing/*`, + Effect: "Allow" + }, + { + Action: [ + "iot:Publish" + ], + Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/*`, + Effect: "Allow" + } + ] }; const policyDocument: iam.PolicyDocument = iam.PolicyDocument.fromJson(policyJSON); const iamRoleProps: iam.RoleProps = { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), - path: '/', - inlinePolicies: {testPolicy: policyDocument} + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + path: '/', + inlinePolicies: {testPolicy: policyDocument} }; // Create a policy that overrides the default policy that gets created with the construct @@ -63,10 +63,10 @@ const apiGatewayExecutionRole: iam.Role = new iam.Role(stack, 'apigateway-iot-ro // Api gateway setup const props: ApiGatewayToIotProps = { - iotEndpoint: 'a1234567890123-ats', // `a1234567890123-ats`, - apiGatewayCreateApiKey: true, - apiGatewayExecutionRole, - apiGatewayProps + iotEndpoint: 'a1234567890123-ats', // `a1234567890123-ats`, + apiGatewayCreateApiKey: true, + apiGatewayExecutionRole, + apiGatewayProps }; // Instantiate construct diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.override_auth_api_keys.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.override_auth_api_keys.ts index e3f0206f0..92095419b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.override_auth_api_keys.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/integ.override_auth_api_keys.ts @@ -23,13 +23,13 @@ stack.templateOptions.description = 'Integration Test for aws-apigateway-iot wit // Definitions const props: ApiGatewayToIotProps = { - iotEndpoint: 'a1234567890123-ats', - apiGatewayCreateApiKey: true, - apiGatewayProps: { - defaultMethodOptions: { - authorizationType: AuthorizationType.NONE - } + iotEndpoint: 'a1234567890123-ats', + apiGatewayCreateApiKey: true, + apiGatewayProps: { + defaultMethodOptions: { + authorizationType: AuthorizationType.NONE } + } }; new ApiGatewayToIot(stack, 'test-apigateway-iot', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/test.apigateway-iot.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/test.apigateway-iot.test.ts index 162f577cc..ef4d3086d 100755 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/test.apigateway-iot.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-iot/test/test.apigateway-iot.test.ts @@ -23,14 +23,14 @@ import '@aws-cdk/assert/jest'; // Snapshot matching // -------------------------------------------------------------- test('Test for default Params snapshot match', () => { - // Initial Setup - const stack = new cdk.Stack(); - const props: ApiGatewayToIotProps = { - iotEndpoint: `a1234567890123-ats` - }; - new ApiGatewayToIot(stack, 'test-apigateway-iot-default-snapshot', props); - // Assertion - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Initial Setup + const stack = new cdk.Stack(); + const props: ApiGatewayToIotProps = { + iotEndpoint: `a1234567890123-ats` + }; + new ApiGatewayToIot(stack, 'test-apigateway-iot-default-snapshot', props); + // Assertion + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- @@ -40,7 +40,7 @@ test('Test for default Params construct props', () => { // Initial Setup const stack = new cdk.Stack(); const props: ApiGatewayToIotProps = { - iotEndpoint: `a1234567890123-ats` + iotEndpoint: `a1234567890123-ats` }; const construct = new ApiGatewayToIot(stack, 'test-apigateway-iot-default-params', props); // Assertion @@ -57,7 +57,7 @@ test('Test for default IAM Role', () => { // Initial Setup const stack = new cdk.Stack(); const props: ApiGatewayToIotProps = { - iotEndpoint: `a1234567890123-ats` + iotEndpoint: `a1234567890123-ats` }; new ApiGatewayToIot(stack, 'test-apigateway-iot-default-iam-role', props); // Check whether default IAM role is creted to access IoT core @@ -135,7 +135,7 @@ test('Test for default Params request validator', () => { // Initial Setup const stack = new cdk.Stack(); const props: ApiGatewayToIotProps = { - iotEndpoint: `a1234567890123-ats` + iotEndpoint: `a1234567890123-ats` }; new ApiGatewayToIot(stack, 'test-apigateway-iot-request-validator', props); // Assertion @@ -152,7 +152,7 @@ test('Test for default Params Integ Props and Method Props', () => { // Initial Setup const stack = new cdk.Stack(); const props: ApiGatewayToIotProps = { - iotEndpoint: `a1234567890123-ats` + iotEndpoint: `a1234567890123-ats` }; new ApiGatewayToIot(stack, 'test-apigateway-iot-integpros-methodprops', props); @@ -246,7 +246,7 @@ test('Test for valid iot enpoint', () => { // Initial Setup const stack = new cdk.Stack(); const props: ApiGatewayToIotProps = { - iotEndpoint: ' ' + iotEndpoint: ' ' }; const app = () => { @@ -264,8 +264,8 @@ test('Test for Binary Media types', () => { const stack = new cdk.Stack(); // Helper declaration new ApiGatewayToIot(stack, 'test-apigateway-iot-binaryMediaTypes', { - iotEndpoint: 'a1234567890123-ats' - } + iotEndpoint: 'a1234567890123-ats' + } ); // Assertion 1 expect(stack).toHaveResourceLike("AWS::ApiGateway::RestApi", { @@ -295,58 +295,58 @@ test('Test for multiple constructs usage', () => { // Check for ApiGateway Overriden Props Snapshot match // -------------------------------------------------------------- test('Test for overriden props snapshot', () => { - // Initial Setup - const stack = new cdk.Stack(); - const apiGatewayProps = { - restApiName: 'RestApi-Regional', - description: 'Description for the Regional Rest Api', - endpointConfiguration: {types: [api.EndpointType.REGIONAL]}, - apiKeySourceType: api.ApiKeySourceType.HEADER, - defaultMethodOptions: { - authorizationType: api.AuthorizationType.NONE, - } - }; + // Initial Setup + const stack = new cdk.Stack(); + const apiGatewayProps = { + restApiName: 'RestApi-Regional', + description: 'Description for the Regional Rest Api', + endpointConfiguration: {types: [api.EndpointType.REGIONAL]}, + apiKeySourceType: api.ApiKeySourceType.HEADER, + defaultMethodOptions: { + authorizationType: api.AuthorizationType.NONE, + } + }; - const policyJSON = { - Version: "2012-10-17", - Statement: [ - { - Action: [ - "iot:UpdateThingShadow" - ], - Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:thing/*`, - Effect: "Allow" - }, - { - Action: [ - "iot:Publish" - ], - Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/*`, - Effect: "Allow" - } - ] - }; - const policyDocument: iam.PolicyDocument = iam.PolicyDocument.fromJson(policyJSON); - const iamRoleProps: iam.RoleProps = { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), - path: '/', - inlinePolicies: {testPolicy: policyDocument} - }; + const policyJSON = { + Version: "2012-10-17", + Statement: [ + { + Action: [ + "iot:UpdateThingShadow" + ], + Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:thing/*`, + Effect: "Allow" + }, + { + Action: [ + "iot:Publish" + ], + Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/*`, + Effect: "Allow" + } + ] + }; + const policyDocument: iam.PolicyDocument = iam.PolicyDocument.fromJson(policyJSON); + const iamRoleProps: iam.RoleProps = { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + path: '/', + inlinePolicies: {testPolicy: policyDocument} + }; - // Create a policy that overrides the default policy that gets created with the construct - const apiGatewayExecutionRole: iam.Role = new iam.Role(stack, 'apigateway-iot-role', iamRoleProps); + // Create a policy that overrides the default policy that gets created with the construct + const apiGatewayExecutionRole: iam.Role = new iam.Role(stack, 'apigateway-iot-role', iamRoleProps); - // Api gateway setup - const props: ApiGatewayToIotProps = { - iotEndpoint: `a1234567890123-ats`, - apiGatewayCreateApiKey: true, - apiGatewayExecutionRole, - apiGatewayProps - }; - new ApiGatewayToIot(stack, 'test-apigateway-iot-overriden-params', props); + // Api gateway setup + const props: ApiGatewayToIotProps = { + iotEndpoint: `a1234567890123-ats`, + apiGatewayCreateApiKey: true, + apiGatewayExecutionRole, + apiGatewayProps + }; + new ApiGatewayToIot(stack, 'test-apigateway-iot-overriden-params', props); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- @@ -361,9 +361,9 @@ test('Test for Api Name and Desc', () => { }; // Helper declaration new ApiGatewayToIot(stack, 'test-apigateway-iot-name-desc', { - iotEndpoint: 'a1234567890123-ats', - apiGatewayProps - } + iotEndpoint: 'a1234567890123-ats', + apiGatewayProps + } ); // Assertion 1 expect(stack).toHaveResourceLike("AWS::ApiGateway::RestApi", { @@ -382,20 +382,20 @@ test('Test for overriden IAM Role', () => { const policyJSON = { Version: "2012-10-17", Statement: [ - { - Action: [ - "iot:UpdateThingShadow" - ], - Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:thing/mything1`, - Effect: "Allow" - }, - { - Action: [ - "iot:Publish" - ], - Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/topic-abc`, - Effect: "Allow" - } + { + Action: [ + "iot:UpdateThingShadow" + ], + Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:thing/mything1`, + Effect: "Allow" + }, + { + Action: [ + "iot:Publish" + ], + Resource: `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/topic-abc`, + Effect: "Allow" + } ] }; const policyDocument: iam.PolicyDocument = iam.PolicyDocument.fromJson(policyJSON); @@ -409,8 +409,8 @@ test('Test for overriden IAM Role', () => { const apiGatewayExecutionRole: iam.Role = new iam.Role(stack, 'apigateway-iot-role', iamRoleProps); const props: ApiGatewayToIotProps = { - iotEndpoint: `a1234567890123-ats`, - apiGatewayExecutionRole, + iotEndpoint: `a1234567890123-ats`, + apiGatewayExecutionRole, }; new ApiGatewayToIot(stack, 'test-apigateway-iot-overriden-iam-role', props); @@ -494,9 +494,9 @@ test('Test for APi Key Source', () => { // Helper declaration new ApiGatewayToIot(stack, 'test-apigateway-iot-api-key-source', { - iotEndpoint: 'a1234567890123-ats', - apiGatewayProps - } + iotEndpoint: 'a1234567890123-ats', + apiGatewayProps + } ); // Assertion 1 expect(stack).toHaveResourceLike("AWS::ApiGateway::RestApi", { @@ -548,18 +548,18 @@ test('Test for deployment ApiGateway AuthorizationType override', () => { const stack = new cdk.Stack(); // Helper declaration new ApiGatewayToIot(stack, 'test-apigateway-iot-auth-none', { - iotEndpoint: 'a1234567890123-ats', - apiGatewayProps: { - endpointConfiguration: { - types: [api.EndpointType.REGIONAL] - } + iotEndpoint: 'a1234567890123-ats', + apiGatewayProps: { + endpointConfiguration: { + types: [api.EndpointType.REGIONAL] } + } }); // Assertion 1 expect(stack).toHaveResourceLike("AWS::ApiGateway::RestApi", { EndpointConfiguration: { - Types: ["REGIONAL"] - } + Types: ["REGIONAL"] + } }); }); @@ -567,25 +567,25 @@ test('Test for deployment ApiGateway AuthorizationType override', () => { // Test deployment for override ApiGateway AuthorizationType to NONE // ----------------------------------------------------------------- test('Test for deployment ApiGateway AuthorizationType override', () => { - // Stack - const stack = new cdk.Stack(); - // Helper declaration - new ApiGatewayToIot(stack, 'test-apigateway-iot-override-auth', { - iotEndpoint: 'a1234567890123-ats', - apiGatewayProps: { - defaultMethodOptions: { - authorizationType: api.AuthorizationType.NONE - } - } - }); - // Assertion 1 - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "POST", - AuthorizationType: "NONE" - }); + // Stack + const stack = new cdk.Stack(); + // Helper declaration + new ApiGatewayToIot(stack, 'test-apigateway-iot-override-auth', { + iotEndpoint: 'a1234567890123-ats', + apiGatewayProps: { + defaultMethodOptions: { + authorizationType: api.AuthorizationType.NONE + } + } + }); + // Assertion 1 + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "POST", + AuthorizationType: "NONE" }); +}); - // ----------------------------------------------------------------- +// ----------------------------------------------------------------- // Test deployment for fully qualified iotEndpoint name // ----------------------------------------------------------------- test('Test for handling fully qualified iotEndpoint', () => { @@ -593,31 +593,31 @@ test('Test for handling fully qualified iotEndpoint', () => { const stack = new cdk.Stack(); // Helper declaration new ApiGatewayToIot(stack, 'test-apigateway-iot-override-auth', { - iotEndpoint: 'a1234567890123-ats.iot.ap-south-1.amazonaws.com', - apiGatewayProps: { - defaultMethodOptions: { - authorizationType: api.AuthorizationType.NONE - } + iotEndpoint: 'a1234567890123-ats.iot.ap-south-1.amazonaws.com', + apiGatewayProps: { + defaultMethodOptions: { + authorizationType: api.AuthorizationType.NONE } + } }); // Assertion 1 expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { Integration: { - Uri: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition" - }, - ":apigateway:", - { - Ref: "AWS::Region" - }, - ":a1234567890123-ats.iotdata:path/topics/{topic-level-1}/{topic-level-2}/{topic-level-3}" + Uri: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition" + }, + ":apigateway:", + { + Ref: "AWS::Region" + }, + ":a1234567890123-ats.iotdata:path/topics/{topic-level-1}/{topic-level-2}/{topic-level-3}" + ] ] - ] - } } + } } }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/lib/index.ts index 408d35aab..cdeb13b08 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/lib/index.ts @@ -101,132 +101,132 @@ export class ApiGatewayToKinesisStreams extends Construct { * @access public */ constructor(scope: Construct, id: string, props: ApiGatewayToKinesisStreamsProps) { - super(scope, id); - - // Setup the Kinesis stream - this.kinesisStream = defaults.buildKinesisStream(scope, { - existingStreamObj: props.existingStreamObj, - kinesisStreamProps: props.kinesisStreamProps - }); - - // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, props.apiGatewayProps); - - // Setup the API Gateway role - this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com') - }); - this.kinesisStream.grantWrite(this.apiGatewayRole); - - // Setup API Gateway methods - const requestValidator = this.apiGateway.addRequestValidator('request-validator', { - requestValidatorName: 'request-body-validator', - validateRequestBody: true - }); - - // PutRecord - const putRecordResource = this.apiGateway.root.addResource('record'); - defaults.addProxyMethodToApiResource({ - service: 'kinesis', - action: 'PutRecord', - apiGatewayRole: this.apiGatewayRole, - apiMethod: 'POST', - apiResource: putRecordResource, - requestTemplate: this.getPutRecordTemplate(props.putRecordRequestTemplate), - contentType: "'x-amz-json-1.1'", - requestValidator, - requestModel: { 'application/json': this.getPutRecordModel(props.putRecordRequestModel) } - }); - - // PutRecords - const putRecordsResource = this.apiGateway.root.addResource('records'); - defaults.addProxyMethodToApiResource({ - service: 'kinesis', - action: 'PutRecords', - apiGatewayRole: this.apiGatewayRole, - apiMethod: 'POST', - apiResource: putRecordsResource, - requestTemplate: this.getPutRecordsTemplate(props.putRecordsRequestTemplate), - contentType: "'x-amz-json-1.1'", - requestValidator, - requestModel: { 'application/json': this.getPutRecordsModel(props.putRecordsRequestModel) } - }); + super(scope, id); + + // Setup the Kinesis stream + this.kinesisStream = defaults.buildKinesisStream(scope, { + existingStreamObj: props.existingStreamObj, + kinesisStreamProps: props.kinesisStreamProps + }); + + // Setup the API Gateway + [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, props.apiGatewayProps); + + // Setup the API Gateway role + this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com') + }); + this.kinesisStream.grantWrite(this.apiGatewayRole); + + // Setup API Gateway methods + const requestValidator = this.apiGateway.addRequestValidator('request-validator', { + requestValidatorName: 'request-body-validator', + validateRequestBody: true + }); + + // PutRecord + const putRecordResource = this.apiGateway.root.addResource('record'); + defaults.addProxyMethodToApiResource({ + service: 'kinesis', + action: 'PutRecord', + apiGatewayRole: this.apiGatewayRole, + apiMethod: 'POST', + apiResource: putRecordResource, + requestTemplate: this.getPutRecordTemplate(props.putRecordRequestTemplate), + contentType: "'x-amz-json-1.1'", + requestValidator, + requestModel: { 'application/json': this.getPutRecordModel(props.putRecordRequestModel) } + }); + + // PutRecords + const putRecordsResource = this.apiGateway.root.addResource('records'); + defaults.addProxyMethodToApiResource({ + service: 'kinesis', + action: 'PutRecords', + apiGatewayRole: this.apiGatewayRole, + apiMethod: 'POST', + apiResource: putRecordsResource, + requestTemplate: this.getPutRecordsTemplate(props.putRecordsRequestTemplate), + contentType: "'x-amz-json-1.1'", + requestValidator, + requestModel: { 'application/json': this.getPutRecordsModel(props.putRecordsRequestModel) } + }); } private getPutRecordTemplate(putRecordTemplate?: string): string { - if (putRecordTemplate !== undefined) { - return putRecordTemplate.replace("${StreamName}", this.kinesisStream.streamName); - } + if (putRecordTemplate !== undefined) { + return putRecordTemplate.replace("${StreamName}", this.kinesisStream.streamName); + } - return `{ "StreamName": "${this.kinesisStream.streamName}", "Data": "$util.base64Encode($input.json('$.data'))", "PartitionKey": "$input.path('$.partitionKey')" }`; + return `{ "StreamName": "${this.kinesisStream.streamName}", "Data": "$util.base64Encode($input.json('$.data'))", "PartitionKey": "$input.path('$.partitionKey')" }`; } private getPutRecordModel(putRecordModel?: api.ModelOptions): api.IModel { - let modelProps: api.ModelOptions; - - if (putRecordModel !== undefined) { - modelProps = putRecordModel; - } else { - modelProps = { - contentType: 'application/json', - modelName: 'PutRecordModel', - description: 'PutRecord proxy single-record payload', - schema: { - schema: api.JsonSchemaVersion.DRAFT4, - title: 'PutRecord proxy single-record payload', - type: api.JsonSchemaType.OBJECT, - required: ['data', 'partitionKey'], - properties: { - data: { type: api.JsonSchemaType.STRING }, - partitionKey: { type: api.JsonSchemaType.STRING } - } - } - }; - } - - return this.apiGateway.addModel('PutRecordModel', modelProps); + let modelProps: api.ModelOptions; + + if (putRecordModel !== undefined) { + modelProps = putRecordModel; + } else { + modelProps = { + contentType: 'application/json', + modelName: 'PutRecordModel', + description: 'PutRecord proxy single-record payload', + schema: { + schema: api.JsonSchemaVersion.DRAFT4, + title: 'PutRecord proxy single-record payload', + type: api.JsonSchemaType.OBJECT, + required: ['data', 'partitionKey'], + properties: { + data: { type: api.JsonSchemaType.STRING }, + partitionKey: { type: api.JsonSchemaType.STRING } + } + } + }; + } + + return this.apiGateway.addModel('PutRecordModel', modelProps); } private getPutRecordsTemplate(putRecordsTemplate?: string): string { - if (putRecordsTemplate !== undefined) { - return putRecordsTemplate.replace("${StreamName}", this.kinesisStream.streamName); - } + if (putRecordsTemplate !== undefined) { + return putRecordsTemplate.replace("${StreamName}", this.kinesisStream.streamName); + } - return `{ "StreamName": "${this.kinesisStream.streamName}", "Records": [ #foreach($elem in $input.path('$.records')) { "Data": "$util.base64Encode($elem.data)", "PartitionKey": "$elem.partitionKey"}#if($foreach.hasNext),#end #end ] }`; + return `{ "StreamName": "${this.kinesisStream.streamName}", "Records": [ #foreach($elem in $input.path('$.records')) { "Data": "$util.base64Encode($elem.data)", "PartitionKey": "$elem.partitionKey"}#if($foreach.hasNext),#end #end ] }`; } private getPutRecordsModel(putRecordsModel?: api.ModelOptions): api.IModel { - let modelProps: api.ModelOptions; - - if (putRecordsModel !== undefined) { - modelProps = putRecordsModel; - } else { - modelProps = { - contentType: 'application/json', - modelName: 'PutRecordsModel', - description: 'PutRecords proxy payload data', - schema: { - schema: api.JsonSchemaVersion.DRAFT4, - title: 'PutRecords proxy payload data', - type: api.JsonSchemaType.OBJECT, - required: ['records'], - properties: { - records: { - type: api.JsonSchemaType.ARRAY, - items: { - type: api.JsonSchemaType.OBJECT, - required: ['data', 'partitionKey'], - properties: { - data: { type: api.JsonSchemaType.STRING }, - partitionKey: { type: api.JsonSchemaType.STRING } - } - } - } - } + let modelProps: api.ModelOptions; + + if (putRecordsModel !== undefined) { + modelProps = putRecordsModel; + } else { + modelProps = { + contentType: 'application/json', + modelName: 'PutRecordsModel', + description: 'PutRecords proxy payload data', + schema: { + schema: api.JsonSchemaVersion.DRAFT4, + title: 'PutRecords proxy payload data', + type: api.JsonSchemaType.OBJECT, + required: ['records'], + properties: { + records: { + type: api.JsonSchemaType.ARRAY, + items: { + type: api.JsonSchemaType.OBJECT, + required: ['data', 'partitionKey'], + properties: { + data: { type: api.JsonSchemaType.STRING }, + partitionKey: { type: api.JsonSchemaType.STRING } + } } - }; - } + } + } + } + }; + } - return this.apiGateway.addModel('PutRecordsModel', modelProps); + return this.apiGateway.addModel('PutRecordsModel', modelProps); } } diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/apigateway-kinesis.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/apigateway-kinesis.test.ts index 1745ed731..a74d1f142 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/apigateway-kinesis.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/apigateway-kinesis.test.ts @@ -22,96 +22,96 @@ import * as kinesis from '@aws-cdk/aws-kinesis'; // Test minimal deployment snapshot // -------------------------------------------------------------- test('Test minimal deployment snapshot', () => { - const stack = new Stack(); - new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', {}); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', {}); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test construct properties // -------------------------------------------------------------- test('Test construct properties', () => { - const stack = new Stack(); - const pattern = new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', {}); + const stack = new Stack(); + const pattern = new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', {}); - expect(pattern.apiGateway !== null); - expect(pattern.apiGatewayRole !== null); - expect(pattern.apiGatewayCloudWatchRole !== null); - expect(pattern.apiGatewayLogGroup !== null); - expect(pattern.kinesisStream !== null); + expect(pattern.apiGateway !== null); + expect(pattern.apiGatewayRole !== null); + expect(pattern.apiGatewayCloudWatchRole !== null); + expect(pattern.apiGatewayLogGroup !== null); + expect(pattern.kinesisStream !== null); }); // -------------------------------------------------------------- // Test deployment w/ overwritten properties // -------------------------------------------------------------- test('Test deployment w/ overwritten properties', () => { - const stack = new Stack(); + const stack = new Stack(); - new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', { - apiGatewayProps: { - restApiName: 'my-api', - deployOptions: { - methodOptions: { - '/*/*': { - throttlingRateLimit: 100, - throttlingBurstLimit: 25 - } - } - } - }, - kinesisStreamProps: { - shardCount: 1, - streamName: 'my-stream' - }, - putRecordRequestTemplate: `{ "Data": "$util.base64Encode($input.json('$.foo'))", "PartitionKey": "$input.path('$.bar')" }`, - putRecordRequestModel: { schema: {} }, - putRecordsRequestTemplate: `{ "Records": [ #foreach($elem in $input.path('$.records')) { "Data": "$util.base64Encode($elem.foo)", "PartitionKey": "$elem.bar"}#if($foreach.hasNext),#end #end ] }`, - putRecordsRequestModel: { schema: {} } - }); + new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', { + apiGatewayProps: { + restApiName: 'my-api', + deployOptions: { + methodOptions: { + '/*/*': { + throttlingRateLimit: 100, + throttlingBurstLimit: 25 + } + } + } + }, + kinesisStreamProps: { + shardCount: 1, + streamName: 'my-stream' + }, + putRecordRequestTemplate: `{ "Data": "$util.base64Encode($input.json('$.foo'))", "PartitionKey": "$input.path('$.bar')" }`, + putRecordRequestModel: { schema: {} }, + putRecordsRequestTemplate: `{ "Records": [ #foreach($elem in $input.path('$.records')) { "Data": "$util.base64Encode($elem.foo)", "PartitionKey": "$elem.bar"}#if($foreach.hasNext),#end #end ] }`, + putRecordsRequestModel: { schema: {} } + }); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - expect(stack).toHaveResourceLike('AWS::ApiGateway::Stage', { - MethodSettings: [ - { - DataTraceEnabled: true, - HttpMethod: '*', - LoggingLevel: 'INFO', - ResourcePath: '/*' - }, - { - HttpMethod: '*', - ResourcePath: '/*', - ThrottlingRateLimit: 100, - ThrottlingBurstLimit: 25 - } - ] - }); + expect(stack).toHaveResourceLike('AWS::ApiGateway::Stage', { + MethodSettings: [ + { + DataTraceEnabled: true, + HttpMethod: '*', + LoggingLevel: 'INFO', + ResourcePath: '/*' + }, + { + HttpMethod: '*', + ResourcePath: '/*', + ThrottlingRateLimit: 100, + ThrottlingBurstLimit: 25 + } + ] + }); - expect(stack).toHaveResource('AWS::Kinesis::Stream', { - ShardCount: 1, - Name: 'my-stream' - }); + expect(stack).toHaveResource('AWS::Kinesis::Stream', { + ShardCount: 1, + Name: 'my-stream' + }); }); // -------------------------------------------------------------- // Test deployment w/ existing stream // -------------------------------------------------------------- test('Test deployment w/ existing stream', () => { - const stack = new Stack(); + const stack = new Stack(); - new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', { - apiGatewayProps: {}, - existingStreamObj: new kinesis.Stream(stack, 'ExistingStream', { - shardCount: 5, - retentionPeriod: Duration.days(4) - }) - }); + new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', { + apiGatewayProps: {}, + existingStreamObj: new kinesis.Stream(stack, 'ExistingStream', { + shardCount: 5, + retentionPeriod: Duration.days(4) + }) + }); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - expect(stack).toHaveResource('AWS::Kinesis::Stream', { - ShardCount: 5, - RetentionPeriodHours: 96 - }); + expect(stack).toHaveResource('AWS::Kinesis::Stream', { + ShardCount: 5, + RetentionPeriodHours: 96 + }); }); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/integ.apigateway-kinesis-overwrite.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/integ.apigateway-kinesis-overwrite.ts index e139db07c..75856ebc6 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/integ.apigateway-kinesis-overwrite.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/integ.apigateway-kinesis-overwrite.ts @@ -22,26 +22,26 @@ stack.templateOptions.description = 'Integration Test for aws-apigateway-kinesis // Definitions const props: ApiGatewayToKinesisStreamsProps = { - apiGatewayProps: { - restApiName: 'my-api', - deployOptions: { - methodOptions: { - '/*/*': { - throttlingRateLimit: 100, - throttlingBurstLimit: 25 - } - } + apiGatewayProps: { + restApiName: 'my-api', + deployOptions: { + methodOptions: { + '/*/*': { + throttlingRateLimit: 100, + throttlingBurstLimit: 25 } - }, - kinesisStreamProps: { - shardCount: 1, - retentionPeriod: Duration.days(4) - }, - putRecordRequestTemplate: `{ "StreamName": "\${StreamName}", "Data": "$util.base64Encode($input.json('$.foo'))", "PartitionKey": "$input.path('$.bar')" }`, - putRecordRequestModel: { schema: {} }, + } + } + }, + kinesisStreamProps: { + shardCount: 1, + retentionPeriod: Duration.days(4) + }, + putRecordRequestTemplate: `{ "StreamName": "\${StreamName}", "Data": "$util.base64Encode($input.json('$.foo'))", "PartitionKey": "$input.path('$.bar')" }`, + putRecordRequestModel: { schema: {} }, - putRecordsRequestTemplate: `{ "StreamName": "\${StreamName}", "Records": [ #foreach($elem in $input.path('$.records')) { "Data": "$util.base64Encode($elem.foo)", "PartitionKey": "$elem.bar"}#if($foreach.hasNext),#end #end ] }`, - putRecordsRequestModel: { schema: {} } + putRecordsRequestTemplate: `{ "StreamName": "\${StreamName}", "Records": [ #foreach($elem in $input.path('$.records')) { "Data": "$util.base64Encode($elem.foo)", "PartitionKey": "$elem.bar"}#if($foreach.hasNext),#end #end ] }`, + putRecordsRequestModel: { schema: {} } }; new ApiGatewayToKinesisStreams(stack, 'test-apigateway-kinesis-overwrite', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/integ.no-arguments.ts index 0769da844..6ecb9fd1a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-kinesisstreams/test/integ.no-arguments.ts @@ -22,8 +22,8 @@ stack.templateOptions.description = 'Integration Test for aws-apigateway-kinesis // Definitions const props: ApiGatewayToKinesisStreamsProps = { - apiGatewayProps: {}, - kinesisStreamProps: {} + apiGatewayProps: {}, + kinesisStreamProps: {} }; new ApiGatewayToKinesisStreams(stack, 'test-apigateway-kinesis-default', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/lib/index.ts index f598ecdce..949679b11 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/lib/index.ts @@ -61,16 +61,16 @@ export class ApiGatewayToLambda extends Construct { * @access public */ constructor(scope: Construct, id: string, props: ApiGatewayToLambdaProps) { - super(scope, id); + super(scope, id); - // Setup the Lambda function - this.lambdaFunction = defaults.buildLambdaFunction(this, { - existingLambdaObj: props.existingLambdaObj, - lambdaFunctionProps: props.lambdaFunctionProps - }); + // Setup the Lambda function + this.lambdaFunction = defaults.buildLambdaFunction(this, { + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps + }); - // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, - this.apiGatewayLogGroup] = defaults.GlobalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps); + // Setup the API Gateway + [this.apiGateway, this.apiGatewayCloudWatchRole, + this.apiGatewayLogGroup] = defaults.GlobalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps); } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/integ.deployFunction.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/integ.deployFunction.ts index 5f4cd75fe..72be86b6a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/integ.deployFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/integ.deployFunction.ts @@ -23,11 +23,11 @@ stack.templateOptions.description = 'Integration Test for aws-apigateway-lambda' // Definitions const props: ApiGatewayToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } }; new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/integ.existingFunction.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/integ.existingFunction.ts index 15fe30a51..53bb2db83 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/integ.existingFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/integ.existingFunction.ts @@ -33,7 +33,7 @@ const func = defaults.deployLambdaFunction(stack, lambdaFunctionProps); // Api gateway setup const props: ApiGatewayToLambdaProps = { - existingLambdaObj: func + existingLambdaObj: func }; // Instantiate construct diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts index 872a3f678..8a6b35ee0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-lambda/test/test.apigateway-lambda.test.ts @@ -23,52 +23,52 @@ import '@aws-cdk/assert/jest'; // Pattern deployment with new Lambda function // -------------------------------------------------------------- test('Pattern deployment with new Lambda function', () => { - // Initial Setup - const stack = new Stack(); - const props: ApiGatewayToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }; - new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Initial Setup + const stack = new Stack(); + const props: ApiGatewayToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }; + new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Pattern deployment with existing Lambda function // -------------------------------------------------------------- test('Pattern deployment with existing Lambda function', () => { - // Initial Setup - const stack = new Stack(); - const fn = new lambda.Function(stack, 'ExistingLambdaFunction', { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }); - const props: ApiGatewayToLambdaProps = { - existingLambdaObj: fn - }; - new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Initial Setup + const stack = new Stack(); + const fn = new lambda.Function(stack, 'ExistingLambdaFunction', { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }); + const props: ApiGatewayToLambdaProps = { + existingLambdaObj: fn + }; + new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test for error with existingLambdaObj=undefined (not supplied by user). // -------------------------------------------------------------- test('Error on existingLambdaObj=undefined', () => { - // Initial Setup - const stack = new Stack(); - const props: ApiGatewayToLambdaProps = { - }; - const app = () => { - new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); - }; + // Initial Setup + const stack = new Stack(); + const props: ApiGatewayToLambdaProps = { + }; + const app = () => { + new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); + }; // Assertion 1 - expect(app).toThrowError(); + expect(app).toThrowError(); }); // -------------------------------------------------------------- @@ -78,26 +78,26 @@ test('Test with lambdaFunctionProps', () => { // Initial Setup const stack = new Stack(); const props: ApiGatewayToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - environment: { - OVERRIDE_STATUS: 'true' - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + environment: { + OVERRIDE_STATUS: 'true' + } }, apiGatewayProps: { - description: "sampleApiProp" + description: "sampleApiProp" } }; new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); expect(stack).toHaveResource('AWS::Lambda::Function', { Environment: { - Variables: { - OVERRIDE_STATUS: "true", - AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1" - } + Variables: { + OVERRIDE_STATUS: "true", + AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1" + } } }); }); @@ -106,117 +106,117 @@ test('Test with lambdaFunctionProps', () => { // Test getter methods // -------------------------------------------------------------- test('Test properties', () => { - // Initial Setup - const stack = new Stack(); - const props: ApiGatewayToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }; - const app = new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); - // Assertion 1 - expect(app.lambdaFunction !== null); - // Assertion 2 - expect(app.apiGateway !== null); - expect(app.apiGatewayCloudWatchRole !== null); - expect(app.apiGatewayLogGroup !== null); + // Initial Setup + const stack = new Stack(); + const props: ApiGatewayToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }; + const app = new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); + // Assertion 1 + expect(app.lambdaFunction !== null); + // Assertion 2 + expect(app.apiGateway !== null); + expect(app.apiGatewayCloudWatchRole !== null); + expect(app.apiGatewayLogGroup !== null); }); // -------------------------------------------------------------- // Test for error with lambdaFunctionProps=undefined (not supplied by user). // -------------------------------------------------------------- test('Error on lambdaFunctionProps=undefined', () => { - // Initial Setup - const stack = new Stack(); - const props: ApiGatewayToLambdaProps = { - }; - const app = () => { - new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); - }; + // Initial Setup + const stack = new Stack(); + const props: ApiGatewayToLambdaProps = { + }; + const app = () => { + new ApiGatewayToLambda(stack, 'test-apigateway-lambda', props); + }; // Assertion 1 - expect(app).toThrowError(); + expect(app).toThrowError(); }); // -------------------------------------------------------------- // Pattern deployment with two ApiGatewayToLambda constructs // -------------------------------------------------------------- test('Pattern deployment with two ApiGatewayToLambda constructs', () => { - // Initial Setup - const stack = new Stack(); - const props1: ApiGatewayToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }; - new ApiGatewayToLambda(stack, 'pattern1', props1); + // Initial Setup + const stack = new Stack(); + const props1: ApiGatewayToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }; + new ApiGatewayToLambda(stack, 'pattern1', props1); - const props2: ApiGatewayToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }; - new ApiGatewayToLambda(stack, 'pattern2', props2); + const props2: ApiGatewayToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }; + new ApiGatewayToLambda(stack, 'pattern2', props2); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // ----------------------------------------------------------------- // Test deployment for override ApiGateway AuthorizationType to NONE // ----------------------------------------------------------------- test('Test deployment ApiGateway AuthorizationType override', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToLambda(stack, 'api-gateway-lambda', { - apiGatewayProps: { - defaultMethodOptions: { - authorizationType: api.AuthorizationType.NONE - } - }, - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }); - // Assertion 1 - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "ANY", - AuthorizationType: "NONE" - }); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToLambda(stack, 'api-gateway-lambda', { + apiGatewayProps: { + defaultMethodOptions: { + authorizationType: api.AuthorizationType.NONE + } + }, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }); + // Assertion 1 + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "ANY", + AuthorizationType: "NONE" + }); }); // ----------------------------------------------------------------- // Test deployment for override ApiGateway cloudWatchRole = false // ----------------------------------------------------------------- test('Test deployment ApiGateway override cloudWatchRole = false', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToLambda(stack, 'api-gateway-lambda', { - apiGatewayProps: { - cloudWatchRole: false - }, - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }); - // Assertion 1 - expect(stack).toHaveResourceLike("AWS::ApiGateway::Account", { - CloudWatchRoleArn: { - "Fn::GetAtt": [ - "apigatewaylambdaLambdaRestApiCloudWatchRoleA759E8AC", - "Arn" - ] - } - }); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToLambda(stack, 'api-gateway-lambda', { + apiGatewayProps: { + cloudWatchRole: false + }, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }); + // Assertion 1 + expect(stack).toHaveResourceLike("AWS::ApiGateway::Account", { + CloudWatchRoleArn: { + "Fn::GetAtt": [ + "apigatewaylambdaLambdaRestApiCloudWatchRoleA759E8AC", + "Arn" + ] + } + }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/lib/index.ts index 973cfc5f5..990961f6b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/lib/index.ts @@ -90,87 +90,87 @@ export class ApiGatewayToSageMakerEndpoint extends Construct { * @access public */ constructor(scope: Construct, id: string, props: ApiGatewayToSageMakerEndpointProps) { - super(scope, id); - - // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, props.apiGatewayProps); - - // Setup the API Gateway role - if (props.apiGatewayExecutionRole !== undefined) { - this.apiGatewayRole = props.apiGatewayExecutionRole; - } else { - this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com') - }); - - // Setup the IAM policy for SageMaker endpoint - const invokePolicy = new iam.Policy(this, 'InvokeEndpointPolicy', { - statements: [ - new iam.PolicyStatement({ - actions: ['sagemaker:InvokeEndpoint'], - resources: [`arn:${Aws.PARTITION}:sagemaker:${Aws.REGION}:${Aws.ACCOUNT_ID}:endpoint/${props.endpointName}`] - }) - ] - }); - - invokePolicy.attachToRole(this.apiGatewayRole); - } - - // Setup request validation - const requestValidator = this.apiGateway.addRequestValidator('request-validator', { - requestValidatorName: 'request-param-validator', - - // Setting this property to true makes sure the following are validated: - // - Required request parameters in the URI - // - Query string - // - Headers - validateRequestParameters: true + super(scope, id); + + // Setup the API Gateway + [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, props.apiGatewayProps); + + // Setup the API Gateway role + if (props.apiGatewayExecutionRole !== undefined) { + this.apiGatewayRole = props.apiGatewayExecutionRole; + } else { + this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com') + }); + + // Setup the IAM policy for SageMaker endpoint + const invokePolicy = new iam.Policy(this, 'InvokeEndpointPolicy', { + statements: [ + new iam.PolicyStatement({ + actions: ['sagemaker:InvokeEndpoint'], + resources: [`arn:${Aws.PARTITION}:sagemaker:${Aws.REGION}:${Aws.ACCOUNT_ID}:endpoint/${props.endpointName}`] + }) + ] }); - // Setup method and integration responses - const methodResponses: api.MethodResponse[] = [ - { statusCode: '200' }, - { statusCode: '500' }, - { statusCode: '400' } - ]; - - const integResponses: api.IntegrationResponse[] = []; - if (props.responseMappingTemplate !== undefined) { - integResponses.push({ - statusCode: '200', - responseTemplates: { 'application/json': props.responseMappingTemplate } - }); - } else { - integResponses.push({ statusCode: '200' }); - } - - integResponses.push( - { statusCode: '500', selectionPattern: '5\\d{2}' }, - { statusCode: '400', selectionPattern: '4\\d{2}' } - ); - - // The SageMaker integration can be added either at the root of the API (GET https://execute-api.amazonaws.com/{some-param}), - // or as a sub-resource (GET https://execute-api.amazonaws.com/inference/{some-param}). - // The following lines will make sure only the necessary resources are created. - let apiResource = this.apiGateway.root; - if (props.resourceName !== undefined) { - apiResource = apiResource.addResource(props.resourceName); - } - apiResource = apiResource.addResource(props.resourcePath); - - // Setup API Gateway method - defaults.addProxyMethodToApiResource({ - service: 'runtime.sagemaker', - path: `endpoints/${props.endpointName}/invocations`, - apiGatewayRole: this.apiGatewayRole, - apiMethod: 'GET', - apiResource, - requestValidator, - requestTemplate: props.requestMappingTemplate, - awsIntegrationProps: { - options: { integrationResponses: integResponses } - }, - methodOptions: { methodResponses } + invokePolicy.attachToRole(this.apiGatewayRole); + } + + // Setup request validation + const requestValidator = this.apiGateway.addRequestValidator('request-validator', { + requestValidatorName: 'request-param-validator', + + // Setting this property to true makes sure the following are validated: + // - Required request parameters in the URI + // - Query string + // - Headers + validateRequestParameters: true + }); + + // Setup method and integration responses + const methodResponses: api.MethodResponse[] = [ + { statusCode: '200' }, + { statusCode: '500' }, + { statusCode: '400' } + ]; + + const integResponses: api.IntegrationResponse[] = []; + if (props.responseMappingTemplate !== undefined) { + integResponses.push({ + statusCode: '200', + responseTemplates: { 'application/json': props.responseMappingTemplate } }); + } else { + integResponses.push({ statusCode: '200' }); + } + + integResponses.push( + { statusCode: '500', selectionPattern: '5\\d{2}' }, + { statusCode: '400', selectionPattern: '4\\d{2}' } + ); + + // The SageMaker integration can be added either at the root of the API (GET https://execute-api.amazonaws.com/{some-param}), + // or as a sub-resource (GET https://execute-api.amazonaws.com/inference/{some-param}). + // The following lines will make sure only the necessary resources are created. + let apiResource = this.apiGateway.root; + if (props.resourceName !== undefined) { + apiResource = apiResource.addResource(props.resourceName); + } + apiResource = apiResource.addResource(props.resourcePath); + + // Setup API Gateway method + defaults.addProxyMethodToApiResource({ + service: 'runtime.sagemaker', + path: `endpoints/${props.endpointName}/invocations`, + apiGatewayRole: this.apiGatewayRole, + apiMethod: 'GET', + apiResource, + requestValidator, + requestTemplate: props.requestMappingTemplate, + awsIntegrationProps: { + options: { integrationResponses: integResponses } + }, + methodOptions: { methodResponses } + }); } } diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/apigateway-sagemakerendpoint.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/apigateway-sagemakerendpoint.test.ts index 5b10ebc73..2771994d4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/apigateway-sagemakerendpoint.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/apigateway-sagemakerendpoint.test.ts @@ -22,122 +22,122 @@ import '@aws-cdk/assert/jest'; // Test minimal deployment snapshot // -------------------------------------------------------------- test('Test minimal deployment snapshot', () => { - const stack = new Stack(); - new ApiGatewayToSageMakerEndpoint(stack, 'api-gateway-sagemakerendpoint', { - endpointName: 'my-endpoint', - resourcePath: '{my_param}', - requestMappingTemplate: 'my-request-vtl-template' - }); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + new ApiGatewayToSageMakerEndpoint(stack, 'api-gateway-sagemakerendpoint', { + endpointName: 'my-endpoint', + resourcePath: '{my_param}', + requestMappingTemplate: 'my-request-vtl-template' + }); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test construct properties // -------------------------------------------------------------- test('Test construct properties', () => { - const stack = new Stack(); - const pattern = new ApiGatewayToSageMakerEndpoint(stack, 'api-gateway-sagemakerendpoint', { - endpointName: 'my-endpoint', - resourcePath: '{my_param}', - requestMappingTemplate: 'my-request-vtl-template' - }); + const stack = new Stack(); + const pattern = new ApiGatewayToSageMakerEndpoint(stack, 'api-gateway-sagemakerendpoint', { + endpointName: 'my-endpoint', + resourcePath: '{my_param}', + requestMappingTemplate: 'my-request-vtl-template' + }); - expect(pattern.apiGateway !== null); - expect(pattern.apiGatewayRole !== null); - expect(pattern.apiGatewayCloudWatchRole !== null); - expect(pattern.apiGatewayLogGroup !== null); + expect(pattern.apiGateway !== null); + expect(pattern.apiGatewayRole !== null); + expect(pattern.apiGatewayCloudWatchRole !== null); + expect(pattern.apiGatewayLogGroup !== null); }); // -------------------------------------------------------------- // Test deployment w/ overwritten properties // -------------------------------------------------------------- test('Test deployment w/ overwritten properties', () => { - const stack = new Stack(); + const stack = new Stack(); - const existingRole = new iam.Role(stack, 'api-gateway-role', { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), - description: 'existing role for SageMaker integration', - inlinePolicies: { - InvokePolicy: new iam.PolicyDocument({ - statements: [new iam.PolicyStatement({ - resources: [`arn:${Aws.PARTITION}:sagemaker:${Aws.REGION}:${Aws.ACCOUNT_ID}:endpoint/my-endpoint`], - actions: ['sagemaker:InvokeEndpoint'] - })] - }) - } - }); + const existingRole = new iam.Role(stack, 'api-gateway-role', { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + description: 'existing role for SageMaker integration', + inlinePolicies: { + InvokePolicy: new iam.PolicyDocument({ + statements: [new iam.PolicyStatement({ + resources: [`arn:${Aws.PARTITION}:sagemaker:${Aws.REGION}:${Aws.ACCOUNT_ID}:endpoint/my-endpoint`], + actions: ['sagemaker:InvokeEndpoint'] + })] + }) + } + }); - new ApiGatewayToSageMakerEndpoint(stack, 'api-gateway-sagemakerendpoint', { - endpointName: 'my-endpoint', - resourcePath: '{my_param}', - requestMappingTemplate: 'my-request-vtl-template', + new ApiGatewayToSageMakerEndpoint(stack, 'api-gateway-sagemakerendpoint', { + endpointName: 'my-endpoint', + resourcePath: '{my_param}', + requestMappingTemplate: 'my-request-vtl-template', - apiGatewayProps: { - restApiName: 'my-api', - deployOptions: { - methodOptions: { - '/*/*': { - throttlingRateLimit: 100, - throttlingBurstLimit: 25 - } - } - } - }, - apiGatewayExecutionRole: existingRole, - resourceName: 'my-resource', - responseMappingTemplate: 'my-response-vtl-template' - }); + apiGatewayProps: { + restApiName: 'my-api', + deployOptions: { + methodOptions: { + '/*/*': { + throttlingRateLimit: 100, + throttlingBurstLimit: 25 + } + } + } + }, + apiGatewayExecutionRole: existingRole, + resourceName: 'my-resource', + responseMappingTemplate: 'my-response-vtl-template' + }); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - expect(stack).toHaveResourceLike('AWS::ApiGateway::Stage', { - MethodSettings: [ - { - DataTraceEnabled: true, - HttpMethod: '*', - LoggingLevel: 'INFO', - ResourcePath: '/*' - }, - { - HttpMethod: '*', - ResourcePath: '/*', - ThrottlingRateLimit: 100, - ThrottlingBurstLimit: 25 - } - ] - }); + expect(stack).toHaveResourceLike('AWS::ApiGateway::Stage', { + MethodSettings: [ + { + DataTraceEnabled: true, + HttpMethod: '*', + LoggingLevel: 'INFO', + ResourcePath: '/*' + }, + { + HttpMethod: '*', + ResourcePath: '/*', + ThrottlingRateLimit: 100, + ThrottlingBurstLimit: 25 + } + ] + }); - expect(stack).toHaveResourceLike('AWS::ApiGateway::Resource', { - PathPart: 'my-resource' - }); + expect(stack).toHaveResourceLike('AWS::ApiGateway::Resource', { + PathPart: 'my-resource' + }); - expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { - Integration: { - IntegrationResponses: [ - { - ResponseTemplates: { - 'application/json': 'my-response-vtl-template', - }, - StatusCode: '200' - }, - { - StatusCode: '500', - SelectionPattern: '5\\d{2}' - }, - { - StatusCode: '400', - SelectionPattern: '4\\d{2}' - } - ] + expect(stack).toHaveResourceLike('AWS::ApiGateway::Method', { + Integration: { + IntegrationResponses: [ + { + ResponseTemplates: { + 'application/json': 'my-response-vtl-template', + }, + StatusCode: '200' }, - MethodResponses: [ - { StatusCode: '200' }, - { StatusCode: '500' }, - { StatusCode: '400' } - ] - }); + { + StatusCode: '500', + SelectionPattern: '5\\d{2}' + }, + { + StatusCode: '400', + SelectionPattern: '4\\d{2}' + } + ] + }, + MethodResponses: [ + { StatusCode: '200' }, + { StatusCode: '500' }, + { StatusCode: '400' } + ] + }); - expect(stack).toHaveResourceLike('AWS::IAM::Role', { - Description: 'existing role for SageMaker integration' - }); + expect(stack).toHaveResourceLike('AWS::IAM::Role', { + Description: 'existing role for SageMaker integration' + }); }); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/integ.apigateway-sagemakerendpoint-overwrite.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/integ.apigateway-sagemakerendpoint-overwrite.ts index 3bda09e3b..665642213 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/integ.apigateway-sagemakerendpoint-overwrite.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/integ.apigateway-sagemakerendpoint-overwrite.ts @@ -22,16 +22,16 @@ const stack = new Stack(app, 'test-apigateway-sagemakerendpoint-overwrite'); stack.templateOptions.description = 'Integration Test for aws-apigateway-sagemakerendpoint'; const existingRole = new iam.Role(stack, 'api-gateway-role', { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), - description: 'existing role for SageMaker integration', - inlinePolicies: { - InvokePolicy: new iam.PolicyDocument({ - statements: [new iam.PolicyStatement({ - resources: [`arn:${Aws.PARTITION}:sagemaker:${Aws.REGION}:${Aws.ACCOUNT_ID}:endpoint/my-endpoint`], - actions: ['sagemaker:InvokeEndpoint'] - })] - }) - } + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + description: 'existing role for SageMaker integration', + inlinePolicies: { + InvokePolicy: new iam.PolicyDocument({ + statements: [new iam.PolicyStatement({ + resources: [`arn:${Aws.PARTITION}:sagemaker:${Aws.REGION}:${Aws.ACCOUNT_ID}:endpoint/my-endpoint`], + actions: ['sagemaker:InvokeEndpoint'] + })] + }) + } }); // Definitions @@ -59,12 +59,12 @@ const responseTemplate = }`; const props: ApiGatewayToSageMakerEndpointProps = { - endpointName: 'my-endpoint', - resourcePath: '{user_id}', - resourceName: 'predicted-ratings', - requestMappingTemplate: requestTemplate, - responseMappingTemplate: responseTemplate, - apiGatewayExecutionRole: existingRole + endpointName: 'my-endpoint', + resourcePath: '{user_id}', + resourceName: 'predicted-ratings', + requestMappingTemplate: requestTemplate, + responseMappingTemplate: responseTemplate, + apiGatewayExecutionRole: existingRole }; new ApiGatewayToSageMakerEndpoint(stack, 'test-apigateway-sagemakerendpoint-overwrite', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/integ.no-overwrite.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/integ.no-overwrite.ts index 417c251f0..f356aabd3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/integ.no-overwrite.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sagemakerendpoint/test/integ.no-overwrite.ts @@ -34,9 +34,9 @@ const requestTemplate = }`; const props: ApiGatewayToSageMakerEndpointProps = { - endpointName: 'my-endpoint', - resourcePath: '{user_id}', - requestMappingTemplate: requestTemplate + endpointName: 'my-endpoint', + resourcePath: '{user_id}', + requestMappingTemplate: requestTemplate }; new ApiGatewayToSageMakerEndpoint(stack, 'test-apigateway-sagemakerendpoint-default', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts index d7485df9d..f35799d1c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/lib/index.ts @@ -118,100 +118,100 @@ export class ApiGatewayToSqs extends Construct { * @access public */ constructor(scope: Construct, id: string, props: ApiGatewayToSqsProps) { - super(scope, id); - - // Setup the dead letter queue, if applicable - this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { - existingQueueObj: props.existingQueueObj, - deployDeadLetterQueue: props.deployDeadLetterQueue, - deadLetterQueueProps: props.deadLetterQueueProps, - maxReceiveCount: props.maxReceiveCount + super(scope, id); + + // Setup the dead letter queue, if applicable + this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { + existingQueueObj: props.existingQueueObj, + deployDeadLetterQueue: props.deployDeadLetterQueue, + deadLetterQueueProps: props.deadLetterQueueProps, + maxReceiveCount: props.maxReceiveCount + }); + + // Setup the queue + [this.sqsQueue] = defaults.buildQueue(this, 'queue', { + queueProps: props.queueProps, + deadLetterQueue: this.deadLetterQueue + }); + + // Setup the API Gateway + [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, props.apiGatewayProps); + + // Setup the API Gateway role + this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com') + }); + + // Setup the API Gateway resource + const apiGatewayResource = this.apiGateway.root.addResource('message'); + + // Create + let createRequestTemplate = "Action=SendMessage&MessageBody=$util.urlEncode(\"$input.body\")"; + + if (props.createRequestTemplate) { + createRequestTemplate = props.createRequestTemplate; + } + + if (props.allowCreateOperation && props.allowCreateOperation === true) { + this.addActionToPolicy("sqs:SendMessage"); + defaults.addProxyMethodToApiResource({ + service: "sqs", + path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, + apiGatewayRole: this.apiGatewayRole, + apiMethod: "POST", + apiResource: this.apiGateway.root, + requestTemplate: createRequestTemplate, + contentType: "'application/x-www-form-urlencoded'" }); - - // Setup the queue - [this.sqsQueue] = defaults.buildQueue(this, 'queue', { - queueProps: props.queueProps, - deadLetterQueue: this.deadLetterQueue + } + + // Read + let readRequestTemplate = "Action=ReceiveMessage"; + + if (props.readRequestTemplate) { + readRequestTemplate = props.readRequestTemplate; + } + + if (props.allowReadOperation === undefined || props.allowReadOperation === true) { + this.addActionToPolicy("sqs:ReceiveMessage"); + defaults.addProxyMethodToApiResource({ + service: "sqs", + path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, + apiGatewayRole: this.apiGatewayRole, + apiMethod: "GET", + apiResource: this.apiGateway.root, + requestTemplate: readRequestTemplate, + contentType: "'application/x-www-form-urlencoded'" }); - - // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, props.apiGatewayProps); - - // Setup the API Gateway role - this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com') + } + + // Delete + let deleteRequestTemplate = "Action=DeleteMessage&ReceiptHandle=$util.urlEncode($input.params('receiptHandle'))"; + + if (props.deleteRequestTemplate) { + deleteRequestTemplate = props.deleteRequestTemplate; + } + + if (props.allowDeleteOperation && props.allowDeleteOperation === true) { + this.addActionToPolicy("sqs:DeleteMessage"); + defaults.addProxyMethodToApiResource({ + service: "sqs", + path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, + apiGatewayRole: this.apiGatewayRole, + apiMethod: "DELETE", + apiResource: apiGatewayResource, + requestTemplate: deleteRequestTemplate, + contentType: "'application/x-www-form-urlencoded'" }); - - // Setup the API Gateway resource - const apiGatewayResource = this.apiGateway.root.addResource('message'); - - // Create - let createRequestTemplate = "Action=SendMessage&MessageBody=$util.urlEncode(\"$input.body\")"; - - if (props.createRequestTemplate) { - createRequestTemplate = props.createRequestTemplate; - } - - if (props.allowCreateOperation && props.allowCreateOperation === true) { - this.addActionToPolicy("sqs:SendMessage"); - defaults.addProxyMethodToApiResource({ - service: "sqs", - path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, - apiGatewayRole: this.apiGatewayRole, - apiMethod: "POST", - apiResource: this.apiGateway.root, - requestTemplate: createRequestTemplate, - contentType: "'application/x-www-form-urlencoded'" - }); - } - - // Read - let readRequestTemplate = "Action=ReceiveMessage"; - - if (props.readRequestTemplate) { - readRequestTemplate = props.readRequestTemplate; - } - - if (props.allowReadOperation === undefined || props.allowReadOperation === true) { - this.addActionToPolicy("sqs:ReceiveMessage"); - defaults.addProxyMethodToApiResource({ - service: "sqs", - path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, - apiGatewayRole: this.apiGatewayRole, - apiMethod: "GET", - apiResource: this.apiGateway.root, - requestTemplate: readRequestTemplate, - contentType: "'application/x-www-form-urlencoded'" - }); - } - - // Delete - let deleteRequestTemplate = "Action=DeleteMessage&ReceiptHandle=$util.urlEncode($input.params('receiptHandle'))"; - - if (props.deleteRequestTemplate) { - deleteRequestTemplate = props.deleteRequestTemplate; - } - - if (props.allowDeleteOperation && props.allowDeleteOperation === true) { - this.addActionToPolicy("sqs:DeleteMessage"); - defaults.addProxyMethodToApiResource({ - service: "sqs", - path: `${cdk.Aws.ACCOUNT_ID}/${this.sqsQueue.queueName}`, - apiGatewayRole: this.apiGatewayRole, - apiMethod: "DELETE", - apiResource: apiGatewayResource, - requestTemplate: deleteRequestTemplate, - contentType: "'application/x-www-form-urlencoded'" - }); - } + } } private addActionToPolicy(action: string) { - this.apiGatewayRole.addToPolicy(new iam.PolicyStatement({ - resources: [ - this.sqsQueue.queueArn - ], - actions: [ `${action}` ] - })); + this.apiGatewayRole.addToPolicy(new iam.PolicyStatement({ + resources: [ + this.sqsQueue.queueArn + ], + actions: [ `${action}` ] + })); } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/apigateway-sqs.test.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/apigateway-sqs.test.ts index f15ad8eef..ab3fa3f03 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/apigateway-sqs.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/apigateway-sqs.test.ts @@ -35,17 +35,17 @@ test('Test minimal deployment', () => { // Test deployment w/ DLQ // -------------------------------------------------------------- test('Test deployment w/ DLQ', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - allowCreateOperation: true, - allowReadOperation: true, - allowDeleteOperation: true, - deployDeadLetterQueue: true - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + allowCreateOperation: true, + allowReadOperation: true, + allowDeleteOperation: true, + deployDeadLetterQueue: true + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- @@ -56,14 +56,14 @@ test('Test deployment w/o DLQ', () => { const stack = new Stack(); // Helper declaration new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - deployDeadLetterQueue: false + deployDeadLetterQueue: false }); // Assertion 1 expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); // Assertion 2 expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "GET", - AuthorizationType: "AWS_IAM" + HttpMethod: "GET", + AuthorizationType: "AWS_IAM" }); }); @@ -71,154 +71,154 @@ test('Test deployment w/o DLQ', () => { // Test deployment w/o allowReadOperation // -------------------------------------------------------------- test('Test deployment w/o allowReadOperation', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - allowCreateOperation: true, - allowReadOperation: false, - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "POST", - AuthorizationType: "AWS_IAM" - }); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + allowCreateOperation: true, + allowReadOperation: false, + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "POST", + AuthorizationType: "AWS_IAM" + }); }); // -------------------------------------------------------------- // Test deployment w/ allowReadOperation // -------------------------------------------------------------- test('Test deployment w/ allowReadOperation', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - allowReadOperation: true, - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "GET", - AuthorizationType: "AWS_IAM" - }); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + allowReadOperation: true, + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "GET", + AuthorizationType: "AWS_IAM" + }); }); // -------------------------------------------------------------- // Test the getter methods // -------------------------------------------------------------- test('Test properties', () => { - // Stack - const stack = new Stack(); - // Helper declaration - const pattern = new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - deployDeadLetterQueue: true, - maxReceiveCount: 3 - }); + // Stack + const stack = new Stack(); + // Helper declaration + const pattern = new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + deployDeadLetterQueue: true, + maxReceiveCount: 3 + }); // Assertion 1 - expect(pattern.apiGateway !== null); - // Assertion 2 - expect(pattern.sqsQueue !== null); - // Assertion 3 - expect(pattern.apiGatewayRole !== null); - expect(pattern.apiGatewayCloudWatchRole !== null); - expect(pattern.apiGatewayLogGroup !== null); - expect(pattern.deadLetterQueue !== null); + expect(pattern.apiGateway !== null); + // Assertion 2 + expect(pattern.sqsQueue !== null); + // Assertion 3 + expect(pattern.apiGatewayRole !== null); + expect(pattern.apiGatewayCloudWatchRole !== null); + expect(pattern.apiGatewayLogGroup !== null); + expect(pattern.deadLetterQueue !== null); }); // ----------------------------------------------------------------- // Test deployment for override ApiGateway AuthorizationType to NONE // ----------------------------------------------------------------- test('Test deployment ApiGateway AuthorizationType override', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - apiGatewayProps: { - defaultMethodOptions: { - authorizationType: api.AuthorizationType.NONE - } - }, - queueProps: {}, - createRequestTemplate: "{}", - allowCreateOperation: true, - allowReadOperation: false, - allowDeleteOperation: true, - deployDeadLetterQueue: false - }); - // Assertion 1 - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "POST", - AuthorizationType: "NONE" - }); - // Assertion 2 - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "DELETE", - AuthorizationType: "NONE" - }); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + apiGatewayProps: { + defaultMethodOptions: { + authorizationType: api.AuthorizationType.NONE + } + }, + queueProps: {}, + createRequestTemplate: "{}", + allowCreateOperation: true, + allowReadOperation: false, + allowDeleteOperation: true, + deployDeadLetterQueue: false + }); + // Assertion 1 + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "POST", + AuthorizationType: "NONE" }); + // Assertion 2 + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "DELETE", + AuthorizationType: "NONE" + }); +}); // ----------------------------------------------------------------- // Test deployment for override ApiGateway createRequestTemplate // ----------------------------------------------------------------- test('Test deployment for override ApiGateway createRequestTemplate', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - createRequestTemplate: "Action=SendMessage&MessageBody=$util.urlEncode(\"HelloWorld\")", - allowCreateOperation: true - }); - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "POST", - Integration: { - RequestTemplates: { - "application/json": "Action=SendMessage&MessageBody=$util.urlEncode(\"HelloWorld\")" - } - } - }); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + createRequestTemplate: "Action=SendMessage&MessageBody=$util.urlEncode(\"HelloWorld\")", + allowCreateOperation: true + }); + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "POST", + Integration: { + RequestTemplates: { + "application/json": "Action=SendMessage&MessageBody=$util.urlEncode(\"HelloWorld\")" + } + } + }); }); // ----------------------------------------------------------------- // Test deployment for override ApiGateway getRequestTemplate // ----------------------------------------------------------------- test('Test deployment for override ApiGateway getRequestTemplate', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - readRequestTemplate: "Action=HelloWorld", - allowReadOperation: true - }); - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "GET", - Integration: { - RequestTemplates: { - "application/json": "Action=HelloWorld" - } - } - }); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + readRequestTemplate: "Action=HelloWorld", + allowReadOperation: true + }); + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "GET", + Integration: { + RequestTemplates: { + "application/json": "Action=HelloWorld" + } + } + }); }); // ----------------------------------------------------------------- // Test deployment for override ApiGateway deleteRequestTemplate // ----------------------------------------------------------------- test('Test deployment for override ApiGateway deleteRequestTemplate', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new ApiGatewayToSqs(stack, 'api-gateway-sqs', { - deleteRequestTemplate: "Action=HelloWorld", - allowDeleteOperation: true - }); - expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { - HttpMethod: "DELETE", - Integration: { - RequestTemplates: { - "application/json": "Action=HelloWorld" - } - } - }); + // Stack + const stack = new Stack(); + // Helper declaration + new ApiGatewayToSqs(stack, 'api-gateway-sqs', { + deleteRequestTemplate: "Action=HelloWorld", + allowDeleteOperation: true + }); + expect(stack).toHaveResourceLike("AWS::ApiGateway::Method", { + HttpMethod: "DELETE", + Integration: { + RequestTemplates: { + "application/json": "Action=HelloWorld" + } + } + }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.ts index 88b361513..d6d89f1e4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.apigateway-sqs-crud.ts @@ -22,9 +22,9 @@ stack.templateOptions.description = 'Integration Test for aws-apigateway-sqs'; // Definitions const props: ApiGatewayToSqsProps = { - allowReadOperation: true, - allowCreateOperation: true, - allowDeleteOperation: true + allowReadOperation: true, + allowCreateOperation: true, + allowDeleteOperation: true }; new ApiGatewayToSqs(stack, 'test-api-gateway-sqs', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/lib/index.ts index 7e874ce3a..02f2d3343 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/lib/index.ts @@ -94,10 +94,10 @@ export class CloudFrontToApiGatewayToLambda extends Construct { child.cfnOptions.metadata = { cfn_nag: { - rules_to_suppress: [{ - id: 'W59', - reason: `AWS::ApiGateway::Method AuthorizationType is set to 'NONE' because API Gateway behind CloudFront does not support AWS_IAM authentication` - }] + rules_to_suppress: [{ + id: 'W59', + reason: `AWS::ApiGateway::Method AuthorizationType is set to 'NONE' because API Gateway behind CloudFront does not support AWS_IAM authentication` + }] } }; } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/integ.no-arguments.ts index cc2cd6cc8..e10a74d5d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/integ.no-arguments.ts @@ -22,13 +22,13 @@ const stack = new Stack(app, 'test-cloudfront-apigateway-lambda-stack'); stack.templateOptions.description = 'Integration Test for aws-cloudfront-apigateway-lambda'; const lambdaProps: lambda.FunctionProps = { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }; new CloudFrontToApiGatewayToLambda(stack, 'test-cloudfront-apigateway-lambda', { - lambdaFunctionProps: lambdaProps, + lambdaFunctionProps: lambdaProps, }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/integ.override-behavior.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/integ.override-behavior.ts index 0161cd60f..f9512ba7c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/integ.override-behavior.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/integ.override-behavior.ts @@ -27,40 +27,40 @@ const stack = new Stack(app, 'test-cf-api-lambda-override-stack'); stack.templateOptions.description = 'Integration Test for aws-cloudfront-apigateway-lambda'; const lambdaProps: lambda.FunctionProps = { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }; // Some Caching for static content const someCachePolicy = new cloudfront.CachePolicy(stack, 'SomeCachePolicy', { - cachePolicyName: 'SomeCachePolicy', - defaultTtl: Duration.hours(8), - minTtl: Duration.hours(5), - maxTtl: Duration.hours(10), + cachePolicyName: 'SomeCachePolicy', + defaultTtl: Duration.hours(8), + minTtl: Duration.hours(5), + maxTtl: Duration.hours(10), }); // Disable Caching for dynamic content const noCachePolicy = new cloudfront.CachePolicy(stack, 'NoCachePolicy', { - cachePolicyName: 'NoCachePolicy', - defaultTtl: Duration.minutes(0), - minTtl: Duration.minutes(0), - maxTtl: Duration.minutes(0), + cachePolicyName: 'NoCachePolicy', + defaultTtl: Duration.minutes(0), + minTtl: Duration.minutes(0), + maxTtl: Duration.minutes(0), }); const construct = new CloudFrontToApiGatewayToLambda(stack, 'cf-api-lambda-override', { - lambdaFunctionProps: lambdaProps, - apiGatewayProps: { - proxy: false, - defaultMethodOptions: { - authorizationType: apigateway.AuthorizationType.NONE, - }, + lambdaFunctionProps: lambdaProps, + apiGatewayProps: { + proxy: false, + defaultMethodOptions: { + authorizationType: apigateway.AuthorizationType.NONE, }, - cloudFrontDistributionProps: { - defaultBehavior: { - cachePolicy: someCachePolicy - } + }, + cloudFrontDistributionProps: { + defaultBehavior: { + cachePolicy: someCachePolicy } + } }); const apiEndPoint = construct.apiGateway; @@ -75,24 +75,24 @@ const dynamicMethod = dynamicResource.addMethod('GET'); // Add behavior construct.cloudFrontWebDistribution.addBehavior('/dynamic', new origins.HttpOrigin(apiEndPointDomainName, { - originPath: `/${apiEndPoint.deploymentStage.stageName}/dynamic` - }), { - cachePolicy: noCachePolicy + originPath: `/${apiEndPoint.deploymentStage.stageName}/dynamic` +}), { + cachePolicy: noCachePolicy }); // Suppress CFN_NAG warnings suppressWarnings(staticMethod); suppressWarnings(dynamicMethod); function suppressWarnings(method: apigateway.Method) { - const child = method.node.findChild('Resource') as apigateway.CfnMethod; - child.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W59', - reason: `AWS::ApiGateway::Method AuthorizationType is set to 'NONE' because API Gateway behind CloudFront does not support AWS_IAM authentication` - }] - } - }; + const child = method.node.findChild('Resource') as apigateway.CfnMethod; + child.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W59', + reason: `AWS::ApiGateway::Method AuthorizationType is set to 'NONE' because API Gateway behind CloudFront does not support AWS_IAM authentication` + }] + } + }; } // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts index d37dfef66..9540ec3ab 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway-lambda/test/test.cloudfront-apigateway-lambda.test.ts @@ -166,15 +166,15 @@ test('override api gateway properties with existingLambdaObj', () => { }); expect(stack).toHaveResource('AWS::ApiGateway::RestApi', - { - Description: "Override description", - EndpointConfiguration: { - Types: [ - "REGIONAL" - ] - }, - Name: "LambdaRestApi" - }); + { + Description: "Override description", + EndpointConfiguration: { + Types: [ + "REGIONAL" + ] + }, + Name: "LambdaRestApi" + }); }); test('override api gateway properties without existingLambdaObj', () => { @@ -197,13 +197,13 @@ test('override api gateway properties without existingLambdaObj', () => { }); expect(stack).toHaveResource('AWS::ApiGateway::RestApi', - { - Description: "Override description", - EndpointConfiguration: { - Types: [ - "PRIVATE" - ] - }, - Name: "LambdaRestApi" - }); + { + Description: "Override description", + EndpointConfiguration: { + Types: [ + "PRIVATE" + ] + }, + Name: "LambdaRestApi" + }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/lib/index.ts index 680add064..664704250 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/lib/index.ts @@ -64,6 +64,6 @@ export class CloudFrontToApiGateway extends Construct { [this.cloudFrontWebDistribution, this.edgeLambdaFunctionVersion, this.cloudFrontLoggingBucket] = defaults.CloudFrontDistributionForApiGateway(this, props.existingApiGatewayObj, - props.cloudFrontDistributionProps, props.insertHttpSecurityHeaders); + props.cloudFrontDistributionProps, props.insertHttpSecurityHeaders); } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/integ.no-arguments.ts index 83a73e32f..17d69caff 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/integ.no-arguments.ts @@ -11,7 +11,7 @@ * and limitations under the License. */ - /// !cdk-integ * +/// !cdk-integ * import { App, Stack } from "@aws-cdk/core"; import { CloudFrontToApiGateway } from "../lib"; import * as lambda from '@aws-cdk/aws-lambda'; @@ -24,9 +24,9 @@ const stack = new Stack(app, 'test-cloudfront-apigateway-stack'); stack.templateOptions.description = 'Integration Test for aws-cloudfront-apigateway'; const inProps: lambda.FunctionProps = { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }; const func = defaults.deployLambdaFunction(stack, inProps); @@ -34,24 +34,24 @@ const func = defaults.deployLambdaFunction(stack, inProps); const [_api] = defaults.RegionalLambdaRestApi(stack, func); _api.methods.forEach((apiMethod) => { - // Override the API Gateway Authorization Type from AWS_IAM to NONE - const child = apiMethod.node.findChild('Resource') as api.CfnMethod; - if (child.authorizationType === 'AWS_IAM') { - child.addPropertyOverride('AuthorizationType', 'NONE'); - - child.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W59', - reason: `AWS::ApiGateway::Method AuthorizationType is set to 'NONE' because API Gateway behind CloudFront does not support AWS_IAM authentication` - }] - } - }; - } + // Override the API Gateway Authorization Type from AWS_IAM to NONE + const child = apiMethod.node.findChild('Resource') as api.CfnMethod; + if (child.authorizationType === 'AWS_IAM') { + child.addPropertyOverride('AuthorizationType', 'NONE'); + + child.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W59', + reason: `AWS::ApiGateway::Method AuthorizationType is set to 'NONE' because API Gateway behind CloudFront does not support AWS_IAM authentication` + }] + } + }; + } }); new CloudFrontToApiGateway(stack, 'test-cloudfront-apigateway', { - existingApiGatewayObj: _api + existingApiGatewayObj: _api }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts index 55906f02c..c639cf21a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts @@ -62,7 +62,7 @@ export class CloudFrontToMediaStore extends Construct { * @param {cdk.App} scope - represents the scope for all the resources. * @param {string} id - this is a scope-unique id. * @param {CloudFrontToMediaStoreProps} props - user provided props for the construct - * @since 1.75.0 + * @since 1.76.0 * @access public */ constructor(scope: Construct, id: string, props: CloudFrontToMediaStoreProps) { diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.withoutHttpSecurityHeaders.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.withoutHttpSecurityHeaders.ts index 8f1b583b5..d1aa56af0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.withoutHttpSecurityHeaders.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.withoutHttpSecurityHeaders.ts @@ -22,7 +22,7 @@ stack.templateOptions.description = 'Integration test for aws-cloudfront-mediast // Instantiate construct new CloudFrontToMediaStore(stack, 'test-cloudfront-mediastore', { - insertHttpSecurityHeaders: false + insertHttpSecurityHeaders: false }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/lib/index.ts index 5cac59dce..b74b59028 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/lib/index.ts @@ -55,29 +55,29 @@ export class CloudFrontToS3 extends Construct { public readonly s3Bucket?: s3.Bucket; public readonly s3LoggingBucket?: s3.Bucket; - /** - * @summary Constructs a new instance of the CloudFrontToS3 class. - * @param {cdk.App} scope - represents the scope for all the resources. - * @param {string} id - this is a a scope-unique id. - * @param {CloudFrontToS3Props} props - user provided props for the construct - * @since 0.8.0 - * @access public - */ + /** + * @summary Constructs a new instance of the CloudFrontToS3 class. + * @param {cdk.App} scope - represents the scope for all the resources. + * @param {string} id - this is a a scope-unique id. + * @param {CloudFrontToS3Props} props - user provided props for the construct + * @since 0.8.0 + * @access public + */ constructor(scope: Construct, id: string, props: CloudFrontToS3Props) { - super(scope, id); - let bucket: s3.Bucket; + super(scope, id); + let bucket: s3.Bucket; - if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { - bucketProps: props.bucketProps - }); - bucket = this.s3Bucket; - } else { - bucket = props.existingBucketObj; - } + if (!props.existingBucketObj) { + [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + bucketProps: props.bucketProps + }); + bucket = this.s3Bucket; + } else { + bucket = props.existingBucketObj; + } - [this.cloudFrontWebDistribution, this.edgeLambdaFunctionVersion, this.cloudFrontLoggingBucket] = + [this.cloudFrontWebDistribution, this.edgeLambdaFunctionVersion, this.cloudFrontLoggingBucket] = defaults.CloudFrontDistributionForS3(this, bucket, - props.cloudFrontDistributionProps, props.insertHttpSecurityHeaders); + props.cloudFrontDistributionProps, props.insertHttpSecurityHeaders); } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/integ.existing-bucket.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/integ.existing-bucket.ts index 98ca1fa08..8519c2960 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/integ.existing-bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/integ.existing-bucket.ts @@ -28,20 +28,20 @@ let mybucket: s3.Bucket; [mybucket] = defaults.buildS3Bucket(stack, {}); const _construct = new CloudFrontToS3(stack, 'test-cloudfront-s3', { - existingBucketObj: mybucket + existingBucketObj: mybucket }); // Add Cache Policy const myCachePolicy = new cloudfront.CachePolicy(stack, 'myCachePolicy', { - cachePolicyName: 'MyPolicy', - defaultTtl: Duration.minutes(0), - minTtl: Duration.minutes(0), - maxTtl: Duration.minutes(0), + cachePolicyName: 'MyPolicy', + defaultTtl: Duration.minutes(0), + minTtl: Duration.minutes(0), + maxTtl: Duration.minutes(0), }); // Add behavior _construct.cloudFrontWebDistribution.addBehavior('/images/*.jpg', new origins.S3Origin(mybucket), { - cachePolicy: myCachePolicy + cachePolicy: myCachePolicy }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/integ.no-security-headers.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/integ.no-security-headers.ts index 42b025760..a000e7806 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/integ.no-security-headers.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-s3/test/integ.no-security-headers.ts @@ -22,7 +22,7 @@ stack.templateOptions.description = 'Integration Test for aws-cloudfront-s3'; // Definitions const props: CloudFrontToS3Props = { - insertHttpSecurityHeaders: false + insertHttpSecurityHeaders: false }; new CloudFrontToS3(stack, 'test-cloudfront-s3-no-security-headers', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/test/integ.no-arguments.ts index 6fcdf74b3..a4554f8f4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/test/integ.no-arguments.ts @@ -21,13 +21,13 @@ const app = new App(); const stack = new Stack(app, 'test-cognito-apigateway-lambda-stack'); const lambdaProps: lambda.FunctionProps = { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }; new CognitoToApiGatewayToLambda(stack, 'test-cognito-apigateway-lambda', { - lambdaFunctionProps: lambdaProps, + lambdaFunctionProps: lambdaProps, }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/test/test.cognito-apigateway-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/test/test.cognito-apigateway-lambda.test.ts index 077e8bb2f..ec99cfdad 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/test/test.cognito-apigateway-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/test/test.cognito-apigateway-lambda.test.ts @@ -57,24 +57,24 @@ test('override cognito properties', () => { }); expect(stack).toHaveResource('AWS::Cognito::UserPool', - { - AdminCreateUserConfig: { - AllowAdminCreateUserOnly: true - }, - EmailVerificationMessage: "The verification code to your new account is {####}", - EmailVerificationSubject: "Verify your new account", - SmsVerificationMessage: "The verification code to your new account is {####}", - UserPoolAddOns: { - AdvancedSecurityMode: "ENFORCED" - }, - UserPoolName: "test", - VerificationMessageTemplate: { - DefaultEmailOption: "CONFIRM_WITH_CODE", - EmailMessage: "The verification code to your new account is {####}", - EmailSubject: "Verify your new account", - SmsMessage: "The verification code to your new account is {####}" - } - }); + { + AdminCreateUserConfig: { + AllowAdminCreateUserOnly: true + }, + EmailVerificationMessage: "The verification code to your new account is {####}", + EmailVerificationSubject: "Verify your new account", + SmsVerificationMessage: "The verification code to your new account is {####}", + UserPoolAddOns: { + AdvancedSecurityMode: "ENFORCED" + }, + UserPoolName: "test", + VerificationMessageTemplate: { + DefaultEmailOption: "CONFIRM_WITH_CODE", + EmailMessage: "The verification code to your new account is {####}", + EmailSubject: "Verify your new account", + SmsMessage: "The verification code to your new account is {####}" + } + }); }); test('check exception for Missing existingObj from props', () => { diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/dynamodb-stream-lambda-elasticsearch-kibana.test.ts b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/dynamodb-stream-lambda-elasticsearch-kibana.test.ts index 67d685de8..3119024e3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/dynamodb-stream-lambda-elasticsearch-kibana.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/dynamodb-stream-lambda-elasticsearch-kibana.test.ts @@ -20,9 +20,9 @@ import '@aws-cdk/assert/jest'; function deployNewFunc(stack: cdk.Stack) { const props: DynamoDBStreamToLambdaToElasticSearchAndKibanaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }, domainName: 'test-domain' }; diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/integ.no-arguments.ts index 44e477b0b..3527e23b6 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda-elasticsearch-kibana/test/integ.no-arguments.ts @@ -21,12 +21,12 @@ const app = new App(); const stack = new Stack(app, 'test-dynamodb-stream-lambda-elasticsearch-kibana-stack'); const props: DynamoDBStreamToLambdaToElasticSearchAndKibanaProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }, - domainName: 'myconstructsdomain1' + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }, + domainName: 'myconstructsdomain1' }; new DynamoDBStreamToLambdaToElasticSearchAndKibana(stack, 'test-dynamodb-stream-lambda-elasticsearch-kibana', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts index 22aa09ad8..9b4607486 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/dynamodb-stream-lambda.test.ts @@ -21,9 +21,9 @@ import '@aws-cdk/assert/jest'; function deployNewFunc(stack: cdk.Stack) { const props: DynamoDBStreamToLambdaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }, }; diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/integ.no-arguments.ts index a7d6a2e86..0e03b7f7a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodb-stream-lambda/test/integ.no-arguments.ts @@ -21,14 +21,14 @@ const app = new App(); const stack = new Stack(app, 'test-dynamodb-stream-lambda-stack'); const props: DynamoDBStreamToLambdaProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }, - dynamoEventSourceProps: { - retryAttempts: 5 - } + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }, + dynamoEventSourceProps: { + retryAttempts: 5 + } }; new DynamoDBStreamToLambda(stack, 'test-dynamodb-stream-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/lib/index.ts index f786b7e59..923bab3da 100755 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/lib/index.ts @@ -91,14 +91,14 @@ export class EventsRuleToKinesisFirehoseToS3 extends Construct { // Setup the IAM policy that grants events rule the permission to send cw events data to kinesis firehose const eventsPolicy = new iam.Policy(this, 'EventsRuleInvokeKinesisFirehosePolicy', { - statements: [new iam.PolicyStatement({ - actions: [ - 'firehose:PutRecord', - 'firehose:PutRecordBatch' - ], - resources: [this.kinesisFirehose.attrArn] - }) - ]}); + statements: [new iam.PolicyStatement({ + actions: [ + 'firehose:PutRecord', + 'firehose:PutRecordBatch' + ], + resources: [this.kinesisFirehose.attrArn] + }) + ]}); // Attach policy to role eventsPolicy.attachToRole(this.eventsRole); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/test/events-rule-kinesisfirehose-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/test/events-rule-kinesisfirehose-s3.test.ts index 702e5d4f2..7ca71d395 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/test/events-rule-kinesisfirehose-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/test/events-rule-kinesisfirehose-s3.test.ts @@ -62,7 +62,7 @@ test('Test default server side s3 bucket encryption', () => { const stack = new cdk.Stack(); deployNewStack(stack); - // Assertions + // Assertions expect(stack).toHaveResource('AWS::S3::Bucket', { BucketEncryption: { ServerSideEncryptionConfiguration: [ @@ -122,5 +122,5 @@ test('Test property override', () => { IntervalInSeconds: 600, SizeInMBs: 55 } - }}); + }}); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/test/integ.events-rule-kinesisfirehose-s3-no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/test/integ.events-rule-kinesisfirehose-s3-no-arguments.ts index d351ff36a..b61eca3d9 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/test/integ.events-rule-kinesisfirehose-s3-no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisfirehose-s3/test/integ.events-rule-kinesisfirehose-s3-no-arguments.ts @@ -20,9 +20,9 @@ const stack = new Stack(app, 'test-events-rule-kinesisfirehose-s3'); stack.templateOptions.description = 'Integration Test for aws-events-rule-kinesisfirehose-s3'; const props: EventsRuleToKinesisFirehoseToS3Props = { - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - } + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + } }; new EventsRuleToKinesisFirehoseToS3(stack, 'test-events-rule-kinesisfirehose-s3', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/lib/index.ts index 6275d616f..f418fdf52 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/lib/index.ts @@ -64,42 +64,42 @@ export class EventsRuleToKinesisStreams extends Construct { * @access public */ constructor(scope: Construct, id: string, props: EventsRuleToKinesisStreamsProps) { - super(scope, id); + super(scope, id); - // Set up the Kinesis Stream - this.kinesisStream = defaults.buildKinesisStream(this, { - existingStreamObj: props.existingStreamObj, - kinesisStreamProps: props.kinesisStreamProps, - }); + // Set up the Kinesis Stream + this.kinesisStream = defaults.buildKinesisStream(this, { + existingStreamObj: props.existingStreamObj, + kinesisStreamProps: props.kinesisStreamProps, + }); - // Create an events service role - this.eventsRole = new iam.Role(this, 'eventsRole', { - assumedBy: new iam.ServicePrincipal('events.amazonaws.com'), - description: 'Events Rule Role', - }); + // Create an events service role + this.eventsRole = new iam.Role(this, 'eventsRole', { + assumedBy: new iam.ServicePrincipal('events.amazonaws.com'), + description: 'Events Rule Role', + }); - // Grant permission to events service role to allow event rule to send events data to the kinesis stream - this.kinesisStream.grantWrite(this.eventsRole); + // Grant permission to events service role to allow event rule to send events data to the kinesis stream + this.kinesisStream.grantWrite(this.eventsRole); - // Set up the Kinesis Stream as the target for event rule - const kinesisStreamEventTarget: events.IRuleTarget = { - bind: () => ({ - id: '', - arn: this.kinesisStream.streamArn, - role: this.eventsRole - }) - }; + // Set up the Kinesis Stream as the target for event rule + const kinesisStreamEventTarget: events.IRuleTarget = { + bind: () => ({ + id: '', + arn: this.kinesisStream.streamArn, + role: this.eventsRole + }) + }; - // Set up the events rule props - const defaultEventsRuleProps = defaults.DefaultEventsRuleProps([kinesisStreamEventTarget]); - const eventsRuleProps = overrideProps(defaultEventsRuleProps, props.eventRuleProps, true); + // Set up the events rule props + const defaultEventsRuleProps = defaults.DefaultEventsRuleProps([kinesisStreamEventTarget]); + const eventsRuleProps = overrideProps(defaultEventsRuleProps, props.eventRuleProps, true); - // Setup up the event rule - this.eventsRule = new events.Rule(this, 'EventsRule', eventsRuleProps); + // Setup up the event rule + this.eventsRule = new events.Rule(this, 'EventsRule', eventsRuleProps); - if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { - // Deploy best practices CW Alarms for Kinesis Stream - this.cloudwatchAlarms = defaults.buildKinesisStreamCWAlarms(this); + if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { + // Deploy best practices CW Alarms for Kinesis Stream + this.cloudwatchAlarms = defaults.buildKinesisStreamCWAlarms(this); } } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/events-rule-kinesisstreams.test.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/events-rule-kinesisstreams.test.ts index 65d33628a..469dd1565 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/events-rule-kinesisstreams.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/events-rule-kinesisstreams.test.ts @@ -59,7 +59,7 @@ test('Test default AWS managed encryption key property', () => { const stack = new cdk.Stack(); deployNewStack(stack); - // Assertions + // Assertions expect(stack).toHaveResource('AWS::Kinesis::Stream', { StreamEncryption: { EncryptionType: "KMS", @@ -76,31 +76,31 @@ test('Test existing resources', () => { // create resource const existingStream = new kinesis.Stream(stack, 'test-existing-stream', { - streamName: 'existing-stream', - shardCount: 5, - retentionPeriod: cdk.Duration.hours(48), - encryption: kinesis.StreamEncryption.UNENCRYPTED + streamName: 'existing-stream', + shardCount: 5, + retentionPeriod: cdk.Duration.hours(48), + encryption: kinesis.StreamEncryption.UNENCRYPTED }); new EventsRuleToKinesisStreams(stack, 'test-events-rule-kinesis-stream-existing-resource', { - existingStreamObj: existingStream, - // These properties will be ignored as existing object was provided - kinesisStreamProps: { - streamName: 'other-name-stream', - shardCount: 1, - retentionPeriod: cdk.Duration.hours(24) - }, - eventRuleProps: { - description: 'event rule props', - schedule: events.Schedule.rate(cdk.Duration.minutes(5)) + existingStreamObj: existingStream, + // These properties will be ignored as existing object was provided + kinesisStreamProps: { + streamName: 'other-name-stream', + shardCount: 1, + retentionPeriod: cdk.Duration.hours(24) + }, + eventRuleProps: { + description: 'event rule props', + schedule: events.Schedule.rate(cdk.Duration.minutes(5)) } }); // Assertions expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); expect(stack).toHaveResource('AWS::Kinesis::Stream', { - Name: 'existing-stream', - ShardCount: 5, - RetentionPeriodHours: 48, + Name: 'existing-stream', + ShardCount: 5, + RetentionPeriodHours: 48, }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/integ.events-rule-kinesisstreams-existing.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/integ.events-rule-kinesisstreams-existing.ts index 6833bc388..049db85e5 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/integ.events-rule-kinesisstreams-existing.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/integ.events-rule-kinesisstreams-existing.ts @@ -21,15 +21,15 @@ const stack = new Stack(app, 'test-existing-rule-kinesisstream'); stack.templateOptions.description = 'Integration Test for aws-events-rule-kinesisstreams with existing kinesis stream'; const stream = new kinesis.Stream(stack, 'test-stream', { - shardCount: 2, - encryption: kinesis.StreamEncryption.MANAGED + shardCount: 2, + encryption: kinesis.StreamEncryption.MANAGED }); const props: EventsRuleToKinesisStreamsProps = { - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - }, - existingStreamObj: stream + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + }, + existingStreamObj: stream }; new EventsRuleToKinesisStreams(stack, 'test-events-rule-kinesis-stream-existing', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/integ.events-rule-kinesisstreams-no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/integ.events-rule-kinesisstreams-no-arguments.ts index 9b3455f3c..c596df716 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/integ.events-rule-kinesisstreams-no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-kinesisstreams/test/integ.events-rule-kinesisstreams-no-arguments.ts @@ -20,9 +20,9 @@ const stack = new Stack(app, 'test-rule-kinesisstream'); stack.templateOptions.description = 'Integration Test for aws-events-rule-kinesisstreams'; const props: EventsRuleToKinesisStreamsProps = { - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - } + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + } }; new EventsRuleToKinesisStreams(stack, 'test-events-rule-kinesis-stream', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/test/events-rule-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/test/events-rule-lambda.test.ts index 4be9e5f0e..a71bc7ef3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/test/events-rule-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/test/events-rule-lambda.test.ts @@ -21,9 +21,9 @@ import * as cdk from '@aws-cdk/core'; function deployNewFunc(stack: cdk.Stack) { const props: EventsRuleToLambdaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }, eventRuleProps: { schedule: events.Schedule.rate(cdk.Duration.minutes(5)) @@ -181,7 +181,7 @@ test('check exception for Missing existingObj from props', () => { eventRuleProps: { schedule: events.Schedule.rate(cdk.Duration.minutes(5)) } - }; + }; try { new EventsRuleToLambda(stack, 'test-events-rule-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/test/integ.events-rule-no-argument.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/test/integ.events-rule-no-argument.ts index 2449bea35..e4d56932e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/test/integ.events-rule-no-argument.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-lambda/test/integ.events-rule-no-argument.ts @@ -22,14 +22,14 @@ const app = new App(); const stack = new Stack(app, 'test-events-rule-lambda-stack'); const props: EventsRuleToLambdaProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }, - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - } + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }, + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + } }; new EventsRuleToLambda(stack, 'test-events-rule-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/lib/index.ts index 6b1431eea..9f7922ef6 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/lib/index.ts @@ -73,40 +73,40 @@ export class EventsRuleToSns extends Construct { * @access public */ constructor(scope: Construct, id: string, props: EventsRuleToSnsProps) { - super(scope, id); + super(scope, id); - let enableEncryptionParam = props.enableEncryptionWithCustomerManagedKey; - if (props.enableEncryptionWithCustomerManagedKey === undefined || + let enableEncryptionParam = props.enableEncryptionWithCustomerManagedKey; + if (props.enableEncryptionWithCustomerManagedKey === undefined || props.enableEncryptionWithCustomerManagedKey === true) { - enableEncryptionParam = true; - } + enableEncryptionParam = true; + } - // Setup the sns topic. - [this.snsTopic, this.encryptionKey] = defaults.buildTopic(this, { - existingTopicObj: props.existingTopicObj, - topicProps: props.topicsProps, - enableEncryptionWithCustomerManagedKey: enableEncryptionParam, - encryptionKey: props.encryptionKey, - encryptionKeyProps: props.encryptionKeyProps - }); + // Setup the sns topic. + [this.snsTopic, this.encryptionKey] = defaults.buildTopic(this, { + existingTopicObj: props.existingTopicObj, + topicProps: props.topicsProps, + enableEncryptionWithCustomerManagedKey: enableEncryptionParam, + encryptionKey: props.encryptionKey, + encryptionKeyProps: props.encryptionKeyProps + }); - // Setup the event rule target as sns topic. - const topicEventTarget: events.IRuleTarget = { - bind: () => ({ - id: this.snsTopic.topicName, - arn: this.snsTopic.topicArn - }) - }; + // Setup the event rule target as sns topic. + const topicEventTarget: events.IRuleTarget = { + bind: () => ({ + id: this.snsTopic.topicName, + arn: this.snsTopic.topicArn + }) + }; - // Setup up the event rule property. - const defaultEventsRuleProps = defaults.DefaultEventsRuleProps([topicEventTarget]); - const eventsRuleProps = overrideProps(defaultEventsRuleProps, props.eventRuleProps, true); + // Setup up the event rule property. + const defaultEventsRuleProps = defaults.DefaultEventsRuleProps([topicEventTarget]); + const eventsRuleProps = overrideProps(defaultEventsRuleProps, props.eventRuleProps, true); - // Setup up the event rule. - this.eventsRule = new events.Rule(this, 'EventsRule', eventsRuleProps); + // Setup up the event rule. + this.eventsRule = new events.Rule(this, 'EventsRule', eventsRuleProps); - // Setup up the grant policy for event to be able to publish to the sns topic. - this.snsTopic.grantPublish(new ServicePrincipal('events.amazonaws.com')); + // Setup up the grant policy for event to be able to publish to the sns topic. + this.snsTopic.grantPublish(new ServicePrincipal('events.amazonaws.com')); // Grant EventBridge service access to the SNS Topic encryption key this.encryptionKey?.grant(new ServicePrincipal('events.amazonaws.com'), diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/test/events-rule-sns-topic.test.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/test/events-rule-sns-topic.test.ts index a116b1dc3..94a070e5e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/test/events-rule-sns-topic.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/test/events-rule-sns-topic.test.ts @@ -37,95 +37,95 @@ test('check if the event rule has permission/policy in place in sns for it to be const stack = new cdk.Stack(); deployNewStack(stack); expect(stack).toHaveResource('AWS::SNS::TopicPolicy', { - PolicyDocument: { - Statement: [ - { - Action: [ - "SNS:Publish", - "SNS:RemovePermission", - "SNS:SetTopicAttributes", - "SNS:DeleteTopic", - "SNS:ListSubscriptionsByTopic", - "SNS:GetTopicAttributes", - "SNS:Receive", - "SNS:AddPermission", - "SNS:Subscribe" - ], - Condition: { - StringEquals: { - "AWS:SourceOwner": { - Ref: "AWS::AccountId" - } + PolicyDocument: { + Statement: [ + { + Action: [ + "SNS:Publish", + "SNS:RemovePermission", + "SNS:SetTopicAttributes", + "SNS:DeleteTopic", + "SNS:ListSubscriptionsByTopic", + "SNS:GetTopicAttributes", + "SNS:Receive", + "SNS:AddPermission", + "SNS:Subscribe" + ], + Condition: { + StringEquals: { + "AWS:SourceOwner": { + Ref: "AWS::AccountId" } - }, - Effect: "Allow", - Principal: { - AWS: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition" - }, - ":iam::", - { - Ref: "AWS::AccountId" - }, - ":root" - ] + } + }, + Effect: "Allow", + Principal: { + AWS: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition" + }, + ":iam::", + { + Ref: "AWS::AccountId" + }, + ":root" ] - } - }, - Resource: { - Ref: "testSnsTopic42942701" - }, - Sid: "TopicOwnerOnlyAccess" + ] + } }, - { - Action: [ - "SNS:Publish", - "SNS:RemovePermission", - "SNS:SetTopicAttributes", - "SNS:DeleteTopic", - "SNS:ListSubscriptionsByTopic", - "SNS:GetTopicAttributes", - "SNS:Receive", - "SNS:AddPermission", - "SNS:Subscribe" - ], - Condition: { - Bool: { - "aws:SecureTransport": "false" - } - }, - Effect: "Deny", - Principal: "*", - Resource: { - Ref: "testSnsTopic42942701" - }, - Sid: "HttpsOnly" + Resource: { + Ref: "testSnsTopic42942701" }, - { - Action: "sns:Publish", - Effect: "Allow", - Principal: { - Service: "events.amazonaws.com" - }, - Resource: { - Ref: "testSnsTopic42942701" - }, - Sid: "2" - } - ], - Version: "2012-10-17" - }, - Topics: [ + Sid: "TopicOwnerOnlyAccess" + }, { - Ref: "testSnsTopic42942701" + Action: [ + "SNS:Publish", + "SNS:RemovePermission", + "SNS:SetTopicAttributes", + "SNS:DeleteTopic", + "SNS:ListSubscriptionsByTopic", + "SNS:GetTopicAttributes", + "SNS:Receive", + "SNS:AddPermission", + "SNS:Subscribe" + ], + Condition: { + Bool: { + "aws:SecureTransport": "false" + } + }, + Effect: "Deny", + Principal: "*", + Resource: { + Ref: "testSnsTopic42942701" + }, + Sid: "HttpsOnly" + }, + { + Action: "sns:Publish", + Effect: "Allow", + Principal: { + Service: "events.amazonaws.com" + }, + Resource: { + Ref: "testSnsTopic42942701" + }, + Sid: "2" } - ] - } + ], + Version: "2012-10-17" + }, + Topics: [ + { + Ref: "testSnsTopic42942701" + } + ] + } ); }); @@ -182,7 +182,7 @@ test('check the sns topic properties with existing KMS key', () => { const props: EventsRuleToSnsProps = { eventRuleProps: { - schedule: events.Schedule.rate(cdk.Duration.minutes(5)) + schedule: events.Schedule.rate(cdk.Duration.minutes(5)) }, encryptionKey: key }; diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/test/integ.events-rule-no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/test/integ.events-rule-no-arguments.ts index fc3006300..8e205d629 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/test/integ.events-rule-no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sns/test/integ.events-rule-no-arguments.ts @@ -20,9 +20,9 @@ const app = new App(); const stack = new Stack(app, 'test-rule-sns'); const props: EventsRuleToSnsProps = { - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - } + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + } }; new EventsRuleToSns(stack, 'test-construct', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/lib/index.ts index 658d2375e..d8798f4b0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/lib/index.ts @@ -114,17 +114,17 @@ export class EventsRuleToSqs extends Construct { let enableEncryptionParam = props.enableEncryptionWithCustomerManagedKey; if (props.enableEncryptionWithCustomerManagedKey === undefined || props.enableEncryptionWithCustomerManagedKey === true) { - enableEncryptionParam = true; + enableEncryptionParam = true; } // Setup the queue [this.sqsQueue, this.encryptionKey] = defaults.buildQueue(this, 'queue', { - existingQueueObj: props.existingQueueObj, - queueProps: props.queueProps, - deadLetterQueue: this.deadLetterQueue, - enableEncryptionWithCustomerManagedKey: enableEncryptionParam, - encryptionKey: props.encryptionKey, - encryptionKeyProps: props.encryptionKeyProps + existingQueueObj: props.existingQueueObj, + queueProps: props.queueProps, + deadLetterQueue: this.deadLetterQueue, + enableEncryptionWithCustomerManagedKey: enableEncryptionParam, + encryptionKey: props.encryptionKey, + encryptionKeyProps: props.encryptionKeyProps }); const sqsEventTarget: events.IRuleTarget = { diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/events-rule-sqs-queue.test.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/events-rule-sqs-queue.test.ts index fd1959c99..4ab1f87fc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/events-rule-sqs-queue.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/events-rule-sqs-queue.test.ts @@ -20,9 +20,9 @@ import * as defaults from '@aws-solutions-constructs/core'; function deployNewStack(stack: cdk.Stack) { const props: EventsRuleToSqsProps = { - eventRuleProps: { - schedule: events.Schedule.rate(cdk.Duration.minutes(5)) - } + eventRuleProps: { + schedule: events.Schedule.rate(cdk.Duration.minutes(5)) + } }; return new EventsRuleToSqs(stack, 'test-events-rule-sqs', props); } @@ -63,7 +63,7 @@ test('check the sqs queue properties with existing KMS key', () => { const props: EventsRuleToSqsProps = { eventRuleProps: { - schedule: events.Schedule.rate(cdk.Duration.minutes(5)) + schedule: events.Schedule.rate(cdk.Duration.minutes(5)) }, encryptionKey: key }; @@ -155,87 +155,87 @@ test('check if the event rule has permission/policy in place in sqs queue for it const stack = new cdk.Stack(); deployNewStack(stack); expect(stack).toHaveResource('AWS::SQS::QueuePolicy', { - PolicyDocument: { - Statement: [ - { - Action: [ - "sqs:DeleteMessage", - "sqs:ReceiveMessage", - "sqs:SendMessage", - "sqs:GetQueueAttributes", - "sqs:RemovePermission", - "sqs:AddPermission", - "sqs:SetQueueAttributes", - ], - Effect: "Allow", - Principal: { - AWS: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition", - }, - ":iam::", - { - Ref: "AWS::AccountId", - }, - ":root" - ], - ], - }, - }, - Resource: { - "Fn::GetAtt": [ - "testeventsrulesqsqueueAACD0364", - "Arn", + PolicyDocument: { + Statement: [ + { + Action: [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes", + ], + Effect: "Allow", + Principal: { + AWS: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition", + }, + ":iam::", + { + Ref: "AWS::AccountId", + }, + ":root" ], - }, - Sid: "QueueOwnerOnlyAccess", + ], }, - { - Action: "SQS:*", - Condition: { - Bool: { - "aws:SecureTransport": "false", - }, - }, - Effect: "Deny", - Principal: "*", - Resource: { - "Fn::GetAtt": [ - "testeventsrulesqsqueueAACD0364", - "Arn", - ], - }, - Sid: "HttpsOnly", + }, + Resource: { + "Fn::GetAtt": [ + "testeventsrulesqsqueueAACD0364", + "Arn", + ], + }, + Sid: "QueueOwnerOnlyAccess", + }, + { + Action: "SQS:*", + Condition: { + Bool: { + "aws:SecureTransport": "false", }, - { - Action: [ - "sqs:SendMessage", - "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" - ], - Effect: "Allow", - Principal: { - Service: "events.amazonaws.com" - }, - Resource: { - "Fn::GetAtt": [ - "testeventsrulesqsqueueAACD0364", - "Arn" - ] - } - } + }, + Effect: "Deny", + Principal: "*", + Resource: { + "Fn::GetAtt": [ + "testeventsrulesqsqueueAACD0364", + "Arn", + ], + }, + Sid: "HttpsOnly", + }, + { + Action: [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" ], - Version: "2012-10-17" - }, - Queues: [ - { - Ref: "testeventsrulesqsqueueAACD0364", - } - ] + Effect: "Allow", + Principal: { + Service: "events.amazonaws.com" + }, + Resource: { + "Fn::GetAtt": [ + "testeventsrulesqsqueueAACD0364", + "Arn" + ] + } + } + ], + Version: "2012-10-17" + }, + Queues: [ + { + Ref: "testeventsrulesqsqueueAACD0364", + } + ] }); }); @@ -243,70 +243,70 @@ test('check if the dead letter queue policy is setup', () => { const stack = new cdk.Stack(); deployNewStack(stack); expect(stack).toHaveResource('AWS::SQS::QueuePolicy', { - PolicyDocument: { - Statement: [ - { - Action: [ - "sqs:DeleteMessage", - "sqs:ReceiveMessage", - "sqs:SendMessage", - "sqs:GetQueueAttributes", - "sqs:RemovePermission", - "sqs:AddPermission", - "sqs:SetQueueAttributes", - ], - Effect: "Allow", - Principal: { - AWS: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition", - }, - ":iam::", - { - Ref: "AWS::AccountId" - }, - ":root" - ], - ], - }, - }, - Resource: { - "Fn::GetAtt": [ - "testeventsrulesqsdeadLetterQueueA4A15A1C", - "Arn", - ], - }, - Sid: "QueueOwnerOnlyAccess", - }, - { - Action: "SQS:*", - Condition: { - Bool: { - "aws:SecureTransport": "false", - }, - }, - Effect: "Deny", - Principal: "*", - Resource: { - "Fn::GetAtt": [ - "testeventsrulesqsdeadLetterQueueA4A15A1C", - "Arn", + PolicyDocument: { + Statement: [ + { + Action: [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes", + ], + Effect: "Allow", + Principal: { + AWS: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition", + }, + ":iam::", + { + Ref: "AWS::AccountId" + }, + ":root" ], - }, - Sid: "HttpsOnly", + ], }, - ], - Version: "2012-10-17", + }, + Resource: { + "Fn::GetAtt": [ + "testeventsrulesqsdeadLetterQueueA4A15A1C", + "Arn", + ], + }, + Sid: "QueueOwnerOnlyAccess", }, - Queues: [ - { - Ref: "testeventsrulesqsdeadLetterQueueA4A15A1C", + { + Action: "SQS:*", + Condition: { + Bool: { + "aws:SecureTransport": "false", + }, }, - ] + Effect: "Deny", + Principal: "*", + Resource: { + "Fn::GetAtt": [ + "testeventsrulesqsdeadLetterQueueA4A15A1C", + "Arn", + ], + }, + Sid: "HttpsOnly", + }, + ], + Version: "2012-10-17", + }, + Queues: [ + { + Ref: "testeventsrulesqsdeadLetterQueueA4A15A1C", + }, + ] }); }); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/integ.events-rule-existing-queue.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/integ.events-rule-existing-queue.ts index 238ebf3ea..65be028d2 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/integ.events-rule-existing-queue.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/integ.events-rule-existing-queue.ts @@ -22,17 +22,17 @@ const app = new App(); const stack = new Stack(app, 'test-rule-exist-sqs'); const existingQueueObj = new sqs.Queue(stack, 'MyQueue', { - encryption: sqs.QueueEncryption.KMS, - encryptionMasterKey: new kms.Key(stack, 'MyKey', { - enableKeyRotation: true - }), + encryption: sqs.QueueEncryption.KMS, + encryptionMasterKey: new kms.Key(stack, 'MyKey', { + enableKeyRotation: true + }), }); const props: EventsRuleToSqsProps = { - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - }, - existingQueueObj + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + }, + existingQueueObj }; new EventsRuleToSqs(stack, 'construct', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/integ.events-rule-no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/integ.events-rule-no-arguments.ts index 1e5777f36..39354f670 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/integ.events-rule-no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-sqs/test/integ.events-rule-no-arguments.ts @@ -20,9 +20,9 @@ const app = new App(); const stack = new Stack(app, 'test-rule-sqs'); const props: EventsRuleToSqsProps = { - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - } + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + } }; new EventsRuleToSqs(stack, 'construct', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/test/integ.events-rule-step-function-no-argument.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/test/integ.events-rule-step-function-no-argument.ts index e781daf1a..6942cf5b0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/test/integ.events-rule-step-function-no-argument.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/test/integ.events-rule-step-function-no-argument.ts @@ -24,12 +24,12 @@ const stack = new Stack(app, 'test-events-rule-step-function-stack'); const startState = new stepfunctions.Pass(stack, 'StartState'); const props: EventsRuleToStepFunctionProps = { - stateMachineProps: { - definition: startState - }, - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - } + stateMachineProps: { + definition: startState + }, + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + } }; new EventsRuleToStepFunction(stack, 'test-events-rule-step-function-stack', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/test/integ.events-rule-step-function-with-lambda.ts b/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/test/integ.events-rule-step-function-with-lambda.ts index 59f0f7752..3d48dfdde 100644 --- a/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/test/integ.events-rule-step-function-with-lambda.ts +++ b/source/patterns/@aws-solutions-constructs/aws-events-rule-step-function/test/integ.events-rule-step-function-with-lambda.ts @@ -33,17 +33,17 @@ const submitLambda = deployLambdaFunction(stack, { const submitJob = new tasks.RunLambdaTask(submitLambda); const startState = new stepfunctions.Pass(stack, 'StartState'); startState.next(new stepfunctions.Task(stack, 'LambdaTask', { - task: submitJob + task: submitJob })); const props: EventsRuleToStepFunctionProps = { - stateMachineProps: { - definition: startState, - timeout: Duration.minutes(5) - }, - eventRuleProps: { - schedule: events.Schedule.rate(Duration.minutes(5)) - } + stateMachineProps: { + definition: startState, + timeout: Duration.minutes(5) + }, + eventRuleProps: { + schedule: events.Schedule.rate(Duration.minutes(5)) + } }; new EventsRuleToStepFunction(stack, 'test-events-rule-step-function-and-lambda-stack', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/lib/index.ts index c1a8bfd5c..1b9d8ab02 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/lib/index.ts @@ -69,47 +69,47 @@ export class IotToKinesisFirehoseToS3 extends Construct { * @access public */ constructor(scope: Construct, id: string, props: IotToKinesisFirehoseToS3Props) { - super(scope, id); + super(scope, id); - const firehoseToS3 = new KinesisFirehoseToS3(this, 'KinesisFirehoseToS3', { - kinesisFirehoseProps: props.kinesisFirehoseProps, - existingBucketObj: props.existingBucketObj, - bucketProps: props.bucketProps - }); - this.kinesisFirehose = firehoseToS3.kinesisFirehose; - this.s3Bucket = firehoseToS3.s3Bucket; + const firehoseToS3 = new KinesisFirehoseToS3(this, 'KinesisFirehoseToS3', { + kinesisFirehoseProps: props.kinesisFirehoseProps, + existingBucketObj: props.existingBucketObj, + bucketProps: props.bucketProps + }); + this.kinesisFirehose = firehoseToS3.kinesisFirehose; + this.s3Bucket = firehoseToS3.s3Bucket; - // Setup the IAM Role for IoT Actions - this.iotActionsRole = new iam.Role(this, 'IotActionsRole', { - assumedBy: new iam.ServicePrincipal('iot.amazonaws.com'), - }); + // Setup the IAM Role for IoT Actions + this.iotActionsRole = new iam.Role(this, 'IotActionsRole', { + assumedBy: new iam.ServicePrincipal('iot.amazonaws.com'), + }); - // Setup the IAM policy for IoT Actions - const iotActionsPolicy = new iam.Policy(this, 'IotActionsPolicy', { - statements: [new iam.PolicyStatement({ - actions: [ - 'firehose:PutRecord' - ], - resources: [this.kinesisFirehose.attrArn] - }) + // Setup the IAM policy for IoT Actions + const iotActionsPolicy = new iam.Policy(this, 'IotActionsPolicy', { + statements: [new iam.PolicyStatement({ + actions: [ + 'firehose:PutRecord' + ], + resources: [this.kinesisFirehose.attrArn] + }) ]}); - // Attach policy to role - iotActionsPolicy.attachToRole(this.iotActionsRole); + // Attach policy to role + iotActionsPolicy.attachToRole(this.iotActionsRole); - const defaultIotTopicProps = defaults.DefaultCfnTopicRuleProps([{ - firehose: { - deliveryStreamName: this.kinesisFirehose.ref, - roleArn: this.iotActionsRole.roleArn - } - }]); - const iotTopicProps = overrideProps(defaultIotTopicProps, props.iotTopicRuleProps, true); + const defaultIotTopicProps = defaults.DefaultCfnTopicRuleProps([{ + firehose: { + deliveryStreamName: this.kinesisFirehose.ref, + roleArn: this.iotActionsRole.roleArn + } + }]); + const iotTopicProps = overrideProps(defaultIotTopicProps, props.iotTopicRuleProps, true); - // Create the IoT topic rule - this.iotTopicRule = new iot.CfnTopicRule(this, 'IotTopic', iotTopicProps); + // Create the IoT topic rule + this.iotTopicRule = new iot.CfnTopicRule(this, 'IotTopic', iotTopicProps); - this.kinesisFirehoseRole = firehoseToS3.kinesisFirehoseRole; - this.s3LoggingBucket = firehoseToS3.s3LoggingBucket; - this.kinesisFirehoseLogGroup = firehoseToS3.kinesisFirehoseLogGroup; + this.kinesisFirehoseRole = firehoseToS3.kinesisFirehoseRole; + this.s3LoggingBucket = firehoseToS3.s3LoggingBucket; + this.kinesisFirehoseLogGroup = firehoseToS3.kinesisFirehoseLogGroup; } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/integ.no-arguments.ts index aacaadfe8..a173ae64c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/integ.no-arguments.ts @@ -22,14 +22,14 @@ stack.templateOptions.description = 'Integration Test for aws-iot-kinesisfirehos // Definitions const props: IotToKinesisFirehoseToS3Props = { - iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Persistent storage of connected vehicle telematics data", - sql: "SELECT * FROM 'connectedcar/telemetry/#'", - actions: [] - } + iotTopicRuleProps: { + topicRulePayload: { + ruleDisabled: false, + description: "Persistent storage of connected vehicle telematics data", + sql: "SELECT * FROM 'connectedcar/telemetry/#'", + actions: [] } + } }; new IotToKinesisFirehoseToS3(stack, 'test-iot-firehose-s3', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/test.iot-kinesisfirehose-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/test.iot-kinesisfirehose-s3.test.ts index d7d9c2953..f6d86f650 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/test.iot-kinesisfirehose-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-kinesisfirehose-s3/test/test.iot-kinesisfirehose-s3.test.ts @@ -19,12 +19,12 @@ import '@aws-cdk/assert/jest'; function deploy(stack: cdk.Stack) { const props: IotToKinesisFirehoseToS3Props = { iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Persistent storage of connected vehicle telematics data", - sql: "SELECT * FROM 'connectedcar/telemetry/#'", - actions: [] - } + topicRulePayload: { + ruleDisabled: false, + description: "Persistent storage of connected vehicle telematics data", + sql: "SELECT * FROM 'connectedcar/telemetry/#'", + actions: [] + } } }; @@ -43,26 +43,26 @@ test('check iot topic rule properties', () => { deploy(stack); expect(stack).toHaveResource('AWS::IoT::TopicRule', { - TopicRulePayload: { - Actions: [ - { - Firehose: { - DeliveryStreamName: { - Ref: "testiotfirehoses3KinesisFirehoseToS3KinesisFirehose68DB2BEE" - }, - RoleArn: { - "Fn::GetAtt": [ - "testiotfirehoses3IotActionsRole743F8973", - "Arn" - ] - } + TopicRulePayload: { + Actions: [ + { + Firehose: { + DeliveryStreamName: { + Ref: "testiotfirehoses3KinesisFirehoseToS3KinesisFirehose68DB2BEE" + }, + RoleArn: { + "Fn::GetAtt": [ + "testiotfirehoses3IotActionsRole743F8973", + "Arn" + ] } } - ], - Description: "Persistent storage of connected vehicle telematics data", - RuleDisabled: false, - Sql: "SELECT * FROM 'connectedcar/telemetry/#'" - } + } + ], + Description: "Persistent storage of connected vehicle telematics data", + RuleDisabled: false, + Sql: "SELECT * FROM 'connectedcar/telemetry/#'" + } }); }); @@ -71,12 +71,12 @@ test('check firehose and s3 overrides', () => { const props: IotToKinesisFirehoseToS3Props = { iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Persistent storage of connected vehicle telematics data", - sql: "SELECT * FROM 'connectedcar/telemetry/#'", - actions: [] - } + topicRulePayload: { + ruleDisabled: false, + description: "Persistent storage of connected vehicle telematics data", + sql: "SELECT * FROM 'connectedcar/telemetry/#'", + actions: [] + } }, kinesisFirehoseProps: { extendedS3DestinationConfiguration: { @@ -112,7 +112,7 @@ test('check firehose and s3 overrides', () => { IntervalInSeconds: 600, SizeInMBs: 55 } - }}); + }}); }); test('check properties', () => { const stack = new cdk.Stack(); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/integ.iot-lambda-dynamodb.ts b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/integ.iot-lambda-dynamodb.ts index 2c36123fc..a9b00571f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/integ.iot-lambda-dynamodb.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/integ.iot-lambda-dynamodb.ts @@ -20,19 +20,19 @@ const app = new App(); const stack = new Stack(app, 'test-iot-lambda-dynamodb-stack'); const props: IotToLambdaToDynamoDBProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' - }, - iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] - } + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' + }, + iotTopicRuleProps: { + topicRulePayload: { + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] } + } }; new IotToLambdaToDynamoDB(stack, 'test-iot-lambda-dynamodb-stack', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts index 22d10e2b7..d77226cdd 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda-dynamodb/test/iot-lambda-dynamodb.test.ts @@ -25,12 +25,12 @@ function deployStack(stack: cdk.Stack) { handler: 'index.handler' }, iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] - } + topicRulePayload: { + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] + } } }; @@ -49,22 +49,22 @@ test('check lambda function properties', () => { deployStack(stack); expect(stack).toHaveResource('AWS::Lambda::Function', { - Handler: "index.handler", - Role: { - "Fn::GetAtt": [ - "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA", - "Arn" - ] - }, - Runtime: "nodejs10.x", - Environment: { - Variables: { - AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1", - DDB_TABLE_NAME: { - Ref: "testiotlambdadynamodbstackLambdaToDynamoDBDynamoTableE17E5733" - } + Handler: "index.handler", + Role: { + "Fn::GetAtt": [ + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionServiceRoleC57F7FDA", + "Arn" + ] + }, + Runtime: "nodejs10.x", + Environment: { + Variables: { + AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1", + DDB_TABLE_NAME: { + Ref: "testiotlambdadynamodbstackLambdaToDynamoDBDynamoTableE17E5733" } } + } }); }); @@ -74,20 +74,20 @@ test('check lambda function permission', () => { deployStack(stack); expect(stack).toHaveResource('AWS::Lambda::Permission', { - Action: "lambda:InvokeFunction", - FunctionName: { - "Fn::GetAtt": [ - "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", - "Arn" - ] - }, - Principal: "iot.amazonaws.com", - SourceArn: { - "Fn::GetAtt": [ - "testiotlambdadynamodbstackIotToLambdaIotTopic74F5E3BB", - "Arn" - ] - } + Action: "lambda:InvokeFunction", + FunctionName: { + "Fn::GetAtt": [ + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", + "Arn" + ] + }, + Principal: "iot.amazonaws.com", + SourceArn: { + "Fn::GetAtt": [ + "testiotlambdadynamodbstackIotToLambdaIotTopic74F5E3BB", + "Arn" + ] + } }); }); @@ -156,23 +156,23 @@ test('check iot topic rule properties', () => { deployStack(stack); expect(stack).toHaveResource('AWS::IoT::TopicRule', { - TopicRulePayload: { - Actions: [ - { - Lambda: { - FunctionArn: { - "Fn::GetAtt": [ - "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", - "Arn" - ] - } + TopicRulePayload: { + Actions: [ + { + Lambda: { + FunctionArn: { + "Fn::GetAtt": [ + "testiotlambdadynamodbstackIotToLambdaLambdaFunctionDFEAF894", + "Arn" + ] } } - ], - Description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - RuleDisabled: false, - Sql: "SELECT * FROM 'connectedcar/dtc/#'" - } + } + ], + Description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + RuleDisabled: false, + Sql: "SELECT * FROM 'connectedcar/dtc/#'" + } }); }); @@ -265,13 +265,13 @@ test('check exception for Missing existingObj from props for deploy = false', () const stack = new cdk.Stack(); const props: IotToLambdaToDynamoDBProps = { - iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] - } + iotTopicRuleProps: { + topicRulePayload: { + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] + } } }; diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/integ.iot-lambda-new-func.ts b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/integ.iot-lambda-new-func.ts index a3c02319a..b700f61fa 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/integ.iot-lambda-new-func.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/integ.iot-lambda-new-func.ts @@ -20,19 +20,19 @@ const app = new App(); const stack = new Stack(app, 'test-iot-lambda-stack'); const props: IotToLambdaProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' - }, - iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] - } + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' + }, + iotTopicRuleProps: { + topicRulePayload: { + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] } + } }; new IotToLambda(stack, 'test-iot-lambda-integration', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/integ.iot-lambda-use-existing-func.ts b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/integ.iot-lambda-use-existing-func.ts index f40fb37a3..553479cdc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/integ.iot-lambda-use-existing-func.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/integ.iot-lambda-use-existing-func.ts @@ -22,24 +22,24 @@ const app = new App(); const stack = new Stack(app, 'test-iot-lambda-stack'); const lambdaFunctionProps = { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) }; const func = defaults.deployLambdaFunction(stack, lambdaFunctionProps); // Definitions const props: IotToLambdaProps = { - existingLambdaObj: func, - iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] - } + existingLambdaObj: func, + iotTopicRuleProps: { + topicRulePayload: { + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] } + } }; new IotToLambda(stack, 'test-iot-lambda-integration', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/iot-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/iot-lambda.test.ts index 85bf98e98..2ddab2594 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/iot-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-lambda/test/iot-lambda.test.ts @@ -25,12 +25,12 @@ function deployNewFunc(stack: cdk.Stack) { handler: 'index.handler' }, iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] - } + topicRulePayload: { + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] + } } }; @@ -40,21 +40,21 @@ function deployNewFunc(stack: cdk.Stack) { function useExistingFunc(stack: cdk.Stack) { const lambdaFunctionProps: lambda.FunctionProps = { - runtime: lambda.Runtime.PYTHON_3_6, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) + runtime: lambda.Runtime.PYTHON_3_6, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) }; const props: IotToLambdaProps = { - existingLambdaObj: new lambda.Function(stack, 'MyExistingFunction', lambdaFunctionProps), - iotTopicRuleProps: { - topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] - } + existingLambdaObj: new lambda.Function(stack, 'MyExistingFunction', lambdaFunctionProps), + iotTopicRuleProps: { + topicRulePayload: { + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] } + } }; return new IotToLambda(stack, 'test-iot-lambda-integration', props); @@ -72,38 +72,38 @@ test('check lambda function properties for deploy: true', () => { deployNewFunc(stack); expect(stack).toHaveResource('AWS::Lambda::Function', { - Handler: "index.handler", - Role: { - "Fn::GetAtt": [ - "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41", - "Arn" - ] - }, - Runtime: "nodejs10.x" + Handler: "index.handler", + Role: { + "Fn::GetAtt": [ + "testiotlambdaintegrationLambdaFunctionServiceRole27C3EE41", + "Arn" + ] + }, + Runtime: "nodejs10.x" }); }); test('check lambda function permission for deploy: true', () => { - const stack = new cdk.Stack(); + const stack = new cdk.Stack(); - deployNewFunc(stack); + deployNewFunc(stack); - expect(stack).toHaveResource('AWS::Lambda::Permission', { - Action: "lambda:InvokeFunction", - FunctionName: { - "Fn::GetAtt": [ - "testiotlambdaintegrationLambdaFunctionC5329DBA", - "Arn" - ] - }, - Principal: "iot.amazonaws.com", - SourceArn: { - "Fn::GetAtt": [ - "testiotlambdaintegrationIotTopic18B6A735", - "Arn" - ] - } - }); + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: "lambda:InvokeFunction", + FunctionName: { + "Fn::GetAtt": [ + "testiotlambdaintegrationLambdaFunctionC5329DBA", + "Arn" + ] + }, + Principal: "iot.amazonaws.com", + SourceArn: { + "Fn::GetAtt": [ + "testiotlambdaintegrationIotTopic18B6A735", + "Arn" + ] + } + }); }); test('check iot lambda function role for deploy: true', () => { @@ -166,46 +166,46 @@ test('check iot lambda function role for deploy: true', () => { }); test('check iot topic rule properties for deploy: true', () => { - const stack = new cdk.Stack(); + const stack = new cdk.Stack(); - deployNewFunc(stack); + deployNewFunc(stack); - expect(stack).toHaveResource('AWS::IoT::TopicRule', { - TopicRulePayload: { - Actions: [ - { - Lambda: { - FunctionArn: { - "Fn::GetAtt": [ - "testiotlambdaintegrationLambdaFunctionC5329DBA", - "Arn" - ] - } - } + expect(stack).toHaveResource('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + { + Lambda: { + FunctionArn: { + "Fn::GetAtt": [ + "testiotlambdaintegrationLambdaFunctionC5329DBA", + "Arn" + ] } - ], - Description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - RuleDisabled: false, - Sql: "SELECT * FROM 'connectedcar/dtc/#'" + } } - }); + ], + Description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + RuleDisabled: false, + Sql: "SELECT * FROM 'connectedcar/dtc/#'" + } + }); }); test('check lambda function properties for deploy: false', () => { - const stack = new cdk.Stack(); + const stack = new cdk.Stack(); - useExistingFunc(stack); + useExistingFunc(stack); - expect(stack).toHaveResource('AWS::Lambda::Function', { - Handler: "index.handler", - Role: { - "Fn::GetAtt": [ - "MyExistingFunctionServiceRoleF9E14BFD", - "Arn" - ] - }, - Runtime: "python3.6" - }); + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: "index.handler", + Role: { + "Fn::GetAtt": [ + "MyExistingFunctionServiceRoleF9E14BFD", + "Arn" + ] + }, + Runtime: "python3.6" + }); }); test('check lambda function permissions for deploy: false', () => { @@ -214,21 +214,21 @@ test('check lambda function permissions for deploy: false', () => { useExistingFunc(stack); expect(stack).toHaveResource('AWS::Lambda::Permission', { - Action: "lambda:InvokeFunction", - FunctionName: { - "Fn::GetAtt": [ - "MyExistingFunction4D772515", - "Arn" - ] - }, - Principal: "iot.amazonaws.com", - SourceArn: { - "Fn::GetAtt": [ - "testiotlambdaintegrationIotTopic18B6A735", - "Arn" - ] - } - }); + Action: "lambda:InvokeFunction", + FunctionName: { + "Fn::GetAtt": [ + "MyExistingFunction4D772515", + "Arn" + ] + }, + Principal: "iot.amazonaws.com", + SourceArn: { + "Fn::GetAtt": [ + "testiotlambdaintegrationIotTopic18B6A735", + "Arn" + ] + } + }); }); test('check iot lambda function role for deploy: false', () => { @@ -267,12 +267,12 @@ test('check iot lambda function role for deploy: false', () => { }); test('check properties', () => { - const stack = new cdk.Stack(); + const stack = new cdk.Stack(); - const construct: IotToLambda = deployNewFunc(stack); + const construct: IotToLambda = deployNewFunc(stack); - expect(construct.iotTopicRule !== null); - expect(construct.lambdaFunction !== null); + expect(construct.iotTopicRule !== null); + expect(construct.lambdaFunction !== null); }); test('check exception for Missing existingObj from props for deploy = false', () => { @@ -281,10 +281,10 @@ test('check exception for Missing existingObj from props for deploy = false', () const props: IotToLambdaProps = { iotTopicRuleProps: { topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] } } }; @@ -302,10 +302,10 @@ test('check deploy = true and no prop', () => { const props: IotToLambdaProps = { iotTopicRuleProps: { topicRulePayload: { - ruleDisabled: false, - description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", - sql: "SELECT * FROM 'connectedcar/dtc/#'", - actions: [] + ruleDisabled: false, + description: "Processing of DTC messages from the AWS Connected Vehicle Solution.", + sql: "SELECT * FROM 'connectedcar/dtc/#'", + actions: [] } } }; diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/lib/index.ts index 893169b9c..e28c93037 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/lib/index.ts @@ -71,28 +71,28 @@ export class KinesisFirehoseToAnalyticsAndS3 extends Construct { * @access public */ constructor(scope: Construct, id: string, props: KinesisFirehoseToAnalyticsAndS3Props) { - super(scope, id); + super(scope, id); - // Setup the kinesisfirehose-s3 pattern - const kinesisFirehoseToS3Props: KinesisFirehoseToS3Props = { - kinesisFirehoseProps: props.kinesisFirehoseProps, - existingBucketObj: props.existingBucketObj, - bucketProps: props.bucketProps - }; + // Setup the kinesisfirehose-s3 pattern + const kinesisFirehoseToS3Props: KinesisFirehoseToS3Props = { + kinesisFirehoseProps: props.kinesisFirehoseProps, + existingBucketObj: props.existingBucketObj, + bucketProps: props.bucketProps + }; - // Add the kinesisfirehose-s3 pattern - const kfs = new KinesisFirehoseToS3(this, 'KinesisFirehoseToS3', kinesisFirehoseToS3Props); + // Add the kinesisfirehose-s3 pattern + const kfs = new KinesisFirehoseToS3(this, 'KinesisFirehoseToS3', kinesisFirehoseToS3Props); - // Add the Kinesis Analytics application - this.kinesisAnalytics = defaults.buildKinesisAnalyticsApp(this, { - kinesisFirehose: kfs.kinesisFirehose, - kinesisAnalyticsProps: props.kinesisAnalyticsProps - }); + // Add the Kinesis Analytics application + this.kinesisAnalytics = defaults.buildKinesisAnalyticsApp(this, { + kinesisFirehose: kfs.kinesisFirehose, + kinesisAnalyticsProps: props.kinesisAnalyticsProps + }); - this.kinesisFirehose = kfs.kinesisFirehose; - this.kinesisFirehoseLogGroup = kfs.kinesisFirehoseLogGroup; - this.kinesisFirehoseRole = kfs.kinesisFirehoseRole; - this.s3Bucket = kfs.s3Bucket; - this.s3LoggingBucket = kfs.s3LoggingBucket; + this.kinesisFirehose = kfs.kinesisFirehose; + this.kinesisFirehoseLogGroup = kfs.kinesisFirehoseLogGroup; + this.kinesisFirehoseRole = kfs.kinesisFirehoseRole; + this.s3Bucket = kfs.s3Bucket; + this.s3LoggingBucket = kfs.s3LoggingBucket; } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/test/integ.no-arguments.ts index 71a7d4ac4..6ca7052ba 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/test/integ.no-arguments.ts @@ -21,34 +21,34 @@ const stack = new Stack(app, 'test-firehose-s3-and-analytics-stack'); // Definitions const props: KinesisFirehoseToAnalyticsAndS3Props = { - kinesisAnalyticsProps: { - inputs: [{ - inputSchema: { - recordColumns: [{ - name: 'ticker_symbol', - sqlType: 'VARCHAR(4)', - mapping: '$.ticker_symbol' - }, { - name: 'sector', - sqlType: 'VARCHAR(16)', - mapping: '$.sector' - }, { - name: 'change', - sqlType: 'REAL', - mapping: '$.change' - }, { - name: 'price', - sqlType: 'REAL', - mapping: '$.price' - }], - recordFormat: { - recordFormatType: 'JSON' - }, - recordEncoding: 'UTF-8' - }, - namePrefix: 'SOURCE_SQL_STREAM' - }] - } + kinesisAnalyticsProps: { + inputs: [{ + inputSchema: { + recordColumns: [{ + name: 'ticker_symbol', + sqlType: 'VARCHAR(4)', + mapping: '$.ticker_symbol' + }, { + name: 'sector', + sqlType: 'VARCHAR(16)', + mapping: '$.sector' + }, { + name: 'change', + sqlType: 'REAL', + mapping: '$.change' + }, { + name: 'price', + sqlType: 'REAL', + mapping: '$.price' + }], + recordFormat: { + recordFormatType: 'JSON' + }, + recordEncoding: 'UTF-8' + }, + namePrefix: 'SOURCE_SQL_STREAM' + }] + } }; new KinesisFirehoseToAnalyticsAndS3(stack, 'test-firehose-s3-and-analytics-stack', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/test/test.kinesisfirehose-analytics-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/test/test.kinesisfirehose-analytics-s3.test.ts index 4cb8cf592..a7503ab08 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/test/test.kinesisfirehose-analytics-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3-and-kinesisanalytics/test/test.kinesisfirehose-analytics-s3.test.ts @@ -21,123 +21,123 @@ import '@aws-cdk/assert/jest'; // Test Case 1 - Pattern deployment w/ default properties // -------------------------------------------------------------- test('Pattern deployment w/ default properties', () => { - // Initial Setup - const stack = new Stack(); - const props: KinesisFirehoseToAnalyticsAndS3Props = { - kinesisAnalyticsProps: { - inputs: [{ - inputSchema: { - recordColumns: [{ - name: 'ticker_symbol', - sqlType: 'VARCHAR(4)', - mapping: '$.ticker_symbol' - }, { - name: 'sector', - sqlType: 'VARCHAR(16)', - mapping: '$.sector' - }, { - name: 'change', - sqlType: 'REAL', - mapping: '$.change' - }, { - name: 'price', - sqlType: 'REAL', - mapping: '$.price' - }], - recordFormat: { - recordFormatType: 'JSON' - }, - recordEncoding: 'UTF-8' - }, - namePrefix: 'SOURCE_SQL_STREAM' - }] - } - }; - new KinesisFirehoseToAnalyticsAndS3(stack, 'test-firehose-s3-and-analytics-stack', props); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Initial Setup + const stack = new Stack(); + const props: KinesisFirehoseToAnalyticsAndS3Props = { + kinesisAnalyticsProps: { + inputs: [{ + inputSchema: { + recordColumns: [{ + name: 'ticker_symbol', + sqlType: 'VARCHAR(4)', + mapping: '$.ticker_symbol' + }, { + name: 'sector', + sqlType: 'VARCHAR(16)', + mapping: '$.sector' + }, { + name: 'change', + sqlType: 'REAL', + mapping: '$.change' + }, { + name: 'price', + sqlType: 'REAL', + mapping: '$.price' + }], + recordFormat: { + recordFormatType: 'JSON' + }, + recordEncoding: 'UTF-8' + }, + namePrefix: 'SOURCE_SQL_STREAM' + }] + } + }; + new KinesisFirehoseToAnalyticsAndS3(stack, 'test-firehose-s3-and-analytics-stack', props); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test Case 2 - Test the getter methods // -------------------------------------------------------------- test('Test properties', () => { - // Initial Setup - const stack = new Stack(); - const props: KinesisFirehoseToAnalyticsAndS3Props = { - 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' - }] - } - }; - const app = new KinesisFirehoseToAnalyticsAndS3(stack, 'test-kinesis-firehose-kinesis-analytics', props); - // Assertions - expect(app.kinesisAnalytics !== null); - expect(app.kinesisFirehose !== null); - expect(app.kinesisFirehoseRole !== null); - expect(app.kinesisFirehoseLogGroup !== null); - expect(app.s3Bucket !== null); - expect(app.s3LoggingBucket !== null); + // Initial Setup + const stack = new Stack(); + const props: KinesisFirehoseToAnalyticsAndS3Props = { + 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' + }] + } + }; + const app = new KinesisFirehoseToAnalyticsAndS3(stack, 'test-kinesis-firehose-kinesis-analytics', props); + // Assertions + expect(app.kinesisAnalytics !== null); + expect(app.kinesisFirehose !== null); + expect(app.kinesisFirehoseRole !== null); + expect(app.kinesisFirehoseLogGroup !== null); + expect(app.s3Bucket !== null); + expect(app.s3LoggingBucket !== null); }); // -------------------------------------------------------------- // Test Case 3 - Override kinesisFirehose props // -------------------------------------------------------------- test('test kinesisFirehose override ', () => { - const stack = new Stack(); + const stack = new Stack(); - new KinesisFirehoseToAnalyticsAndS3(stack, 'test-firehose-s3', { - kinesisFirehoseProps: { - extendedS3DestinationConfiguration: { - bufferingHints: { - intervalInSeconds: 600, - sizeInMBs: 55 - }, - } - }, - 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' - }] + new KinesisFirehoseToAnalyticsAndS3(stack, 'test-firehose-s3', { + kinesisFirehoseProps: { + extendedS3DestinationConfiguration: { + bufferingHints: { + intervalInSeconds: 600, + sizeInMBs: 55 + }, } - }); + }, + 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' + }] + } + }); - expect(stack).toHaveResourceLike("AWS::KinesisFirehose::DeliveryStream", { - ExtendedS3DestinationConfiguration: { - BufferingHints: { - IntervalInSeconds: 600, - SizeInMBs: 55 - } + expect(stack).toHaveResourceLike("AWS::KinesisFirehose::DeliveryStream", { + ExtendedS3DestinationConfiguration: { + BufferingHints: { + IntervalInSeconds: 600, + SizeInMBs: 55 + } }}); - }); \ No newline at end of file +}); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/lib/index.ts index 8af316110..08fa68037 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/lib/index.ts @@ -56,67 +56,67 @@ export class KinesisFirehoseToS3 extends Construct { * Constructs a new instance of the IotToLambda class. */ constructor(scope: Construct, id: string, props: KinesisFirehoseToS3Props) { - super(scope, id); + super(scope, id); - let bucket: s3.IBucket; + let bucket: s3.IBucket; - // Setup S3 Bucket - if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { - bucketProps: props.bucketProps - }); + // Setup S3 Bucket + if (!props.existingBucketObj) { + [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + bucketProps: props.bucketProps + }); - bucket = this.s3Bucket; - } else { - bucket = props.existingBucketObj; - } + bucket = this.s3Bucket; + } else { + bucket = props.existingBucketObj; + } - // Setup Cloudwatch Log group & stream for Kinesis Firehose - this.kinesisFirehoseLogGroup = new logs.LogGroup(this, 'firehose-log-group', defaults.DefaultLogGroupProps()); - const cwLogStream: logs.LogStream = this.kinesisFirehoseLogGroup.addStream('firehose-log-stream'); + // Setup Cloudwatch Log group & stream for Kinesis Firehose + this.kinesisFirehoseLogGroup = new logs.LogGroup(this, 'firehose-log-group', defaults.DefaultLogGroupProps()); + const cwLogStream: logs.LogStream = this.kinesisFirehoseLogGroup.addStream('firehose-log-stream'); - // Setup the IAM Role for Kinesis Firehose - this.kinesisFirehoseRole = new iam.Role(this, 'KinesisFirehoseRole', { - assumedBy: new iam.ServicePrincipal('firehose.amazonaws.com'), - }); + // Setup the IAM Role for Kinesis Firehose + this.kinesisFirehoseRole = new iam.Role(this, 'KinesisFirehoseRole', { + assumedBy: new iam.ServicePrincipal('firehose.amazonaws.com'), + }); - // Setup the IAM policy for Kinesis Firehose - const firehosePolicy = new iam.Policy(this, 'KinesisFirehosePolicy', { - statements: [new iam.PolicyStatement({ - actions: [ - 's3:AbortMultipartUpload', - 's3:GetBucketLocation', - 's3:GetObject', - 's3:ListBucket', - 's3:ListBucketMultipartUploads', - 's3:PutObject' - ], - resources: [`${bucket.bucketArn}`, `${bucket.bucketArn}/*`] - }), - new iam.PolicyStatement({ - actions: [ - 'logs:PutLogEvents' - ], - resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:${this.kinesisFirehoseLogGroup.logGroupName}:log-stream:${cwLogStream.logStreamName}`] - }) + // Setup the IAM policy for Kinesis Firehose + const firehosePolicy = new iam.Policy(this, 'KinesisFirehosePolicy', { + statements: [new iam.PolicyStatement({ + actions: [ + 's3:AbortMultipartUpload', + 's3:GetBucketLocation', + 's3:GetObject', + 's3:ListBucket', + 's3:ListBucketMultipartUploads', + 's3:PutObject' + ], + resources: [`${bucket.bucketArn}`, `${bucket.bucketArn}/*`] + }), + new iam.PolicyStatement({ + actions: [ + 'logs:PutLogEvents' + ], + resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:${this.kinesisFirehoseLogGroup.logGroupName}:log-stream:${cwLogStream.logStreamName}`] + }) ]}); - // Attach policy to role - firehosePolicy.attachToRole(this.kinesisFirehoseRole); + // Attach policy to role + firehosePolicy.attachToRole(this.kinesisFirehoseRole); - const awsManagedKey: kms.IKey = kms.Alias.fromAliasName(scope, 'aws-managed-key', 'alias/aws/s3'); + const awsManagedKey: kms.IKey = kms.Alias.fromAliasName(scope, 'aws-managed-key', 'alias/aws/s3'); - // Setup the default Kinesis Firehose props - const defaultKinesisFirehoseProps: kinesisfirehose.CfnDeliveryStreamProps = + // Setup the default Kinesis Firehose props + const defaultKinesisFirehoseProps: kinesisfirehose.CfnDeliveryStreamProps = defaults.DefaultCfnDeliveryStreamProps(bucket.bucketArn, this.kinesisFirehoseRole.roleArn, - this.kinesisFirehoseLogGroup.logGroupName, cwLogStream.logStreamName, awsManagedKey); + this.kinesisFirehoseLogGroup.logGroupName, cwLogStream.logStreamName, awsManagedKey); - // Override with the input props - if (props.kinesisFirehoseProps) { - const kinesisFirehoseProps = overrideProps(defaultKinesisFirehoseProps, props.kinesisFirehoseProps); - this.kinesisFirehose = new kinesisfirehose.CfnDeliveryStream(this, 'KinesisFirehose', kinesisFirehoseProps); - } else { - this.kinesisFirehose = new kinesisfirehose.CfnDeliveryStream(this, 'KinesisFirehose', defaultKinesisFirehoseProps); - } + // Override with the input props + if (props.kinesisFirehoseProps) { + const kinesisFirehoseProps = overrideProps(defaultKinesisFirehoseProps, props.kinesisFirehoseProps); + this.kinesisFirehose = new kinesisfirehose.CfnDeliveryStream(this, 'KinesisFirehose', kinesisFirehoseProps); + } else { + this.kinesisFirehose = new kinesisfirehose.CfnDeliveryStream(this, 'KinesisFirehose', defaultKinesisFirehoseProps); + } } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/integ.pre-existing-bucket.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/integ.pre-existing-bucket.ts index 2df4b7eb8..5676eb388 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/integ.pre-existing-bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/integ.pre-existing-bucket.ts @@ -24,16 +24,16 @@ stack.templateOptions.description = 'Integration Test for aws-kinesisfirehose-s3 const mybucket: s3.IBucket = s3.Bucket.fromBucketName(stack, 'mybucket', 'cdktoolkit-stagingbucket-1cjqz1mn5psg3'); new KinesisFirehoseToS3(stack, 'test-firehose-s3-pre-existing-bucket-stack', { - existingBucketObj: mybucket, - kinesisFirehoseProps: { - extendedS3DestinationConfiguration : { - encryptionConfiguration: { - kmsEncryptionConfig: { - awskmsKeyArn: `arn:aws:kms:us-west-2:${cdk.Aws.ACCOUNT_ID}:alias/aws/s3` - } - } + existingBucketObj: mybucket, + kinesisFirehoseProps: { + extendedS3DestinationConfiguration : { + encryptionConfiguration: { + kmsEncryptionConfig: { + awskmsKeyArn: `arn:aws:kms:us-west-2:${cdk.Aws.ACCOUNT_ID}:alias/aws/s3` } + } } + } }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/test.kinesisfirehose-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/test.kinesisfirehose-s3.test.ts index 4572d7912..ac75ac226 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/test.kinesisfirehose-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisfirehose-s3/test/test.kinesisfirehose-s3.test.ts @@ -99,7 +99,7 @@ test('test kinesisFirehose override ', () => { IntervalInSeconds: 600, SizeInMBs: 55 } - }}); + }}); }); test('check properties', () => { diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/lib/index.ts index 2d79f0e82..52b252a04 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/lib/index.ts @@ -82,63 +82,63 @@ export class KinesisStreamsToKinesisFirehoseToS3 extends Construct { * @access public */ constructor(scope: Construct, id: string, props: KinesisStreamsToKinesisFirehoseToS3Props) { - super(scope, id); + super(scope, id); - // Setup the Kinesis Stream - this.kinesisStream = defaults.buildKinesisStream(this, { - existingStreamObj: props.existingStreamObj, - kinesisStreamProps: props.kinesisStreamProps - }); + // Setup the Kinesis Stream + this.kinesisStream = defaults.buildKinesisStream(this, { + existingStreamObj: props.existingStreamObj, + kinesisStreamProps: props.kinesisStreamProps + }); - const kinesisStreamsRole = new iam.Role(scope, 'KinesisStreamsRole', { - assumedBy: new iam.ServicePrincipal('firehose.amazonaws.com'), - inlinePolicies: { - KinesisStreamsRoleRolePolicy: new iam.PolicyDocument({ - statements: [new iam.PolicyStatement({ - actions: [ - "kinesis:DescribeStream", - "kinesis:GetShardIterator", - "kinesis:GetRecords", - "kinesis:ListShards" - ], - resources: [this.kinesisStream.streamArn] - })] - }) - } - }); + const kinesisStreamsRole = new iam.Role(scope, 'KinesisStreamsRole', { + assumedBy: new iam.ServicePrincipal('firehose.amazonaws.com'), + inlinePolicies: { + KinesisStreamsRoleRolePolicy: new iam.PolicyDocument({ + statements: [new iam.PolicyStatement({ + actions: [ + "kinesis:DescribeStream", + "kinesis:GetShardIterator", + "kinesis:GetRecords", + "kinesis:ListShards" + ], + resources: [this.kinesisStream.streamArn] + })] + }) + } + }); - // This Construct requires that the deliveryStreamType be overriden regardless of what is specified in the user props - if (props.kinesisFirehoseProps) { - if (props.kinesisFirehoseProps.deliveryStreamType !== undefined) { - defaults.printWarning('Overriding deliveryStreamType type to be KinesisStreamAsSource'); - } + // This Construct requires that the deliveryStreamType be overriden regardless of what is specified in the user props + if (props.kinesisFirehoseProps) { + if (props.kinesisFirehoseProps.deliveryStreamType !== undefined) { + defaults.printWarning('Overriding deliveryStreamType type to be KinesisStreamAsSource'); + } - if (props.kinesisFirehoseProps.kinesisStreamSourceConfiguration !== undefined) { - defaults.printWarning('Overriding kinesisStreamSourceConfiguration'); - } + if (props.kinesisFirehoseProps.kinesisStreamSourceConfiguration !== undefined) { + defaults.printWarning('Overriding kinesisStreamSourceConfiguration'); } + } - const _kinesisFirehoseProps: kinesisfirehose.CfnDeliveryStreamProps = { - deliveryStreamType: 'KinesisStreamAsSource', - kinesisStreamSourceConfiguration: { - kinesisStreamArn: this.kinesisStream.streamArn, - roleArn: kinesisStreamsRole.roleArn - } - }; + const _kinesisFirehoseProps: kinesisfirehose.CfnDeliveryStreamProps = { + deliveryStreamType: 'KinesisStreamAsSource', + kinesisStreamSourceConfiguration: { + kinesisStreamArn: this.kinesisStream.streamArn, + roleArn: kinesisStreamsRole.roleArn + } + }; - const kdfToS3Construct = new kdfToS3.KinesisFirehoseToS3(this, 'KinesisFirehoseToS3', { - kinesisFirehoseProps: overrideProps(props.kinesisFirehoseProps, _kinesisFirehoseProps), - existingBucketObj: props.existingBucketObj, - bucketProps: props.bucketProps - }); + const kdfToS3Construct = new kdfToS3.KinesisFirehoseToS3(this, 'KinesisFirehoseToS3', { + kinesisFirehoseProps: overrideProps(props.kinesisFirehoseProps, _kinesisFirehoseProps), + existingBucketObj: props.existingBucketObj, + bucketProps: props.bucketProps + }); - this.kinesisFirehose = kdfToS3Construct.kinesisFirehose; - this.kinesisFirehoseRole = kdfToS3Construct.kinesisFirehoseRole; - this.kinesisFirehoseLogGroup = kdfToS3Construct.kinesisFirehoseLogGroup; + this.kinesisFirehose = kdfToS3Construct.kinesisFirehose; + this.kinesisFirehoseRole = kdfToS3Construct.kinesisFirehoseRole; + this.kinesisFirehoseLogGroup = kdfToS3Construct.kinesisFirehoseLogGroup; - if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { - // Deploy best practices CW Alarms for Kinesis Stream - this.cloudwatchAlarms = defaults.buildKinesisStreamCWAlarms(this); - } + if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { + // Deploy best practices CW Alarms for Kinesis Stream + this.cloudwatchAlarms = defaults.buildKinesisStreamCWAlarms(this); + } } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/integ.existingStreamObj.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/integ.existingStreamObj.ts index a2f20993f..587b6a279 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/integ.existingStreamObj.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/integ.existingStreamObj.ts @@ -23,16 +23,16 @@ const stack = new Stack(app, 'test-existing-stream-firehose-s3-stack'); stack.templateOptions.description = 'Integration Test for aws-kinesisstreams-kinesisfirehose-s3'; const construct = new KinesisStreamsToLambda(stack, 'test-kinesis-lambda', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } }); new KinesisStreamsToKinesisFirehoseToS3(stack, 'test-existing-stream-firehose-s3-stack', { - existingStreamObj: construct.kinesisStream, - createCloudWatchAlarms: false + existingStreamObj: construct.kinesisStream, + createCloudWatchAlarms: false }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/test.kinesisfirehose-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/test.kinesisfirehose-s3.test.ts index 9cd7033bd..532c999c5 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/test.kinesisfirehose-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-kinesisfirehose-s3/test/test.kinesisfirehose-s3.test.ts @@ -51,7 +51,7 @@ test('test kinesisFirehose override ', () => { IntervalInSeconds: 600, SizeInMBs: 55 } - }}); + }}); }); test('test kinesisFirehose.deliveryStreamType override ', () => { @@ -136,7 +136,7 @@ test('Test All properties', () => { test('Test properties with no CW Alarms', () => { const stack = new Stack(); const props: KinesisStreamsToKinesisFirehoseToS3Props = { - createCloudWatchAlarms: false + createCloudWatchAlarms: false }; const app = new KinesisStreamsToKinesisFirehoseToS3(stack, 'test-stream-firehose-s3', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/lib/index.ts index a8e839570..b9889b5fe 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/lib/index.ts @@ -92,34 +92,34 @@ export class KinesisStreamsToLambda extends Construct { * @access public */ constructor(scope: Construct, id: string, props: KinesisStreamsToLambdaProps) { - super(scope, id); + super(scope, id); - // Setup the Kinesis Stream - this.kinesisStream = defaults.buildKinesisStream(this, { - existingStreamObj: props.existingStreamObj, - kinesisStreamProps: props.kinesisStreamProps - }); + // Setup the Kinesis Stream + this.kinesisStream = defaults.buildKinesisStream(this, { + existingStreamObj: props.existingStreamObj, + kinesisStreamProps: props.kinesisStreamProps + }); - // Setup the Lambda function - this.lambdaFunction = defaults.buildLambdaFunction(this, { - existingLambdaObj: props.existingLambdaObj, - lambdaFunctionProps: props.lambdaFunctionProps - }); + // Setup the Lambda function + this.lambdaFunction = defaults.buildLambdaFunction(this, { + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps + }); - // Grant Kinesis Stream read perimssion for lambda function - this.kinesisStream.grantRead(this.lambdaFunction.grantPrincipal); + // Grant Kinesis Stream read perimssion for lambda function + this.kinesisStream.grantRead(this.lambdaFunction.grantPrincipal); - // Add the Lambda event source mapping - const eventSourceProps = defaults.KinesisEventSourceProps(this, { - eventSourceProps: props.kinesisEventSourceProps, - deploySqsDlqQueue: props.deploySqsDlqQueue, - sqsDlqQueueProps: props.sqsDlqQueueProps - }); - this.lambdaFunction.addEventSource(new KinesisEventSource(this.kinesisStream, eventSourceProps)); + // Add the Lambda event source mapping + const eventSourceProps = defaults.KinesisEventSourceProps(this, { + eventSourceProps: props.kinesisEventSourceProps, + deploySqsDlqQueue: props.deploySqsDlqQueue, + sqsDlqQueueProps: props.sqsDlqQueueProps + }); + this.lambdaFunction.addEventSource(new KinesisEventSource(this.kinesisStream, eventSourceProps)); - if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { - // Deploy best practices CW Alarms for Kinesis Stream - this.cloudwatchAlarms = defaults.buildKinesisStreamCWAlarms(this); - } + if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { + // Deploy best practices CW Alarms for Kinesis Stream + this.cloudwatchAlarms = defaults.buildKinesisStreamCWAlarms(this); + } } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/integ.existing.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/integ.existing.ts index cd4126617..1b3eefb77 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/integ.existing.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/integ.existing.ts @@ -24,41 +24,41 @@ const stack = new Stack(app, 'test-ks-existing-lambda-stack'); stack.templateOptions.description = 'Integration Test for aws-kinesisstreams-lambda'; const lambdaRole = new iam.Role(stack, 'test-role', { - assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), - inlinePolicies: { - LambdaFunctionServiceRolePolicy: new iam.PolicyDocument({ - statements: [new iam.PolicyStatement({ - actions: [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:PutLogEvents' - ], - resources: [`arn:${Aws.PARTITION}:logs:${Aws.REGION}:${Aws.ACCOUNT_ID}:log-group:/aws/lambda/*`] - })] - }) - } + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + inlinePolicies: { + LambdaFunctionServiceRolePolicy: new iam.PolicyDocument({ + statements: [new iam.PolicyStatement({ + actions: [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:PutLogEvents' + ], + resources: [`arn:${Aws.PARTITION}:logs:${Aws.REGION}:${Aws.ACCOUNT_ID}:log-group:/aws/lambda/*`] + })] + }) + } }); const lambdaFn = new lambda.Function(stack, 'test-fn', { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - role: lambdaRole, + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + role: lambdaRole, }); const stream = new kinesis.Stream(stack, 'test-stream', { - shardCount: 2, - encryption: kinesis.StreamEncryption.MANAGED + shardCount: 2, + encryption: kinesis.StreamEncryption.MANAGED }); // Definitions const props: KinesisStreamsToLambdaProps = { - existingStreamObj: stream, - existingLambdaObj: lambdaFn, - kinesisEventSourceProps: { - startingPosition: lambda.StartingPosition.LATEST, - batchSize: 1 - }, + existingStreamObj: stream, + existingLambdaObj: lambdaFn, + kinesisEventSourceProps: { + startingPosition: lambda.StartingPosition.LATEST, + batchSize: 1 + }, }; new KinesisStreamsToLambda(stack, 'test-ks-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/integ.no-arguments.ts index db74d2acf..ae2d3d92a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/integ.no-arguments.ts @@ -23,14 +23,14 @@ stack.templateOptions.description = 'Integration Test for aws-kinesisstreams-lam // Definitions const props: KinesisStreamsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - kinesisEventSourceProps: { - retryAttempts: 5 - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + kinesisEventSourceProps: { + retryAttempts: 5 + } }; new KinesisStreamsToLambda(stack, 'test-kinesisstreams-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/test.kinesisstreams-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/test.kinesisstreams-lambda.test.ts index 58d892092..215266d11 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/test.kinesisstreams-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-lambda/test/test.kinesisstreams-lambda.test.ts @@ -23,137 +23,137 @@ import '@aws-cdk/assert/jest'; // Pattern minimal deployment // -------------------------------------------------------------- test('Pattern minimal deployment', () => { - // Initial setup - const stack = new Stack(); - const props: KinesisStreamsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }; - new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Initial setup + const stack = new Stack(); + const props: KinesisStreamsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }; + new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test properties // -------------------------------------------------------------- test('Test properties', () => { - // Initial Setup - const stack = new Stack(); - const props: KinesisStreamsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }; - const app = new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); - // Assertion 1 - expect(app.lambdaFunction !== null); - // Assertion 2 - expect(app.kinesisStream !== null); - // Assertion 3 - expect(app.cloudwatchAlarms !== null); + // Initial Setup + const stack = new Stack(); + const props: KinesisStreamsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }; + const app = new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); + // Assertion 1 + expect(app.lambdaFunction !== null); + // Assertion 2 + expect(app.kinesisStream !== null); + // Assertion 3 + expect(app.cloudwatchAlarms !== null); }); // -------------------------------------------------------------- // Test existing resources // -------------------------------------------------------------- test('Test existing resources', () => { - // Initial Setup - const stack = new Stack(); + // Initial Setup + const stack = new Stack(); - const fn = new lambda.Function(stack, 'test-fn', { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }); + const fn = new lambda.Function(stack, 'test-fn', { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }); - const stream = new kinesis.Stream(stack, 'test-stream', { - streamName: 'existing-stream', - shardCount: 5, - retentionPeriod: Duration.hours(48), - encryption: kinesis.StreamEncryption.UNENCRYPTED - }); + const stream = new kinesis.Stream(stack, 'test-stream', { + streamName: 'existing-stream', + shardCount: 5, + retentionPeriod: Duration.hours(48), + encryption: kinesis.StreamEncryption.UNENCRYPTED + }); - new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', { - existingLambdaObj: fn, - existingStreamObj: stream, + new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', { + existingLambdaObj: fn, + existingStreamObj: stream, - // These properties will be ignored as existing objects were provided - lambdaFunctionProps: { - runtime: lambda.Runtime.PYTHON_3_8, - handler: 'lambda_function.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - kinesisStreamProps: { - streamName: 'other-name-stream', - shardCount: 1, - retentionPeriod: Duration.hours(24) - } - }); + // These properties will be ignored as existing objects were provided + lambdaFunctionProps: { + runtime: lambda.Runtime.PYTHON_3_8, + handler: 'lambda_function.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + kinesisStreamProps: { + streamName: 'other-name-stream', + shardCount: 1, + retentionPeriod: Duration.hours(24) + } + }); - // Assertions - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertions + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - expect(stack).toHaveResource('AWS::Kinesis::Stream', { - Name: 'existing-stream', - ShardCount: 5, - RetentionPeriodHours: 48, - }); + expect(stack).toHaveResource('AWS::Kinesis::Stream', { + Name: 'existing-stream', + ShardCount: 5, + RetentionPeriodHours: 48, + }); - expect(stack).toHaveResource('AWS::Lambda::Function', { - Handler: 'index.handler', - Runtime: 'nodejs10.x', - }); + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'index.handler', + Runtime: 'nodejs10.x', + }); }); // -------------------------------------------------------------- // Test sqsDlqQueueProps override // -------------------------------------------------------------- test('test sqsDlqQueueProps override', () => { - const stack = new Stack(); - const props: KinesisStreamsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - sqsDlqQueueProps: { - queueName: 'hello-world', - visibilityTimeout: Duration.seconds(50) - } - }; - new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); + const stack = new Stack(); + const props: KinesisStreamsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + sqsDlqQueueProps: { + queueName: 'hello-world', + visibilityTimeout: Duration.seconds(50) + } + }; + new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); - expect(stack).toHaveResource("AWS::SQS::Queue", { - QueueName: "hello-world", - VisibilityTimeout: 50 - }); + expect(stack).toHaveResource("AWS::SQS::Queue", { + QueueName: "hello-world", + VisibilityTimeout: 50 }); +}); // -------------------------------------------------------------- // Test properties with no CW Alarms // -------------------------------------------------------------- test('Test properties with no CW Alarms', () => { - // Initial Setup - const stack = new Stack(); - const props: KinesisStreamsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - createCloudWatchAlarms: false - }; - const app = new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); - // Assertion 1 - expect(app.lambdaFunction !== null); - // Assertion 2 - expect(app.kinesisStream !== null); - // Assertion 3 - expect(app.cloudwatchAlarms === null); + // Initial Setup + const stack = new Stack(); + const props: KinesisStreamsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + createCloudWatchAlarms: false + }; + const app = new KinesisStreamsToLambda(stack, 'test-kinesis-streams-lambda', props); + // Assertion 1 + expect(app.lambdaFunction !== null); + // Assertion 2 + expect(app.kinesisStream !== null); + // Assertion 3 + expect(app.cloudwatchAlarms === null); }); \ No newline at end of file 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 cbf02f88d..91fd346e6 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 @@ -84,28 +84,28 @@ export class LambdaToDynamoDB extends Construct { if (props.tablePermissions) { const _permissions = props.tablePermissions.toUpperCase(); if (_permissions === 'ALL') { - this.dynamoTable.grantFullAccess(this.lambdaFunction.grantPrincipal); + this.dynamoTable.grantFullAccess(this.lambdaFunction.grantPrincipal); } else if (_permissions === 'READ') { - this.dynamoTable.grantReadData(this.lambdaFunction.grantPrincipal); + this.dynamoTable.grantReadData(this.lambdaFunction.grantPrincipal); } else if (_permissions === 'READWRITE') { - this.dynamoTable.grantReadWriteData(this.lambdaFunction.grantPrincipal); + this.dynamoTable.grantReadWriteData(this.lambdaFunction.grantPrincipal); } else if (_permissions === 'WRITE') { - this.dynamoTable.grantWriteData(this.lambdaFunction.grantPrincipal); + this.dynamoTable.grantWriteData(this.lambdaFunction.grantPrincipal); } - } else { - this.dynamoTable.grantReadWriteData(this.lambdaFunction.grantPrincipal); - } + } else { + this.dynamoTable.grantReadWriteData(this.lambdaFunction.grantPrincipal); + } // Conditional metadata for cfn_nag if (props.dynamoTableProps?.billingMode === dynamodb.BillingMode.PROVISIONED) { const cfnTable: dynamodb.CfnTable = this.dynamoTable.node.findChild('Resource') as dynamodb.CfnTable; cfnTable.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W73', - reason: `PROVISIONED billing mode is a default and is not explicitly applied as a setting.` - }] - } + cfn_nag: { + rules_to_suppress: [{ + id: 'W73', + reason: `PROVISIONED billing mode is a default and is not explicitly applied as a setting.` + }] + } }; } } diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.add-secondary-index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.add-secondary-index.ts index ec9a2eec3..d786f0077 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.add-secondary-index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.add-secondary-index.ts @@ -22,19 +22,19 @@ const app = new App(); const stack = new Stack(app, 'test-lambda-dynamodb-stack'); const construct: LambdaToDynamoDB = new LambdaToDynamoDB(stack, 'test-lambda-dynamodb-stack', { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' - }, + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' + }, }); const props: dynamodb.GlobalSecondaryIndexProps = { - partitionKey: { - name: 'id2', - type: dynamodb.AttributeType.STRING - }, - indexName: 'test_id2' + partitionKey: { + name: 'id2', + type: dynamodb.AttributeType.STRING + }, + indexName: 'test_id2' }; construct.dynamoTable.addGlobalSecondaryIndex(props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.no-arguments.ts index 201310a36..f9921ca5c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.no-arguments.ts @@ -21,11 +21,11 @@ const app = new App(); const stack = new Stack(app, 'test-lambda-dynamodb-stack'); const props: LambdaToDynamoDBProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' - }, + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' + }, }; new LambdaToDynamoDB(stack, 'test-lambda-dynamodb-stack', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.set-billing-mode.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.set-billing-mode.ts index 898cbc04a..a6840dc23 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.set-billing-mode.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.set-billing-mode.ts @@ -22,20 +22,20 @@ const app = new App(); const stack = new Stack(app, 'test-lambda-dynamodb-stack'); new LambdaToDynamoDB(stack, 'test-lambda-dynamodb-stack', { - dynamoTableProps: { - billingMode: dynamodb.BillingMode.PROVISIONED, - readCapacity: 3, - writeCapacity: 3, - partitionKey: { - name: 'id', - type: dynamodb.AttributeType.STRING - } - }, - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + dynamoTableProps: { + billingMode: dynamodb.BillingMode.PROVISIONED, + readCapacity: 3, + writeCapacity: 3, + partitionKey: { + name: 'id', + type: dynamodb.AttributeType.STRING } + }, + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' + } }); app.synth(); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.use-existing-func.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.use-existing-func.ts index 785a58ca5..5ce7f4ed7 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.use-existing-func.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/integ.use-existing-func.ts @@ -20,15 +20,15 @@ import * as defaults from '@aws-solutions-constructs/core'; const app = new App(); const stack = new Stack(app, 'test-lambda-dynamodb-stack'); const lambdaFunctionProps = { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) }; const func = defaults.deployLambdaFunction(stack, lambdaFunctionProps); new LambdaToDynamoDB(stack, 'test-lambda-dynamodb-stack', { - existingLambdaObj: func + existingLambdaObj: func }); app.synth(); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts index b75d12000..a0f568601 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-dynamodb/test/lambda-dynamodb.test.ts @@ -21,9 +21,9 @@ import '@aws-cdk/assert/jest'; function deployNewFunc(stack: cdk.Stack) { const props: LambdaToDynamoDBProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }, }; @@ -44,8 +44,8 @@ function useExistingFunc(stack: cdk.Stack) { readCapacity: 3, writeCapacity: 3, partitionKey: { - name: 'id', - type: dynamodb.AttributeType.STRING + name: 'id', + type: dynamodb.AttributeType.STRING } }, }; @@ -77,7 +77,7 @@ test('check lambda function properties for deploy: true', () => { Variables: { AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1", DDB_TABLE_NAME: { - Ref: "testlambdadynamodbstackDynamoTable8138E93B" + Ref: "testlambdadynamodbstackDynamoTable8138E93B" } } } @@ -222,14 +222,14 @@ test('check lambda function properties for deploy: false', () => { useExistingFunc(stack); expect(stack).toHaveResource('AWS::Lambda::Function', { - Handler: "index.handler", - Role: { - "Fn::GetAtt": [ - "MyExistingFunctionServiceRoleF9E14BFD", - "Arn" - ] - }, - Runtime: "python3.6" + Handler: "index.handler", + Role: { + "Fn::GetAtt": [ + "MyExistingFunctionServiceRoleF9E14BFD", + "Arn" + ] + }, + Runtime: "python3.6" }); }); @@ -327,9 +327,9 @@ test('check lambda function policy ReadOnly table permissions', () => { const props: LambdaToDynamoDBProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }, tablePermissions: 'Read' }; @@ -381,9 +381,9 @@ test('check lambda function policy WriteOnly table permissions', () => { const props: LambdaToDynamoDBProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }, tablePermissions: 'Write' }; @@ -433,9 +433,9 @@ test('check lambda function policy ReadWrite table permissions', () => { const props: LambdaToDynamoDBProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }, tablePermissions: 'ReadWrite' }; @@ -491,9 +491,9 @@ test('check lambda function policy All table permissions', () => { const props: LambdaToDynamoDBProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }, tablePermissions: 'All' }; 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 d27eee0b1..16af91128 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 @@ -107,10 +107,10 @@ export class LambdaToElasticSearchAndKibana extends Construct { }); [this.elasticsearchDomain, this.elasticsearchRole] = defaults.buildElasticSearch(this, props.domainName, { - userpool: this.userPool, - identitypool: this.identityPool, - cognitoAuthorizedRoleARN: cognitoAuthorizedRole.roleArn, - serviceRoleARN: lambdaFunctionRoleARN}, props.esDomainProps); + userpool: this.userPool, + identitypool: this.identityPool, + cognitoAuthorizedRoleARN: cognitoAuthorizedRole.roleArn, + serviceRoleARN: lambdaFunctionRoleARN}, props.esDomainProps); // Add ES Domain to lambda envrionment variable this.lambdaFunction.addEnvironment('DOMAIN_ENDPOINT', this.elasticsearchDomain.attrDomainEndpoint); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/integ.domain-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/integ.domain-arguments.ts index 8bacfd7b7..6c15b4df3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/integ.domain-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/integ.domain-arguments.ts @@ -21,18 +21,18 @@ const app = new App(); const stack = new Stack(app, 'test-lambda-elasticsearch-kibana-stack2'); const lambdaProps: lambda.FunctionProps = { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }; const esDomain = 'domain-' + Aws.ACCOUNT_ID; const cognitoDomain = 'globallyuniquedomain'; new LambdaToElasticSearchAndKibana(stack, 'test-lambda-elasticsearch-kibana2', { - lambdaFunctionProps: lambdaProps, - domainName: esDomain, - cognitoDomainName: cognitoDomain + lambdaFunctionProps: lambdaProps, + domainName: esDomain, + cognitoDomainName: cognitoDomain }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/integ.no-arguments.ts index 93d055920..ec2bcc397 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/integ.no-arguments.ts @@ -21,14 +21,14 @@ const app = new App(); const stack = new Stack(app, 'test-lambda-elasticsearch-kibana-stack'); const lambdaProps: lambda.FunctionProps = { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }; new LambdaToElasticSearchAndKibana(stack, 'test-lambda-elasticsearch-kibana', { - lambdaFunctionProps: lambdaProps, - domainName: 'myconstructsdomain' + lambdaFunctionProps: lambdaProps, + domainName: 'myconstructsdomain' }); // Synth diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/lambda-elasticsearch-kibana.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/lambda-elasticsearch-kibana.test.ts index 30e3911ea..ccc4109b3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/lambda-elasticsearch-kibana.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-elasticsearch-kibana/test/lambda-elasticsearch-kibana.test.ts @@ -20,9 +20,9 @@ import '@aws-cdk/assert/jest'; function deployNewFunc(stack: cdk.Stack) { const props: LambdaToElasticSearchAndKibanaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }, domainName: 'test-domain' }; @@ -87,9 +87,9 @@ test('check properties with no CW Alarms ', () => { const props: LambdaToElasticSearchAndKibanaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler' }, domainName: 'test-domain', createCloudWatchAlarms: false 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 e59a0ace7..ff32ab1f8 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 @@ -71,47 +71,47 @@ export class LambdaToS3 extends Construct { * @access public */ constructor(scope: Construct, id: string, props: LambdaToS3Props) { - super(scope, id); - let bucket: s3.IBucket; + super(scope, id); + let bucket: s3.IBucket; - // Setup the Lambda function - this.lambdaFunction = defaults.buildLambdaFunction(this, { - existingLambdaObj: props.existingLambdaObj, - lambdaFunctionProps: props.lambdaFunctionProps - }); + // Setup the Lambda function + this.lambdaFunction = defaults.buildLambdaFunction(this, { + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps + }); - // Setup S3 Bucket - if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { - bucketProps: props.bucketProps - }); - bucket = this.s3Bucket; - } else { - bucket = props.existingBucketObj; - } + // Setup S3 Bucket + if (!props.existingBucketObj) { + [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + bucketProps: props.bucketProps + }); + bucket = this.s3Bucket; + } else { + bucket = props.existingBucketObj; + } - // Configure environment variables - this.lambdaFunction.addEnvironment('S3_BUCKET_NAME', bucket.bucketName); + // Configure environment variables + this.lambdaFunction.addEnvironment('S3_BUCKET_NAME', bucket.bucketName); - // Add the requested or default bucket permissions - if (props.bucketPermissions) { - if (props.bucketPermissions.includes('Delete')) { - bucket.grantDelete(this.lambdaFunction.grantPrincipal); - } - if (props.bucketPermissions.includes('Put')) { - bucket.grantPut(this.lambdaFunction.grantPrincipal); - } - if (props.bucketPermissions.includes('Read')) { - bucket.grantRead(this.lambdaFunction.grantPrincipal); - } - if (props.bucketPermissions.includes('ReadWrite')) { - bucket.grantReadWrite(this.lambdaFunction.grantPrincipal); - } - if (props.bucketPermissions.includes('Write')) { - bucket.grantWrite(this.lambdaFunction.grantPrincipal); - } - } else { - bucket.grantReadWrite(this.lambdaFunction.grantPrincipal); + // Add the requested or default bucket permissions + if (props.bucketPermissions) { + if (props.bucketPermissions.includes('Delete')) { + bucket.grantDelete(this.lambdaFunction.grantPrincipal); + } + if (props.bucketPermissions.includes('Put')) { + bucket.grantPut(this.lambdaFunction.grantPrincipal); + } + if (props.bucketPermissions.includes('Read')) { + bucket.grantRead(this.lambdaFunction.grantPrincipal); + } + if (props.bucketPermissions.includes('ReadWrite')) { + bucket.grantReadWrite(this.lambdaFunction.grantPrincipal); + } + if (props.bucketPermissions.includes('Write')) { + bucket.grantWrite(this.lambdaFunction.grantPrincipal); } + } else { + bucket.grantReadWrite(this.lambdaFunction.grantPrincipal); + } } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.deployFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.deployFunction.ts index 3160abd88..2fdf36993 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.deployFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.deployFunction.ts @@ -23,11 +23,11 @@ stack.templateOptions.description = 'Integration Test for aws-lambda-s3'; // Definitions const props: LambdaToS3Props = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } }; new LambdaToS3(stack, 'test-lambda-s3', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.existingFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.existingFunction.ts index e9c733547..214ffda54 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.existingFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.existingFunction.ts @@ -32,7 +32,7 @@ const lambdaFunctionProps = { const func = defaults.deployLambdaFunction(stack, lambdaFunctionProps); const props: LambdaToS3Props = { - existingLambdaObj: func + existingLambdaObj: func }; new LambdaToS3(stack, 'test-lambda-s3', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.pre-existing-bucket.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.pre-existing-bucket.ts index f9cf10a63..d7dd3552d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.pre-existing-bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/integ.pre-existing-bucket.ts @@ -25,12 +25,12 @@ const mybucket: s3.IBucket = s3.Bucket.fromBucketName(stack, 'mybucket', 'cdktoo // Definitions const props: LambdaToS3Props = { - existingBucketObj: mybucket, - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } + existingBucketObj: mybucket, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } }; new LambdaToS3(stack, 'test-lambda-s3-pre-existing-bucket', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/lambda-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/lambda-s3.test.ts index 9ccbddaf0..c942286cd 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/lambda-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-s3/test/lambda-s3.test.ts @@ -22,181 +22,181 @@ import '@aws-cdk/assert/jest'; // Test minimal deployment with new Lambda function // -------------------------------------------------------------- test('Test minimal deployment with new Lambda function', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ s3:Delete only // -------------------------------------------------------------- test('Test deployment w/ s3:Delete only', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - bucketPermissions: ['Delete'] - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + bucketPermissions: ['Delete'] + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ s3:Put only // -------------------------------------------------------------- test('Test deployment w/ s3:Put only', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - bucketPermissions: ['Put'] - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + bucketPermissions: ['Put'] + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ s3:Read only // -------------------------------------------------------------- test('Test deployment w/ s3:Read only', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - bucketPermissions: ['Read'] - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + bucketPermissions: ['Read'] + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ s3:ReadWrite only // -------------------------------------------------------------- test('Test deployment w/ s3:ReadWrite only', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - bucketPermissions: ['ReadWrite'] - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + bucketPermissions: ['ReadWrite'] + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ s3:Write only // -------------------------------------------------------------- test('Test deployment w/ s3:Write only', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - bucketPermissions: ['Write'] - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + bucketPermissions: ['Write'] + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ s3 multiple permissions // -------------------------------------------------------------- test('Test deployment w/ s3 multiple permissions', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - bucketPermissions: ['Write', 'Delete'] - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + bucketPermissions: ['Write', 'Delete'] + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test the getter methods // -------------------------------------------------------------- test('Test the properties', () => { - // Stack - const stack = new Stack(); - // Helper declaration - const pattern = new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - bucketPermissions: ['Write'] - }); + // Stack + const stack = new Stack(); + // Helper declaration + const pattern = new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + bucketPermissions: ['Write'] + }); // Assertion 1 - const func = pattern.lambdaFunction; - expect(func !== null); - // Assertion 2 - const bucket = pattern.s3Bucket; - expect(bucket !== null); - expect(pattern.s3LoggingBucket !== null); + const func = pattern.lambdaFunction; + expect(func !== null); + // Assertion 2 + const bucket = pattern.s3Bucket; + expect(bucket !== null); + expect(pattern.s3LoggingBucket !== null); }); // -------------------------------------------------------------- // Test the bucketProps override // -------------------------------------------------------------- test('Test the bucketProps override', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToS3(stack, 'lambda-to-s3-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - bucketProps: { - websiteIndexDocument: 'index.main.html' - } - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResource("AWS::S3::Bucket", { - WebsiteConfiguration: { - IndexDocument: 'index.main.html' - } - }); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToS3(stack, 'lambda-to-s3-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + bucketProps: { + websiteIndexDocument: 'index.main.html' + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResource("AWS::S3::Bucket", { + WebsiteConfiguration: { + IndexDocument: 'index.main.html' + } + }); }); \ No newline at end of file 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 6775d77c1..a10888c38 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 @@ -63,25 +63,25 @@ export class LambdaToSns extends Construct { * @access public */ constructor(scope: Construct, id: string, props: LambdaToSnsProps) { - super(scope, id); + super(scope, id); - // Setup the Lambda function - this.lambdaFunction = defaults.buildLambdaFunction(this, { - existingLambdaObj: props.existingLambdaObj, - lambdaFunctionProps: props.lambdaFunctionProps - }); + // Setup the Lambda function + this.lambdaFunction = defaults.buildLambdaFunction(this, { + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps + }); - // Setup the SNS topic - [this.snsTopic] = defaults.buildTopic(this, { - existingTopicObj: props.existingTopicObj, - topicProps: props.topicProps - }); + // Setup the SNS topic + [this.snsTopic] = defaults.buildTopic(this, { + existingTopicObj: props.existingTopicObj, + topicProps: props.topicProps + }); - // Configure environment variables - this.lambdaFunction.addEnvironment('SNS_TOPIC_NAME', this.snsTopic.topicName); - this.lambdaFunction.addEnvironment('SNS_TOPIC_ARN', this.snsTopic.topicArn); + // Configure environment variables + this.lambdaFunction.addEnvironment('SNS_TOPIC_NAME', this.snsTopic.topicName); + this.lambdaFunction.addEnvironment('SNS_TOPIC_ARN', this.snsTopic.topicArn); - // Add publishing permissions to the function - this.snsTopic.grantPublish(this.lambdaFunction.grantPrincipal); + // Add publishing permissions to the function + this.snsTopic.grantPublish(this.lambdaFunction.grantPrincipal); } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/integ.deployFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/integ.deployFunction.ts index 1ce430082..dd504863d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/integ.deployFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/integ.deployFunction.ts @@ -23,11 +23,11 @@ stack.templateOptions.description = 'Integration Test for aws-lambda-sns'; // Definitions const props: LambdaToSnsProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } }; new LambdaToSns(stack, 'test-lambda-sns', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/integ.existingFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/integ.existingFunction.ts index d29623d1d..3905d2d21 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/integ.existingFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/integ.existingFunction.ts @@ -24,15 +24,15 @@ stack.templateOptions.description = 'Integration Test for aws-lambda-sns'; // Definitions const lambdaFunctionProps = { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) }; const func = defaults.deployLambdaFunction(stack, lambdaFunctionProps); const props: LambdaToSnsProps = { - existingLambdaObj: func + existingLambdaObj: func }; new LambdaToSns(stack, 'test-lambda-sns', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/lambda-sns.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/lambda-sns.test.ts index 2527c3caf..b17d0e866 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/lambda-sns.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sns/test/lambda-sns.test.ts @@ -23,126 +23,126 @@ import '@aws-cdk/assert/jest'; // Test deployment with new Lambda function // -------------------------------------------------------------- test('Test deployment with new Lambda function', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new LambdaToSns(stack, 'lambda-to-sns-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - environment: { - LAMBDA_NAME: 'deployed-function' - } - } - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResourceLike("AWS::Lambda::Function", { - Environment: { - Variables: { - LAMBDA_NAME: 'deployed-function' - } - } - }); - expect(stack).toHaveResource("AWS::SNS::Topic", { - KmsMasterKeyId: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition" - }, - ":kms:", - { - Ref: "AWS::Region" - }, - ":", - { - Ref: "AWS::AccountId" - }, - ":alias/aws/sns" - ] - ] - } - }); + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToSns(stack, 'lambda-to-sns-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + environment: { + LAMBDA_NAME: 'deployed-function' + } + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResourceLike("AWS::Lambda::Function", { + Environment: { + Variables: { + LAMBDA_NAME: 'deployed-function' + } + } + }); + expect(stack).toHaveResource("AWS::SNS::Topic", { + KmsMasterKeyId: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition" + }, + ":kms:", + { + Ref: "AWS::Region" + }, + ":", + { + Ref: "AWS::AccountId" + }, + ":alias/aws/sns" + ] + ] + } + }); }); // -------------------------------------------------------------- // Test deployment with existing existingTopicObj // -------------------------------------------------------------- test('Test deployment with existing existingTopicObj', () => { - // Stack - const stack = new Stack(); + // Stack + const stack = new Stack(); - const topic = new sns.Topic(stack, 'MyTopic', { - topicName: "custom-topic" - }); + const topic = new sns.Topic(stack, 'MyTopic', { + topicName: "custom-topic" + }); - // Helper declaration - new LambdaToSns(stack, 'lambda-to-sns-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - environment: { - LAMBDA_NAME: 'override-function' - } - }, - existingTopicObj: topic - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expectCDK(stack).to(haveResource("AWS::SNS::Topic", { - TopicName: "custom-topic" - })); + // Helper declaration + new LambdaToSns(stack, 'lambda-to-sns-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + environment: { + LAMBDA_NAME: 'override-function' + } + }, + existingTopicObj: topic + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expectCDK(stack).to(haveResource("AWS::SNS::Topic", { + TopicName: "custom-topic" + })); }); // -------------------------------------------------------------- // Test deployment with imported encryption key // -------------------------------------------------------------- test('override topicProps', () => { - const stack = new Stack(); + const stack = new Stack(); - const props: LambdaToSnsProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }, - topicProps: { - topicName: "custom-topic" - } - }; + const props: LambdaToSnsProps = { + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }, + topicProps: { + topicName: "custom-topic" + } + }; - new LambdaToSns(stack, 'test-sns-lambda', props); + new LambdaToSns(stack, 'test-sns-lambda', props); - expectCDK(stack).to(haveResource("AWS::SNS::Topic", { - TopicName: "custom-topic" - })); + expectCDK(stack).to(haveResource("AWS::SNS::Topic", { + TopicName: "custom-topic" + })); }); // -------------------------------------------------------------- // Test the getter methods // -------------------------------------------------------------- test('Test the properties', () => { - // Stack - const stack = new Stack(); - // Helper declaration - const pattern = new LambdaToSns(stack, 'lambda-to-sns-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }); + // Stack + const stack = new Stack(); + // Helper declaration + const pattern = new LambdaToSns(stack, 'lambda-to-sns-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }); // Assertion 1 - const func = pattern.lambdaFunction; - expect(func !== null); - // Assertion 2 - const topic = pattern.snsTopic; - expect(topic !== null); + const func = pattern.lambdaFunction; + expect(func !== null); + // Assertion 2 + const topic = pattern.snsTopic; + expect(topic !== null); }); \ No newline at end of file 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 cd7358cb0..e9bbf8dbc 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 @@ -104,33 +104,33 @@ export class LambdaToSqsToLambda extends Construct { * @access public */ constructor(scope: Construct, id: string, props: LambdaToSqsToLambdaProps) { - super(scope, id); + super(scope, id); - // Setup the aws-lambda-sqs pattern - const lambdaToSqs = new LambdaToSqs(this, 'lambda-to-sqs', { - existingLambdaObj: props.existingProducerLambdaObj, - lambdaFunctionProps: props.producerLambdaFunctionProps, - existingQueueObj: props.existingQueueObj, - queueProps: props.queueProps, - deadLetterQueueProps: props.deadLetterQueueProps, - deployDeadLetterQueue: props.deployDeadLetterQueue, - maxReceiveCount: props.maxReceiveCount - }); + // Setup the aws-lambda-sqs pattern + const lambdaToSqs = new LambdaToSqs(this, 'lambda-to-sqs', { + existingLambdaObj: props.existingProducerLambdaObj, + lambdaFunctionProps: props.producerLambdaFunctionProps, + existingQueueObj: props.existingQueueObj, + queueProps: props.queueProps, + deadLetterQueueProps: props.deadLetterQueueProps, + deployDeadLetterQueue: props.deployDeadLetterQueue, + maxReceiveCount: props.maxReceiveCount + }); - // Set the queue as a pattern property - this.sqsQueue = lambdaToSqs.sqsQueue; + // Set the queue as a pattern property + this.sqsQueue = lambdaToSqs.sqsQueue; - // Setup the aws-sqs-lambda pattern - const sqsToLambda = new SqsToLambda(this, 'sqs-to-lambda', { - existingLambdaObj: props.existingConsumerLambdaObj, - lambdaFunctionProps: props.consumerLambdaFunctionProps, - existingQueueObj: this.sqsQueue, - deployDeadLetterQueue: false - }); + // Setup the aws-sqs-lambda pattern + const sqsToLambda = new SqsToLambda(this, 'sqs-to-lambda', { + existingLambdaObj: props.existingConsumerLambdaObj, + lambdaFunctionProps: props.consumerLambdaFunctionProps, + existingQueueObj: this.sqsQueue, + deployDeadLetterQueue: false + }); - // Set other relevant pattern properties - this.producerLambdaFunction = lambdaToSqs.lambdaFunction; - this.deadLetterQueue = lambdaToSqs.deadLetterQueue; - this.consumerLambdaFunction = sqsToLambda.lambdaFunction; + // Set other relevant pattern properties + this.producerLambdaFunction = lambdaToSqs.lambdaFunction; + this.deadLetterQueue = lambdaToSqs.deadLetterQueue; + this.consumerLambdaFunction = sqsToLambda.lambdaFunction; } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.defaultDeployment.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.defaultDeployment.ts index 968759801..96995a402 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.defaultDeployment.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.defaultDeployment.ts @@ -23,16 +23,16 @@ stack.templateOptions.description = 'Integration Test for aws-lambda-sqs-lambda' // Definitions const props: LambdaToSqsToLambdaProps = { - producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) - }, - consumerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/consumer-function`) - } + producerLambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) + }, + consumerLambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/consumer-function`) + } }; new LambdaToSqsToLambda(stack, 'test-lambda-sqs-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingConsumerFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingConsumerFunction.ts index 11f7edc12..9ba7422a9 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingConsumerFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingConsumerFunction.ts @@ -32,12 +32,12 @@ const lambdaFunctionProps: lambda.FunctionProps = { const existingConsumerFn = defaults.deployLambdaFunction(stack, lambdaFunctionProps); const props: LambdaToSqsToLambdaProps = { - producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) - }, - existingConsumerLambdaObj: existingConsumerFn, + producerLambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) + }, + existingConsumerLambdaObj: existingConsumerFn, }; new LambdaToSqsToLambda(stack, 'test-lambda-sqs-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingProducerFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingProducerFunction.ts index 91a9d0d38..954287f30 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingProducerFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingProducerFunction.ts @@ -32,12 +32,12 @@ const lambdaFunctionProps: lambda.FunctionProps = { const existingProducerFn = defaults.deployLambdaFunction(stack, lambdaFunctionProps); const props: LambdaToSqsToLambdaProps = { - existingProducerLambdaObj: existingProducerFn, - consumerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/consumer-function`) - } + existingProducerLambdaObj: existingProducerFn, + consumerLambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/consumer-function`) + } }; new LambdaToSqsToLambda(stack, 'test-lambda-sqs-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingQueue.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingQueue.ts index 958893dba..cd8b37014 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingQueue.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/integ.existingQueue.ts @@ -26,17 +26,17 @@ stack.templateOptions.description = 'Integration Test for aws-lambda-sqs-lambda' const [existingQueue] = defaults.buildQueue(stack, 'existing-sqs-queue', {}); const props: LambdaToSqsToLambdaProps = { - producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) - }, - existingQueueObj: existingQueue, - consumerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/consumer-function`) - } + producerLambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) + }, + existingQueueObj: existingQueue, + consumerLambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/consumer-function`) + } }; new LambdaToSqsToLambda(stack, 'test-lambda-sqs-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/lambda-sqs-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/lambda-sqs-lambda.test.ts index e85fbf21d..a1cb34486 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/lambda-sqs-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs-lambda/test/lambda-sqs-lambda.test.ts @@ -28,10 +28,10 @@ test('Test minimal deployment', () => { // Helper declaration const props: LambdaToSqsToLambdaProps = { producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`), - functionName: 'producer-function' + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`), + functionName: 'producer-function' }, consumerLambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_10_X, @@ -208,10 +208,10 @@ test('Test deployment w/ existing queue', () => { // Helper declaration const props: LambdaToSqsToLambdaProps = { producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`), - functionName: 'producer-function' + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`), + functionName: 'producer-function' }, consumerLambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_10_X, @@ -239,9 +239,9 @@ test('Test deployment w/ DLQ explicitly disabled', () => { // Helper declaration const props: LambdaToSqsToLambdaProps = { producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) }, consumerLambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_10_X, @@ -270,9 +270,9 @@ test('Test deployment w/ DLQ explicitly enabled and w/ MRC override', () => { // Helper declaration const props: LambdaToSqsToLambdaProps = { producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) }, consumerLambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_10_X, @@ -308,10 +308,10 @@ test('Test overrides for producer and consumer functions', () => { // Helper declaration const props: LambdaToSqsToLambdaProps = { producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`), - functionName: 'producer-function' + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`), + functionName: 'producer-function' }, consumerLambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_12_X, @@ -342,10 +342,10 @@ test('Test the public pattern props', () => { // Helper declaration const props: LambdaToSqsToLambdaProps = { producerLambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`), - functionName: 'producer-function' + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`), + functionName: 'producer-function' }, consumerLambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_10_X, 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 1999b5742..8413ff5da 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/README.md @@ -63,7 +63,15 @@ _Parameters_ |deployDeadLetterQueue?|`boolean`|Whether to create a secondary queue to be used as a dead letter queue. Defaults to `true`.| |deadLetterQueueProps?|[`sqs.QueueProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.QueueProps.html)|Optional user-provided props to override the default props for the dead letter queue. Only used if the `deployDeadLetterQueue` property is set to true.| |maxReceiveCount?|`number`|The number of times a message can be unsuccessfully dequeued before being moved to the dead letter queue. Defaults to `15`.| +|existingVpc?|`ec2.Vpc`|An optional, existing VPC into which this construct 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`| +|deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this construct. Setting this to true will deploy the minimal, most private VPC to run the construct: +* 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`.| +|vpcProps?|`ec2.VpcProps`|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.| + ## Pattern Properties | **Name** | **Type** | **Description** | 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 4516ac68a..db4464f28 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 @@ -12,63 +12,79 @@ */ // Imports -import * as defaults from '@aws-solutions-constructs/core'; -import * as lambda from '@aws-cdk/aws-lambda'; -import * as sqs from '@aws-cdk/aws-sqs'; -import { Construct } from '@aws-cdk/core'; +import * as defaults from "@aws-solutions-constructs/core"; +import * as lambda from "@aws-cdk/aws-lambda"; +import * as sqs from "@aws-cdk/aws-sqs"; +import * as ec2 from "@aws-cdk/aws-ec2"; +import { Construct } from "@aws-cdk/core"; +import { AddAwsServiceEndpoint } from "@aws-solutions-constructs/core"; /** * @summary The properties for the LambdaToSqs class. */ export interface LambdaToSqsProps { - /** - * Existing instance of Lambda Function object, if this is set then the lambdaFunctionProps is ignored. - * - * @default - None - */ - readonly existingLambdaObj?: lambda.Function, - /** - * User provided props to override the default props for the Lambda function. - * - * @default - Default properties are used. - */ - readonly lambdaFunctionProps?: lambda.FunctionProps, - /** - * Existing instance of SQS queue object, if this is set then queueProps is ignored. - * - * @default - Default props are used - */ - readonly existingQueueObj?: sqs.Queue, - /** - * Optional user-provided props to override the default props for the SQS queue. - * - * @default - Default props are used - */ - readonly queueProps?: sqs.QueueProps, - /** - * Whether to grant additional permissions to the Lambda function enabling it to purge the SQS queue. - * - * @default - "false", disabled by default. - */ - readonly enableQueuePurging?: boolean, - /** - * Optional user provided properties for the dead letter queue - * - * @default - Default props are used - */ - readonly deadLetterQueueProps?: sqs.QueueProps, - /** - * Whether to deploy a secondary queue to be used as a dead letter queue. - * - * @default - true. - */ - readonly deployDeadLetterQueue?: boolean, - /** - * The number of times a message can be unsuccessfully dequeued before being moved to the dead-letter queue. - * - * @default - required field if deployDeadLetterQueue=true. - */ - readonly maxReceiveCount?: number + /** + * Existing instance of Lambda Function object, if this is set then the lambdaFunctionProps is ignored. + * + * @default - None + */ + readonly existingLambdaObj?: lambda.Function; + /** + * User provided props to override the default props for the Lambda function. + * + * @default - Default properties are used. + */ + readonly lambdaFunctionProps?: lambda.FunctionProps; + /** + * Existing instance of SQS queue object, if this is set then queueProps is ignored. + * + * @default - Default props are used + */ + readonly existingQueueObj?: sqs.Queue; + /** + * Optional user-provided props to override the default props for the SQS queue. + * + * @default - Default props are used + */ + readonly queueProps?: sqs.QueueProps; + /** + * Whether to grant additional permissions to the Lambda function enabling it to purge the SQS queue. + * + * @default - "false", disabled by default. + */ + readonly enableQueuePurging?: boolean; + /** + * Optional user provided properties for the dead letter queue + * + * @default - Default props are used + */ + readonly deadLetterQueueProps?: sqs.QueueProps; + /** + * Whether to deploy a secondary queue to be used as a dead letter queue. + * + * @default - true. + */ + readonly deployDeadLetterQueue?: boolean; + /** + * The number of times a message can be unsuccessfully dequeued before being moved to the dead-letter queue. + * + * @default - required field if deployDeadLetterQueue=true. + */ + readonly maxReceiveCount?: number; + /** + * An existing VPC for the construct to use (construct will NOT create a new VPC in this case) + */ + readonly existingVpc?: ec2.Vpc; + /** + * Properties to override default properties if deployVpc is true + */ + readonly vpcProps?: ec2.VpcProps; + /** + * Whether to deploy a new VPC + * + * @default - false + */ + readonly deployVpc?: boolean; } /** @@ -78,6 +94,7 @@ export class LambdaToSqs extends Construct { public readonly lambdaFunction: lambda.Function; public readonly sqsQueue: sqs.Queue; public readonly deadLetterQueue?: sqs.DeadLetterQueue; + public readonly vpc?: ec2.Vpc; /** * @summary Constructs a new instance of the LambdaToSqs class. @@ -88,38 +105,64 @@ export class LambdaToSqs extends Construct { * @access public */ constructor(scope: Construct, id: string, props: LambdaToSqsProps) { - super(scope, id); + super(scope, id); - // Setup the Lambda function - this.lambdaFunction = defaults.buildLambdaFunction(this, { - existingLambdaObj: props.existingLambdaObj, - lambdaFunctionProps: props.lambdaFunctionProps - }); + if (props.deployVpc || props.existingVpc) { + if (props.deployVpc && props.existingVpc) { + throw new Error("More than 1 VPC specified in the properties"); + } - // Setup the dead letter queue, if applicable - this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { - existingQueueObj: props.existingQueueObj, - deployDeadLetterQueue: props.deployDeadLetterQueue, - deadLetterQueueProps: props.deadLetterQueueProps, - maxReceiveCount: props.maxReceiveCount + this.vpc = defaults.buildVpc(scope, { + existingVpc: props.existingVpc, + userVpcProps: props.vpcProps, + constructVpcProps: { + enableDnsHostnames: true, + enableDnsSupport: true, + natGateways: 0, + subnetConfiguration: [ + { + cidrMask: 18, + name: "isolated", + subnetType: ec2.SubnetType.ISOLATED, + }, + ], + }, }); - // Setup the queue - [this.sqsQueue] = defaults.buildQueue(this, 'queue', { - existingQueueObj: props.existingQueueObj, - queueProps: props.queueProps, - deadLetterQueue: this.deadLetterQueue - }); + AddAwsServiceEndpoint(scope, this.vpc, defaults.ServiceEndpointTypes.SQS); + } - // Configure environment variables - this.lambdaFunction.addEnvironment('SQS_QUEUE_URL', this.sqsQueue.queueUrl); + // Setup the Lambda function + this.lambdaFunction = defaults.buildLambdaFunction(this, { + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps, + vpc: this.vpc, + }); - // Enable queue purging permissions for the Lambda function, if enabled - if (props.enableQueuePurging) { - this.sqsQueue.grantPurge(this.lambdaFunction); - } + // Setup the dead letter queue, if applicable + this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { + existingQueueObj: props.existingQueueObj, + deployDeadLetterQueue: props.deployDeadLetterQueue, + deadLetterQueueProps: props.deadLetterQueueProps, + maxReceiveCount: props.maxReceiveCount + }); + + // Setup the queue + [this.sqsQueue] = defaults.buildQueue(this, 'queue', { + existingQueueObj: props.existingQueueObj, + queueProps: props.queueProps, + deadLetterQueue: this.deadLetterQueue + }); + + // Configure environment variables + this.lambdaFunction.addEnvironment('SQS_QUEUE_URL', this.sqsQueue.queueUrl); + + // Enable queue purging permissions for the Lambda function, if enabled + if (props.enableQueuePurging) { + this.sqsQueue.grantPurge(this.lambdaFunction); + } - // Enable message send permissions for the Lambda function by default - this.sqsQueue.grantSendMessages(this.lambdaFunction); + // Enable message send permissions for the Lambda function by default + this.sqsQueue.grantSendMessages(this.lambdaFunction); } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/package.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/package.json index 366156bca..8491bf2bf 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/package.json +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/package.json @@ -55,6 +55,7 @@ "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-solutions-constructs/core": "0.0.0", "constructs": "^3.2.0" @@ -74,6 +75,7 @@ "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-solutions-constructs/core": "0.0.0", - "constructs": "^3.2.0" + "constructs": "^3.2.0", + "@aws-cdk/aws-ec2": "0.0.0" } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/cdk.out b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/cdk.out new file mode 100644 index 000000000..bdc5a9f30 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/cdk.out @@ -0,0 +1 @@ +{"version":"7.0.0"} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/manifest.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/manifest.json new file mode 100644 index 000000000..8530d325d --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/manifest.json @@ -0,0 +1,621 @@ +{ + "version": "7.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-lambda-sqs": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-lambda-sqs.template.json" + }, + "metadata": { + "/test-lambda-sqs": [ + { + "type": "aws:cdk:asset", + "data": { + "path": "/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda", + "id": "8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b", + "packaging": "zip", + "sourceHash": "8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b", + "s3BucketParameter": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3Bucket99C6FD3D", + "s3KeyParameter": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED", + "artifactHashParameter": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bArtifactHash81FE0B06" + }, + "trace": [ + "ConstructNode.addMetadata (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/construct-compat.js:358:62)", + "LegacyStackSynthesizer.doAddFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:157:29)", + "LegacyStackSynthesizer.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:75:25)", + "Stack.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack.js:363:33)", + "LegacyStackSynthesizer.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:79:31)", + "new Asset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-s3-assets/lib/asset.js:41:44)", + "AssetCode.bind (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/code.js:165:26)", + "new Function (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/function.js:84:33)", + "deployLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:103:28)", + "Object.buildLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:26:20)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:58:40)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/test-lambda-sqs/LambdaFunctionServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testlambdasqsLambdaFunctionServiceRoleC0430CA8", + "trace": [ + "new Role (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-iam/lib/role.js:62:22)", + "deployLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:45:31)", + "Object.buildLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:26:20)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:58:40)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/test-lambda-sqs/LambdaFunctionServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D", + "trace": [ + "new Policy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-iam/lib/policy.js:49:26)", + "Role.addToPrincipalPolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-iam/lib/role.js:193:34)", + "Role.addToPolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-iam/lib/role.js:203:21)", + "deployLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:63:27)", + "Object.buildLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:26:20)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:58:40)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/test-lambda-sqs/ReplaceDefaultSecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testlambdasqsReplaceDefaultSecurityGroup53A5E043", + "trace": [ + "new SecurityGroup (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/security-group.js:193:30)", + "deployLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:79:37)", + "Object.buildLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:26:20)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:58:40)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/test-lambda-sqs/LambdaFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testlambdasqsLambdaFunction28E890A1", + "trace": [ + "new Function (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/function.js:115:26)", + "deployLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:103:28)", + "Object.buildLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:26:20)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:58:40)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/test-lambda-sqs/deadLetterQueue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testlambdasqsdeadLetterQueueC34BC0BD", + "trace": [ + "new Queue (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-sqs/lib/queue.js:45:23)", + "buildQueue (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.js:50:23)", + "Object.buildDeadLetterQueue (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.js:64:23)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:64:41)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/test-lambda-sqs/deadLetterQueue/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testlambdasqsdeadLetterQueuePolicy270F1626", + "trace": [ + "new QueuePolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-sqs/lib/policy.js:20:9)", + "Queue.addToResourcePolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-sqs/lib/queue-base.js:20:27)", + "applySecureQueuePolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.js:81:11)", + "buildQueue (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.js:51:9)", + "Object.buildDeadLetterQueue (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.js:64:23)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:64:41)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/test-lambda-sqs/queue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testlambdasqsqueueDD178B7C", + "trace": [ + "new Queue (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-sqs/lib/queue.js:45:23)", + "Object.buildQueue (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.js:50:23)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:71:36)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/test-lambda-sqs/queue/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testlambdasqsqueuePolicy3FC623C5", + "trace": [ + "new QueuePolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-sqs/lib/policy.js:20:9)", + "Queue.addToResourcePolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-sqs/lib/queue-base.js:20:27)", + "applySecureQueuePolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.js:81:11)", + "Object.buildQueue (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.js:51:9)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:71:36)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Vpc8378EB38", + "trace": [ + "new Vpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:309:25)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:30:17)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/isolatedSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcisolatedSubnet1SubnetE62B1B9B", + "trace": [ + "new Subnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:609:24)", + "new PrivateSubnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:799:9)", + "availabilityZones.forEach (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:528:44)", + "Array.forEach ()", + "Vpc.createSubnetResources (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:502:32)", + "Vpc.createSubnets (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:493:18)", + "new Vpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:330:14)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:30:17)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/isolatedSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcisolatedSubnet1RouteTableE442650B", + "trace": [ + "new Subnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:625:23)", + "new PrivateSubnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:799:9)", + "availabilityZones.forEach (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:528:44)", + "Array.forEach ()", + "Vpc.createSubnetResources (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:502:32)", + "Vpc.createSubnets (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:493:18)", + "new Vpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:330:14)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:30:17)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/isolatedSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcisolatedSubnet1RouteTableAssociationD259E31A", + "trace": [ + "new Subnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:630:9)", + "new PrivateSubnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:799:9)", + "availabilityZones.forEach (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:528:44)", + "Array.forEach ()", + "Vpc.createSubnetResources (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:502:32)", + "Vpc.createSubnets (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:493:18)", + "new Vpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:330:14)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:30:17)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/isolatedSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcisolatedSubnet2Subnet39217055", + "trace": [ + "new Subnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:609:24)", + "new PrivateSubnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:799:9)", + "availabilityZones.forEach (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:528:44)", + "Array.forEach ()", + "Vpc.createSubnetResources (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:502:32)", + "Vpc.createSubnets (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:493:18)", + "new Vpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:330:14)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:30:17)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/isolatedSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcisolatedSubnet2RouteTable334F9764", + "trace": [ + "new Subnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:625:23)", + "new PrivateSubnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:799:9)", + "availabilityZones.forEach (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:528:44)", + "Array.forEach ()", + "Vpc.createSubnetResources (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:502:32)", + "Vpc.createSubnets (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:493:18)", + "new Vpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:330:14)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:30:17)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/isolatedSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcisolatedSubnet2RouteTableAssociation25A4716F", + "trace": [ + "new Subnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:630:9)", + "new PrivateSubnet (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:799:9)", + "availabilityZones.forEach (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:528:44)", + "Array.forEach ()", + "Vpc.createSubnetResources (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:502:32)", + "Vpc.createSubnets (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:493:18)", + "new Vpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:330:14)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:30:17)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/FlowLog/IAMRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcFlowLogIAMRole6A475D41", + "trace": [ + "new Role (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-iam/lib/role.js:62:22)", + "CloudWatchLogsDestination.bind (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc-flow-logs.js:141:23)", + "new FlowLog (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc-flow-logs.js:198:47)", + "Vpc.addFlowLog (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:124:16)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:32:9)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/FlowLog/IAMRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcFlowLogIAMRoleDefaultPolicy406FB995", + "trace": [ + "new Policy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-iam/lib/policy.js:49:26)", + "Role.addToPrincipalPolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-iam/lib/role.js:193:34)", + "Role.addToPolicy (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-iam/lib/role.js:203:21)", + "CloudWatchLogsDestination.bind (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc-flow-logs.js:155:17)", + "new FlowLog (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc-flow-logs.js:198:47)", + "Vpc.addFlowLog (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:124:16)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:32:9)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/FlowLog/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcFlowLogLogGroup7B5C56B9", + "trace": [ + "new LogGroup (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-logs/lib/log-group.js:142:26)", + "CloudWatchLogsDestination.bind (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc-flow-logs.js:150:24)", + "new FlowLog (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc-flow-logs.js:198:47)", + "Vpc.addFlowLog (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:124:16)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:32:9)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/FlowLog/FlowLog": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcFlowLog8FF33A73", + "trace": [ + "new FlowLog (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc-flow-logs.js:207:25)", + "Vpc.addFlowLog (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:124:16)", + "Object.buildVpc (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:32:9)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:39:33)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/Vpc/SQS/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcSQSDF166A88", + "trace": [ + "new InterfaceVpcEndpoint (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc-endpoint.js:350:26)", + "Vpc.addInterfaceEndpoint (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/vpc.js:106:16)", + "Object.AddAwsServiceEndpoint (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:116:17)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:55:20)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/ReplaceEndpointDefaultSecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ReplaceEndpointDefaultSecurityGroupCF0CCAF1", + "trace": [ + "new SecurityGroup (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-ec2/lib/security-group.js:193:30)", + "Object.AddAwsServiceEndpoint (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.js:95:50)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:55:20)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/AssetParameters/8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b/S3Bucket": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3Bucket99C6FD3D", + "trace": [ + "new FileAssetParameters (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/private/asset-parameters.js:12:36)", + "LegacyStackSynthesizer.doAddFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:147:22)", + "LegacyStackSynthesizer.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:75:25)", + "Stack.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack.js:363:33)", + "LegacyStackSynthesizer.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:79:31)", + "new Asset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-s3-assets/lib/asset.js:41:44)", + "AssetCode.bind (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/code.js:165:26)", + "new Function (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/function.js:84:33)", + "deployLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:103:28)", + "Object.buildLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:26:20)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:58:40)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/AssetParameters/8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b/S3VersionKey": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED", + "trace": [ + "new FileAssetParameters (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/private/asset-parameters.js:16:35)", + "LegacyStackSynthesizer.doAddFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:147:22)", + "LegacyStackSynthesizer.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:75:25)", + "Stack.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack.js:363:33)", + "LegacyStackSynthesizer.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:79:31)", + "new Asset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-s3-assets/lib/asset.js:41:44)", + "AssetCode.bind (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/code.js:165:26)", + "new Function (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/function.js:84:33)", + "deployLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:103:28)", + "Object.buildLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:26:20)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:58:40)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ], + "/test-lambda-sqs/AssetParameters/8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b/ArtifactHash": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bArtifactHash81FE0B06", + "trace": [ + "new FileAssetParameters (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/private/asset-parameters.js:20:38)", + "LegacyStackSynthesizer.doAddFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:147:22)", + "LegacyStackSynthesizer.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:75:25)", + "Stack.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack.js:363:33)", + "LegacyStackSynthesizer.addFileAsset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/core/lib/stack-synthesizers/legacy.js:79:31)", + "new Asset (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-s3-assets/lib/asset.js:41:44)", + "AssetCode.bind (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/code.js:165:26)", + "new Function (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/node_modules/@aws-cdk/aws-lambda/lib/function.js:84:33)", + "deployLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:103:28)", + "Object.buildLambdaFunction (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.js:26:20)", + "new LambdaToSqs (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/lib/index.js:58:40)", + "Object. (/Users/biffgaut/Documents/Active/AWS/Constructs/pull-requests/viplight-fix/project-vesper/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.js:32:1)", + "Module._compile (internal/modules/cjs/loader.js:778:30)", + "Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)", + "Module.load (internal/modules/cjs/loader.js:653:32)", + "tryModuleLoad (internal/modules/cjs/loader.js:593:12)", + "Function.Module._load (internal/modules/cjs/loader.js:585:3)", + "Function.Module.runMain (internal/modules/cjs/loader.js:831:12)", + "startup (internal/bootstrap/node.js:283:19)", + "bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)" + ] + } + ] + } + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/test-lambda-sqs.template.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/test-lambda-sqs.template.json new file mode 100644 index 000000000..04d1f3d24 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/test-lambda-sqs.template.json @@ -0,0 +1,738 @@ +{ + "Description": "Integration Test for aws-lambda-sqs", + "Resources": { + "testlambdasqsLambdaFunctionServiceRoleC0430CA8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:CreateNetworkInterface", + "ec2:DescribeNetworkInterfaces", + "ec2:DeleteNetworkInterface", + "ec2:AssignPrivateIpAddresses", + "ec2:UnassignPrivateIpAddresses" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "xray:PutTraceSegments", + "xray:PutTelemetryRecords" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D", + "Roles": [ + { + "Ref": "testlambdasqsLambdaFunctionServiceRoleC0430CA8" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W12", + "reason": "Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC." + } + ] + } + } + }, + "testlambdasqsReplaceDefaultSecurityGroup53A5E043": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "test-lambda-sqs/test-lambda-sqs/ReplaceDefaultSecurityGroup", + "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" + } + ] + } + } + }, + "testlambdasqsLambdaFunction28E890A1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3Bucket99C6FD3D" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testlambdasqsLambdaFunctionServiceRoleC0430CA8", + "Arn" + ] + }, + "Runtime": "nodejs10.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": { + "Ref": "testlambdasqsqueueDD178B7C" + } + } + }, + "TracingConfig": { + "Mode": "Active" + }, + "VpcConfig": { + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "testlambdasqsReplaceDefaultSecurityGroup53A5E043", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + }, + { + "Ref": "VpcisolatedSubnet2Subnet39217055" + } + ] + } + }, + "DependsOn": [ + "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D", + "testlambdasqsLambdaFunctionServiceRoleC0430CA8" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testlambdasqsdeadLetterQueueC34BC0BD": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": "alias/aws/sqs" + } + }, + "testlambdasqsdeadLetterQueuePolicy270F1626": { + "Type": "AWS::SQS::QueuePolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "Sid": "QueueOwnerOnlyAccess" + }, + { + "Action": "SQS:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "Sid": "HttpsOnly" + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "testlambdasqsdeadLetterQueueC34BC0BD" + } + ] + } + }, + "testlambdasqsqueueDD178B7C": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": "alias/aws/sqs", + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "maxReceiveCount": 15 + } + } + }, + "testlambdasqsqueuePolicy3FC623C5": { + "Type": "AWS::SQS::QueuePolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + }, + "Sid": "QueueOwnerOnlyAccess" + }, + { + "Action": "SQS:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + }, + "Sid": "HttpsOnly" + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "testlambdasqsqueueDD178B7C" + } + ] + } + }, + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc" + } + ] + } + }, + "VpcisolatedSubnet1SubnetE62B1B9B": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet1" + } + ] + } + }, + "VpcisolatedSubnet1RouteTableE442650B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet1" + } + ] + } + }, + "VpcisolatedSubnet1RouteTableAssociationD259E31A": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcisolatedSubnet1RouteTableE442650B" + }, + "SubnetId": { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + } + } + }, + "VpcisolatedSubnet2Subnet39217055": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet2" + } + ] + } + }, + "VpcisolatedSubnet2RouteTable334F9764": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet2" + } + ] + } + }, + "VpcisolatedSubnet2RouteTableAssociation25A4716F": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcisolatedSubnet2RouteTable334F9764" + }, + "SubnetId": { + "Ref": "VpcisolatedSubnet2Subnet39217055" + } + } + }, + "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": "test-lambda-sqs/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 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "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": "test-lambda-sqs/Vpc" + } + ] + } + }, + "VpcSQSDF166A88": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".sqs" + ] + ] + }, + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ReplaceEndpointDefaultSecurityGroupCF0CCAF1", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + }, + { + "Ref": "VpcisolatedSubnet2Subnet39217055" + } + ], + "VpcEndpointType": "Interface" + } + }, + "ReplaceEndpointDefaultSecurityGroupCF0CCAF1": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "test-lambda-sqs/ReplaceEndpointDefaultSecurityGroup", + "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": { + "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3Bucket99C6FD3D": { + "Type": "String", + "Description": "S3 bucket for asset \"8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b\"" + }, + "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED": { + "Type": "String", + "Description": "S3 key for asset version \"8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b\"" + }, + "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bArtifactHash81FE0B06": { + "Type": "String", + "Description": "Artifact hash for asset \"8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b\"" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/tree.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/tree.json new file mode 100644 index 000000000..d45a41ab5 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/cdk-integ.out/tree.json @@ -0,0 +1,922 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree" + }, + "test-lambda-sqs": { + "id": "test-lambda-sqs", + "path": "test-lambda-sqs", + "children": { + "test-lambda-sqs": { + "id": "test-lambda-sqs", + "path": "test-lambda-sqs/test-lambda-sqs", + "children": { + "LambdaFunctionServiceRole": { + "id": "LambdaFunctionServiceRole", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunctionServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunctionServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "policies": [ + { + "policyName": "LambdaFunctionServiceRolePolicy", + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + ] + } + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunctionServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunctionServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "ec2:CreateNetworkInterface", + "ec2:DescribeNetworkInterfaces", + "ec2:DeleteNetworkInterface", + "ec2:AssignPrivateIpAddresses", + "ec2:UnassignPrivateIpAddresses" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "xray:PutTraceSegments", + "xray:PutTelemetryRecords" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D", + "roles": [ + { + "Ref": "testlambdasqsLambdaFunctionServiceRoleC0430CA8" + } + ] + } + } + } + } + } + } + }, + "ReplaceDefaultSecurityGroup": { + "id": "ReplaceDefaultSecurityGroup", + "path": "test-lambda-sqs/test-lambda-sqs/ReplaceDefaultSecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/test-lambda-sqs/ReplaceDefaultSecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "test-lambda-sqs/test-lambda-sqs/ReplaceDefaultSecurityGroup", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + } + } + } + }, + "LambdaFunction": { + "id": "LambdaFunction", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunction", + "children": { + "Code": { + "id": "Code", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunction/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunction/Code/Stage" + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunction/Code/AssetBucket" + } + } + }, + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/test-lambda-sqs/LambdaFunction/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3Bucket99C6FD3D" + }, + "s3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED" + } + ] + } + ] + } + ] + ] + } + }, + "handler": "index.handler", + "role": { + "Fn::GetAtt": [ + "testlambdasqsLambdaFunctionServiceRoleC0430CA8", + "Arn" + ] + }, + "runtime": "nodejs10.x", + "environment": { + "variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": { + "Ref": "testlambdasqsqueueDD178B7C" + } + } + }, + "tracingConfig": { + "mode": "Active" + }, + "vpcConfig": { + "subnetIds": [ + { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + }, + { + "Ref": "VpcisolatedSubnet2Subnet39217055" + } + ], + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "testlambdasqsReplaceDefaultSecurityGroup53A5E043", + "GroupId" + ] + } + ] + } + } + } + } + } + }, + "deadLetterQueue": { + "id": "deadLetterQueue", + "path": "test-lambda-sqs/test-lambda-sqs/deadLetterQueue", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/test-lambda-sqs/deadLetterQueue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": { + "kmsMasterKeyId": "alias/aws/sqs" + } + } + }, + "Policy": { + "id": "Policy", + "path": "test-lambda-sqs/test-lambda-sqs/deadLetterQueue/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/test-lambda-sqs/deadLetterQueue/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::QueuePolicy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "Sid": "QueueOwnerOnlyAccess" + }, + { + "Action": "SQS:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "Sid": "HttpsOnly" + } + ], + "Version": "2012-10-17" + }, + "queues": [ + { + "Ref": "testlambdasqsdeadLetterQueueC34BC0BD" + } + ] + } + } + } + } + } + } + }, + "queue": { + "id": "queue", + "path": "test-lambda-sqs/test-lambda-sqs/queue", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/test-lambda-sqs/queue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": { + "kmsMasterKeyId": "alias/aws/sqs", + "redrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "maxReceiveCount": 15 + } + } + } + }, + "Policy": { + "id": "Policy", + "path": "test-lambda-sqs/test-lambda-sqs/queue/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/test-lambda-sqs/queue/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::QueuePolicy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + }, + "Sid": "QueueOwnerOnlyAccess" + }, + { + "Action": "SQS:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + }, + "Sid": "HttpsOnly" + } + ], + "Version": "2012-10-17" + }, + "queues": [ + { + "Ref": "testlambdasqsqueueDD178B7C" + } + ] + } + } + } + } + } + } + } + } + }, + "Vpc": { + "id": "Vpc", + "path": "test-lambda-sqs/Vpc", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/Vpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "test-lambda-sqs/Vpc" + } + ] + } + } + }, + "isolatedSubnet1": { + "id": "isolatedSubnet1", + "path": "test-lambda-sqs/Vpc/isolatedSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "test-lambda-sqs/Vpc/isolatedSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/18", + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "isolated" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "test-lambda-sqs/Vpc/isolatedSubnet1" + } + ] + } + } + }, + "Acl": { + "id": "Acl", + "path": "test-lambda-sqs/Vpc/isolatedSubnet1/Acl" + }, + "RouteTable": { + "id": "RouteTable", + "path": "test-lambda-sqs/Vpc/isolatedSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "test-lambda-sqs/Vpc/isolatedSubnet1" + } + ] + } + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "test-lambda-sqs/Vpc/isolatedSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcisolatedSubnet1RouteTableE442650B" + }, + "subnetId": { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + } + } + } + } + } + }, + "isolatedSubnet2": { + "id": "isolatedSubnet2", + "path": "test-lambda-sqs/Vpc/isolatedSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "test-lambda-sqs/Vpc/isolatedSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.64.0/18", + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "isolated" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "test-lambda-sqs/Vpc/isolatedSubnet2" + } + ] + } + } + }, + "Acl": { + "id": "Acl", + "path": "test-lambda-sqs/Vpc/isolatedSubnet2/Acl" + }, + "RouteTable": { + "id": "RouteTable", + "path": "test-lambda-sqs/Vpc/isolatedSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "test-lambda-sqs/Vpc/isolatedSubnet2" + } + ] + } + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "test-lambda-sqs/Vpc/isolatedSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcisolatedSubnet2RouteTable334F9764" + }, + "subnetId": { + "Ref": "VpcisolatedSubnet2Subnet39217055" + } + } + } + } + } + }, + "FlowLog": { + "id": "FlowLog", + "path": "test-lambda-sqs/Vpc/FlowLog", + "children": { + "IAMRole": { + "id": "IAMRole", + "path": "test-lambda-sqs/Vpc/FlowLog/IAMRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/Vpc/FlowLog/IAMRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "vpc-flow-logs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "tags": [ + { + "key": "Name", + "value": "test-lambda-sqs/Vpc" + } + ] + } + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "test-lambda-sqs/Vpc/FlowLog/IAMRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/Vpc/FlowLog/IAMRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "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" + } + ] + } + } + } + } + } + } + }, + "LogGroup": { + "id": "LogGroup", + "path": "test-lambda-sqs/Vpc/FlowLog/LogGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/Vpc/FlowLog/LogGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::LogGroup", + "aws:cdk:cloudformation:props": { + "retentionInDays": 731 + } + } + } + } + }, + "FlowLog": { + "id": "FlowLog", + "path": "test-lambda-sqs/Vpc/FlowLog/FlowLog", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::FlowLog", + "aws:cdk:cloudformation:props": { + "resourceId": { + "Ref": "Vpc8378EB38" + }, + "resourceType": "VPC", + "trafficType": "ALL", + "deliverLogsPermissionArn": { + "Fn::GetAtt": [ + "VpcFlowLogIAMRole6A475D41", + "Arn" + ] + }, + "logDestinationType": "cloud-watch-logs", + "logGroupName": { + "Ref": "VpcFlowLogLogGroup7B5C56B9" + }, + "tags": [ + { + "key": "Name", + "value": "test-lambda-sqs/Vpc" + } + ] + } + } + } + } + }, + "SQS": { + "id": "SQS", + "path": "test-lambda-sqs/Vpc/SQS", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/Vpc/SQS/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPCEndpoint", + "aws:cdk:cloudformation:props": { + "serviceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".sqs" + ] + ] + }, + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "privateDnsEnabled": true, + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "ReplaceEndpointDefaultSecurityGroupCF0CCAF1", + "GroupId" + ] + } + ], + "subnetIds": [ + { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + }, + { + "Ref": "VpcisolatedSubnet2Subnet39217055" + } + ], + "vpcEndpointType": "Interface" + } + } + } + } + } + } + }, + "ReplaceEndpointDefaultSecurityGroup": { + "id": "ReplaceEndpointDefaultSecurityGroup", + "path": "test-lambda-sqs/ReplaceEndpointDefaultSecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "test-lambda-sqs/ReplaceEndpointDefaultSecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "test-lambda-sqs/ReplaceEndpointDefaultSecurityGroup", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "securityGroupIngress": [ + { + "cidrIp": { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + "ipProtocol": "tcp", + "fromPort": 443, + "toPort": 443, + "description": { + "Fn::Join": [ + "", + [ + "from ", + { + "Fn::GetAtt": [ + "Vpc8378EB38", + "CidrBlock" + ] + }, + ":443" + ] + ] + } + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + } + } + } + }, + "AssetParameters": { + "id": "AssetParameters", + "path": "test-lambda-sqs/AssetParameters", + "children": { + "8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b": { + "id": "8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b", + "path": "test-lambda-sqs/AssetParameters/8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b", + "children": { + "S3Bucket": { + "id": "S3Bucket", + "path": "test-lambda-sqs/AssetParameters/8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b/S3Bucket" + }, + "S3VersionKey": { + "id": "S3VersionKey", + "path": "test-lambda-sqs/AssetParameters/8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b/S3VersionKey" + }, + "ArtifactHash": { + "id": "ArtifactHash", + "path": "test-lambda-sqs/AssetParameters/8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b/ArtifactHash" + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.ts index f084836e1..c755222de 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunction.ts @@ -23,11 +23,11 @@ stack.templateOptions.description = 'Integration Test for aws-lambda-sqs'; // Definitions const props: LambdaToSqsProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } }; new LambdaToSqs(stack, 'test-lambda-sqs', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.expected.json b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.expected.json new file mode 100644 index 000000000..f672047b6 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.expected.json @@ -0,0 +1,780 @@ +{ + "Description": "Integration Test for aws-lambda-sqs", + "Resources": { + "testlambdasqsLambdaFunctionServiceRoleC0430CA8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaFunctionServiceRolePolicy" + } + ] + } + }, + "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:CreateNetworkInterface", + "ec2:DescribeNetworkInterfaces", + "ec2:DeleteNetworkInterface", + "ec2:AssignPrivateIpAddresses", + "ec2:UnassignPrivateIpAddresses" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "xray:PutTraceSegments", + "xray:PutTelemetryRecords" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D", + "Roles": [ + { + "Ref": "testlambdasqsLambdaFunctionServiceRoleC0430CA8" + } + ] + }, + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W12", + "reason": "Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC." + } + ] + } + } + }, + "testlambdasqsReplaceDefaultSecurityGroup53A5E043": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "test-lambda-sqs/test-lambda-sqs/ReplaceDefaultSecurityGroup", + "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" + } + ] + } + } + }, + "testlambdasqsLambdaFunction28E890A1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3Bucket99C6FD3D" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED" + } + ] + } + ] + } + ] + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "testlambdasqsLambdaFunctionServiceRoleC0430CA8", + "Arn" + ] + }, + "Runtime": "nodejs10.x", + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", + "SQS_QUEUE_URL": { + "Ref": "testlambdasqsqueueDD178B7C" + } + } + }, + "TracingConfig": { + "Mode": "Active" + }, + "VpcConfig": { + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "testlambdasqsReplaceDefaultSecurityGroup53A5E043", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + }, + { + "Ref": "VpcisolatedSubnet2Subnet39217055" + }, + { + "Ref": "VpcisolatedSubnet3Subnet44F2537D" + } + ] + } + }, + "DependsOn": [ + "testlambdasqsLambdaFunctionServiceRoleDefaultPolicyE3CAD09D", + "testlambdasqsLambdaFunctionServiceRoleC0430CA8" + ], + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W58", + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions." + } + ] + } + } + }, + "testlambdasqsdeadLetterQueueC34BC0BD": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": "alias/aws/sqs" + } + }, + "testlambdasqsdeadLetterQueuePolicy270F1626": { + "Type": "AWS::SQS::QueuePolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "Sid": "QueueOwnerOnlyAccess" + }, + { + "Action": "SQS:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "Sid": "HttpsOnly" + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "testlambdasqsdeadLetterQueueC34BC0BD" + } + ] + } + }, + "testlambdasqsqueueDD178B7C": { + "Type": "AWS::SQS::Queue", + "Properties": { + "KmsMasterKeyId": "alias/aws/sqs", + "RedrivePolicy": { + "deadLetterTargetArn": { + "Fn::GetAtt": [ + "testlambdasqsdeadLetterQueueC34BC0BD", + "Arn" + ] + }, + "maxReceiveCount": 15 + } + } + }, + "testlambdasqsqueuePolicy3FC623C5": { + "Type": "AWS::SQS::QueuePolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + }, + "Sid": "QueueOwnerOnlyAccess" + }, + { + "Action": "SQS:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": "*", + "Resource": { + "Fn::GetAtt": [ + "testlambdasqsqueueDD178B7C", + "Arn" + ] + }, + "Sid": "HttpsOnly" + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "testlambdasqsqueueDD178B7C" + } + ] + } + }, + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc" + } + ] + } + }, + "VpcisolatedSubnet1SubnetE62B1B9B": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet1" + } + ] + } + }, + "VpcisolatedSubnet1RouteTableE442650B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet1" + } + ] + } + }, + "VpcisolatedSubnet1RouteTableAssociationD259E31A": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcisolatedSubnet1RouteTableE442650B" + }, + "SubnetId": { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + } + } + }, + "VpcisolatedSubnet2Subnet39217055": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet2" + } + ] + } + }, + "VpcisolatedSubnet2RouteTable334F9764": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet2" + } + ] + } + }, + "VpcisolatedSubnet2RouteTableAssociation25A4716F": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcisolatedSubnet2RouteTable334F9764" + }, + "SubnetId": { + "Ref": "VpcisolatedSubnet2Subnet39217055" + } + } + }, + "VpcisolatedSubnet3Subnet44F2537D": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "isolated" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet3" + } + ] + } + }, + "VpcisolatedSubnet3RouteTableA2F6BBC0": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "test-lambda-sqs/Vpc/isolatedSubnet3" + } + ] + } + }, + "VpcisolatedSubnet3RouteTableAssociationDC010BEB": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcisolatedSubnet3RouteTableA2F6BBC0" + }, + "SubnetId": { + "Ref": "VpcisolatedSubnet3Subnet44F2537D" + } + } + }, + "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": "test-lambda-sqs/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 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "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": "test-lambda-sqs/Vpc" + } + ] + } + }, + "VpcSQSDF166A88": { + "Type": "AWS::EC2::VPCEndpoint", + "Properties": { + "ServiceName": { + "Fn::Join": [ + "", + [ + "com.amazonaws.", + { + "Ref": "AWS::Region" + }, + ".sqs" + ] + ] + }, + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "PrivateDnsEnabled": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ReplaceEndpointDefaultSecurityGroupCF0CCAF1", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VpcisolatedSubnet1SubnetE62B1B9B" + }, + { + "Ref": "VpcisolatedSubnet2Subnet39217055" + }, + { + "Ref": "VpcisolatedSubnet3Subnet44F2537D" + } + ], + "VpcEndpointType": "Interface" + } + }, + "ReplaceEndpointDefaultSecurityGroupCF0CCAF1": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "test-lambda-sqs/ReplaceEndpointDefaultSecurityGroup", + "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": { + "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3Bucket99C6FD3D": { + "Type": "String", + "Description": "S3 bucket for asset \"8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b\"" + }, + "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bS3VersionKey7DE82FED": { + "Type": "String", + "Description": "S3 key for asset version \"8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b\"" + }, + "AssetParameters8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2bArtifactHash81FE0B06": { + "Type": "String", + "Description": "Artifact hash for asset \"8522cf47e408b8532776f54567f9fd125e5ee78fb2dadb4aa7014d320a77fa2b\"" + } + } +} \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.ts new file mode 100644 index 000000000..98e52e574 --- /dev/null +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.deployFunctionWithVpc.ts @@ -0,0 +1,37 @@ +/** + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// Imports +import { App, Stack } from "@aws-cdk/core"; +import { LambdaToSqs, LambdaToSqsProps } from "../lib"; +import * as lambda from "@aws-cdk/aws-lambda"; + +// Setup +const app = new App(); +const stack = new Stack(app, "test-lambda-sqs"); +stack.templateOptions.description = "Integration Test for aws-lambda-sqs"; + +// Definitions +const props: LambdaToSqsProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: "index.handler", + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + deployVpc: true, +}; + +new LambdaToSqs(stack, "test-lambda-sqs", props); + +// Synth +app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.ts index 16ef06e3b..b61de9f36 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/integ.existingFunction.ts @@ -32,7 +32,7 @@ const lambdaFunctionProps = { const func = defaults.deployLambdaFunction(stack, lambdaFunctionProps); const props: LambdaToSqsProps = { - existingLambdaObj: func + existingLambdaObj: func }; new LambdaToSqs(stack, 'test-lambda-sqs', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda-sqs.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda-sqs.test.ts index 7a2b7b0fa..ca32e7b32 100755 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda-sqs.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sqs/test/lambda-sqs.test.ts @@ -15,6 +15,7 @@ import { Stack } from "@aws-cdk/core"; import * as lambda from "@aws-cdk/aws-lambda"; import * as sqs from "@aws-cdk/aws-sqs"; +import * as ec2 from "@aws-cdk/aws-ec2"; import { LambdaToSqs } from '../lib'; import { SynthUtils } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; @@ -145,4 +146,180 @@ test('Test deployment w/ existing queue', () => { }); // Assertion 1 expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); -}); \ No newline at end of file +}); + +// -------------------------------------------------------------- +// Test minimal deployment that deploys a VPC without vpcProps +// -------------------------------------------------------------- +test("Test minimal deployment that deploys a VPC without vpcProps", () => { + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToSqs(stack, "lambda-to-sqs-stack", { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: "index.handler", + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + deployVpc: true, + }); + + expect(stack).toHaveResource("AWS::Lambda::Function", { + VpcConfig: { + SecurityGroupIds: [ + { + "Fn::GetAtt": [ + "lambdatosqsstackReplaceDefaultSecurityGroup7FE5F431", + "GroupId", + ], + }, + ], + SubnetIds: [ + { + Ref: "VpcisolatedSubnet1SubnetE62B1B9B", + }, + { + Ref: "VpcisolatedSubnet2Subnet39217055", + }, + ], + }, + }); + + expect(stack).toHaveResource("AWS::EC2::VPC", { + EnableDnsHostnames: true, + EnableDnsSupport: true, + }); + + expect(stack).toHaveResource("AWS::EC2::VPCEndpoint", { + VpcEndpointType: "Interface", + }); + + expect(stack).toCountResources("AWS::EC2::Subnet", 2); + expect(stack).toCountResources("AWS::EC2::InternetGateway", 0); +}); + +// -------------------------------------------------------------- +// Test minimal deployment that deploys a VPC w/vpcProps +// -------------------------------------------------------------- +test("Test minimal deployment that deploys a VPC w/vpcProps", () => { + // Stack + const stack = new Stack(); + // Helper declaration + new LambdaToSqs(stack, "lambda-to-sqs-stack", { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: "index.handler", + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + vpcProps: { + enableDnsHostnames: false, + enableDnsSupport: false, + cidr: "192.68.0.0/16", + }, + deployVpc: true, + }); + + expect(stack).toHaveResource("AWS::Lambda::Function", { + VpcConfig: { + SecurityGroupIds: [ + { + "Fn::GetAtt": [ + "lambdatosqsstackReplaceDefaultSecurityGroup7FE5F431", + "GroupId", + ], + }, + ], + SubnetIds: [ + { + Ref: "VpcisolatedSubnet1SubnetE62B1B9B", + }, + { + Ref: "VpcisolatedSubnet2Subnet39217055", + }, + ], + }, + }); + + expect(stack).toHaveResource("AWS::EC2::VPC", { + CidrBlock: "192.68.0.0/16", + EnableDnsHostnames: true, + EnableDnsSupport: true, + }); + + expect(stack).toHaveResource("AWS::EC2::VPCEndpoint", { + VpcEndpointType: "Interface", + }); + + expect(stack).toCountResources("AWS::EC2::Subnet", 2); + expect(stack).toCountResources("AWS::EC2::InternetGateway", 0); +}); + +// -------------------------------------------------------------- +// Test minimal deployment with an existing VPC +// -------------------------------------------------------------- +test("Test minimal deployment with an existing VPC", () => { + // Stack + const stack = new Stack(); + + const testVpc = new ec2.Vpc(stack, "test-vpc", {}); + + // Helper declaration + new LambdaToSqs(stack, "lambda-to-sqs-stack", { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: "index.handler", + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + existingVpc: testVpc, + }); + + expect(stack).toHaveResource("AWS::Lambda::Function", { + VpcConfig: { + SecurityGroupIds: [ + { + "Fn::GetAtt": [ + "lambdatosqsstackReplaceDefaultSecurityGroup7FE5F431", + "GroupId", + ], + }, + ], + SubnetIds: [ + { + Ref: "testvpcPrivateSubnet1Subnet865FB50A", + }, + { + Ref: "testvpcPrivateSubnet2Subnet23D3396F", + }, + ], + }, + }); + + expect(stack).toHaveResource("AWS::EC2::VPCEndpoint", { + VpcEndpointType: "Interface", + }); +}); + +// -------------------------------------------------------------- +// Test bad call with existingVpc and deployVpc +// -------------------------------------------------------------- +test("Test bad call with existingVpc and deployVpc", () => { + // Stack + const stack = new Stack(); + + const testVpc = new ec2.Vpc(stack, "test-vpc", {}); + + const app = () => { + // Helper declaration + new LambdaToSqs(stack, "lambda-to-sqs-stack", { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: "index.handler", + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + existingVpc: testVpc, + deployVpc: true, + }); + }; + // Assertion + expect(app).toThrowError(); +}); 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 7e5f8e1c4..07160624f 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 @@ -74,8 +74,8 @@ export class LambdaToStepFunction extends Construct { // Setup the Lambda function this.lambdaFunction = defaults.buildLambdaFunction(this, { - existingLambdaObj: props.existingLambdaObj, - lambdaFunctionProps: props.lambdaFunctionProps, + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps, }); // Assign the state machine ARN as an environment variable diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.ts index e8f5d587b..aa2e62502 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.deploy-lambda.ts @@ -26,14 +26,14 @@ const startState = new stepfunctions.Pass(stack, 'StartState'); // Setup the pattern props const props: LambdaToStepFunctionProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - stateMachineProps: { - definition: startState - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + stateMachineProps: { + definition: startState + } }; // Add the pattern diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.ts index 44c6d8e7f..c5aed032c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/integ.existing-function.ts @@ -37,10 +37,10 @@ const fn = defaults.deployLambdaFunction(stack, lambdaFunctionProps); // Setup the pattern props const props: LambdaToStepFunctionProps = { - existingLambdaObj: fn, - stateMachineProps: { - definition: startState - } + existingLambdaObj: fn, + stateMachineProps: { + definition: startState + } }; // Add the pattern diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda-step-function.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda-step-function.test.ts index 39876b316..4dc082271 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda-step-function.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-step-function/test/lambda-step-function.test.ts @@ -24,33 +24,33 @@ import '@aws-cdk/assert/jest'; // Test deployment with new Lambda function // -------------------------------------------------------------- test('Test deployment with new Lambda function', () => { - // Stack - const stack = new Stack(); - // Helper declaration - const startState = new stepfunctions.Pass(stack, 'StartState'); - new LambdaToStepFunction(stack, 'lambda-to-step-function-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - environment: { - LAMBDA_NAME: 'deploy-function' - } - }, - stateMachineProps: { - definition: startState + // Stack + const stack = new Stack(); + // Helper declaration + const startState = new stepfunctions.Pass(stack, 'StartState'); + new LambdaToStepFunction(stack, 'lambda-to-step-function-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + environment: { + LAMBDA_NAME: 'deploy-function' } - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResourceLike("AWS::Lambda::Function", { - Environment: { - Variables: { - LAMBDA_NAME: 'deploy-function' - } + }, + stateMachineProps: { + definition: startState + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResourceLike("AWS::Lambda::Function", { + Environment: { + Variables: { + LAMBDA_NAME: 'deploy-function' } - }); + } + }); }); // -------------------------------------------------------------- @@ -142,33 +142,33 @@ test('Test invocation permissions', () => { // Test the properties // -------------------------------------------------------------- test('Test the properties', () => { - // Stack - const stack = new Stack(); - // Helper declaration - const startState = new stepfunctions.Pass(stack, 'StartState'); - const pattern = new LambdaToStepFunction(stack, 'lambda-to-step-function-stack', { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - environment: { - LAMBDA_NAME: 'existing-function' - } - }, - stateMachineProps: { - definition: startState + // Stack + const stack = new Stack(); + // Helper declaration + const startState = new stepfunctions.Pass(stack, 'StartState'); + const pattern = new LambdaToStepFunction(stack, 'lambda-to-step-function-stack', { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + environment: { + LAMBDA_NAME: 'existing-function' } - }); + }, + stateMachineProps: { + definition: startState + } + }); // Assertion 1 - const func = pattern.lambdaFunction; - expect(func !== null); - // Assertion 2 - const stateMachine = pattern.stateMachine; - expect(stateMachine !== null); - // Assertion 3 - const cwAlarm = pattern.cloudwatchAlarms; - expect(cwAlarm !== null); - expect(pattern.stateMachineLogGroup !== null); + const func = pattern.lambdaFunction; + expect(func !== null); + // Assertion 2 + const stateMachine = pattern.stateMachine; + expect(stateMachine !== null); + // Assertion 3 + const cwAlarm = pattern.cloudwatchAlarms; + expect(cwAlarm !== null); + expect(pattern.stateMachineLogGroup !== null); }); // -------------------------------------------------------------- diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/lib/index.ts index 5aab24952..ffbfd8efc 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/lib/index.ts @@ -104,10 +104,10 @@ export class S3ToLambda extends Construct { fnResource.cfnOptions.metadata = { cfn_nag: { - rules_to_suppress: [{ - id: 'W58', - reason: `Lambda function has permission to write CloudWatch Logs via AWSLambdaBasicExecutionRole policy attached to the lambda role` - }] + rules_to_suppress: [{ + id: 'W58', + reason: `Lambda function has permission to write CloudWatch Logs via AWSLambdaBasicExecutionRole policy attached to the lambda role` + }] } }; @@ -116,10 +116,10 @@ export class S3ToLambda extends Construct { policyResource.cfnOptions.metadata = { cfn_nag: { - rules_to_suppress: [{ - id: 'W12', - reason: `Bucket resource is '*' due to circular dependency with bucket and role creation at the same time` - }] + rules_to_suppress: [{ + id: 'W12', + reason: `Bucket resource is '*' due to circular dependency with bucket and role creation at the same time` + }] } }; } diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.existing-s3-bucket.ts b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.existing-s3-bucket.ts index dc0ffe66c..1bd993918 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.existing-s3-bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.existing-s3-bucket.ts @@ -25,9 +25,9 @@ const [myBucket] = defaults.buildS3Bucket(stack, {}); const props: S3ToLambdaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }, existingBucketObj: myBucket }; diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.no-arguments.ts index 11478d160..658e537ef 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/integ.no-arguments.ts @@ -21,11 +21,11 @@ const app = new App(); const stack = new Stack(app, 'test-s3-lambda-new-bucket-stack'); const props: S3ToLambdaProps = { - lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }, + lambdaFunctionProps: { + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }, }; new S3ToLambda(stack, 'test-s3-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/s3-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/s3-lambda.test.ts index f26f2c072..6fd9d357c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/s3-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-lambda/test/s3-lambda.test.ts @@ -20,9 +20,9 @@ import '@aws-cdk/assert/jest'; function deployNewFunc(stack: cdk.Stack) { const props: S3ToLambdaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }, }; @@ -50,9 +50,9 @@ test('snapshot test S3ToLambda with versioning turned off', () => { const props: S3ToLambdaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }, bucketProps: { versioned: false 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 9e7fa32f7..5985ae1e0 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 @@ -24,6 +24,8 @@ This AWS Solutions Construct implements an Amazon S3 bucket connected to an AWS Step Function. +*Note - This construct uses Amazon EventBridge (Amazon CloudWatch Events) to trigger AWS Step Functions. EventBridge is more flexible, but triggering Step Functions with S3 Event Notifications has less latency and is more cost effective. If cost and/or latency is an issue, you should consider deploy aws-s3-lambda and aws-lambda-stepfunctions in place of this construct.* + Here is a minimal deployable pattern definition in Typescript: ``` typescript diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.ts b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.ts index 0e58e4b0e..03565d91b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.ts @@ -24,10 +24,10 @@ const mybucket: s3.IBucket = s3.Bucket.fromBucketName(stack, 'mybucket', 'cdktoo const startState = new stepfunctions.Pass(stack, 'StartState'); const props: S3ToStepFunctionProps = { - existingBucketObj: mybucket, - stateMachineProps: { - definition: startState - } + existingBucketObj: mybucket, + stateMachineProps: { + definition: startState + } }; new S3ToStepFunction(stack, 'test-s3-step-function-pre-existing-bucket-stack', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.ts b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.ts index 6f65ce7c3..3de00a848 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.ts @@ -22,9 +22,9 @@ const stack = new Stack(app, 'test-s3-step-function-stack'); const startState = new stepfunctions.Pass(stack, 'StartState'); const props: S3ToStepFunctionProps = { - stateMachineProps: { - definition: startState - } + stateMachineProps: { + definition: startState + } }; new S3ToStepFunction(stack, 'test-s3-step-function-stack', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/s3-step-function.test.ts b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/s3-step-function.test.ts index 1993a1381..7be61d79c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/s3-step-function.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/s3-step-function.test.ts @@ -67,21 +67,21 @@ test('override eventRuleProps', () => { existingBucketObj: mybucket, eventRuleProps: { eventPattern: { - source: ['aws.s3'], - detailType: ['AWS API Call via CloudTrail'], - detail: { - eventSource: [ - "s3.amazonaws.com" - ], - eventName: [ - "GetObject" - ], - requestParameters: { - bucketName: [ - mybucket.bucketName - ] - } + source: ['aws.s3'], + detailType: ['AWS API Call via CloudTrail'], + detail: { + eventSource: [ + "s3.amazonaws.com" + ], + eventName: [ + "GetObject" + ], + requestParameters: { + bucketName: [ + mybucket.bucketName + ] } + } } } }; diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/lib/index.ts index cd1abcdd9..a7c5c246f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/lib/index.ts @@ -67,8 +67,8 @@ export class SnsToLambda extends Construct { // Setup the Lambda function this.lambdaFunction = defaults.buildLambdaFunction(this, { - existingLambdaObj: props.existingLambdaObj, - lambdaFunctionProps: props.lambdaFunctionProps + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps }); // Setup the SNS topic diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/test/integ.no-arguments.ts index db7c3b9b0..a01e18eea 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/test/integ.no-arguments.ts @@ -23,11 +23,11 @@ stack.templateOptions.description = 'Integration Test for aws-sns-lambda'; // Definitions const props: SnsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } }; new SnsToLambda(stack, 'test-sns-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/test/sns-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/test/sns-lambda.test.ts index e8422cf50..b3ba627f4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-lambda/test/sns-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sns-lambda/test/sns-lambda.test.ts @@ -21,9 +21,9 @@ import '@aws-cdk/assert/jest'; function deployNewFunc(stack: cdk.Stack) { const props: SnsToLambdaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }, }; @@ -50,9 +50,9 @@ test('override topicProps', () => { const props: SnsToLambdaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }, topicProps: { topicName: "custom-topic" @@ -75,9 +75,9 @@ test('provide existingTopicObj', () => { const props: SnsToLambdaProps = { lambdaFunctionProps: { - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' }, existingTopicObj: topic }; diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/lib/index.ts index 8b84a71a2..cc5e697c8 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/lib/index.ts @@ -106,58 +106,58 @@ export class SnsToSqs extends Construct { * @access public */ constructor(scope: Construct, id: string, props: SnsToSqsProps) { - super(scope, id); + super(scope, id); - // Setup the dead letter queue, if applicable - this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { - existingQueueObj: props.existingQueueObj, - deployDeadLetterQueue: props.deployDeadLetterQueue, - deadLetterQueueProps: props.deadLetterQueueProps, - maxReceiveCount: props.maxReceiveCount - }); + // Setup the dead letter queue, if applicable + this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { + existingQueueObj: props.existingQueueObj, + deployDeadLetterQueue: props.deployDeadLetterQueue, + deadLetterQueueProps: props.deadLetterQueueProps, + maxReceiveCount: props.maxReceiveCount + }); - let enableEncryptionParam = props.enableEncryptionWithCustomerManagedKey; - let encryptionKeyParam = props.encryptionKey; + let enableEncryptionParam = props.enableEncryptionWithCustomerManagedKey; + let encryptionKeyParam = props.encryptionKey; - if (props.enableEncryptionWithCustomerManagedKey === undefined || + if (props.enableEncryptionWithCustomerManagedKey === undefined || props.enableEncryptionWithCustomerManagedKey === true) { - enableEncryptionParam = true; - // Create the encryptionKey if none was provided - if (!props.encryptionKey) { - encryptionKeyParam = buildEncryptionKey(scope, props.encryptionKeyProps); - } - } - // Setup the SNS topic - if (!props.existingTopicObj) { - // If an existingTopicObj was not specified create new topic - [this.snsTopic, this.encryptionKey] = defaults.buildTopic(this, { - topicProps: props.topicProps, - enableEncryptionWithCustomerManagedKey: enableEncryptionParam, - encryptionKey: encryptionKeyParam - }); - } else { - // If an existingTopicObj was specified utilize the provided topic - this.snsTopic = props.existingTopicObj; + enableEncryptionParam = true; + // Create the encryptionKey if none was provided + if (!props.encryptionKey) { + encryptionKeyParam = buildEncryptionKey(scope, props.encryptionKeyProps); } - - // Setup the queue - [this.sqsQueue] = defaults.buildQueue(this, 'queue', { - existingQueueObj: props.existingQueueObj, - queueProps: props.queueProps, - deadLetterQueue: this.deadLetterQueue, - enableEncryptionWithCustomerManagedKey: enableEncryptionParam, - encryptionKey: encryptionKeyParam + } + // Setup the SNS topic + if (!props.existingTopicObj) { + // If an existingTopicObj was not specified create new topic + [this.snsTopic, this.encryptionKey] = defaults.buildTopic(this, { + topicProps: props.topicProps, + enableEncryptionWithCustomerManagedKey: enableEncryptionParam, + encryptionKey: encryptionKeyParam }); + } else { + // If an existingTopicObj was specified utilize the provided topic + this.snsTopic = props.existingTopicObj; + } - // Setup the SQS queue subscription to the SNS topic - this.snsTopic.addSubscription(new subscriptions.SqsSubscription(this.sqsQueue)); + // Setup the queue + [this.sqsQueue] = defaults.buildQueue(this, 'queue', { + existingQueueObj: props.existingQueueObj, + queueProps: props.queueProps, + deadLetterQueue: this.deadLetterQueue, + enableEncryptionWithCustomerManagedKey: enableEncryptionParam, + encryptionKey: encryptionKeyParam + }); - // Grant SNS service access to the SQS queue encryption key - if (this.sqsQueue.encryptionMasterKey) { - this.sqsQueue.encryptionMasterKey.grant(new iam.ServicePrincipal("sns.amazonaws.com"), - 'kms:Decrypt', - 'kms:GenerateDataKey*', - ); - } + // Setup the SQS queue subscription to the SNS topic + this.snsTopic.addSubscription(new subscriptions.SqsSubscription(this.sqsQueue)); + + // Grant SNS service access to the SQS queue encryption key + if (this.sqsQueue.encryptionMasterKey) { + this.sqsQueue.encryptionMasterKey.grant(new iam.ServicePrincipal("sns.amazonaws.com"), + 'kms:Decrypt', + 'kms:GenerateDataKey*', + ); + } } } diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/test/integ.no-arguments.ts b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/test/integ.no-arguments.ts index 0d67b8f67..a6b29530f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/test/integ.no-arguments.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/test/integ.no-arguments.ts @@ -28,10 +28,10 @@ const snsToSqsStack = new SnsToSqs(stack, 'test-sns-sqs-stack', props); // Grant yourself permissions to use the Customer Managed KMS Key const policyStatement = new iam.PolicyStatement({ - actions: ["kms:Encrypt", "kms:Decrypt"], - effect: iam.Effect.ALLOW, - principals: [ new iam.AccountRootPrincipal() ], - resources: [ "*" ] + actions: ["kms:Encrypt", "kms:Decrypt"], + effect: iam.Effect.ALLOW, + principals: [ new iam.AccountRootPrincipal() ], + resources: [ "*" ] }); snsToSqsStack.encryptionKey?.addToResourcePolicy(policyStatement); diff --git a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/test/sns-sqs.test.ts b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/test/sns-sqs.test.ts index 7f7ec7d7a..6343223c1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sns-sqs/test/sns-sqs.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sns-sqs/test/sns-sqs.test.ts @@ -25,43 +25,43 @@ import '@aws-cdk/assert/jest'; // default properties // -------------------------------------------------------------- test('Pattern deployment w/ new Topic, new Queue and default props', () => { - // Initial Setup - const stack = new Stack(); - const props: SnsToSqsProps = {}; - new SnsToSqs(stack, 'test-sns-sqs', props); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResource("AWS::SNS::Topic", { - KmsMasterKeyId: { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - } - }); - // Assertion 3 - expect(stack).toHaveResource("AWS::SQS::Queue", { - KmsMasterKeyId: { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - } - }); - // Assertion 4 - expect(stack).toHaveResource("AWS::SNS::Subscription", { - Protocol: "sqs", - TopicArn: { - Ref: "testsnssqsSnsTopic2CD0065B" - }, - Endpoint: { - "Fn::GetAtt": [ - "testsnssqsqueueB02504BF", - "Arn" - ] - } - }); + // Initial Setup + const stack = new Stack(); + const props: SnsToSqsProps = {}; + new SnsToSqs(stack, 'test-sns-sqs', props); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResource("AWS::SNS::Topic", { + KmsMasterKeyId: { + "Fn::GetAtt": [ + "EncryptionKey1B843E66", + "Arn" + ] + } + }); + // Assertion 3 + expect(stack).toHaveResource("AWS::SQS::Queue", { + KmsMasterKeyId: { + "Fn::GetAtt": [ + "EncryptionKey1B843E66", + "Arn" + ] + } + }); + // Assertion 4 + expect(stack).toHaveResource("AWS::SNS::Subscription", { + Protocol: "sqs", + TopicArn: { + Ref: "testsnssqsSnsTopic2CD0065B" + }, + Endpoint: { + "Fn::GetAtt": [ + "testsnssqsqueueB02504BF", + "Arn" + ] + } + }); }); // -------------------------------------------------------------- @@ -69,178 +69,178 @@ test('Pattern deployment w/ new Topic, new Queue and default props', () => { // overridden properties // -------------------------------------------------------------- test('Pattern deployment w/ new topic, new queue, and overridden props', () => { - // Initial Setup - const stack = new Stack(); - const props: SnsToSqsProps = { - topicProps: { - topicName: "new-topic", - }, - queueProps: { - queueName: "new-queue.fifo", - fifo: true - }, - enableEncryptionWithCustomerManagedKey: true, - encryptionKeyProps: { - enableKeyRotation: false - }, - deployDeadLetterQueue: false, - maxReceiveCount: 0 - }; - new SnsToSqs(stack, 'test-sns-sqs', props); - // Assertion 1 - expect(stack).toHaveResource("AWS::SNS::Topic", { - TopicName: "new-topic", - KmsMasterKeyId: { - "Fn::GetAtt": [ - "EncryptionKey1B843E66", - "Arn" - ] - } - }); - // Assertion 2 - expect(stack).toHaveResource("AWS::SQS::Queue", { - QueueName: "new-queue.fifo", - FifoQueue: true - }); - // Assertion 3 - expect(stack).toHaveResource("AWS::KMS::Key", { - EnableKeyRotation: false - }); + // Initial Setup + const stack = new Stack(); + const props: SnsToSqsProps = { + topicProps: { + topicName: "new-topic", + }, + queueProps: { + queueName: "new-queue.fifo", + fifo: true + }, + enableEncryptionWithCustomerManagedKey: true, + encryptionKeyProps: { + enableKeyRotation: false + }, + deployDeadLetterQueue: false, + maxReceiveCount: 0 + }; + new SnsToSqs(stack, 'test-sns-sqs', props); + // Assertion 1 + expect(stack).toHaveResource("AWS::SNS::Topic", { + TopicName: "new-topic", + KmsMasterKeyId: { + "Fn::GetAtt": [ + "EncryptionKey1B843E66", + "Arn" + ] + } + }); + // Assertion 2 + expect(stack).toHaveResource("AWS::SQS::Queue", { + QueueName: "new-queue.fifo", + FifoQueue: true + }); + // Assertion 3 + expect(stack).toHaveResource("AWS::KMS::Key", { + EnableKeyRotation: false + }); }); // -------------------------------------------------------------- // Test the getter methods // -------------------------------------------------------------- test('Test getter methods', () => { - // Initial Setup - const stack = new Stack(); - const props: SnsToSqsProps = { - enableEncryptionWithCustomerManagedKey: true, - deployDeadLetterQueue: true, - maxReceiveCount: 0 - }; - const app = new SnsToSqs(stack, 'test-sns-sqs', props); - // Assertion 1 - expect(app.snsTopic !== null); - // Assertion 2 - expect(app.encryptionKey !== null); - // Assertion 3 - expect(app.sqsQueue !== null); - // Assertion 4 - expect(app.deadLetterQueue !== null); + // Initial Setup + const stack = new Stack(); + const props: SnsToSqsProps = { + enableEncryptionWithCustomerManagedKey: true, + deployDeadLetterQueue: true, + maxReceiveCount: 0 + }; + const app = new SnsToSqs(stack, 'test-sns-sqs', props); + // Assertion 1 + expect(app.snsTopic !== null); + // Assertion 2 + expect(app.encryptionKey !== null); + // Assertion 3 + expect(app.sqsQueue !== null); + // Assertion 4 + expect(app.deadLetterQueue !== null); }); // -------------------------------------------------------------- // Test deployment with existing queue, and topic // -------------------------------------------------------------- test('Test deployment w/ existing queue, and topic', () => { - // Stack - const stack = new Stack(); - // Helper declaration - const topic = new sns.Topic(stack, "existing-topic-obj", { - topicName: 'existing-topic-obj' - }); - const queue = new sqs.Queue(stack, 'existing-queue-obj', { - queueName: 'existing-queue-obj' - }); - const app = new SnsToSqs(stack, 'sns-to-sqs-stack', { - existingTopicObj: topic, - existingQueueObj: queue - }); + // Stack + const stack = new Stack(); + // Helper declaration + const topic = new sns.Topic(stack, "existing-topic-obj", { + topicName: 'existing-topic-obj' + }); + const queue = new sqs.Queue(stack, 'existing-queue-obj', { + queueName: 'existing-queue-obj' + }); + const app = new SnsToSqs(stack, 'sns-to-sqs-stack', { + existingTopicObj: topic, + existingQueueObj: queue + }); // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(app.snsTopic !== null); - // Assertion 3 - expect(stack).toHaveResource("AWS::SNS::Topic", { - TopicName: "existing-topic-obj" - }); - // Assertion 4 - expect(stack).toHaveResource("AWS::SQS::Queue", { - QueueName: "existing-queue-obj" - }); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(app.snsTopic !== null); + // Assertion 3 + expect(stack).toHaveResource("AWS::SNS::Topic", { + TopicName: "existing-topic-obj" + }); + // Assertion 4 + expect(stack).toHaveResource("AWS::SQS::Queue", { + QueueName: "existing-queue-obj" + }); }); // -------------------------------------------------------------- // Test deployment with imported encryption key // -------------------------------------------------------------- test('Test deployment with imported encryption key', () => { - // Stack - const stack = new Stack(); - // Setup - const kmsKey = new kms.Key(stack, 'imported-key', { - enableKeyRotation: false - }); + // Stack + const stack = new Stack(); + // Setup + const kmsKey = new kms.Key(stack, 'imported-key', { + enableKeyRotation: false + }); // Helper declaration - new SnsToSqs(stack, 'sns-to-sqs-stack', { - enableEncryptionWithCustomerManagedKey: true, - encryptionKey: kmsKey - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResource("AWS::KMS::Key", { - EnableKeyRotation: false - }); - // Assertion 3 - expect(stack).toHaveResource("AWS::SNS::Topic", { - KmsMasterKeyId: { - "Fn::GetAtt": [ - "importedkey38675D68", - "Arn" - ] - } - }); + new SnsToSqs(stack, 'sns-to-sqs-stack', { + enableEncryptionWithCustomerManagedKey: true, + encryptionKey: kmsKey + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResource("AWS::KMS::Key", { + EnableKeyRotation: false + }); + // Assertion 3 + expect(stack).toHaveResource("AWS::SNS::Topic", { + KmsMasterKeyId: { + "Fn::GetAtt": [ + "importedkey38675D68", + "Arn" + ] + } + }); }); // -------------------------------------------------------------- // Test deployment with SNS managed KMS key // -------------------------------------------------------------- test('Test deployment with SNS managed KMS key', () => { - // Stack - const stack = new Stack(); - // Helper declaration - new SnsToSqs(stack, 'sns-to-sqs-stack', { - topicProps: { - masterKey: kms.Alias.fromAliasName(stack, 'sns-managed-key', 'alias/aws/sns') - }, - queueProps: { - encryption: sqs.QueueEncryption.KMS - }, - enableEncryptionWithCustomerManagedKey: false - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResource("AWS::SNS::Topic", { - KmsMasterKeyId: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition" - }, - ":kms:", - { - Ref: "AWS::Region" - }, - ":", - { - Ref: "AWS::AccountId" - }, - ":alias/aws/sns" - ] - ] - } - }); - // Assertion 3 - expect(stack).toHaveResource("AWS::SQS::Queue", { - KmsMasterKeyId: { - "Fn::GetAtt": [ - "snstosqsstackqueueKey743636E7", - "Arn" - ] - } - }); + // Stack + const stack = new Stack(); + // Helper declaration + new SnsToSqs(stack, 'sns-to-sqs-stack', { + topicProps: { + masterKey: kms.Alias.fromAliasName(stack, 'sns-managed-key', 'alias/aws/sns') + }, + queueProps: { + encryption: sqs.QueueEncryption.KMS + }, + enableEncryptionWithCustomerManagedKey: false + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResource("AWS::SNS::Topic", { + KmsMasterKeyId: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition" + }, + ":kms:", + { + Ref: "AWS::Region" + }, + ":", + { + Ref: "AWS::AccountId" + }, + ":alias/aws/sns" + ] + ] + } + }); + // Assertion 3 + expect(stack).toHaveResource("AWS::SQS::Queue", { + KmsMasterKeyId: { + "Fn::GetAtt": [ + "snstosqsstackqueueKey743636E7", + "Arn" + ] + } + }); }); diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts index ad5d31ad0..d84cae272 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/lib/index.ts @@ -89,30 +89,30 @@ export class SqsToLambda extends Construct { * @access public */ constructor(scope: Construct, id: string, props: SqsToLambdaProps) { - super(scope, id); + super(scope, id); - // Setup the Lambda function - this.lambdaFunction = defaults.buildLambdaFunction(this, { - existingLambdaObj: props.existingLambdaObj, - lambdaFunctionProps: props.lambdaFunctionProps - }); + // Setup the Lambda function + this.lambdaFunction = defaults.buildLambdaFunction(this, { + existingLambdaObj: props.existingLambdaObj, + lambdaFunctionProps: props.lambdaFunctionProps + }); - // Setup the dead letter queue, if applicable - this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { - existingQueueObj: props.existingQueueObj, - deployDeadLetterQueue: props.deployDeadLetterQueue, - deadLetterQueueProps: props.deadLetterQueueProps, - maxReceiveCount: props.maxReceiveCount - }); + // Setup the dead letter queue, if applicable + this.deadLetterQueue = defaults.buildDeadLetterQueue(this, { + existingQueueObj: props.existingQueueObj, + deployDeadLetterQueue: props.deployDeadLetterQueue, + deadLetterQueueProps: props.deadLetterQueueProps, + maxReceiveCount: props.maxReceiveCount + }); - // Setup the queue - [this.sqsQueue] = defaults.buildQueue(this, 'queue', { - existingQueueObj: props.existingQueueObj, - queueProps: props.queueProps, - deadLetterQueue: this.deadLetterQueue - }); + // Setup the queue + [this.sqsQueue] = defaults.buildQueue(this, 'queue', { + existingQueueObj: props.existingQueueObj, + queueProps: props.queueProps, + deadLetterQueue: this.deadLetterQueue + }); - // Setup the event source mapping - this.lambdaFunction.addEventSource(new SqsEventSource(this.sqsQueue, props.sqsEventSourceProps)); + // Setup the event source mapping + this.lambdaFunction.addEventSource(new SqsEventSource(this.sqsQueue, props.sqsEventSourceProps)); } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.ts index 50a20129f..28e078d3e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFifoQueue.ts @@ -23,19 +23,19 @@ stack.templateOptions.description = 'Integration Test for aws-sqs-lambda with FI // Definitions const props: SqsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - queueProps: { - queueName: `myQueue.fifo`, - fifo: true, - }, - deadLetterQueueProps: { - queueName: `myDLQueue.fifo`, - fifo: true, - }, + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + queueProps: { + queueName: `myQueue.fifo`, + fifo: true, + }, + deadLetterQueueProps: { + queueName: `myDLQueue.fifo`, + fifo: true, + }, }; new SqsToLambda(stack, 'test-sqs-lambda-fifo', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFunction.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFunction.ts index 0cc86a470..dd1d4ca5d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.deployFunction.ts @@ -23,14 +23,14 @@ stack.templateOptions.description = 'Integration Test for aws-sqs-lambda'; // Definitions const props: SqsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - queueProps: {}, - deployDeadLetterQueue: true, - maxReceiveCount: 3 + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + queueProps: {}, + deployDeadLetterQueue: true, + maxReceiveCount: 3 }; new SqsToLambda(stack, 'test-sqs-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.existingFunction.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.existingFunction.ts index ecf59dc6b..1bab9ddd3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.existingFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/integ.existingFunction.ts @@ -32,10 +32,10 @@ const lambdaFunctionProps = { const func = defaults.deployLambdaFunction(stack, lambdaFunctionProps); const props: SqsToLambdaProps = { - existingLambdaObj: func, - queueProps: {}, - deployDeadLetterQueue: true, - maxReceiveCount: 3 + existingLambdaObj: func, + queueProps: {}, + deployDeadLetterQueue: true, + maxReceiveCount: 3 }; new SqsToLambda(stack, 'test-sqs-lambda', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/test.sqs-lambda.test.ts b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/test.sqs-lambda.test.ts index edbfee310..dd6bf65eb 100644 --- a/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/test.sqs-lambda.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-sqs-lambda/test/test.sqs-lambda.test.ts @@ -24,18 +24,18 @@ import '@aws-cdk/assert/jest'; // default properties // -------------------------------------------------------------- test('Pattern deployment w/ new Lambda function and default props', () => { - // Initial Setup - const stack = new Stack(); - const props: SqsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - } - }; - new SqsToLambda(stack, 'test-sqs-lambda', props); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Initial Setup + const stack = new Stack(); + const props: SqsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + } + }; + new SqsToLambda(stack, 'test-sqs-lambda', props); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- @@ -43,100 +43,100 @@ test('Pattern deployment w/ new Lambda function and default props', () => { // overridden properties // -------------------------------------------------------------- test('Pattern deployment w/ new Lambda function and overridden props', () => { - // Initial Setup - const stack = new Stack(); - const props: SqsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - environment: { - OVERRIDE: "TRUE" - } - }, - queueProps: { - fifo: true - }, - deployDeadLetterQueue: false, - maxReceiveCount: 0 - }; - const app = new SqsToLambda(stack, 'test-sqs-lambda', props); - // Assertion 1 - expect(app.sqsQueue).toHaveProperty('fifo', true); - // Assertion 2 - expect(stack).toHaveResource('AWS::Lambda::Function', { - Environment: { - Variables: { - OVERRIDE: "TRUE", - AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1" - } - } - }); + // Initial Setup + const stack = new Stack(); + const props: SqsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + environment: { + OVERRIDE: "TRUE" + } + }, + queueProps: { + fifo: true + }, + deployDeadLetterQueue: false, + maxReceiveCount: 0 + }; + const app = new SqsToLambda(stack, 'test-sqs-lambda', props); + // Assertion 1 + expect(app.sqsQueue).toHaveProperty('fifo', true); + // Assertion 2 + expect(stack).toHaveResource('AWS::Lambda::Function', { + Environment: { + Variables: { + OVERRIDE: "TRUE", + AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1" + } + } + }); }); // -------------------------------------------------------------- // Pattern Deployment w/ Existing Lambda function // -------------------------------------------------------------- test('Pattern deployment w/ Existing Lambda Function', () => { - // Initial Setup - const stack = new Stack(); - const fn = new lambda.Function(stack, 'ExistingLambdaFunction', { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }); - const props: SqsToLambdaProps = { - existingLambdaObj: fn, - deployDeadLetterQueue: false, - maxReceiveCount: 0, - queueProps: {} - }; - new SqsToLambda(stack, 'test-apigateway-lambda', props); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Initial Setup + const stack = new Stack(); + const fn = new lambda.Function(stack, 'ExistingLambdaFunction', { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }); + const props: SqsToLambdaProps = { + existingLambdaObj: fn, + deployDeadLetterQueue: false, + maxReceiveCount: 0, + queueProps: {} + }; + new SqsToLambda(stack, 'test-apigateway-lambda', props); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test the getter methods // -------------------------------------------------------------- test('Test getter methods', () => { - // Initial Setup - const stack = new Stack(); - const props: SqsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }, - deployDeadLetterQueue: true, - maxReceiveCount: 0, - queueProps: {} - }; - const app = new SqsToLambda(stack, 'test-apigateway-lambda', props); - // Assertion 1 - expect(app.lambdaFunction !== null); - // Assertion 2 - expect(app.sqsQueue !== null); - // Assertion 3 - expect(app.deadLetterQueue !== null); + // Initial Setup + const stack = new Stack(); + const props: SqsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }, + deployDeadLetterQueue: true, + maxReceiveCount: 0, + queueProps: {} + }; + const app = new SqsToLambda(stack, 'test-apigateway-lambda', props); + // Assertion 1 + expect(app.lambdaFunction !== null); + // Assertion 2 + expect(app.sqsQueue !== null); + // Assertion 3 + expect(app.deadLetterQueue !== null); }); // -------------------------------------------------------------- // Test error handling for existing Lambda function // -------------------------------------------------------------- test('Test error handling for existing Lambda function', () => { - // Initial Setup - const stack = new Stack(); - const props: SqsToLambdaProps = { - existingLambdaObj: undefined, - deployDeadLetterQueue: false, - maxReceiveCount: 0, - queueProps: {} - }; + // Initial Setup + const stack = new Stack(); + const props: SqsToLambdaProps = { + existingLambdaObj: undefined, + deployDeadLetterQueue: false, + maxReceiveCount: 0, + queueProps: {} + }; // Assertion 1 - expect(() => { - new SqsToLambda(stack, 'test-sqs-lambda', props); - }).toThrowError(); + expect(() => { + new SqsToLambda(stack, 'test-sqs-lambda', props); + }).toThrowError(); }); // -------------------------------------------------------------- @@ -144,17 +144,17 @@ test('Test error handling for existing Lambda function', () => { // w/o required properties // -------------------------------------------------------------- test('Test error handling for new Lambda function w/o required properties', () => { - // Initial Setup - const stack = new Stack(); - const props: SqsToLambdaProps = { - deployDeadLetterQueue: false, - maxReceiveCount: 0, - queueProps: {} - }; + // Initial Setup + const stack = new Stack(); + const props: SqsToLambdaProps = { + deployDeadLetterQueue: false, + maxReceiveCount: 0, + queueProps: {} + }; // Assertion 1 - expect(() => { - new SqsToLambda(stack, 'test-sqs-lambda', props); - }).toThrowError(); + expect(() => { + new SqsToLambda(stack, 'test-sqs-lambda', props); + }).toThrowError(); }); // -------------------------------------------------------------- @@ -183,20 +183,20 @@ test('Test deployment w/ existing queue', () => { // Pattern deployment w/ batch size // -------------------------------------------------------------- test('Pattern deployment w/ batch size', () => { - const stack = new Stack(); - const props: SqsToLambdaProps = { - lambdaFunctionProps: { - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - }, - sqsEventSourceProps: { - batchSize: 5 - } - }; - new SqsToLambda(stack, 'test-sqs-lambda', props); + const stack = new Stack(); + const props: SqsToLambdaProps = { + lambdaFunctionProps: { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + }, + sqsEventSourceProps: { + batchSize: 5 + } + }; + new SqsToLambda(stack, 'test-sqs-lambda', props); - expect(stack).toHaveResource('AWS::Lambda::EventSourceMapping', { - BatchSize: 5 - }); + expect(stack).toHaveResource('AWS::Lambda::EventSourceMapping', { + BatchSize: 5 + }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/apigateway-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/apigateway-defaults.ts index 5cbb1ab8d..a90a38809 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/apigateway-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/apigateway-defaults.ts @@ -22,24 +22,24 @@ import { LogGroup } from '@aws-cdk/aws-logs'; * @param _logGroup - CW Log group for Api Gateway access logging */ function DefaultRestApiProps(_endpointType: api.EndpointType[], _logGroup: LogGroup): api.RestApiProps { - return { - endpointConfiguration: { - types: _endpointType - }, - cloudWatchRole: false, - // Configure API Gateway Access logging - deployOptions: { - accessLogDestination: new api.LogGroupLogDestination(_logGroup), - accessLogFormat: api.AccessLogFormat.jsonWithStandardFields(), - loggingLevel: api.MethodLoggingLevel.INFO, - dataTraceEnabled: true, - tracingEnabled: true - }, - defaultMethodOptions: { - authorizationType: api.AuthorizationType.IAM - } + return { + endpointConfiguration: { + types: _endpointType + }, + cloudWatchRole: false, + // Configure API Gateway Access logging + deployOptions: { + accessLogDestination: new api.LogGroupLogDestination(_logGroup), + accessLogFormat: api.AccessLogFormat.jsonWithStandardFields(), + loggingLevel: api.MethodLoggingLevel.INFO, + dataTraceEnabled: true, + tracingEnabled: true + }, + defaultMethodOptions: { + authorizationType: api.AuthorizationType.IAM + } - } as api.RestApiProps; + } as api.RestApiProps; } /** @@ -49,13 +49,13 @@ function DefaultRestApiProps(_endpointType: api.EndpointType[], _logGroup: LogGr * @param _logGroup - CW Log group for Api Gateway access logging */ export function DefaultGlobalLambdaRestApiProps(_existingLambdaObj: lambda.Function, _logGroup: LogGroup): api.LambdaRestApiProps { - const baseProps: api.RestApiProps = DefaultRestApiProps([api.EndpointType.EDGE], _logGroup); + const baseProps: api.RestApiProps = DefaultRestApiProps([api.EndpointType.EDGE], _logGroup); - const extraProps: api.LambdaRestApiProps = { - handler: _existingLambdaObj, - }; + const extraProps: api.LambdaRestApiProps = { + handler: _existingLambdaObj, + }; - return Object.assign(baseProps, extraProps); + return Object.assign(baseProps, extraProps); } /** @@ -65,13 +65,13 @@ export function DefaultGlobalLambdaRestApiProps(_existingLambdaObj: lambda.Funct * @param _logGroup - CW Log group for Api Gateway access logging */ export function DefaultRegionalLambdaRestApiProps(_existingLambdaObj: lambda.Function, _logGroup: LogGroup): api.LambdaRestApiProps { - const baseProps: api.RestApiProps = DefaultRestApiProps([api.EndpointType.REGIONAL], _logGroup); + const baseProps: api.RestApiProps = DefaultRestApiProps([api.EndpointType.REGIONAL], _logGroup); - const extraProps: api.LambdaRestApiProps = { - handler: _existingLambdaObj, - }; + const extraProps: api.LambdaRestApiProps = { + handler: _existingLambdaObj, + }; - return Object.assign(baseProps, extraProps); + return Object.assign(baseProps, extraProps); } /** @@ -79,7 +79,7 @@ export function DefaultRegionalLambdaRestApiProps(_existingLambdaObj: lambda.Fun * @param _logGroup - CW Log group for Api Gateway access logging */ export function DefaultGlobalRestApiProps(_logGroup: LogGroup) { - return DefaultRestApiProps([api.EndpointType.EDGE], _logGroup); + return DefaultRestApiProps([api.EndpointType.EDGE], _logGroup); } /** @@ -87,5 +87,5 @@ export function DefaultGlobalRestApiProps(_logGroup: LogGroup) { * @param _logGroup - CW Log group for Api Gateway access logging */ export function DefaultRegionalRestApiProps(_logGroup: LogGroup) { - return DefaultRestApiProps([api.EndpointType.REGIONAL], _logGroup); + return DefaultRestApiProps([api.EndpointType.REGIONAL], _logGroup); } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/apigateway-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/apigateway-helper.ts index 231689e1e..7a239531d 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/apigateway-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/apigateway-helper.ts @@ -11,7 +11,7 @@ * and limitations under the License. */ - // Imports +// Imports import * as logs from '@aws-cdk/aws-logs'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; @@ -28,46 +28,46 @@ import { IRole } from '@aws-cdk/aws-iam'; * @param _api - an existing api.RestApi or api.LambdaRestApi. */ function configureCloudwatchRoleForApi(scope: cdk.Construct, _api: api.RestApi): iam.Role { - // Setup the IAM Role for API Gateway CloudWatch access - const restApiCloudwatchRole = new iam.Role(scope, 'LambdaRestApiCloudWatchRole', { - assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), - inlinePolicies: { - LambdaRestApiCloudWatchRolePolicy: new iam.PolicyDocument({ - statements: [new iam.PolicyStatement({ - actions: [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:DescribeLogGroups', - 'logs:DescribeLogStreams', - 'logs:PutLogEvents', - 'logs:GetLogEvents', - 'logs:FilterLogEvents' - ], - resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:*`] - })] - }) - } - }); + // Setup the IAM Role for API Gateway CloudWatch access + const restApiCloudwatchRole = new iam.Role(scope, 'LambdaRestApiCloudWatchRole', { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), + inlinePolicies: { + LambdaRestApiCloudWatchRolePolicy: new iam.PolicyDocument({ + statements: [new iam.PolicyStatement({ + actions: [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:DescribeLogGroups', + 'logs:DescribeLogStreams', + 'logs:PutLogEvents', + 'logs:GetLogEvents', + 'logs:FilterLogEvents' + ], + resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:*`] + })] + }) + } + }); // Create and configure AWS::ApiGateway::Account with CloudWatch Role for ApiGateway - const CfnApi = _api.node.findChild('Resource') as api.CfnRestApi; - const cfnAccount: api.CfnAccount = new api.CfnAccount(scope, 'LambdaRestApiAccount', { - cloudWatchRoleArn: restApiCloudwatchRole.roleArn - }); - cfnAccount.addDependsOn(CfnApi); - - // Suppress Cfn Nag warning for APIG - const deployment: api.CfnDeployment = _api.latestDeployment?.node.findChild('Resource') as api.CfnDeployment; - deployment.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W45', - reason: `ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource` - }] - } - }; + const CfnApi = _api.node.findChild('Resource') as api.CfnRestApi; + const cfnAccount: api.CfnAccount = new api.CfnAccount(scope, 'LambdaRestApiAccount', { + cloudWatchRoleArn: restApiCloudwatchRole.roleArn + }); + cfnAccount.addDependsOn(CfnApi); + + // Suppress Cfn Nag warning for APIG + const deployment: api.CfnDeployment = _api.latestDeployment?.node.findChild('Resource') as api.CfnDeployment; + deployment.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W45', + reason: `ApiGateway has AccessLogging enabled in AWS::ApiGateway::Stage resource, but cfn_nag checkes for it in AWS::ApiGateway::Deployment resource` + }] + } + }; - // Return the CW Role - return restApiCloudwatchRole; + // Return the CW Role + return restApiCloudwatchRole; } /** @@ -77,43 +77,43 @@ function configureCloudwatchRoleForApi(scope: cdk.Construct, _api: api.RestApi): * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ function configureLambdaRestApi(scope: cdk.Construct, defaultApiGatewayProps: api.LambdaRestApiProps, - apiGatewayProps?: api.LambdaRestApiProps): [api.RestApi, iam.Role] { - - // API Gateway doesn't allow both endpointTypes and endpointConfiguration, check whether endPointTypes exists - if (apiGatewayProps?.endpointTypes) { - throw Error('Solutions Constructs internally uses endpointConfiguration, use endpointConfiguration instead of endpointTypes'); - } - - // Define the API object - let _api: api.RestApi; - if (apiGatewayProps) { - // If property overrides have been provided, incorporate them and deploy - const _apiGatewayProps = overrideProps(defaultApiGatewayProps, apiGatewayProps); - _api = new api.LambdaRestApi(scope, 'LambdaRestApi', _apiGatewayProps); - } else { - // If no property overrides, deploy using the default configuration - _api = new api.LambdaRestApi(scope, 'LambdaRestApi', defaultApiGatewayProps); - } - // Configure API access logging - const cwRole = configureCloudwatchRoleForApi(scope, _api); - - let usagePlanProps: api.UsagePlanProps = { - apiStages: [{ - api: _api, - stage: _api.deploymentStage - }] - }; + apiGatewayProps?: api.LambdaRestApiProps): [api.RestApi, iam.Role] { + + // API Gateway doesn't allow both endpointTypes and endpointConfiguration, check whether endPointTypes exists + if (apiGatewayProps?.endpointTypes) { + throw Error('Solutions Constructs internally uses endpointConfiguration, use endpointConfiguration instead of endpointTypes'); + } + + // Define the API object + let _api: api.RestApi; + if (apiGatewayProps) { + // If property overrides have been provided, incorporate them and deploy + const _apiGatewayProps = overrideProps(defaultApiGatewayProps, apiGatewayProps); + _api = new api.LambdaRestApi(scope, 'LambdaRestApi', _apiGatewayProps); + } else { + // If no property overrides, deploy using the default configuration + _api = new api.LambdaRestApi(scope, 'LambdaRestApi', defaultApiGatewayProps); + } + // Configure API access logging + const cwRole = configureCloudwatchRoleForApi(scope, _api); + + let usagePlanProps: api.UsagePlanProps = { + apiStages: [{ + api: _api, + stage: _api.deploymentStage + }] + }; // If requireApiKey param is set to true, create a api key & associate to Usage Plan - if (apiGatewayProps?.defaultMethodOptions?.apiKeyRequired === true) { - const extraParams = { apiKey: _api.addApiKey('ApiKey')}; - usagePlanProps = Object.assign(usagePlanProps, extraParams); - } + if (apiGatewayProps?.defaultMethodOptions?.apiKeyRequired === true) { + const extraParams = { apiKey: _api.addApiKey('ApiKey')}; + usagePlanProps = Object.assign(usagePlanProps, extraParams); + } - // Configure Usage Plan - _api.addUsagePlan('UsagePlan', usagePlanProps); + // Configure Usage Plan + _api.addUsagePlan('UsagePlan', usagePlanProps); - // Return the API and CW Role - return [_api, cwRole]; + // Return the API and CW Role + return [_api, cwRole]; } /** @@ -123,44 +123,44 @@ function configureLambdaRestApi(scope: cdk.Construct, defaultApiGatewayProps: ap * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ function configureRestApi(scope: cdk.Construct, defaultApiGatewayProps: api.RestApiProps, - apiGatewayProps?: api.RestApiProps): [api.RestApi, iam.Role] { - - // API Gateway doesn't allow both endpointTypes and endpointConfiguration, check whether endPointTypes exists - if (apiGatewayProps?.endpointTypes) { - throw Error('Solutions Constructs internally uses endpointConfiguration, use endpointConfiguration instead of endpointTypes'); - } - - // Define the API - let _api: api.RestApi; - if (apiGatewayProps) { - // If property overrides have been provided, incorporate them and deploy - const _apiGatewayProps = overrideProps(defaultApiGatewayProps, apiGatewayProps); - _api = new api.RestApi(scope, 'RestApi', _apiGatewayProps); - } else { - // If no property overrides, deploy using the default configuration - _api = new api.RestApi(scope, 'RestApi', defaultApiGatewayProps); - } - // Configure API access logging - const cwRole = configureCloudwatchRoleForApi(scope, _api); - - let usagePlanProps: api.UsagePlanProps = { - apiStages: [{ - api: _api, - stage: _api.deploymentStage - }] - }; - - // If requireApiKey param is set to true, create a api key & associate to Usage Plan - if (apiGatewayProps?.defaultMethodOptions?.apiKeyRequired === true) { - const extraParams = { apiKey: _api.addApiKey('ApiKey')}; - usagePlanProps = Object.assign(usagePlanProps, extraParams); - } - - // Configure Usage Plan - _api.addUsagePlan('UsagePlan', usagePlanProps); - - // Return the API and CW Role - return [_api, cwRole]; + apiGatewayProps?: api.RestApiProps): [api.RestApi, iam.Role] { + + // API Gateway doesn't allow both endpointTypes and endpointConfiguration, check whether endPointTypes exists + if (apiGatewayProps?.endpointTypes) { + throw Error('Solutions Constructs internally uses endpointConfiguration, use endpointConfiguration instead of endpointTypes'); + } + + // Define the API + let _api: api.RestApi; + if (apiGatewayProps) { + // If property overrides have been provided, incorporate them and deploy + const _apiGatewayProps = overrideProps(defaultApiGatewayProps, apiGatewayProps); + _api = new api.RestApi(scope, 'RestApi', _apiGatewayProps); + } else { + // If no property overrides, deploy using the default configuration + _api = new api.RestApi(scope, 'RestApi', defaultApiGatewayProps); + } + // Configure API access logging + const cwRole = configureCloudwatchRoleForApi(scope, _api); + + let usagePlanProps: api.UsagePlanProps = { + apiStages: [{ + api: _api, + stage: _api.deploymentStage + }] + }; + + // If requireApiKey param is set to true, create a api key & associate to Usage Plan + if (apiGatewayProps?.defaultMethodOptions?.apiKeyRequired === true) { + const extraParams = { apiKey: _api.addApiKey('ApiKey')}; + usagePlanProps = Object.assign(usagePlanProps, extraParams); + } + + // Configure Usage Plan + _api.addUsagePlan('UsagePlan', usagePlanProps); + + // Return the API and CW Role + return [_api, cwRole]; } /** @@ -170,14 +170,14 @@ function configureRestApi(scope: cdk.Construct, defaultApiGatewayProps: api.Rest * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ export function GlobalLambdaRestApi(scope: cdk.Construct, _existingLambdaObj: lambda.Function, - apiGatewayProps?: api.LambdaRestApiProps): [api.RestApi, iam.Role, logs.LogGroup] { + apiGatewayProps?: api.LambdaRestApiProps): [api.RestApi, iam.Role, logs.LogGroup] { - // Configure log group for API Gateway AccessLogging - const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); + // Configure log group for API Gateway AccessLogging + const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); - const defaultProps = apiDefaults.DefaultGlobalLambdaRestApiProps(_existingLambdaObj, logGroup); - const [restApi, apiCWRole] = configureLambdaRestApi(scope, defaultProps, apiGatewayProps); - return [restApi, apiCWRole, logGroup ]; + const defaultProps = apiDefaults.DefaultGlobalLambdaRestApiProps(_existingLambdaObj, logGroup); + const [restApi, apiCWRole] = configureLambdaRestApi(scope, defaultProps, apiGatewayProps); + return [restApi, apiCWRole, logGroup ]; } /** @@ -187,13 +187,13 @@ export function GlobalLambdaRestApi(scope: cdk.Construct, _existingLambdaObj: la * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ export function RegionalLambdaRestApi(scope: cdk.Construct, _existingLambdaObj: lambda.Function, - apiGatewayProps?: api.LambdaRestApiProps): [api.RestApi, iam.Role, logs.LogGroup] { - // Configure log group for API Gateway AccessLogging - const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); + apiGatewayProps?: api.LambdaRestApiProps): [api.RestApi, iam.Role, logs.LogGroup] { + // Configure log group for API Gateway AccessLogging + const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); - const defaultProps = apiDefaults.DefaultRegionalLambdaRestApiProps(_existingLambdaObj, logGroup); - const [restApi, apiCWRole] = configureLambdaRestApi(scope, defaultProps, apiGatewayProps); - return [restApi, apiCWRole, logGroup ]; + const defaultProps = apiDefaults.DefaultRegionalLambdaRestApiProps(_existingLambdaObj, logGroup); + const [restApi, apiCWRole] = configureLambdaRestApi(scope, defaultProps, apiGatewayProps); + return [restApi, apiCWRole, logGroup ]; } /** @@ -202,12 +202,12 @@ export function RegionalLambdaRestApi(scope: cdk.Construct, _existingLambdaObj: * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ export function GlobalRestApi(scope: cdk.Construct, apiGatewayProps?: api.RestApiProps): [api.RestApi, iam.Role, logs.LogGroup] { - // Configure log group for API Gateway AccessLogging - const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); + // Configure log group for API Gateway AccessLogging + const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); - const defaultProps = apiDefaults.DefaultGlobalRestApiProps(logGroup); - const [restApi, apiCWRole] = configureRestApi(scope, defaultProps, apiGatewayProps); - return [restApi, apiCWRole, logGroup ]; + const defaultProps = apiDefaults.DefaultGlobalRestApiProps(logGroup); + const [restApi, apiCWRole] = configureRestApi(scope, defaultProps, apiGatewayProps); + return [restApi, apiCWRole, logGroup ]; } /** @@ -216,12 +216,12 @@ export function GlobalRestApi(scope: cdk.Construct, apiGatewayProps?: api.RestAp * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ export function RegionalRestApi(scope: cdk.Construct, apiGatewayProps?: api.RestApiProps): [api.RestApi, iam.Role, logs.LogGroup] { - // Configure log group for API Gateway AccessLogging - const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); + // Configure log group for API Gateway AccessLogging + const logGroup = new logs.LogGroup(scope, 'ApiAccessLogGroup', DefaultLogGroupProps()); - const defaultProps = apiDefaults.DefaultRegionalRestApiProps(logGroup); - const [restApi, apiCWRole] = configureRestApi(scope, defaultProps, apiGatewayProps); - return [restApi, apiCWRole, logGroup ]; + const defaultProps = apiDefaults.DefaultRegionalRestApiProps(logGroup); + const [restApi, apiCWRole] = configureRestApi(scope, defaultProps, apiGatewayProps); + return [restApi, apiCWRole, logGroup ]; } export interface AddProxyMethodToApiResourceInputParams { @@ -240,83 +240,83 @@ export interface AddProxyMethodToApiResourceInputParams { } export function addProxyMethodToApiResource(params: AddProxyMethodToApiResourceInputParams): api.Method { - let baseProps: api.AwsIntegrationProps = { - service: params.service, - integrationHttpMethod: "POST", - options: { - passthroughBehavior: api.PassthroughBehavior.NEVER, - credentialsRole: params.apiGatewayRole, - requestParameters: { - "integration.request.header.Content-Type": params.contentType ? params.contentType : "'application/json'" - }, - requestTemplates: { - "application/json": params.requestTemplate + let baseProps: api.AwsIntegrationProps = { + service: params.service, + integrationHttpMethod: "POST", + options: { + passthroughBehavior: api.PassthroughBehavior.NEVER, + credentialsRole: params.apiGatewayRole, + requestParameters: { + "integration.request.header.Content-Type": params.contentType ? params.contentType : "'application/json'" + }, + requestTemplates: { + "application/json": params.requestTemplate + }, + integrationResponses: [ + { + statusCode: "200" + }, + { + statusCode: "500", + responseTemplates: { + "text/html": "Error" }, - integrationResponses: [ - { - statusCode: "200" - }, - { - statusCode: "500", - responseTemplates: { - "text/html": "Error" - }, - selectionPattern: "500" - } - ] + selectionPattern: "500" } - }; - - let extraProps; - - if (params.action) { - extraProps = { - action: params.action - }; - } else if (params.path) { - extraProps = { - path: params.path - }; - } else { - throw Error('Either action or path is required'); + ] } + }; - // Setup the API Gateway AWS Integration - baseProps = Object.assign(baseProps, extraProps); - let apiGatewayIntegration; - if (params.awsIntegrationProps) { - const overridenProps = overrideProps(baseProps, params.awsIntegrationProps); - apiGatewayIntegration = new api.AwsIntegration(overridenProps); - } else { - apiGatewayIntegration = new api.AwsIntegration(baseProps); - } + let extraProps; - const defaultMethodOptions = { - methodResponses: [ - { - statusCode: "200", - responseParameters: { - "method.response.header.Content-Type": true - } - }, - { - statusCode: "500", - responseParameters: { - "method.response.header.Content-Type": true - }, - } - ], - requestValidator: params.requestValidator, - requestModels: params.requestModel + if (params.action) { + extraProps = { + action: params.action }; - - let apiMethod; - // Setup the API Gateway method - if (params.methodOptions) { - const overridenProps = overrideProps(defaultMethodOptions, params.methodOptions); - apiMethod = params.apiResource.addMethod(params.apiMethod, apiGatewayIntegration, overridenProps); - } else { - apiMethod = params.apiResource.addMethod(params.apiMethod, apiGatewayIntegration, defaultMethodOptions); - } - return apiMethod; + } else if (params.path) { + extraProps = { + path: params.path + }; + } else { + throw Error('Either action or path is required'); + } + + // Setup the API Gateway AWS Integration + baseProps = Object.assign(baseProps, extraProps); + let apiGatewayIntegration; + if (params.awsIntegrationProps) { + const overridenProps = overrideProps(baseProps, params.awsIntegrationProps); + apiGatewayIntegration = new api.AwsIntegration(overridenProps); + } else { + apiGatewayIntegration = new api.AwsIntegration(baseProps); + } + + const defaultMethodOptions = { + methodResponses: [ + { + statusCode: "200", + responseParameters: { + "method.response.header.Content-Type": true + } + }, + { + statusCode: "500", + responseParameters: { + "method.response.header.Content-Type": true + }, + } + ], + requestValidator: params.requestValidator, + requestModels: params.requestModel + }; + + let apiMethod; + // Setup the API Gateway method + if (params.methodOptions) { + const overridenProps = overrideProps(defaultMethodOptions, params.methodOptions); + apiMethod = params.apiResource.addMethod(params.apiMethod, apiGatewayIntegration, overridenProps); + } else { + apiMethod = params.apiResource.addMethod(params.apiMethod, apiGatewayIntegration, defaultMethodOptions); + } + return apiMethod; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts index 2c05c65cf..f12d4e92b 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts @@ -20,120 +20,120 @@ import * as mediastore from '@aws-cdk/aws-mediastore'; import * as cdk from '@aws-cdk/core'; export function DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint: api.RestApi, - loggingBucket: s3.Bucket, - setHttpSecurityHeaders: boolean, - edgeLambda?: lambda.Version): cloudfront.DistributionProps { + loggingBucket: s3.Bucket, + setHttpSecurityHeaders: boolean, + edgeLambda?: lambda.Version): cloudfront.DistributionProps { - const apiEndPointUrlWithoutProtocol = cdk.Fn.select(1, cdk.Fn.split("://", apiEndPoint.url)); - const apiEndPointDomainName = cdk.Fn.select(0, cdk.Fn.split("/", apiEndPointUrlWithoutProtocol)); + const apiEndPointUrlWithoutProtocol = cdk.Fn.select(1, cdk.Fn.split("://", apiEndPoint.url)); + const apiEndPointDomainName = cdk.Fn.select(0, cdk.Fn.split("/", apiEndPointUrlWithoutProtocol)); - if (setHttpSecurityHeaders) { - return { - defaultBehavior: { - origin: new origins.HttpOrigin(apiEndPointDomainName, { - originPath: `/${apiEndPoint.deploymentStage.stageName}` - }), - edgeLambdas: [ - { - eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, - functionVersion: edgeLambda - } - ], - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS - }, - enableLogging: true, - logBucket: loggingBucket, - } as cloudfront.DistributionProps; - } else { - return { - defaultBehavior: { - origin: new origins.HttpOrigin(apiEndPointDomainName, { - originPath: `/${apiEndPoint.deploymentStage.stageName}` - }), - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS - }, - enableLogging: true, - logBucket: loggingBucket, - } as cloudfront.DistributionProps; - } + if (setHttpSecurityHeaders) { + return { + defaultBehavior: { + origin: new origins.HttpOrigin(apiEndPointDomainName, { + originPath: `/${apiEndPoint.deploymentStage.stageName}` + }), + edgeLambdas: [ + { + eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, + functionVersion: edgeLambda + } + ], + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS + }, + enableLogging: true, + logBucket: loggingBucket, + } as cloudfront.DistributionProps; + } else { + return { + defaultBehavior: { + origin: new origins.HttpOrigin(apiEndPointDomainName, { + originPath: `/${apiEndPoint.deploymentStage.stageName}` + }), + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS + }, + enableLogging: true, + logBucket: loggingBucket, + } as cloudfront.DistributionProps; + } } export function DefaultCloudFrontWebDistributionForS3Props(sourceBucket: s3.Bucket, loggingBucket: s3.Bucket, - setHttpSecurityHeaders: boolean, - edgeLambda?: lambda.Version): - cloudfront.DistributionProps { + setHttpSecurityHeaders: boolean, + edgeLambda?: lambda.Version): cloudfront.DistributionProps { - if (setHttpSecurityHeaders) { - return { - defaultBehavior: { - origin: new origins.S3Origin(sourceBucket), - edgeLambdas: [ - { - eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, - functionVersion: edgeLambda - } - ], - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS - }, - enableLogging: true, - logBucket: loggingBucket, - defaultRootObject: 'index.html' - } as cloudfront.DistributionProps; - } else { - return { - defaultBehavior: { - origin: new origins.S3Origin(sourceBucket), - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS - }, - enableLogging: true, - logBucket: loggingBucket, - defaultRootObject: 'index.html' - } as cloudfront.DistributionProps; - } + if (setHttpSecurityHeaders) { + return { + defaultBehavior: { + origin: new origins.S3Origin(sourceBucket), + edgeLambdas: [ + { + eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, + functionVersion: edgeLambda + } + ], + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS + }, + enableLogging: true, + logBucket: loggingBucket, + defaultRootObject: 'index.html' + } as cloudfront.DistributionProps; + } else { + return { + defaultBehavior: { + origin: new origins.S3Origin(sourceBucket), + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS + }, + enableLogging: true, + logBucket: loggingBucket, + defaultRootObject: 'index.html' + } as cloudfront.DistributionProps; + } } export function DefaultCloudFrontDisributionForMediaStoreProps(mediastoreContainer: mediastore.CfnContainer, - loggingBucket: s3.Bucket, - originRequestPolicy: cloudfront.OriginRequestPolicy, - setHttpSecurityHeaders: boolean, - customHeaders?: Record, - edgeLambda?: lambda.Version): cloudfront.DistributionProps { - const mediaStoreContainerUrlWithoutProtocol = cdk.Fn.select(1, cdk.Fn.split('://', mediastoreContainer.attrEndpoint)); - const mediaStoreContainerDomainName = cdk.Fn.select(0, cdk.Fn.split('/', mediaStoreContainerUrlWithoutProtocol)); + loggingBucket: s3.Bucket, + originRequestPolicy: cloudfront.OriginRequestPolicy, + setHttpSecurityHeaders: boolean, + customHeaders?: Record, + edgeLambda?: lambda.Version): cloudfront.DistributionProps { - const httpOrigin: origins.HttpOrigin = customHeaders ? - new origins.HttpOrigin(mediaStoreContainerDomainName, { customHeaders }) : - new origins.HttpOrigin(mediaStoreContainerDomainName); + const mediaStoreContainerUrlWithoutProtocol = cdk.Fn.select(1, cdk.Fn.split('://', mediastoreContainer.attrEndpoint)); + const mediaStoreContainerDomainName = cdk.Fn.select(0, cdk.Fn.split('/', mediaStoreContainerUrlWithoutProtocol)); - if (setHttpSecurityHeaders) { - return { - defaultBehavior: { - origin: httpOrigin, - edgeLambdas: [ - { - eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, - functionVersion: edgeLambda - } - ], - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, - allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS, - cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS, - originRequestPolicy - }, - enableLogging: true, - logBucket: loggingBucket - } as cloudfront.DistributionProps; - } else { - return { - defaultBehavior: { - origin: httpOrigin, - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, - allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS, - cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS, - originRequestPolicy - }, - enableLogging: true, - logBucket: loggingBucket - } as cloudfront.DistributionProps; - } + const httpOrigin: origins.HttpOrigin = customHeaders ? + new origins.HttpOrigin(mediaStoreContainerDomainName, { customHeaders }) : + new origins.HttpOrigin(mediaStoreContainerDomainName); + + if (setHttpSecurityHeaders) { + return { + defaultBehavior: { + origin: httpOrigin, + edgeLambdas: [ + { + eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, + functionVersion: edgeLambda + } + ], + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS, + cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS, + originRequestPolicy + }, + enableLogging: true, + logBucket: loggingBucket + } as cloudfront.DistributionProps; + } else { + return { + defaultBehavior: { + origin: httpOrigin, + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS, + cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS, + originRequestPolicy + }, + enableLogging: true, + logBucket: loggingBucket + } as cloudfront.DistributionProps; + } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts index 5b373a7b2..661c7a35e 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts @@ -19,9 +19,9 @@ import * as api from '@aws-cdk/aws-apigateway'; import * as lambda from '@aws-cdk/aws-lambda'; import * as mediastore from '@aws-cdk/aws-mediastore'; import { - DefaultCloudFrontWebDistributionForS3Props, - DefaultCloudFrontWebDistributionForApiGatewayProps, - DefaultCloudFrontDisributionForMediaStoreProps + DefaultCloudFrontWebDistributionForS3Props, + DefaultCloudFrontWebDistributionForApiGatewayProps, + DefaultCloudFrontDisributionForMediaStoreProps } from './cloudfront-distribution-defaults'; import { overrideProps } from './utils'; import { deployLambdaFunction } from './lambda-helper'; @@ -29,23 +29,23 @@ import { createLoggingBucket } from './s3-bucket-helper'; // Override Cfn_Nag rule: Cloudfront TLS-1.2 rule (https://github.com/stelligent/cfn_nag/issues/384) function updateSecurityPolicy(cfDistribution: cloudfront.Distribution) { - const cfnCfDistribution = cfDistribution.node.defaultChild as cloudfront.CfnDistribution; - cfnCfDistribution.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W70', - reason: `Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion` - }] - } - }; - return cfDistribution; + const cfnCfDistribution = cfDistribution.node.defaultChild as cloudfront.CfnDistribution; + cfnCfDistribution.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W70', + reason: `Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion` + }] + } + }; + return cfDistribution; } // Lambda@Edge function to insert the HTTP Security Headers into the response coming from the origin servers // and before it is sent to the client function defaultLambdaEdgeFunction(scope: cdk.Construct): lambda.Function { - const edgeLambdaFunc = deployLambdaFunction(scope, { - code: new lambda.InlineCode("exports.handler = (event, context, callback) => { \ + const edgeLambdaFunc = deployLambdaFunction(scope, { + code: new lambda.InlineCode("exports.handler = (event, context, callback) => { \ const response = event.Records[0].cf.response; \ const headers = response.headers; \ headers['x-xss-protection'] = [ \ @@ -86,182 +86,182 @@ function defaultLambdaEdgeFunction(scope: cdk.Construct): lambda.Function { ]; \ callback(null, response); \ };"), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }, 'SetHttpSecurityHeaders'); + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler' + }, 'SetHttpSecurityHeaders'); - // Switching from cloudfront.CloudFrontWebDistribution -> cloudfront.Distribution breaks the Lamba@Edge as it does not automatically update - // the lambda role AssumePolicy for 'edgelambda.amazonaws.com' - if (edgeLambdaFunc.role && edgeLambdaFunc.role instanceof iam.Role && edgeLambdaFunc.role.assumeRolePolicy) { - edgeLambdaFunc.role.assumeRolePolicy.addStatements(new iam.PolicyStatement({ - actions: [ 'sts:AssumeRole' ], - principals: [ new iam.ServicePrincipal('edgelambda.amazonaws.com') ], - })); - } + // Switching from cloudfront.CloudFrontWebDistribution -> cloudfront.Distribution breaks the Lamba@Edge as it does not automatically update + // the lambda role AssumePolicy for 'edgelambda.amazonaws.com' + if (edgeLambdaFunc.role && edgeLambdaFunc.role instanceof iam.Role && edgeLambdaFunc.role.assumeRolePolicy) { + edgeLambdaFunc.role.assumeRolePolicy.addStatements(new iam.PolicyStatement({ + actions: [ 'sts:AssumeRole' ], + principals: [ new iam.ServicePrincipal('edgelambda.amazonaws.com') ], + })); + } - return edgeLambdaFunc; + return edgeLambdaFunc; } export function CloudFrontDistributionForApiGateway(scope: cdk.Construct, - apiEndPoint: api.RestApi, - cloudFrontDistributionProps?: cloudfront.DistributionProps | any, - httpSecurityHeaders?: boolean): [cloudfront.Distribution, + apiEndPoint: api.RestApi, + cloudFrontDistributionProps?: cloudfront.DistributionProps | any, + httpSecurityHeaders?: boolean): [cloudfront.Distribution, lambda.Version?, s3.Bucket?] { - const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; + const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; - let defaultprops: cloudfront.DistributionProps; - let edgeLambdaVersion; - let loggingBucket; + let defaultprops: cloudfront.DistributionProps; + let edgeLambdaVersion; + let loggingBucket; - if (_httpSecurityHeaders) { - edgeLambdaVersion = new lambda.Version(scope, "SetHttpSecurityHeadersVersion", { - lambda: defaultLambdaEdgeFunction(scope) - }); - } + if (_httpSecurityHeaders) { + edgeLambdaVersion = new lambda.Version(scope, "SetHttpSecurityHeadersVersion", { + lambda: defaultLambdaEdgeFunction(scope) + }); + } - if (cloudFrontDistributionProps && cloudFrontDistributionProps.loggingConfig) { - defaultprops = DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint, - cloudFrontDistributionProps.loggingConfig.bucket, _httpSecurityHeaders, - edgeLambdaVersion); - } else { - loggingBucket = createLoggingBucket(scope, 'CloudfrontLoggingBucket'); - defaultprops = DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint, - loggingBucket, _httpSecurityHeaders, - edgeLambdaVersion); - } + if (cloudFrontDistributionProps && cloudFrontDistributionProps.loggingConfig) { + defaultprops = DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint, + cloudFrontDistributionProps.loggingConfig.bucket, _httpSecurityHeaders, + edgeLambdaVersion); + } else { + loggingBucket = createLoggingBucket(scope, 'CloudfrontLoggingBucket'); + defaultprops = DefaultCloudFrontWebDistributionForApiGatewayProps(apiEndPoint, + loggingBucket, _httpSecurityHeaders, + edgeLambdaVersion); + } - const cfprops = cloudFrontDistributionProps ? overrideProps(defaultprops, cloudFrontDistributionProps) : defaultprops; - // Create the Cloudfront Distribution - const cfDistribution: cloudfront.Distribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); - updateSecurityPolicy(cfDistribution); + const cfprops = cloudFrontDistributionProps ? overrideProps(defaultprops, cloudFrontDistributionProps) : defaultprops; + // Create the Cloudfront Distribution + const cfDistribution: cloudfront.Distribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); + updateSecurityPolicy(cfDistribution); - return [cfDistribution, edgeLambdaVersion, loggingBucket]; + return [cfDistribution, edgeLambdaVersion, loggingBucket]; } export function CloudFrontDistributionForS3(scope: cdk.Construct, - sourceBucket: s3.Bucket, - cloudFrontDistributionProps?: cloudfront.DistributionProps | any, - httpSecurityHeaders?: boolean): [cloudfront.Distribution, + sourceBucket: s3.Bucket, + cloudFrontDistributionProps?: cloudfront.DistributionProps | any, + httpSecurityHeaders?: boolean): [cloudfront.Distribution, lambda.Version?, s3.Bucket?] { - let defaultprops: cloudfront.DistributionProps; - let edgeLambdaVersion; - let loggingBucket; - const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; + let defaultprops: cloudfront.DistributionProps; + let edgeLambdaVersion; + let loggingBucket; + const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; - if (_httpSecurityHeaders) { - edgeLambdaVersion = new lambda.Version(scope, "SetHttpSecurityHeadersVersion", { - lambda: defaultLambdaEdgeFunction(scope) - }); - } + if (_httpSecurityHeaders) { + edgeLambdaVersion = new lambda.Version(scope, "SetHttpSecurityHeadersVersion", { + lambda: defaultLambdaEdgeFunction(scope) + }); + } - if (cloudFrontDistributionProps && cloudFrontDistributionProps.loggingConfig) { - defaultprops = DefaultCloudFrontWebDistributionForS3Props(sourceBucket, - cloudFrontDistributionProps.loggingConfig.bucket, _httpSecurityHeaders, edgeLambdaVersion); - } else { - loggingBucket = createLoggingBucket(scope, 'CloudfrontLoggingBucket'); - defaultprops = DefaultCloudFrontWebDistributionForS3Props(sourceBucket, loggingBucket, - _httpSecurityHeaders, edgeLambdaVersion); - } + if (cloudFrontDistributionProps && cloudFrontDistributionProps.loggingConfig) { + defaultprops = DefaultCloudFrontWebDistributionForS3Props(sourceBucket, + cloudFrontDistributionProps.loggingConfig.bucket, _httpSecurityHeaders, edgeLambdaVersion); + } else { + loggingBucket = createLoggingBucket(scope, 'CloudfrontLoggingBucket'); + defaultprops = DefaultCloudFrontWebDistributionForS3Props(sourceBucket, loggingBucket, + _httpSecurityHeaders, edgeLambdaVersion); + } - const cfprops = cloudFrontDistributionProps ? overrideProps(defaultprops, cloudFrontDistributionProps) : defaultprops; - // Create the Cloudfront Distribution - const cfDistribution: cloudfront.Distribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); - updateSecurityPolicy(cfDistribution); + const cfprops = cloudFrontDistributionProps ? overrideProps(defaultprops, cloudFrontDistributionProps) : defaultprops; + // Create the Cloudfront Distribution + const cfDistribution: cloudfront.Distribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); + updateSecurityPolicy(cfDistribution); - // Extract the CfnBucketPolicy from the sourceBucket - const bucketPolicy = sourceBucket.policy as s3.BucketPolicy; - const sourceBucketPolicy = bucketPolicy.node.findChild('Resource') as s3.CfnBucketPolicy; - sourceBucketPolicy.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'F16', - reason: `Public website bucket policy requires a wildcard principal` - }] - } - }; - return [cfDistribution, edgeLambdaVersion, loggingBucket]; + // Extract the CfnBucketPolicy from the sourceBucket + const bucketPolicy = sourceBucket.policy as s3.BucketPolicy; + const sourceBucketPolicy = bucketPolicy.node.findChild('Resource') as s3.CfnBucketPolicy; + sourceBucketPolicy.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'F16', + reason: `Public website bucket policy requires a wildcard principal` + }] + } + }; + return [cfDistribution, edgeLambdaVersion, loggingBucket]; } export function CloudFrontDistributionForMediaStore(scope: cdk.Construct, - mediaStoreContainer: mediastore.CfnContainer, - cloudFrontDistributionProps?: cloudfront.DistributionProps | any, - httpSecurityHeaders?: boolean): - [cloudfront.Distribution, s3.Bucket, cloudfront.OriginRequestPolicy, lambda.Version?] { + mediaStoreContainer: mediastore.CfnContainer, + cloudFrontDistributionProps?: cloudfront.DistributionProps | any, + httpSecurityHeaders?: boolean): [cloudfront.Distribution, + s3.Bucket, cloudfront.OriginRequestPolicy, lambda.Version?] { - let defaultprops: cloudfront.DistributionProps; - let originRequestPolicy: cloudfront.OriginRequestPolicy; - let loggingBucket: s3.Bucket; - let edgeLambdaVersion: lambda.Version | undefined; - const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; + let defaultprops: cloudfront.DistributionProps; + let originRequestPolicy: cloudfront.OriginRequestPolicy; + let loggingBucket: s3.Bucket; + let edgeLambdaVersion: lambda.Version | undefined; + const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; - if (_httpSecurityHeaders) { - edgeLambdaVersion = new lambda.Version(scope, 'SetHttpSecurityHeadersVersion', { - lambda: defaultLambdaEdgeFunction(scope) - }); - } + if (_httpSecurityHeaders) { + edgeLambdaVersion = new lambda.Version(scope, 'SetHttpSecurityHeadersVersion', { + lambda: defaultLambdaEdgeFunction(scope) + }); + } - if (cloudFrontDistributionProps && cloudFrontDistributionProps.enableLogging && cloudFrontDistributionProps.logBucket) { - loggingBucket = cloudFrontDistributionProps.logBucket as s3.Bucket; - } else { - loggingBucket = createLoggingBucket(scope, 'CloudfrontLoggingBucket'); - } + if (cloudFrontDistributionProps && cloudFrontDistributionProps.enableLogging && cloudFrontDistributionProps.logBucket) { + loggingBucket = cloudFrontDistributionProps.logBucket as s3.Bucket; + } else { + loggingBucket = createLoggingBucket(scope, 'CloudfrontLoggingBucket'); + } - if (cloudFrontDistributionProps - && cloudFrontDistributionProps.defaultBehavior - && cloudFrontDistributionProps.defaultBehavior.originRequestPolicy) { - originRequestPolicy = cloudFrontDistributionProps.defaultBehavior.originRequestPolicy; - } else { - const originRequestPolicyProps: cloudfront.OriginRequestPolicyProps = { - headerBehavior: { - behavior: 'whitelist', - headers: [ - 'Access-Control-Allow-Origin', - 'Access-Control-Request-Method', - 'Access-Control-Request-Header', - 'Origin' - ] - }, - queryStringBehavior: { - behavior: 'all' - }, - cookieBehavior: { - behavior: 'none' - }, - comment: 'Policy for Constructs CloudFrontDistributionForMediaStore', - originRequestPolicyName: `${cdk.Aws.STACK_NAME}-${cdk.Aws.REGION}-CloudFrontDistributionForMediaStore` - }; + if (cloudFrontDistributionProps + && cloudFrontDistributionProps.defaultBehavior + && cloudFrontDistributionProps.defaultBehavior.originRequestPolicy) { + originRequestPolicy = cloudFrontDistributionProps.defaultBehavior.originRequestPolicy; + } else { + const originRequestPolicyProps: cloudfront.OriginRequestPolicyProps = { + headerBehavior: { + behavior: 'whitelist', + headers: [ + 'Access-Control-Allow-Origin', + 'Access-Control-Request-Method', + 'Access-Control-Request-Header', + 'Origin' + ] + }, + queryStringBehavior: { + behavior: 'all' + }, + cookieBehavior: { + behavior: 'none' + }, + comment: 'Policy for Constructs CloudFrontDistributionForMediaStore', + originRequestPolicyName: `${cdk.Aws.STACK_NAME}-${cdk.Aws.REGION}-CloudFrontDistributionForMediaStore` + }; - originRequestPolicy = new cloudfront.OriginRequestPolicy(scope, 'CloudfrontOriginRequestPolicy', originRequestPolicyProps); - } + originRequestPolicy = new cloudfront.OriginRequestPolicy(scope, 'CloudfrontOriginRequestPolicy', originRequestPolicyProps); + } - defaultprops = DefaultCloudFrontDisributionForMediaStoreProps( - mediaStoreContainer, - loggingBucket, - originRequestPolicy, - _httpSecurityHeaders, - cloudFrontDistributionProps?.customHeaders, - edgeLambdaVersion - ); + defaultprops = DefaultCloudFrontDisributionForMediaStoreProps( + mediaStoreContainer, + loggingBucket, + originRequestPolicy, + _httpSecurityHeaders, + cloudFrontDistributionProps?.customHeaders, + edgeLambdaVersion + ); - let cfprops: cloudfront.DistributionProps; + let cfprops: cloudfront.DistributionProps; - if (cloudFrontDistributionProps) { - cfprops = overrideProps(defaultprops, cloudFrontDistributionProps); - } else { - cfprops = defaultprops; - } + if (cloudFrontDistributionProps) { + cfprops = overrideProps(defaultprops, cloudFrontDistributionProps); + } else { + cfprops = defaultprops; + } - // Create the CloudFront Distribution - const cfDistribution: cloudfront.Distribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); - updateSecurityPolicy(cfDistribution); + // Create the CloudFront Distribution + const cfDistribution: cloudfront.Distribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); + updateSecurityPolicy(cfDistribution); - return [cfDistribution, loggingBucket, originRequestPolicy, edgeLambdaVersion]; + return [cfDistribution, loggingBucket, originRequestPolicy, edgeLambdaVersion]; } export function CloudFrontOriginAccessIdentity(scope: cdk.Construct, comment?: string) { - return new cloudfront.OriginAccessIdentity(scope, 'CloudFrontOriginAccessIdentity', { - comment: comment ? comment : `access-identity-${cdk.Aws.REGION}-${cdk.Aws.STACK_NAME}` - }); + return new cloudfront.OriginAccessIdentity(scope, 'CloudFrontOriginAccessIdentity', { + comment: comment ? comment : `access-identity-${cdk.Aws.REGION}-${cdk.Aws.STACK_NAME}` + }); } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/cloudwatch-log-group-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/cloudwatch-log-group-defaults.ts index 8ae1a2e15..54492c76c 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/cloudwatch-log-group-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/cloudwatch-log-group-defaults.ts @@ -14,14 +14,14 @@ import * as logs from '@aws-cdk/aws-logs'; export function DefaultLogGroupProps(_logGroupName: string = ''): logs.LogGroupProps { - if (_logGroupName !== '') { - return { - logGroupName: _logGroupName, - retention: logs.RetentionDays.INFINITE - } as logs.LogGroupProps; - } else { - return { - retention: logs.RetentionDays.INFINITE - } as logs.LogGroupProps; - } + if (_logGroupName !== '') { + return { + logGroupName: _logGroupName, + retention: logs.RetentionDays.INFINITE + } as logs.LogGroupProps; + } else { + return { + retention: logs.RetentionDays.INFINITE + } as logs.LogGroupProps; + } } diff --git a/source/patterns/@aws-solutions-constructs/core/lib/cognito-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/cognito-helper.ts index 1d56bcdbf..e0baf161f 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/cognito-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/cognito-helper.ts @@ -61,7 +61,7 @@ export function buildUserPool(scope: cdk.Construct, userPoolProps?: cognito.User } export function buildUserPoolClient(scope: cdk.Construct, userPool: cognito.UserPool, - cognitoUserPoolClientProps?: cognito.UserPoolClientProps): cognito.UserPoolClient { + cognitoUserPoolClientProps?: cognito.UserPoolClientProps): cognito.UserPoolClient { let userPoolClientProps: cognito.UserPoolClientProps; @@ -75,7 +75,7 @@ export function buildUserPoolClient(scope: cdk.Construct, userPool: cognito.User } export function buildIdentityPool(scope: cdk.Construct, userpool: cognito.UserPool, userpoolclient: cognito.UserPoolClient, - identityPoolProps?: cognito.CfnIdentityPoolProps): cognito.CfnIdentityPool { + identityPoolProps?: cognito.CfnIdentityPoolProps): cognito.CfnIdentityPool { let cognitoIdentityPoolProps: cognito.CfnIdentityPoolProps = DefaultIdentityPoolProps(userpoolclient.userPoolClientId, userpool.userPoolProviderName); @@ -91,44 +91,44 @@ export function buildIdentityPool(scope: cdk.Construct, userpool: cognito.UserPo export function setupCognitoForElasticSearch(scope: cdk.Construct, domainName: string, options: CognitoOptions): iam.Role { - // Create the domain for Cognito UserPool - const userpooldomain = new cognito.CfnUserPoolDomain(scope, 'UserPoolDomain', { - domain: domainName, - userPoolId: options.userpool.userPoolId - }); - userpooldomain.addDependsOn(options.userpool.node.findChild('Resource') as cognito.CfnUserPool); - - // Setup the IAM Role for Cognito Authorized Users - const cognitoPrincipal = new iam.FederatedPrincipal( - 'cognito-identity.amazonaws.com', - { - 'StringEquals': { 'cognito-identity.amazonaws.com:aud': options.identitypool.ref }, - 'ForAnyValue:StringLike': { 'cognito-identity.amazonaws.com:amr': 'authenticated' } - }, - 'sts:AssumeRoleWithWebIdentity'); - - const cognitoAuthorizedRole = new iam.Role(scope, 'CognitoAuthorizedRole', { - assumedBy: cognitoPrincipal, - inlinePolicies: { - CognitoAccessPolicy: new iam.PolicyDocument({ - statements: [new iam.PolicyStatement({ - actions: [ - 'es:ESHttp*' - ], - resources: [`arn:${cdk.Aws.PARTITION}:es:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:domain/${domainName}/*`] - }) - ] + // Create the domain for Cognito UserPool + const userpooldomain = new cognito.CfnUserPoolDomain(scope, 'UserPoolDomain', { + domain: domainName, + userPoolId: options.userpool.userPoolId + }); + userpooldomain.addDependsOn(options.userpool.node.findChild('Resource') as cognito.CfnUserPool); + + // Setup the IAM Role for Cognito Authorized Users + const cognitoPrincipal = new iam.FederatedPrincipal( + 'cognito-identity.amazonaws.com', + { + 'StringEquals': { 'cognito-identity.amazonaws.com:aud': options.identitypool.ref }, + 'ForAnyValue:StringLike': { 'cognito-identity.amazonaws.com:amr': 'authenticated' } + }, + 'sts:AssumeRoleWithWebIdentity'); + + const cognitoAuthorizedRole = new iam.Role(scope, 'CognitoAuthorizedRole', { + assumedBy: cognitoPrincipal, + inlinePolicies: { + CognitoAccessPolicy: new iam.PolicyDocument({ + statements: [new iam.PolicyStatement({ + actions: [ + 'es:ESHttp*' + ], + resources: [`arn:${cdk.Aws.PARTITION}:es:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:domain/${domainName}/*`] }) - } - }); - - // Attach the IAM Role for Cognito Authorized Users - new cognito.CfnIdentityPoolRoleAttachment(scope, 'IdentityPoolRoleMapping', { - identityPoolId: options.identitypool.ref, - roles: { - authenticated: cognitoAuthorizedRole.roleArn - } - }); - - return cognitoAuthorizedRole; + ] + }) + } + }); + + // Attach the IAM Role for Cognito Authorized Users + new cognito.CfnIdentityPoolRoleAttachment(scope, 'IdentityPoolRoleMapping', { + identityPoolId: options.identitypool.ref, + roles: { + authenticated: cognitoAuthorizedRole.roleArn + } + }); + + return cognitoAuthorizedRole; } diff --git a/source/patterns/@aws-solutions-constructs/core/lib/dynamodb-table-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/dynamodb-table-helper.ts index 28c44f0d7..cf3fef324 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/dynamodb-table-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/dynamodb-table-helper.ts @@ -33,31 +33,31 @@ export interface BuildDynamoDBTableProps { } export function buildDynamoDBTable(scope: cdk.Construct, props: BuildDynamoDBTableProps): dynamodb.Table { - // Conditional DynamoDB Table creation - if (!props.existingTableObj) { - // Set the default props for DynamoDB table - if (props.dynamoTableProps) { - const dynamoTableProps = overrideProps(DefaultTableProps, props.dynamoTableProps); - return new dynamodb.Table(scope, 'DynamoTable', dynamoTableProps); - } else { - return new dynamodb.Table(scope, 'DynamoTable', DefaultTableProps); - } + // Conditional DynamoDB Table creation + if (!props.existingTableObj) { + // Set the default props for DynamoDB table + if (props.dynamoTableProps) { + const dynamoTableProps = overrideProps(DefaultTableProps, props.dynamoTableProps); + return new dynamodb.Table(scope, 'DynamoTable', dynamoTableProps); } else { - return props.existingTableObj; + return new dynamodb.Table(scope, 'DynamoTable', DefaultTableProps); } + } else { + return props.existingTableObj; + } } export function buildDynamoDBTableWithStream(scope: cdk.Construct, props: BuildDynamoDBTableProps): dynamodb.Table { - // Conditional DynamoDB Table creation - if (!props.existingTableObj) { - // Set the default props for DynamoDB table - if (props.dynamoTableProps) { - const dynamoTableProps = overrideProps(DefaultTableWithStreamProps, props.dynamoTableProps); - return new dynamodb.Table(scope, 'DynamoTable', dynamoTableProps); - } else { - return new dynamodb.Table(scope, 'DynamoTable', DefaultTableWithStreamProps); - } + // Conditional DynamoDB Table creation + if (!props.existingTableObj) { + // Set the default props for DynamoDB table + if (props.dynamoTableProps) { + const dynamoTableProps = overrideProps(DefaultTableWithStreamProps, props.dynamoTableProps); + return new dynamodb.Table(scope, 'DynamoTable', dynamoTableProps); } else { - return props.existingTableObj; + return new dynamodb.Table(scope, 'DynamoTable', DefaultTableWithStreamProps); } + } else { + return props.existingTableObj; + } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/elasticsearch-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/elasticsearch-helper.ts index 122cbd058..65fe6e785 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/elasticsearch-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/elasticsearch-helper.ts @@ -19,7 +19,7 @@ import * as cdk from '@aws-cdk/core'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; export function buildElasticSearch(scope: cdk.Construct, domainName: string, - options: CfnDomainOptions, cfnDomainProps?: elasticsearch.CfnDomainProps): [elasticsearch.CfnDomain, iam.Role] { + options: CfnDomainOptions, cfnDomainProps?: elasticsearch.CfnDomainProps): [elasticsearch.CfnDomain, iam.Role] { // Setup the IAM Role & policy for ES to configure Cognito User pool and Identity pool const cognitoKibanaConfigureRole = new iam.Role(scope, 'CognitoKibanaConfigureRole', { diff --git a/source/patterns/@aws-solutions-constructs/core/lib/events-rule-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/events-rule-defaults.ts index 32e04451d..ecf84c1e2 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/events-rule-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/events-rule-defaults.ts @@ -14,9 +14,9 @@ import * as events from '@aws-cdk/aws-events'; export function DefaultEventsRuleProps(_targets: events.IRuleTarget[]) { - const defaultEventsRuleProps: events.RuleProps = { - targets: _targets - }; + const defaultEventsRuleProps: events.RuleProps = { + targets: _targets + }; - return defaultEventsRuleProps; + return defaultEventsRuleProps; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/iot-topic-rule-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/iot-topic-rule-defaults.ts index d784c2d03..ff4e9fd71 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/iot-topic-rule-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/iot-topic-rule-defaults.ts @@ -14,15 +14,15 @@ import * as iot from '@aws-cdk/aws-iot'; export function DefaultCfnTopicRuleProps(_actions: iot.CfnTopicRule.ActionProperty[], _sql: string = '') { - const _topicRulePayload: iot.CfnTopicRule.TopicRulePayloadProperty = { - ruleDisabled: false, - actions: _actions, - sql: _sql - }; + const _topicRulePayload: iot.CfnTopicRule.TopicRulePayloadProperty = { + ruleDisabled: false, + actions: _actions, + sql: _sql + }; - const defaultCfnTopicRuleProps: iot.CfnTopicRuleProps = { - topicRulePayload: _topicRulePayload - }; + const defaultCfnTopicRuleProps: iot.CfnTopicRuleProps = { + topicRulePayload: _topicRulePayload + }; - return defaultCfnTopicRuleProps; + return defaultCfnTopicRuleProps; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-analytics-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-analytics-defaults.ts index 6b955d918..94cddd250 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-analytics-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-analytics-defaults.ts @@ -14,7 +14,7 @@ import * as kinesisanalytics from '@aws-cdk/aws-kinesisanalytics'; const DefaultCfnApplicationProps: kinesisanalytics.CfnApplicationProps = { - inputs: [] + inputs: [] }; export { DefaultCfnApplicationProps }; \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-analytics-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-analytics-helper.ts index 6be5c6e10..c94fd4527 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-analytics-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-analytics-helper.ts @@ -11,15 +11,15 @@ * and limitations under the License. */ - // Imports - 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 defaults from './kinesis-analytics-defaults'; - import * as cdk from '@aws-cdk/core'; - import { overrideProps } from './utils'; +// Imports +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 defaults from './kinesis-analytics-defaults'; +import * as cdk from '@aws-cdk/core'; +import { overrideProps } from './utils'; - export interface BuildKinesisAnalyticsAppProps { +export interface BuildKinesisAnalyticsAppProps { /** * A Kinesis Data Firehose for the Kinesis Streams application to connect to. * @@ -34,39 +34,39 @@ readonly kinesisAnalyticsProps?: kinesisAnalytics.CfnApplicationProps | any } - export function buildKinesisAnalyticsApp(scope: cdk.Construct, props: BuildKinesisAnalyticsAppProps): kinesisAnalytics.CfnApplication { +export function buildKinesisAnalyticsApp(scope: cdk.Construct, props: BuildKinesisAnalyticsAppProps): kinesisAnalytics.CfnApplication { - // Setup the IAM role for Kinesis Analytics - const analyticsRole = new iam.Role(scope, 'KinesisAnalyticsRole', { - assumedBy: new iam.ServicePrincipal('kinesisanalytics.amazonaws.com'), - }); + // Setup the IAM role for Kinesis Analytics + const analyticsRole = new iam.Role(scope, 'KinesisAnalyticsRole', { + assumedBy: new iam.ServicePrincipal('kinesisanalytics.amazonaws.com'), + }); - // Setup the IAM policy for Kinesis Analytics - const analyticsPolicy = new iam.Policy(scope, 'KinesisAnalyticsPolicy', { - statements: [ - new iam.PolicyStatement({ - actions: [ - 'firehose:DescribeDeliveryStream', - 'firehose:Get*' - ], - resources: [props.kinesisFirehose.attrArn] - }) + // Setup the IAM policy for Kinesis Analytics + const analyticsPolicy = new iam.Policy(scope, 'KinesisAnalyticsPolicy', { + statements: [ + new iam.PolicyStatement({ + actions: [ + 'firehose:DescribeDeliveryStream', + 'firehose:Get*' + ], + resources: [props.kinesisFirehose.attrArn] + }) ]}); - // Attach policy to role - analyticsPolicy.attachToRole(analyticsRole); + // Attach policy to role + analyticsPolicy.attachToRole(analyticsRole); - // Setup the Kinesis application properties - const kinesisAnalyticsProps = overrideProps(defaults.DefaultCfnApplicationProps, props.kinesisAnalyticsProps); - kinesisAnalyticsProps.inputs[0].kinesisFirehoseInput = { - resourceArn: props.kinesisFirehose.attrArn, - roleArn: analyticsRole.roleArn - }; + // Setup the Kinesis application properties + const kinesisAnalyticsProps = overrideProps(defaults.DefaultCfnApplicationProps, props.kinesisAnalyticsProps); + kinesisAnalyticsProps.inputs[0].kinesisFirehoseInput = { + resourceArn: props.kinesisFirehose.attrArn, + roleArn: analyticsRole.roleArn + }; - // Setup the Kinesis application and add dependencies - const kinesisAnalyticsApp = new kinesisAnalytics.CfnApplication(scope, 'KinesisAnalytics', kinesisAnalyticsProps); - kinesisAnalyticsApp.addDependsOn(analyticsPolicy.node.findChild('Resource') as iam.CfnPolicy); + // Setup the Kinesis application and add dependencies + const kinesisAnalyticsApp = new kinesisAnalytics.CfnApplication(scope, 'KinesisAnalytics', kinesisAnalyticsProps); + kinesisAnalyticsApp.addDependsOn(analyticsPolicy.node.findChild('Resource') as iam.CfnPolicy); - // Create the application and return - return kinesisAnalyticsApp; + // Create the application and return + return kinesisAnalyticsApp; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-firehose-s3-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-firehose-s3-defaults.ts index 259f74612..b01cd6ef1 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-firehose-s3-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-firehose-s3-defaults.ts @@ -15,27 +15,27 @@ import { CfnDeliveryStreamProps } from '@aws-cdk/aws-kinesisfirehose'; import { IKey } from '@aws-cdk/aws-kms'; export function DefaultCfnDeliveryStreamProps(_bucketArn: string, _roleArn: string, - _logGroupName: string, _logStreamName: string, _kms: IKey): CfnDeliveryStreamProps { + _logGroupName: string, _logStreamName: string, _kms: IKey): CfnDeliveryStreamProps { - return { - extendedS3DestinationConfiguration : { - bucketArn: _bucketArn, - bufferingHints: { - intervalInSeconds: 300, - sizeInMBs: 5 - }, - compressionFormat: 'GZIP', - roleArn: _roleArn, - cloudWatchLoggingOptions: { - enabled: true, - logGroupName: _logGroupName, - logStreamName: _logStreamName - }, - encryptionConfiguration: { - kmsEncryptionConfig: { - awskmsKeyArn: _kms.keyArn - } - } + return { + extendedS3DestinationConfiguration : { + bucketArn: _bucketArn, + bufferingHints: { + intervalInSeconds: 300, + sizeInMBs: 5 + }, + compressionFormat: 'GZIP', + roleArn: _roleArn, + cloudWatchLoggingOptions: { + enabled: true, + logGroupName: _logGroupName, + logStreamName: _logStreamName + }, + encryptionConfiguration: { + kmsEncryptionConfig: { + awskmsKeyArn: _kms.keyArn } - } as CfnDeliveryStreamProps; + } + } + } as CfnDeliveryStreamProps; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-defaults.ts index 2eba97d61..4f928e38c 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-defaults.ts @@ -14,7 +14,7 @@ import * as kinesis from '@aws-cdk/aws-kinesis'; const DefaultStreamProps: kinesis.StreamProps = { - encryption: kinesis.StreamEncryption.MANAGED + encryption: kinesis.StreamEncryption.MANAGED }; export { DefaultStreamProps }; \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-helper.ts index 781fcaacd..1cdc6a143 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/kinesis-streams-helper.ts @@ -11,7 +11,7 @@ * and limitations under the License. */ - // Imports +// Imports import * as kinesis from '@aws-cdk/aws-kinesis'; import { DefaultStreamProps } from './kinesis-streams-defaults'; import * as cdk from '@aws-cdk/core'; @@ -36,55 +36,55 @@ export interface BuildKinesisStreamProps { export function buildKinesisStream(scope: cdk.Construct, props: BuildKinesisStreamProps): kinesis.Stream { - if (props.existingStreamObj) { - return props.existingStreamObj; - } + if (props.existingStreamObj) { + return props.existingStreamObj; + } - // Setup the stream properties - let kinesisStreamProps; - if (props.kinesisStreamProps) { - // If property overrides have been provided, incorporate them and deploy - kinesisStreamProps = overrideProps(DefaultStreamProps, props.kinesisStreamProps); - } else { - // If no property overrides, deploy using the default configuration - kinesisStreamProps = DefaultStreamProps; - } + // Setup the stream properties + let kinesisStreamProps; + if (props.kinesisStreamProps) { + // If property overrides have been provided, incorporate them and deploy + kinesisStreamProps = overrideProps(DefaultStreamProps, props.kinesisStreamProps); + } else { + // If no property overrides, deploy using the default configuration + kinesisStreamProps = DefaultStreamProps; + } - // Create the stream and return - return new kinesis.Stream(scope, 'KinesisStream', kinesisStreamProps); + // Create the stream and return + return new kinesis.Stream(scope, 'KinesisStream', kinesisStreamProps); } export function buildKinesisStreamCWAlarms(scope: cdk.Construct): cloudwatch.Alarm[] { - // Setup CW Alarms for KinesisStream - const alarms: cloudwatch.Alarm[] = new Array(); + // Setup CW Alarms for KinesisStream + const alarms: cloudwatch.Alarm[] = new Array(); - // Alarm if Max (GetRecords.IteratorAgeMilliseconds): >= 12 hours (50% of 24 hours default retention period) - alarms.push(new cloudwatch.Alarm(scope, 'KinesisStreamGetRecordsIteratorAgeAlarm', { - metric: new cloudwatch.Metric({ - namespace: 'AWS/Kinesis', - metricName: 'GetRecords.IteratorAgeMilliseconds' - }), - threshold: 2592000, // 12 Hours (50% of 24 hours - default record retention period) - evaluationPeriods: 1, - statistic: 'Maximum', - period: cdk.Duration.minutes(5), - comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, - alarmDescription: 'Consumer Record Processing Falling Behind, there is risk for data loss due to record expiration.' - })); + // Alarm if Max (GetRecords.IteratorAgeMilliseconds): >= 12 hours (50% of 24 hours default retention period) + alarms.push(new cloudwatch.Alarm(scope, 'KinesisStreamGetRecordsIteratorAgeAlarm', { + metric: new cloudwatch.Metric({ + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.IteratorAgeMilliseconds' + }), + threshold: 2592000, // 12 Hours (50% of 24 hours - default record retention period) + evaluationPeriods: 1, + statistic: 'Maximum', + period: cdk.Duration.minutes(5), + comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, + alarmDescription: 'Consumer Record Processing Falling Behind, there is risk for data loss due to record expiration.' + })); - // Alarm if Avg (ReadProvisionedThroughputExceeded): > 0 - alarms.push(new cloudwatch.Alarm(scope, 'KinesisStreamReadProvisionedThroughputExceededAlarm', { - metric: new cloudwatch.Metric({ - namespace: 'AWS/Kinesis', - metricName: 'ReadProvisionedThroughputExceeded' - }), - threshold: 0, - evaluationPeriods: 1, - statistic: 'Average', - period: cdk.Duration.minutes(5), - comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, - alarmDescription: 'Consumer Application is Reading at a Slower Rate Than Expected.' - })); + // Alarm if Avg (ReadProvisionedThroughputExceeded): > 0 + alarms.push(new cloudwatch.Alarm(scope, 'KinesisStreamReadProvisionedThroughputExceededAlarm', { + metric: new cloudwatch.Metric({ + namespace: 'AWS/Kinesis', + metricName: 'ReadProvisionedThroughputExceeded' + }), + threshold: 0, + evaluationPeriods: 1, + statistic: 'Average', + period: cdk.Duration.minutes(5), + comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, + alarmDescription: 'Consumer Application is Reading at a Slower Rate Than Expected.' + })); - return alarms; + return alarms; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/kms-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/kms-defaults.ts index 8691b5336..acf22958b 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/kms-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/kms-defaults.ts @@ -14,7 +14,7 @@ import { KeyProps } from '@aws-cdk/aws-kms'; const DefaultEncryptionProps: KeyProps = { - enableKeyRotation: true + enableKeyRotation: true }; export { DefaultEncryptionProps }; \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/kms-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/kms-helper.ts index b04537b37..ca671b272 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/kms-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/kms-helper.ts @@ -17,15 +17,15 @@ import * as cdk from '@aws-cdk/core'; import { overrideProps } from './utils'; export function buildEncryptionKey(scope: cdk.Construct, keyProps?: kms.KeyProps): kms.Key { - // Setup the key properties - let encryptionKeyProps; - if (keyProps) { - // If property overrides have been provided, incorporate them and deploy - encryptionKeyProps = overrideProps(DefaultEncryptionProps, keyProps); - } else { - // If no property overrides, deploy using the default configuration - encryptionKeyProps = DefaultEncryptionProps; - } - // Create the encryption key and return - return new kms.Key(scope, 'EncryptionKey', encryptionKeyProps); + // Setup the key properties + let encryptionKeyProps; + if (keyProps) { + // If property overrides have been provided, incorporate them and deploy + encryptionKeyProps = overrideProps(DefaultEncryptionProps, keyProps); + } else { + // If no property overrides, deploy using the default configuration + encryptionKeyProps = DefaultEncryptionProps; + } + // Create the encryption key and return + return new kms.Key(scope, 'EncryptionKey', encryptionKeyProps); } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/lambda-event-source-mapping-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/lambda-event-source-mapping-defaults.ts index 4f123507a..d2056ab59 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/lambda-event-source-mapping-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/lambda-event-source-mapping-defaults.ts @@ -27,74 +27,74 @@ export interface EventSourceProps { export function DynamoEventSourceProps(scope: Construct, _dynamoEventSourceProps?: EventSourceProps): DynamoEventSourceProps { - const baseProps: DynamoEventSourceProps = { - startingPosition: lambda.StartingPosition.TRIM_HORIZON, - bisectBatchOnError: true, - maxRecordAge: Duration.hours(24), - retryAttempts: 500 - }; + const baseProps: DynamoEventSourceProps = { + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + bisectBatchOnError: true, + maxRecordAge: Duration.hours(24), + retryAttempts: 500 + }; - let extraProps = {}; + let extraProps = {}; - if (_dynamoEventSourceProps === undefined || _dynamoEventSourceProps?.deploySqsDlqQueue === undefined + if (_dynamoEventSourceProps === undefined || _dynamoEventSourceProps?.deploySqsDlqQueue === undefined || _dynamoEventSourceProps.deploySqsDlqQueue ) { - const [sqsQueue] = buildQueue(scope, 'SqsDlqQueue', { - queueProps: _dynamoEventSourceProps?.sqsDlqQueueProps - }); - - extraProps = { - onFailure: new SqsDlq(sqsQueue), - }; - } - - const defaultDynamoEventSourceProps = Object.assign(baseProps, extraProps); - - if (_dynamoEventSourceProps?.eventSourceProps) { - return overrideProps(defaultDynamoEventSourceProps, _dynamoEventSourceProps.eventSourceProps as DynamoEventSourceProps); - } else { - return defaultDynamoEventSourceProps; - } + const [sqsQueue] = buildQueue(scope, 'SqsDlqQueue', { + queueProps: _dynamoEventSourceProps?.sqsDlqQueueProps + }); + + extraProps = { + onFailure: new SqsDlq(sqsQueue), + }; + } + + const defaultDynamoEventSourceProps = Object.assign(baseProps, extraProps); + + if (_dynamoEventSourceProps?.eventSourceProps) { + return overrideProps(defaultDynamoEventSourceProps, _dynamoEventSourceProps.eventSourceProps as DynamoEventSourceProps); + } else { + return defaultDynamoEventSourceProps; + } } export function S3EventSourceProps(_s3EventSourceProps?: S3EventSourceProps) { - const defaultS3EventSourceProps: S3EventSourceProps = { - events: [s3.EventType.OBJECT_CREATED] - }; + const defaultS3EventSourceProps: S3EventSourceProps = { + events: [s3.EventType.OBJECT_CREATED] + }; - if (_s3EventSourceProps) { - return overrideProps(defaultS3EventSourceProps, _s3EventSourceProps, false); - } else { - return defaultS3EventSourceProps; - } + if (_s3EventSourceProps) { + return overrideProps(defaultS3EventSourceProps, _s3EventSourceProps, false); + } else { + return defaultS3EventSourceProps; + } } export function KinesisEventSourceProps(scope: Construct, _kinesisEventSourceProps?: EventSourceProps): KinesisEventSourceProps { - const baseProps: KinesisEventSourceProps = { - startingPosition: lambda.StartingPosition.TRIM_HORIZON, - bisectBatchOnError: true, - maxRecordAge: Duration.hours(24), - retryAttempts: 500 - }; + const baseProps: KinesisEventSourceProps = { + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + bisectBatchOnError: true, + maxRecordAge: Duration.hours(24), + retryAttempts: 500 + }; - let extraProps = {}; + let extraProps = {}; - if (_kinesisEventSourceProps === undefined || _kinesisEventSourceProps?.deploySqsDlqQueue === undefined + if (_kinesisEventSourceProps === undefined || _kinesisEventSourceProps?.deploySqsDlqQueue === undefined || _kinesisEventSourceProps.deploySqsDlqQueue ) { - const [sqsQueue] = buildQueue(scope, 'SqsDlqQueue', { - queueProps: _kinesisEventSourceProps?.sqsDlqQueueProps - }); - - extraProps = { - onFailure: new SqsDlq(sqsQueue), - }; - } - - const defaultKinesisEventSourceProps = Object.assign(baseProps, extraProps); - - if (_kinesisEventSourceProps?.eventSourceProps) { - return overrideProps(defaultKinesisEventSourceProps, _kinesisEventSourceProps.eventSourceProps as KinesisEventSourceProps); - } else { - return defaultKinesisEventSourceProps; - } + const [sqsQueue] = buildQueue(scope, 'SqsDlqQueue', { + queueProps: _kinesisEventSourceProps?.sqsDlqQueueProps + }); + + extraProps = { + onFailure: new SqsDlq(sqsQueue), + }; + } + + const defaultKinesisEventSourceProps = Object.assign(baseProps, extraProps); + + if (_kinesisEventSourceProps?.eventSourceProps) { + return overrideProps(defaultKinesisEventSourceProps, _kinesisEventSourceProps.eventSourceProps as KinesisEventSourceProps); + } else { + return defaultKinesisEventSourceProps; + } } diff --git a/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts index 924ccd932..dafc0ad5b 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts @@ -13,6 +13,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as iam from '@aws-cdk/aws-iam'; +import * as ec2 from "@aws-cdk/aws-ec2"; import { DefaultLambdaFunctionProps } from './lambda-defaults'; import * as cdk from '@aws-cdk/core'; import { overrideProps } from './utils'; @@ -23,20 +24,26 @@ export interface BuildLambdaFunctionProps { * * @default - None */ - readonly existingLambdaObj?: lambda.Function, + readonly existingLambdaObj?: lambda.Function; /** * User provided props to override the default props for the Lambda function. * * @default - Default props are used */ - readonly lambdaFunctionProps?: lambda.FunctionProps + readonly lambdaFunctionProps?: lambda.FunctionProps; + /** + * A VPC where the Lambda function will access internal resources + * + * @default - none + */ + readonly vpc?: ec2.Vpc; } export function buildLambdaFunction(scope: cdk.Construct, props: BuildLambdaFunctionProps): lambda.Function { // Conditional lambda function creation if (!props.existingLambdaObj) { if (props.lambdaFunctionProps) { - return deployLambdaFunction(scope, props.lambdaFunctionProps); + return deployLambdaFunction(scope, props.lambdaFunctionProps, undefined, props.vpc); } else { throw Error('Either existingLambdaObj or lambdaFunctionProps is required'); } @@ -46,12 +53,19 @@ export function buildLambdaFunction(scope: cdk.Construct, props: BuildLambdaFunc } export function deployLambdaFunction(scope: cdk.Construct, - lambdaFunctionProps: lambda.FunctionProps, - functionId?: string): lambda.Function { + lambdaFunctionProps: lambda.FunctionProps, + functionId?: string, + vpc?: ec2.Vpc): lambda.Function { const _functionId = functionId ? functionId : 'LambdaFunction'; const _functionRoleId = _functionId + 'ServiceRole'; + if (vpc && lambdaFunctionProps.vpc) { + throw new Error( + "Cannot provide a VPC in both the lambdaFunctionProps and the function argument" + ); + } + // Setup the IAM Role for Lambda Service const lambdaServiceRole = new iam.Role(scope, _functionRoleId, { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), @@ -71,7 +85,7 @@ export function deployLambdaFunction(scope: cdk.Construct, // If this Lambda function is going to access resoures in a // VPC, then it needs privileges to access an ENI in that VPC - if (lambdaFunctionProps.vpc) { + if (lambdaFunctionProps.vpc || vpc) { lambdaServiceRole.addToPolicy(new iam.PolicyStatement({ actions: [ "ec2:CreateNetworkInterface", @@ -85,23 +99,62 @@ export function deployLambdaFunction(scope: cdk.Construct, } // Override the DefaultFunctionProps with user provided lambdaFunctionProps - const _lambdaFunctionProps = overrideProps(DefaultLambdaFunctionProps(lambdaServiceRole), lambdaFunctionProps); + let finalLambdaFunctionProps: lambda.FunctionProps = overrideProps(DefaultLambdaFunctionProps(lambdaServiceRole), lambdaFunctionProps); - const lambdafunction = new lambda.Function(scope, _functionId, _lambdaFunctionProps); + if (vpc) { + + // This is literally setting up what would be the default SG, but + // we need to to it explicitly to disable the cfn_nag error + const lambdaSecurityGroup = new ec2.SecurityGroup( + scope, + "ReplaceDefaultSecurityGroup", + { + vpc, + allowAllOutbound: true, + } + ); + + const cfnSecurityGroup = lambdaSecurityGroup.node.findChild( + "Resource" + ) as ec2.CfnSecurityGroup; + cfnSecurityGroup.cfnOptions.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", + }, + ], + }, + }; + + finalLambdaFunctionProps = overrideProps(finalLambdaFunctionProps, { + securityGroups: [ lambdaSecurityGroup ], + vpc, + }); + } + + const lambdafunction = new lambda.Function(scope, _functionId, finalLambdaFunctionProps); if (lambdaFunctionProps.runtime === lambda.Runtime.NODEJS_10_X || lambdaFunctionProps.runtime === lambda.Runtime.NODEJS_12_X) { - lambdafunction.addEnvironment('AWS_NODEJS_CONNECTION_REUSE_ENABLED', '1', { removeInEdge: true }); + lambdafunction.addEnvironment('AWS_NODEJS_CONNECTION_REUSE_ENABLED', '1', { removeInEdge: true }); } const cfnLambdafunction: lambda.CfnFunction = lambdafunction.node.findChild('Resource') as lambda.CfnFunction; cfnLambdafunction.cfnOptions.metadata = { cfn_nag: { - rules_to_suppress: [{ - id: 'W58', - reason: `Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.` - }] + rules_to_suppress: [{ + id: 'W58', + reason: `Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with more tighter permissions.` + }] } }; @@ -112,10 +165,10 @@ export function deployLambdaFunction(scope: cdk.Construct, // Add the CFN NAG suppress to allow for "Resource": "*" for AWS X-Ray cfnLambdafunctionDefPolicy.cfnOptions.metadata = { cfn_nag: { - rules_to_suppress: [{ - id: 'W12', - reason: `Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC.` - }] + rules_to_suppress: [{ + id: 'W12', + reason: `Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC.` + }] } }; } diff --git a/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-defaults.ts index 2cf79f52b..ec8a13d91 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-defaults.ts @@ -16,12 +16,12 @@ import { RemovalPolicy } from '@aws-cdk/core'; import { Bucket, BucketProps } from '@aws-cdk/aws-s3'; export function DefaultS3Props(loggingBucket ?: Bucket, lifecycleRules?: s3.LifecycleRule[]): s3.BucketProps { - return { - encryption: s3.BucketEncryption.S3_MANAGED, - versioned: true, - blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, - removalPolicy: RemovalPolicy.RETAIN, - ...((lifecycleRules !== undefined) && { lifecycleRules }), - ...((loggingBucket !== undefined) && { serverAccessLogsBucket: loggingBucket }) - } as BucketProps; + return { + encryption: s3.BucketEncryption.S3_MANAGED, + versioned: true, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + removalPolicy: RemovalPolicy.RETAIN, + ...((lifecycleRules !== undefined) && { lifecycleRules }), + ...((loggingBucket !== undefined) && { serverAccessLogsBucket: loggingBucket }) + } as BucketProps; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts index f91deac2b..a10139930 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/s3-bucket-helper.ts @@ -29,114 +29,114 @@ export interface BuildS3BucketProps { } export function buildS3Bucket(scope: cdk.Construct, props: BuildS3BucketProps, bucketId?: string): [s3.Bucket, s3.Bucket?] { - if (props.bucketProps) { - return s3BucketWithLogging(scope, props.bucketProps, bucketId); - } else { - return s3BucketWithLogging(scope, DefaultS3Props(), bucketId); - } + if (props.bucketProps) { + return s3BucketWithLogging(scope, props.bucketProps, bucketId); + } else { + return s3BucketWithLogging(scope, DefaultS3Props(), bucketId); + } } export function applySecureBucketPolicy(s3Bucket: s3.Bucket): void { - // Apply bucket policy to enforce encryption of data in transit - - s3Bucket.addToResourcePolicy( - new PolicyStatement({ - sid: 'HttpsOnly', - resources: [ - `${s3Bucket.bucketArn}/*` - ], - actions: ['*'], - principals: [new AnyPrincipal()], - effect: Effect.DENY, - conditions: + // Apply bucket policy to enforce encryption of data in transit + + s3Bucket.addToResourcePolicy( + new PolicyStatement({ + sid: 'HttpsOnly', + resources: [ + `${s3Bucket.bucketArn}/*` + ], + actions: ['*'], + principals: [new AnyPrincipal()], + effect: Effect.DENY, + conditions: { - Bool: { - 'aws:SecureTransport': 'false' - } + Bool: { + 'aws:SecureTransport': 'false' + } } - }) - ); + }) + ); } export function createLoggingBucket(scope: cdk.Construct, bucketId: string): s3.Bucket { - // Create the Logging Bucket - const loggingBucket: s3.Bucket = new s3.Bucket(scope, bucketId, DefaultS3Props()); + // Create the Logging Bucket + const loggingBucket: s3.Bucket = new s3.Bucket(scope, bucketId, DefaultS3Props()); - applySecureBucketPolicy(loggingBucket); + applySecureBucketPolicy(loggingBucket); - // Extract the CfnBucket from the loggingBucket - const loggingBucketResource = loggingBucket.node.findChild('Resource') as s3.CfnBucket; + // Extract the CfnBucket from the loggingBucket + const loggingBucketResource = loggingBucket.node.findChild('Resource') as s3.CfnBucket; - // Override accessControl configuration and add metadata for the logging bucket - loggingBucketResource.addPropertyOverride('AccessControl', 'LogDeliveryWrite'); + // Override accessControl configuration and add metadata for the logging bucket + loggingBucketResource.addPropertyOverride('AccessControl', 'LogDeliveryWrite'); - // Turn off Versioning for the logging bucket as objects will be written only ONCE - loggingBucketResource.addPropertyDeletionOverride('VersioningConfiguration.Status'); + // Turn off Versioning for the logging bucket as objects will be written only ONCE + loggingBucketResource.addPropertyDeletionOverride('VersioningConfiguration.Status'); - // Remove the default LifecycleConfiguration for the Logging Bucket - loggingBucketResource.addPropertyDeletionOverride('LifecycleConfiguration.Rules'); + // Remove the default LifecycleConfiguration for the Logging Bucket + loggingBucketResource.addPropertyDeletionOverride('LifecycleConfiguration.Rules'); - let _reason = "This S3 bucket is used as the access logging bucket for another bucket"; + let _reason = "This S3 bucket is used as the access logging bucket for another bucket"; - if (bucketId === 'CloudfrontLoggingBucket') { - _reason = "This S3 bucket is used as the access logging bucket for CloudFront Distribution"; - } + if (bucketId === 'CloudfrontLoggingBucket') { + _reason = "This S3 bucket is used as the access logging bucket for CloudFront Distribution"; + } - loggingBucketResource.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W35', - reason: _reason - }] - } - }; + loggingBucketResource.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W35', + reason: _reason + }] + } + }; - return loggingBucket; + return loggingBucket; } function s3BucketWithLogging(scope: cdk.Construct, s3BucketProps?: s3.BucketProps, bucketId?: string): [s3.Bucket, s3.Bucket?] { - /** Default Life Cycle policy to transition older versions to Glacier after 90 days */ - const lifecycleRules: s3.LifecycleRule[] = [{ - noncurrentVersionTransitions: [{ - storageClass: StorageClass.GLACIER, - transitionAfter: Duration.days(90) - }] - }]; - - // Create the Application Bucket - let bucketprops: s3.BucketProps; - let loggingBucket; - const _bucketId = bucketId ? bucketId + 'S3Bucket' : 'S3Bucket'; - const _loggingBucketId = bucketId ? bucketId + 'S3LoggingBucket' : 'S3LoggingBucket'; - - if (s3BucketProps?.serverAccessLogsBucket) { - // Attach the Default Life Cycle policy ONLY IF the versioning is ENABLED - if (s3BucketProps.versioned === undefined || s3BucketProps.versioned) { - bucketprops = DefaultS3Props(undefined, lifecycleRules); - } else { - bucketprops = DefaultS3Props(); - } + /** Default Life Cycle policy to transition older versions to Glacier after 90 days */ + const lifecycleRules: s3.LifecycleRule[] = [{ + noncurrentVersionTransitions: [{ + storageClass: StorageClass.GLACIER, + transitionAfter: Duration.days(90) + }] + }]; + + // Create the Application Bucket + let bucketprops: s3.BucketProps; + let loggingBucket; + const _bucketId = bucketId ? bucketId + 'S3Bucket' : 'S3Bucket'; + const _loggingBucketId = bucketId ? bucketId + 'S3LoggingBucket' : 'S3LoggingBucket'; + + if (s3BucketProps?.serverAccessLogsBucket) { + // Attach the Default Life Cycle policy ONLY IF the versioning is ENABLED + if (s3BucketProps.versioned === undefined || s3BucketProps.versioned) { + bucketprops = DefaultS3Props(undefined, lifecycleRules); } else { - // Create the Logging Bucket - loggingBucket = createLoggingBucket(scope, _loggingBucketId); - - // Attach the Default Life Cycle policy ONLY IF the versioning is ENABLED - if (s3BucketProps?.versioned === undefined || s3BucketProps.versioned) { - bucketprops = DefaultS3Props(loggingBucket, lifecycleRules); - } else { - bucketprops = DefaultS3Props(loggingBucket); - } + bucketprops = DefaultS3Props(); } + } else { + // Create the Logging Bucket + loggingBucket = createLoggingBucket(scope, _loggingBucketId); - if (s3BucketProps) { - bucketprops = overrideProps(bucketprops, s3BucketProps); + // Attach the Default Life Cycle policy ONLY IF the versioning is ENABLED + if (s3BucketProps?.versioned === undefined || s3BucketProps.versioned) { + bucketprops = DefaultS3Props(loggingBucket, lifecycleRules); + } else { + bucketprops = DefaultS3Props(loggingBucket); } + } + + if (s3BucketProps) { + bucketprops = overrideProps(bucketprops, s3BucketProps); + } - const s3Bucket: s3.Bucket = new s3.Bucket(scope, _bucketId, bucketprops); + const s3Bucket: s3.Bucket = new s3.Bucket(scope, _bucketId, bucketprops); - applySecureBucketPolicy(s3Bucket); + applySecureBucketPolicy(s3Bucket); - return [s3Bucket, loggingBucket]; + return [s3Bucket, loggingBucket]; } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-defaults.ts index 103cee063..695faae0c 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-defaults.ts @@ -14,7 +14,7 @@ import { CfnNotebookInstanceProps } from '@aws-cdk/aws-sagemaker'; export function DefaultSagemakerNotebookProps(roleArn: string, kmsKeyId: string, - subnetId?: string, securityGroupIds?: string[]): CfnNotebookInstanceProps { + subnetId?: string, securityGroupIds?: string[]): CfnNotebookInstanceProps { return { instanceType: 'ml.t2.medium', roleArn, diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts index b52efa08f..b3a5b18a6 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts @@ -74,11 +74,11 @@ function addPermissions(_role: iam.Role) { _role.addToPolicy(new iam.PolicyStatement({ resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:/aws/sagemaker/*`], actions: [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:DescribeLogStreams', - 'logs:GetLogEvents', - 'logs:PutLogEvents' + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:DescribeLogStreams', + 'logs:GetLogEvents', + 'logs:PutLogEvents' ], })); @@ -86,7 +86,7 @@ function addPermissions(_role: iam.Role) { _role.addToPolicy(new iam.PolicyStatement({ resources: [_role.roleArn], actions: [ - 'iam:GetRole' + 'iam:GetRole' ], })); @@ -94,7 +94,7 @@ function addPermissions(_role: iam.Role) { _role.addToPolicy(new iam.PolicyStatement({ resources: [_role.roleArn], actions: [ - 'iam:PassRole' + 'iam:PassRole' ], conditions: { StringLike: {'iam:PassedToService': 'sagemaker.amazonaws.com'} @@ -122,7 +122,7 @@ export function buildSagemakerNotebook(scope: cdk.Construct, props: BuildSagemak addPermissions(props.role); if (props.sagemakerNotebookProps?.kmsKeyId === undefined) { - kmsKeyId = buildEncryptionKey(scope).keyId; + kmsKeyId = buildEncryptionKey(scope).keyId; } else { kmsKeyId = props.sagemakerNotebookProps.kmsKeyId; } @@ -140,10 +140,10 @@ export function buildSagemakerNotebook(scope: cdk.Construct, props: BuildSagemak const cfnSecurityGroup = securityGroup.node.findChild('Resource') as ec2.CfnSecurityGroup; cfnSecurityGroup.cfnOptions.metadata = { cfn_nag: { - rules_to_suppress: [{ - id: 'W5', - reason: 'Allow notebook users to access the Internet from the notebook' - }] + rules_to_suppress: [{ + id: 'W5', + reason: 'Allow notebook users to access the Internet from the notebook' + }] } }; @@ -170,7 +170,7 @@ export function buildSagemakerNotebook(scope: cdk.Construct, props: BuildSagemak return [sagemakerInstance]; } } else { - // Return existing notebook object - return [props.existingNotebookObj]; + // Return existing notebook object + return [props.existingNotebookObj]; } } diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts index 632b7cb66..74cc09977 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts @@ -57,97 +57,97 @@ export interface BuildTopicProps { function applySecureTopicPolicy(topic: sns.Topic): void { - // Apply topic policy to enforce only the topic owner can publish and subscribe to this topic - topic.addToResourcePolicy( - new PolicyStatement({ - sid: 'TopicOwnerOnlyAccess', - resources: [ - `${topic.topicArn}` - ], - actions: [ - "SNS:Publish", - "SNS:RemovePermission", - "SNS:SetTopicAttributes", - "SNS:DeleteTopic", - "SNS:ListSubscriptionsByTopic", - "SNS:GetTopicAttributes", - "SNS:Receive", - "SNS:AddPermission", - "SNS:Subscribe" - ], - principals: [new AccountPrincipal(Stack.of(topic).account)], - effect: Effect.ALLOW, - conditions: + // Apply topic policy to enforce only the topic owner can publish and subscribe to this topic + topic.addToResourcePolicy( + new PolicyStatement({ + sid: 'TopicOwnerOnlyAccess', + resources: [ + `${topic.topicArn}` + ], + actions: [ + "SNS:Publish", + "SNS:RemovePermission", + "SNS:SetTopicAttributes", + "SNS:DeleteTopic", + "SNS:ListSubscriptionsByTopic", + "SNS:GetTopicAttributes", + "SNS:Receive", + "SNS:AddPermission", + "SNS:Subscribe" + ], + principals: [new AccountPrincipal(Stack.of(topic).account)], + effect: Effect.ALLOW, + conditions: { - StringEquals: { - "AWS:SourceOwner": Stack.of(topic).account - } + StringEquals: { + "AWS:SourceOwner": Stack.of(topic).account + } } - }) - ); + }) + ); - // Apply Topic policy to enforce encryption of data in transit - topic.addToResourcePolicy( - new PolicyStatement({ - sid: 'HttpsOnly', - resources: [ - `${topic.topicArn}` - ], - actions: [ - "SNS:Publish", - "SNS:RemovePermission", - "SNS:SetTopicAttributes", - "SNS:DeleteTopic", - "SNS:ListSubscriptionsByTopic", - "SNS:GetTopicAttributes", - "SNS:Receive", - "SNS:AddPermission", - "SNS:Subscribe" - ], - principals: [new AnyPrincipal()], - effect: Effect.DENY, - conditions: + // Apply Topic policy to enforce encryption of data in transit + topic.addToResourcePolicy( + new PolicyStatement({ + sid: 'HttpsOnly', + resources: [ + `${topic.topicArn}` + ], + actions: [ + "SNS:Publish", + "SNS:RemovePermission", + "SNS:SetTopicAttributes", + "SNS:DeleteTopic", + "SNS:ListSubscriptionsByTopic", + "SNS:GetTopicAttributes", + "SNS:Receive", + "SNS:AddPermission", + "SNS:Subscribe" + ], + principals: [new AnyPrincipal()], + effect: Effect.DENY, + conditions: { - Bool: { - 'aws:SecureTransport': 'false' - } + Bool: { + 'aws:SecureTransport': 'false' + } } - }) - ); + }) + ); } export function buildTopic(scope: cdk.Construct, props: BuildTopicProps): [sns.Topic, kms.Key?] { - if (!props.existingTopicObj) { - // Setup the topic properties - let snsTopicProps; - if (props.topicProps) { - // If property overrides have been provided, incorporate them and deploy - snsTopicProps = overrideProps(DefaultSnsTopicProps, props.topicProps); - } else { - // If no property overrides, deploy using the default configuration - snsTopicProps = DefaultSnsTopicProps; - } - // Set encryption properties - if (props.enableEncryptionWithCustomerManagedKey === undefined || props.enableEncryptionWithCustomerManagedKey === false) { - // Retrieve SNS managed key to encrypt the SNS Topic - const awsManagedKey = kms.Alias.fromAliasName(scope, 'aws-managed-key', 'alias/aws/sns'); - snsTopicProps.masterKey = awsManagedKey; - } else { - // Use the imported Customer Managed KMS key - if (props.encryptionKey) { - snsTopicProps.masterKey = props.encryptionKey; - } else { - // Create a new Customer Managed KMS key - snsTopicProps.masterKey = buildEncryptionKey(scope, props.encryptionKeyProps); - } - } - // Create the SNS Topic - const topic: sns.Topic = new sns.Topic(scope, 'SnsTopic', snsTopicProps); - - applySecureTopicPolicy(topic); - - return [topic, snsTopicProps.masterKey]; + if (!props.existingTopicObj) { + // Setup the topic properties + let snsTopicProps; + if (props.topicProps) { + // If property overrides have been provided, incorporate them and deploy + snsTopicProps = overrideProps(DefaultSnsTopicProps, props.topicProps); } else { - return [props.existingTopicObj]; + // If no property overrides, deploy using the default configuration + snsTopicProps = DefaultSnsTopicProps; } + // Set encryption properties + if (props.enableEncryptionWithCustomerManagedKey === undefined || props.enableEncryptionWithCustomerManagedKey === false) { + // Retrieve SNS managed key to encrypt the SNS Topic + const awsManagedKey = kms.Alias.fromAliasName(scope, 'aws-managed-key', 'alias/aws/sns'); + snsTopicProps.masterKey = awsManagedKey; + } else { + // Use the imported Customer Managed KMS key + if (props.encryptionKey) { + snsTopicProps.masterKey = props.encryptionKey; + } else { + // Create a new Customer Managed KMS key + snsTopicProps.masterKey = buildEncryptionKey(scope, props.encryptionKeyProps); + } + } + // Create the SNS Topic + const topic: sns.Topic = new sns.Topic(scope, 'SnsTopic', snsTopicProps); + + applySecureTopicPolicy(topic); + + return [topic, snsTopicProps.masterKey]; + } else { + return [props.existingTopicObj]; + } } diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sqs-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/sqs-defaults.ts index f06101675..e08f3e93e 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sqs-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sqs-defaults.ts @@ -14,10 +14,10 @@ import * as sqs from '@aws-cdk/aws-sqs'; export function DefaultQueueProps() { - const _DefaultQueueProps: sqs.QueueProps = { - encryption: sqs.QueueEncryption.KMS_MANAGED - }; - return _DefaultQueueProps; + const _DefaultQueueProps: sqs.QueueProps = { + encryption: sqs.QueueEncryption.KMS_MANAGED + }; + return _DefaultQueueProps; } // Default value for the max receive count of a dead letter queue diff --git a/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts index 2ea90ec1d..6434846a1 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts @@ -131,15 +131,15 @@ export function buildDeadLetterQueue(scope: cdk.Construct, props: BuildDeadLette if (!props.existingQueueObj && (props.deployDeadLetterQueue || props.deployDeadLetterQueue === undefined)) { // Create the Dead Letter Queue const [dlq] = buildQueue(scope, 'deadLetterQueue', { - queueProps: props.deadLetterQueueProps + queueProps: props.deadLetterQueueProps }); const mrc = (props.maxReceiveCount) ? props.maxReceiveCount : defaults.defaultMaxReceiveCount; // Setup the Dead Letter Queue interface const dlqInterface: sqs.DeadLetterQueue = { - maxReceiveCount: mrc, - queue: dlq + maxReceiveCount: mrc, + queue: dlq }; // Return the dead letter queue interface @@ -152,43 +152,43 @@ function applySecureQueuePolicy(queue: sqs.Queue): void { // Apply queue policy to enforce only the queue owner can perform operations on queue queue.addToResourcePolicy( - new PolicyStatement({ - sid: 'QueueOwnerOnlyAccess', - resources: [ - `${queue.queueArn}` - ], - actions: [ - "sqs:DeleteMessage", - "sqs:ReceiveMessage", - "sqs:SendMessage", - "sqs:GetQueueAttributes", - "sqs:RemovePermission", - "sqs:AddPermission", - "sqs:SetQueueAttributes" - ], - principals: [new AccountPrincipal(Stack.of(queue).account)], - effect: Effect.ALLOW - }) + new PolicyStatement({ + sid: 'QueueOwnerOnlyAccess', + resources: [ + `${queue.queueArn}` + ], + actions: [ + "sqs:DeleteMessage", + "sqs:ReceiveMessage", + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:RemovePermission", + "sqs:AddPermission", + "sqs:SetQueueAttributes" + ], + principals: [new AccountPrincipal(Stack.of(queue).account)], + effect: Effect.ALLOW + }) ); // Apply Topic policy to enforce encryption of data in transit queue.addToResourcePolicy( - new PolicyStatement({ - sid: 'HttpsOnly', - resources: [ - `${queue.queueArn}` - ], - actions: [ - "SQS:*" - ], - principals: [new AnyPrincipal()], - effect: Effect.DENY, - conditions: + new PolicyStatement({ + sid: 'HttpsOnly', + resources: [ + `${queue.queueArn}` + ], + actions: [ + "SQS:*" + ], + principals: [new AnyPrincipal()], + effect: Effect.DENY, + conditions: { - Bool: { - 'aws:SecureTransport': 'false' - } + Bool: { + 'aws:SecureTransport': 'false' + } } - }) + }) ); } diff --git a/source/patterns/@aws-solutions-constructs/core/lib/step-function-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/step-function-defaults.ts index df2f2c74d..910c0782f 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/step-function-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/step-function-defaults.ts @@ -17,10 +17,10 @@ import { LogGroup } from '@aws-cdk/aws-logs'; export function DefaultStateMachineProps(_logGroup: LogGroup): sfn.StateMachineProps | any { const stateMachineProps: sfn.StateMachineProps | any = { - logs: { - destination: _logGroup, - level: sfn.LogLevel.ERROR - } + logs: { + destination: _logGroup, + level: sfn.LogLevel.ERROR + } }; return stateMachineProps; diff --git a/source/patterns/@aws-solutions-constructs/core/lib/step-function-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/step-function-helper.ts index 8930f8906..c9a82f514 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/step-function-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/step-function-helper.ts @@ -28,54 +28,54 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; */ export function buildStateMachine(scope: cdk.Construct, stateMachineProps: sfn.StateMachineProps): [sfn.StateMachine, LogGroup] { - let logGroup: LogGroup; + let logGroup: LogGroup; - // Configure Cloudwatch log group for Step function State Machine - if (!stateMachineProps.logs) { - logGroup = new LogGroup(scope, 'StateMachineLogGroup', DefaultLogGroupProps()); - } else { - logGroup = stateMachineProps.logs.destination as LogGroup; - } + // Configure Cloudwatch log group for Step function State Machine + if (!stateMachineProps.logs) { + logGroup = new LogGroup(scope, 'StateMachineLogGroup', DefaultLogGroupProps()); + } else { + logGroup = stateMachineProps.logs.destination as LogGroup; + } - // Override the defaults with the user provided props - const _smProps = overrideProps(smDefaults.DefaultStateMachineProps(logGroup), stateMachineProps); + // Override the defaults with the user provided props + const _smProps = overrideProps(smDefaults.DefaultStateMachineProps(logGroup), stateMachineProps); - // Override the Cloudwatch permissions to make it more fine grained - const _sm = new sfn.StateMachine(scope, 'StateMachine', _smProps); - const role = _sm.node.findChild('Role') as iam.Role; - const cfnDefaultPolicy = role.node.findChild('DefaultPolicy').node.defaultChild as iam.CfnPolicy; + // Override the Cloudwatch permissions to make it more fine grained + const _sm = new sfn.StateMachine(scope, 'StateMachine', _smProps); + const role = _sm.node.findChild('Role') as iam.Role; + const cfnDefaultPolicy = role.node.findChild('DefaultPolicy').node.defaultChild as iam.CfnPolicy; - // Reduce the scope of actions for the existing DefaultPolicy - cfnDefaultPolicy.addPropertyOverride('PolicyDocument.Statement.0.Action', - [ - "logs:CreateLogDelivery", - 'logs:GetLogDelivery', - 'logs:UpdateLogDelivery', - 'logs:DeleteLogDelivery', - 'logs:ListLogDeliveries' - ]); + // Reduce the scope of actions for the existing DefaultPolicy + cfnDefaultPolicy.addPropertyOverride('PolicyDocument.Statement.0.Action', + [ + "logs:CreateLogDelivery", + 'logs:GetLogDelivery', + 'logs:UpdateLogDelivery', + 'logs:DeleteLogDelivery', + 'logs:ListLogDeliveries' + ]); - // Override Cfn Nag warning W12: IAM policy should not allow * resource - cfnDefaultPolicy.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W12', - reason: `The 'LogDelivery' actions do not support resource-level authorizations` - }] - } - }; + // Override Cfn Nag warning W12: IAM policy should not allow * resource + cfnDefaultPolicy.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W12', + reason: `The 'LogDelivery' actions do not support resource-level authorizations` + }] + } + }; - // Add a new policy with logging permissions for the given cloudwatch log group - _sm.addToRolePolicy(new iam.PolicyStatement({ - actions: [ - 'logs:PutResourcePolicy', - 'logs:DescribeResourcePolicies', - 'logs:DescribeLogGroups' - ], - resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:*`] - })); + // Add a new policy with logging permissions for the given cloudwatch log group + _sm.addToRolePolicy(new iam.PolicyStatement({ + actions: [ + 'logs:PutResourcePolicy', + 'logs:DescribeResourcePolicies', + 'logs:DescribeLogGroups' + ], + resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:*`] + })); - return [_sm, logGroup]; + return [_sm, logGroup]; } export function buildStepFunctionCWAlarms(scope: cdk.Construct, sm: sfn.StateMachine): cloudwatch.Alarm[] { diff --git a/source/patterns/@aws-solutions-constructs/core/lib/utils.ts b/source/patterns/@aws-solutions-constructs/core/lib/utils.ts index d92cd8fa8..9ba470e16 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/utils.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/utils.ts @@ -16,7 +16,7 @@ import { flagOverriddenDefaults } from './override-warning-service'; import * as log from 'npmlog'; function isObject(val: object) { - return val != null && typeof val === 'object' + return val != null && typeof val === 'object' && Object.prototype.toString.call(val) === '[object Object]'; } @@ -51,7 +51,7 @@ function isPlainObject(o: object) { } function combineMerge(target: any[], source: any[]) { - return target.concat(source); + return target.concat(source); } function overwriteMerge(target: any[], source: any[]) { diff --git a/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.ts index a313547ce..acd715951 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/vpc-helper.ts @@ -17,39 +17,165 @@ import { overrideProps } from "./utils"; import { DefaultVpcProps } from './vpc-defaults'; export interface BuildVpcProps { - /** - * User provided props to override the default props for the VPC. - * - * @default - Default props are used - */ - readonly vpcProps?: ec2.VpcProps + /** + * Existing instance of a VPC, if this is set then the all Props are ignored + */ + readonly existingVpc?: ec2.Vpc; + /** + * User provided props to override the default props for the VPC. + */ + readonly userVpcProps?: ec2.VpcProps; + /** + * Construct specified props that override both the default props + * and user props for the VPC. + */ + readonly constructVpcProps?: ec2.VpcProps; } export function buildVpc(scope: Construct, props?: BuildVpcProps): ec2.Vpc { + if (props?.existingVpc) { + return props?.existingVpc; + } - let bucketprops: ec2.VpcProps = DefaultVpcProps(); + let cumulativeProps: ec2.VpcProps = DefaultVpcProps(); - if (props?.vpcProps) { - bucketprops = overrideProps(bucketprops, props?.vpcProps); + if (props?.userVpcProps) { + cumulativeProps = overrideProps(cumulativeProps, props?.userVpcProps); + } + + if (props?.constructVpcProps) { + cumulativeProps = overrideProps( + cumulativeProps, + props?.constructVpcProps + ); + } + + const vpc = new ec2.Vpc(scope, "Vpc", cumulativeProps); + + // Add VPC FlowLogs with the default setting of trafficType:ALL and destination: CloudWatch Logs + vpc.addFlowLog("FlowLog"); + + // Add Cfn Nag suppression for PUBLIC subnets to suppress WARN W33: EC2 Subnet should not have MapPublicIpOnLaunch set to true + vpc.publicSubnets.forEach((subnet) => { + const cfnSubnet = subnet.node.defaultChild as ec2.CfnSubnet; + cfnSubnet.cfnOptions.metadata = { + cfn_nag: { + rules_to_suppress: [{ + id: 'W33', + reason: 'Allow Public Subnets to have MapPublicIpOnLaunch set to true' + }] + } + }; + }); + + return vpc; +} + +export enum ServiceEndpointTypes { + DYNAMODB = "DDB", + SNS = "SNS", + SQS = "SQS", + S3 = "S3", + STEPFUNCTIONS = "STEPFUNCTIONS", +} + +enum EndpointTypes { + GATEWAY = "Gateway", + INTERFACE = "Interface", +} + +interface EndpointDefinition { + endpointName: ServiceEndpointTypes; + endpointType: EndpointTypes; + endpointGatewayService?: ec2.GatewayVpcEndpointAwsService; + endpointInterfaceService?: ec2.InterfaceVpcEndpointAwsService; +} + +const endpointSettings: EndpointDefinition[] = [ + { + endpointName: ServiceEndpointTypes.DYNAMODB, + endpointType: EndpointTypes.GATEWAY, + endpointGatewayService: ec2.GatewayVpcEndpointAwsService.DYNAMODB, + }, + { + endpointName: ServiceEndpointTypes.S3, + endpointType: EndpointTypes.GATEWAY, + endpointGatewayService: ec2.GatewayVpcEndpointAwsService.S3, + }, + { + endpointName: ServiceEndpointTypes.SNS, + endpointType: EndpointTypes.INTERFACE, + endpointInterfaceService: ec2.InterfaceVpcEndpointAwsService.SNS, + }, + { + endpointName: ServiceEndpointTypes.SQS, + endpointType: EndpointTypes.INTERFACE, + endpointInterfaceService: ec2.InterfaceVpcEndpointAwsService.SQS, + }, +]; + +export function AddAwsServiceEndpoint( + scope: Construct, + vpc: ec2.Vpc, + interfaceTag: ServiceEndpointTypes +) { + if (!vpc.node.children.some((child) => child.node.id === interfaceTag)) { + const service = endpointSettings.find( + (endpoint) => endpoint.endpointName === interfaceTag + ); + + if (!service) { + throw new Error("Unsupported Service sent to AddServiceEndpoint"); } - const vpc = new ec2.Vpc(scope, "Vpc", bucketprops); - - // Add VPC FlowLogs with the default setting of trafficType:ALL and destination: CloudWatch Logs - vpc.addFlowLog('FlowLog'); - - // Add Cfn Nag suppression for PUBLIC subnets to suppress WARN W33: EC2 Subnet should not have MapPublicIpOnLaunch set to true - vpc.publicSubnets.forEach((subnet) => { - const cfnSubnet = subnet.node.defaultChild as ec2.CfnSubnet; - cfnSubnet.cfnOptions.metadata = { - cfn_nag: { - rules_to_suppress: [{ - id: 'W33', - reason: 'Allow Public Subnets to have MapPublicIpOnLaunch set to true' - }] - } - }; - }); - - return vpc; -} \ No newline at end of file + if (service.endpointType === EndpointTypes.GATEWAY) { + vpc.addGatewayEndpoint(interfaceTag, { + service: service.endpointGatewayService as ec2.GatewayVpcEndpointAwsService, + }); + } + if (service.endpointType === EndpointTypes.INTERFACE) { + + const endpointDefaultSecurityGroup = new ec2.SecurityGroup( + scope, + "ReplaceEndpointDefaultSecurityGroup", + { + vpc, + allowAllOutbound: true, + } + ); + + // Allow https traffic from within the VPC + endpointDefaultSecurityGroup.addIngressRule( + ec2.Peer.ipv4(vpc.vpcCidrBlock), + ec2.Port.tcp(443), + ); + + const cfnSecurityGroup = endpointDefaultSecurityGroup.node.findChild( + "Resource" + ) as ec2.CfnSecurityGroup; + cfnSecurityGroup.cfnOptions.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", + }, + ], + }, + }; + + vpc.addInterfaceEndpoint(interfaceTag, { + service: service.endpointInterfaceService as ec2.InterfaceVpcEndpointAwsService, + securityGroups: [ endpointDefaultSecurityGroup ], + }); + } + } + + return; +} diff --git a/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/lambda-func.test.js.snap b/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/lambda-helper.test.js.snap similarity index 100% rename from source/patterns/@aws-solutions-constructs/core/test/__snapshots__/lambda-func.test.js.snap rename to source/patterns/@aws-solutions-constructs/core/test/__snapshots__/lambda-helper.test.js.snap diff --git a/source/patterns/@aws-solutions-constructs/core/test/apigateway-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/apigateway-helper.test.ts index eae86a715..a45ebd414 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/apigateway-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/apigateway-helper.test.ts @@ -40,50 +40,50 @@ function setupRestApi(stack: Stack, apiProps?: any): void { service: "sqs", integrationHttpMethod: "POST", options: { - passthroughBehavior: api.PassthroughBehavior.NEVER, - requestParameters: { - "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'" - }, - requestTemplates: { - "application/x-www-form-urlencoded": "Action=SendMessage&MessageBody=$util.urlEncode(\"$input.body\")&MessageAttribute.1.Name=queryParam1&MessageAttribute.1.Value.StringValue=$input.params(\"query_param_1\")&MessageAttribute.1.Value.DataType=String" + passthroughBehavior: api.PassthroughBehavior.NEVER, + requestParameters: { + "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'" + }, + requestTemplates: { + "application/x-www-form-urlencoded": "Action=SendMessage&MessageBody=$util.urlEncode(\"$input.body\")&MessageAttribute.1.Name=queryParam1&MessageAttribute.1.Value.StringValue=$input.params(\"query_param_1\")&MessageAttribute.1.Value.DataType=String" + }, + integrationResponses: [ + { + statusCode: "200", + responseTemplates: { + "text/html": "Success" + } }, - integrationResponses: [ - { - statusCode: "200", - responseTemplates: { - "text/html": "Success" - } - }, - { - statusCode: "500", - responseTemplates: { - "text/html": "Error" - }, - selectionPattern: "500" - } - ] + { + statusCode: "500", + responseTemplates: { + "text/html": "Error" + }, + selectionPattern: "500" + } + ] }, path: '11112222' + "/" + 'thisqueuequeueName' }); // Setup the API Gateway method(s) apiGatewayResource.addMethod('POST', apiGatewayIntegration, { - requestParameters: { - "method.request.querystring.query_param_1": true + requestParameters: { + "method.request.querystring.query_param_1": true + }, + methodResponses: [ + { + statusCode: "200", + responseParameters: { + "method.response.header.Content-Type": true + } }, - methodResponses: [ - { - statusCode: "200", - responseParameters: { - "method.response.header.Content-Type": true - } - }, - { - statusCode: "500", - responseParameters: { - "method.response.header.Content-Type": true - }, - } - ] + { + statusCode: "500", + responseParameters: { + "method.response.header.Content-Type": true + }, + } + ] }); } @@ -549,9 +549,9 @@ test('Test for Method Request Props Override', () => { { StatusCode: "500", ResponseTemplates: { - "text/html": "Error" - }, - SelectionPattern: "500" + "text/html": "Error" + }, + SelectionPattern: "500" } ], PassthroughBehavior: "NEVER", diff --git a/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-helper.test.ts index f4eff14e8..56faf6043 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-helper.test.ts @@ -65,23 +65,60 @@ test('check bucket metadata', () => { }); test('test cloudfront check bucket policy', () => { - const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); - CloudFrontDistributionForS3(stack, sourceBucket); + const stack = new Stack(); + const [sourceBucket] = buildS3Bucket(stack, {}); + CloudFrontDistributionForS3(stack, sourceBucket); - expect(stack).toHaveResourceLike("AWS::S3::BucketPolicy", { - PolicyDocument: { - Statement: [ - { - Action: "*", - Condition: { - Bool: { - "aws:SecureTransport": "false" - } + expect(stack).toHaveResourceLike("AWS::S3::BucketPolicy", { + PolicyDocument: { + Statement: [ + { + Action: "*", + Condition: { + Bool: { + "aws:SecureTransport": "false" + } + }, + Effect: "Deny", + Principal: "*", + Resource: { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "S3Bucket07682993", + "Arn" + ] + }, + "/*" + ] + ] + } + }, + { + Action: [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + Effect: "Allow", + Principal: { + CanonicalUser: { + "Fn::GetAtt": [ + "CloudFrontDistributionOrigin1S3Origin3D9CA0E9", + "S3CanonicalUserId" + ] + } + }, + Resource: [ + { + "Fn::GetAtt": [ + "S3Bucket07682993", + "Arn" + ] }, - Effect: "Deny", - Principal: "*", - Resource: { + { "Fn::Join": [ "", [ @@ -95,49 +132,12 @@ test('test cloudfront check bucket policy', () => { ] ] } - }, - { - Action: [ - "s3:GetObject*", - "s3:GetBucket*", - "s3:List*" - ], - Effect: "Allow", - Principal: { - CanonicalUser: { - "Fn::GetAtt": [ - "CloudFrontDistributionOrigin1S3Origin3D9CA0E9", - "S3CanonicalUserId" - ] - } - }, - Resource: [ - { - "Fn::GetAtt": [ - "S3Bucket07682993", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "S3Bucket07682993", - "Arn" - ] - }, - "/*" - ] - ] - } - ] - } - ], - Version: "2012-10-17" - } - }); + ] + } + ], + Version: "2012-10-17" + } + }); }); test('test cloudfront with no security headers ', () => { @@ -341,85 +341,85 @@ test('test cloudfront override cloudfront logging bucket ', () => { }); test('test cloudfront override properties', () => { - const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); - const props: cloudfront.DistributionProps = { - defaultBehavior: { - origin: new origins.S3Origin(sourceBucket), - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, - allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, - cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS - }, - }; + const stack = new Stack(); + const [sourceBucket] = buildS3Bucket(stack, {}); + const props: cloudfront.DistributionProps = { + defaultBehavior: { + origin: new origins.S3Origin(sourceBucket), + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, + cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS + }, + }; - CloudFrontDistributionForS3(stack, sourceBucket, props); + CloudFrontDistributionForS3(stack, sourceBucket, props); - expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { - DistributionConfig: { - DefaultCacheBehavior: { - AllowedMethods: [ - "GET", - "HEAD", - "OPTIONS", - "PUT", - "PATCH", - "POST", - "DELETE" - ], - CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", - CachedMethods: [ - "GET", - "HEAD", - "OPTIONS" - ], - Compress: true, - LambdaFunctionAssociations: [ - { - EventType: "origin-response", - LambdaFunctionARN: { - Ref: "SetHttpSecurityHeadersVersion660E2F72" - } + expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { + DistributionConfig: { + DefaultCacheBehavior: { + AllowedMethods: [ + "GET", + "HEAD", + "OPTIONS", + "PUT", + "PATCH", + "POST", + "DELETE" + ], + CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", + CachedMethods: [ + "GET", + "HEAD", + "OPTIONS" + ], + Compress: true, + LambdaFunctionAssociations: [ + { + EventType: "origin-response", + LambdaFunctionARN: { + Ref: "SetHttpSecurityHeadersVersion660E2F72" } - ], - TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", - ViewerProtocolPolicy: "redirect-to-https" - }, - DefaultRootObject: "index.html", - Enabled: true, - HttpVersion: "http2", - IPV6Enabled: true, - Logging: { - Bucket: { + } + ], + TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", + ViewerProtocolPolicy: "redirect-to-https" + }, + DefaultRootObject: "index.html", + Enabled: true, + HttpVersion: "http2", + IPV6Enabled: true, + Logging: { + Bucket: { + "Fn::GetAtt": [ + "CloudfrontLoggingBucket3C3EFAA7", + "RegionalDomainName" + ] + } + }, + Origins: [ + { + DomainName: { "Fn::GetAtt": [ - "CloudfrontLoggingBucket3C3EFAA7", + "S3Bucket07682993", "RegionalDomainName" ] - } - }, - Origins: [ - { - DomainName: { - "Fn::GetAtt": [ - "S3Bucket07682993", - "RegionalDomainName" - ] - }, - Id: "CloudFrontDistributionOrigin176EC3A12", - S3OriginConfig: { - OriginAccessIdentity: { - "Fn::Join": [ - "", - [ - "origin-access-identity/cloudfront/", - { - Ref: "CloudFrontDistributionOrigin1S3Origin3D9CA0E9" - } - ] + }, + Id: "CloudFrontDistributionOrigin176EC3A12", + S3OriginConfig: { + OriginAccessIdentity: { + "Fn::Join": [ + "", + [ + "origin-access-identity/cloudfront/", + { + Ref: "CloudFrontDistributionOrigin1S3Origin3D9CA0E9" + } ] - } + ] } } - ] - } - }); - }); \ No newline at end of file + } + ] + } + }); +}); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/test/cloudwatch-log-group.test.ts b/source/patterns/@aws-solutions-constructs/core/test/cloudwatch-log-group.test.ts index 3de0ee861..d0d45a366 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/cloudwatch-log-group.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/cloudwatch-log-group.test.ts @@ -18,13 +18,13 @@ import '@aws-cdk/assert/jest'; import * as logs from '@aws-cdk/aws-logs'; test('cw log group with default params', () => { - const stack = new Stack(); - new logs.LogGroup(stack, 'test-cw-logs-default', defaults.DefaultLogGroupProps()); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + new logs.LogGroup(stack, 'test-cw-logs-default', defaults.DefaultLogGroupProps()); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); test('cw log group with log group name', () => { - const stack = new Stack(); - new logs.LogGroup(stack, 'test-cw-logs-default', defaults.DefaultLogGroupProps('lambda-log-group')); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + new logs.LogGroup(stack, 'test-cw-logs-default', defaults.DefaultLogGroupProps('lambda-log-group')); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/test/dynamo-table.test.ts b/source/patterns/@aws-solutions-constructs/core/test/dynamo-table.test.ts index 22f1d85f4..7289314ec 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/dynamo-table.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/dynamo-table.test.ts @@ -19,9 +19,9 @@ import { overrideProps } from '../lib/utils'; import '@aws-cdk/assert/jest'; test('snapshot test TableProps default params', () => { - const stack = new Stack(); - new dynamodb.Table(stack, 'test-dynamo-defaults', defaults.DefaultTableProps); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + new dynamodb.Table(stack, 'test-dynamo-defaults', defaults.DefaultTableProps); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); test('snapshot test TableWithStream default params', () => { @@ -31,91 +31,91 @@ test('snapshot test TableWithStream default params', () => { }); test('test TableProps change billing mode', () => { - const stack = new Stack(); - - const defaultProps: dynamodb.TableProps = defaults.DefaultTableProps; - - const inProps: dynamodb.TableProps = { - billingMode: dynamodb.BillingMode.PROVISIONED, - readCapacity: 3, - writeCapacity: 3, - partitionKey: { - name: 'id', - type: dynamodb.AttributeType.STRING - } - }; - - const outProps = overrideProps(defaultProps, inProps); - new dynamodb.Table(stack, 'test-dynamo-override', outProps); - - expect(stack).toHaveResource("AWS::DynamoDB::Table", { - KeySchema: [ - { - AttributeName: "id", - KeyType: "HASH" - } - ], - AttributeDefinitions: [ - { - AttributeName: "id", - AttributeType: "S" - } - ], - ProvisionedThroughput: { - ReadCapacityUnits: 3, - WriteCapacityUnits: 3 - }, - SSESpecification: { - SSEEnabled: true - } - }); + const stack = new Stack(); + + const defaultProps: dynamodb.TableProps = defaults.DefaultTableProps; + + const inProps: dynamodb.TableProps = { + billingMode: dynamodb.BillingMode.PROVISIONED, + readCapacity: 3, + writeCapacity: 3, + partitionKey: { + name: 'id', + type: dynamodb.AttributeType.STRING + } + }; + + const outProps = overrideProps(defaultProps, inProps); + new dynamodb.Table(stack, 'test-dynamo-override', outProps); + + expect(stack).toHaveResource("AWS::DynamoDB::Table", { + KeySchema: [ + { + AttributeName: "id", + KeyType: "HASH" + } + ], + AttributeDefinitions: [ + { + AttributeName: "id", + AttributeType: "S" + } + ], + ProvisionedThroughput: { + ReadCapacityUnits: 3, + WriteCapacityUnits: 3 + }, + SSESpecification: { + SSEEnabled: true + } + }); }); test('test TableProps override add sort key', () => { - const stack = new Stack(); - - const defaultProps: dynamodb.TableProps = defaults.DefaultTableProps; - - const inProps: dynamodb.TableProps = { - partitionKey: { - name: 'id', - type: dynamodb.AttributeType.STRING - }, - sortKey: { - name: 'sort_key', - type: dynamodb.AttributeType.STRING - } - }; - - const outProps = overrideProps(defaultProps, inProps); - new dynamodb.Table(stack, 'test-dynamo-override', outProps); - - expect(stack).toHaveResource("AWS::DynamoDB::Table", { - KeySchema: [ - { - AttributeName: "id", - KeyType: "HASH" - }, - { - AttributeName: "sort_key", - KeyType: "RANGE" - } - ], - AttributeDefinitions: [ - { - AttributeName: "id", - AttributeType: "S" - }, - { - AttributeName: "sort_key", - AttributeType: "S" - } - ], - BillingMode: "PAY_PER_REQUEST", - SSESpecification: { - SSEEnabled: true - } - }); + const stack = new Stack(); + + const defaultProps: dynamodb.TableProps = defaults.DefaultTableProps; + + const inProps: dynamodb.TableProps = { + partitionKey: { + name: 'id', + type: dynamodb.AttributeType.STRING + }, + sortKey: { + name: 'sort_key', + type: dynamodb.AttributeType.STRING + } + }; + + const outProps = overrideProps(defaultProps, inProps); + new dynamodb.Table(stack, 'test-dynamo-override', outProps); + + expect(stack).toHaveResource("AWS::DynamoDB::Table", { + KeySchema: [ + { + AttributeName: "id", + KeyType: "HASH" + }, + { + AttributeName: "sort_key", + KeyType: "RANGE" + } + ], + AttributeDefinitions: [ + { + AttributeName: "id", + AttributeType: "S" + }, + { + AttributeName: "sort_key", + AttributeType: "S" + } + ], + BillingMode: "PAY_PER_REQUEST", + SSESpecification: { + SSEEnabled: true + } + }); }); test('test TableWithStreamProps override stream view type', () => { @@ -124,11 +124,11 @@ test('test TableWithStreamProps override stream view type', () => { const defaultProps: dynamodb.TableProps = defaults.DefaultTableWithStreamProps; const inProps: dynamodb.TableProps = { - partitionKey: { - name: 'id', - type: dynamodb.AttributeType.STRING - }, - stream: dynamodb.StreamViewType.NEW_IMAGE + partitionKey: { + name: 'id', + type: dynamodb.AttributeType.STRING + }, + stream: dynamodb.StreamViewType.NEW_IMAGE }; const outProps = overrideProps(defaultProps, inProps); diff --git a/source/patterns/@aws-solutions-constructs/core/test/elasticsearch-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/elasticsearch-helper.test.ts index 8ee751209..8f55398a7 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/elasticsearch-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/elasticsearch-helper.test.ts @@ -19,7 +19,7 @@ import '@aws-cdk/assert/jest'; import * as iam from '@aws-cdk/aws-iam'; function deployES(stack: Stack, domainName: string, cfnDomainProps?: elasticsearch.CfnDomainProps, - lambdaRoleARN?: string): [elasticsearch.CfnDomain, iam.Role] { + lambdaRoleARN?: string): [elasticsearch.CfnDomain, iam.Role] { const userpool = defaults.buildUserPool(stack); const userpoolclient = defaults.buildUserPoolClient(stack, userpool, { userPoolClientName: 'test', diff --git a/source/patterns/@aws-solutions-constructs/core/test/iot-rule.test.ts b/source/patterns/@aws-solutions-constructs/core/test/iot-rule.test.ts index 647393972..06a0c114c 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/iot-rule.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/iot-rule.test.ts @@ -20,99 +20,99 @@ import { overrideProps } from '../lib/utils'; import '@aws-cdk/assert/jest'; test('snapshot test TopicRuleProps default params', () => { - const stack = new Stack(); - - const lambdaFunctionProps: lambda.FunctionProps = { - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`) - }; - - const fn = new lambda.Function(stack, 'LambdaFunction', lambdaFunctionProps); - - const defaultIotTopicProps = defaults.DefaultCfnTopicRuleProps([{ - lambda: { - functionArn: fn.functionArn - } - }], "SELECT * FROM 'topic/#'"); - new iot.CfnTopicRule(stack, 'IotTopic', defaultIotTopicProps); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + + const lambdaFunctionProps: lambda.FunctionProps = { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(`${__dirname}/lambda`) + }; + + const fn = new lambda.Function(stack, 'LambdaFunction', lambdaFunctionProps); + + const defaultIotTopicProps = defaults.DefaultCfnTopicRuleProps([{ + lambda: { + functionArn: fn.functionArn + } + }], "SELECT * FROM 'topic/#'"); + new iot.CfnTopicRule(stack, 'IotTopic', defaultIotTopicProps); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); test('test TopicRuleProps override sql and description', () => { - const stack = new Stack(); - - const action1: iot.CfnTopicRule.ActionProperty = { - lambda: { - functionArn: 'xyz' - } - }; - - const defaultProps: iot.CfnTopicRuleProps = defaults.DefaultCfnTopicRuleProps([action1]); - - const inProps: iot.CfnTopicRuleProps = { - topicRulePayload: { - ruleDisabled: true, - description: "Processing of vehicle messages", - sql: "SELECT * FROM 'connectedcar/#'", - actions: [] - } - }; - - const outProps = overrideProps(defaultProps, inProps, true); - - new iot.CfnTopicRule(stack, 'IotTopic', outProps); - - expect(stack).toHaveResource('AWS::IoT::TopicRule', { - TopicRulePayload: { - Actions: [ - { - Lambda: { - FunctionArn: "xyz" - } - } - ], - Description: "Processing of vehicle messages", - RuleDisabled: true, - Sql: "SELECT * FROM 'connectedcar/#'" + const stack = new Stack(); + + const action1: iot.CfnTopicRule.ActionProperty = { + lambda: { + functionArn: 'xyz' + } + }; + + const defaultProps: iot.CfnTopicRuleProps = defaults.DefaultCfnTopicRuleProps([action1]); + + const inProps: iot.CfnTopicRuleProps = { + topicRulePayload: { + ruleDisabled: true, + description: "Processing of vehicle messages", + sql: "SELECT * FROM 'connectedcar/#'", + actions: [] + } + }; + + const outProps = overrideProps(defaultProps, inProps, true); + + new iot.CfnTopicRule(stack, 'IotTopic', outProps); + + expect(stack).toHaveResource('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + { + Lambda: { + FunctionArn: "xyz" + } } - }); + ], + Description: "Processing of vehicle messages", + RuleDisabled: true, + Sql: "SELECT * FROM 'connectedcar/#'" + } + }); }); test('test TopicRuleProps override actions', () => { - const stack = new Stack(); - - const defaultProps: iot.CfnTopicRuleProps = defaults.DefaultCfnTopicRuleProps([], ''); - - const action: iot.CfnTopicRule.ActionProperty = { - lambda: { - functionArn: 'abc' - } - }; - - const inProps: iot.CfnTopicRuleProps = { - topicRulePayload: { - ruleDisabled: true, - sql: '', - actions: [action] - } - }; - - const outProps = overrideProps(defaultProps, inProps); - - new iot.CfnTopicRule(stack, 'IotTopic', outProps); - - expect(stack).toHaveResource('AWS::IoT::TopicRule', { - TopicRulePayload: { - Actions: [ - { - Lambda: { - FunctionArn: "abc" - } - } - ], - RuleDisabled: true, - Sql: "" + const stack = new Stack(); + + const defaultProps: iot.CfnTopicRuleProps = defaults.DefaultCfnTopicRuleProps([], ''); + + const action: iot.CfnTopicRule.ActionProperty = { + lambda: { + functionArn: 'abc' + } + }; + + const inProps: iot.CfnTopicRuleProps = { + topicRulePayload: { + ruleDisabled: true, + sql: '', + actions: [action] + } + }; + + const outProps = overrideProps(defaultProps, inProps); + + new iot.CfnTopicRule(stack, 'IotTopic', outProps); + + expect(stack).toHaveResource('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + { + Lambda: { + FunctionArn: "abc" + } } - }); + ], + RuleDisabled: true, + Sql: "" + } + }); }); diff --git a/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics-helper.test.ts index ae3ed3fbc..6d4ffcff3 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/kinesis-analytics-helper.test.ts @@ -22,41 +22,41 @@ import '@aws-cdk/assert/jest'; // Test default functionality // -------------------------------------------------------------- test('Test default functionality', () => { - // Setup the stack - const stack = new Stack(); - const firehose = new kinesisFirehose.CfnDeliveryStream(stack, 'KinesisFirehose'); - // Setup the Kinesis Analytics application - defaults.buildKinesisAnalyticsApp(stack, { - kinesisFirehose: firehose, - kinesisAnalyticsProps: { - inputs: [{ - inputSchema: { - recordColumns: [{ - name: 'ticker_symbol', - sqlType: 'VARCHAR(4)', - mapping: '$.ticker_symbol' - }, { - name: 'sector', - sqlType: 'VARCHAR(16)', - mapping: '$.sector' - }, { - name: 'change', - sqlType: 'REAL', - mapping: '$.change' - }, { - name: 'price', - sqlType: 'REAL', - mapping: '$.price' - }], - recordFormat: { - recordFormatType: 'JSON' - }, - recordEncoding: 'UTF-8' - }, - namePrefix: 'SOURCE_SQL_STREAM' - }] - } - }); - // Assertions - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Setup the stack + const stack = new Stack(); + const firehose = new kinesisFirehose.CfnDeliveryStream(stack, 'KinesisFirehose'); + // Setup the Kinesis Analytics application + defaults.buildKinesisAnalyticsApp(stack, { + kinesisFirehose: firehose, + kinesisAnalyticsProps: { + inputs: [{ + inputSchema: { + recordColumns: [{ + name: 'ticker_symbol', + sqlType: 'VARCHAR(4)', + mapping: '$.ticker_symbol' + }, { + name: 'sector', + sqlType: 'VARCHAR(16)', + mapping: '$.sector' + }, { + name: 'change', + sqlType: 'REAL', + mapping: '$.change' + }, { + name: 'price', + sqlType: 'REAL', + mapping: '$.price' + }], + recordFormat: { + recordFormatType: 'JSON' + }, + recordEncoding: 'UTF-8' + }, + namePrefix: 'SOURCE_SQL_STREAM' + }] + } + }); + // Assertions + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); \ No newline at end of file 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 4751605a5..8b58b8558 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 @@ -19,48 +19,48 @@ import { overrideProps } from '../lib/utils'; import '@aws-cdk/assert/jest'; test('snapshot test kinesisanalytics default params', () => { - const stack = new Stack(); - new kinesisanalytics.CfnApplication(stack, 'KinesisAnalytics', defaults.DefaultCfnApplicationProps); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + new kinesisanalytics.CfnApplication(stack, 'KinesisAnalytics', defaults.DefaultCfnApplicationProps); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); test('test kinesisanalytics override inputProperty', () => { - const stack = new Stack(); + const stack = new Stack(); - const inputProperty: kinesisanalytics.CfnApplication.InputProperty = { - inputSchema: { - recordColumns: [{name: 'x', sqlType: 'y'}], - recordFormat: { recordFormatType: 'csv' } - }, - namePrefix: 'zzz' - }; + const inputProperty: kinesisanalytics.CfnApplication.InputProperty = { + inputSchema: { + recordColumns: [{name: 'x', sqlType: 'y'}], + recordFormat: { recordFormatType: 'csv' } + }, + namePrefix: 'zzz' + }; - const defaultProps: kinesisanalytics.CfnApplicationProps = defaults.DefaultCfnApplicationProps; + const defaultProps: kinesisanalytics.CfnApplicationProps = defaults.DefaultCfnApplicationProps; - const inProps: kinesisanalytics.CfnApplicationProps = { - inputs: [inputProperty] - }; + const inProps: kinesisanalytics.CfnApplicationProps = { + inputs: [inputProperty] + }; - const outProps = overrideProps(defaultProps, inProps); + const outProps = overrideProps(defaultProps, inProps); - new kinesisanalytics.CfnApplication(stack, 'KinesisAnalytics', outProps); + new kinesisanalytics.CfnApplication(stack, 'KinesisAnalytics', outProps); - expect(stack).toHaveResource("AWS::KinesisAnalytics::Application", { - Inputs: [ - { - InputSchema: { - RecordColumns: [ - { - Name: "x", - SqlType: "y" - } - ], - RecordFormat: { - RecordFormatType: "csv" - } - }, - NamePrefix: "zzz" + expect(stack).toHaveResource("AWS::KinesisAnalytics::Application", { + Inputs: [ + { + InputSchema: { + RecordColumns: [ + { + Name: "x", + SqlType: "y" + } + ], + RecordFormat: { + RecordFormatType: "csv" } - ] - }); + }, + NamePrefix: "zzz" + } + ] + }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/test/kinesis-firehose-s3-defaults.test.ts b/source/patterns/@aws-solutions-constructs/core/test/kinesis-firehose-s3-defaults.test.ts index 67b6adf34..b315caa7f 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/kinesis-firehose-s3-defaults.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/kinesis-firehose-s3-defaults.test.ts @@ -20,72 +20,72 @@ import '@aws-cdk/assert/jest'; import * as kms from '@aws-cdk/aws-kms'; test('snapshot test kinesisfirehose default params', () => { - const stack = new Stack(); + const stack = new Stack(); - const awsManagedKey: kms.IKey = kms.Alias.fromAliasName(stack, 'aws-managed-key', 'alias/aws/s3'); + const awsManagedKey: kms.IKey = kms.Alias.fromAliasName(stack, 'aws-managed-key', 'alias/aws/s3'); - new kinesisfirehose.CfnDeliveryStream(stack, 'KinesisFirehose', - defaults.DefaultCfnDeliveryStreamProps('bucket_arn', 'role_arn', 'log_group', 'log_stream', awsManagedKey)); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + new kinesisfirehose.CfnDeliveryStream(stack, 'KinesisFirehose', + defaults.DefaultCfnDeliveryStreamProps('bucket_arn', 'role_arn', 'log_group', 'log_stream', awsManagedKey)); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); test('test kinesisanalytics override buffer conditions', () => { - const stack = new Stack(); + const stack = new Stack(); - const inProps = { - extendedS3DestinationConfiguration: { - bufferingHints: { - intervalInSeconds: 600, - sizeInMBs: 10 - }, - } - }; - const awsManagedKey: kms.IKey = kms.Alias.fromAliasName(stack, 'aws-managed-key', 'alias/aws/s3'); + const inProps = { + extendedS3DestinationConfiguration: { + bufferingHints: { + intervalInSeconds: 600, + sizeInMBs: 10 + }, + } + }; + const awsManagedKey: kms.IKey = kms.Alias.fromAliasName(stack, 'aws-managed-key', 'alias/aws/s3'); - const defaultProps = defaults.DefaultCfnDeliveryStreamProps('bucket_arn', 'role_arn', 'log_group', 'log_stream', awsManagedKey); + const defaultProps = defaults.DefaultCfnDeliveryStreamProps('bucket_arn', 'role_arn', 'log_group', 'log_stream', awsManagedKey); - const outProps = overrideProps(defaultProps, inProps); + const outProps = overrideProps(defaultProps, inProps); - new kinesisfirehose.CfnDeliveryStream(stack, 'KinesisFirehose', outProps); + new kinesisfirehose.CfnDeliveryStream(stack, 'KinesisFirehose', outProps); - expect(stack).toHaveResource("AWS::KinesisFirehose::DeliveryStream", { - ExtendedS3DestinationConfiguration: { - BucketARN: "bucket_arn", - BufferingHints: { - IntervalInSeconds: 600, - SizeInMBs: 10 - }, - CloudWatchLoggingOptions: { - Enabled: true, - LogGroupName: "log_group", - LogStreamName: "log_stream" - }, - CompressionFormat: "GZIP", - EncryptionConfiguration: { - KMSEncryptionConfig: { - AWSKMSKeyARN: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition" - }, - ":kms:", - { - Ref: "AWS::Region" - }, - ":", - { - Ref: "AWS::AccountId" - }, - ":alias/aws/s3" - ] - ] - } - } - }, - RoleARN: "role_arn" + expect(stack).toHaveResource("AWS::KinesisFirehose::DeliveryStream", { + ExtendedS3DestinationConfiguration: { + BucketARN: "bucket_arn", + BufferingHints: { + IntervalInSeconds: 600, + SizeInMBs: 10 + }, + CloudWatchLoggingOptions: { + Enabled: true, + LogGroupName: "log_group", + LogStreamName: "log_stream" + }, + CompressionFormat: "GZIP", + EncryptionConfiguration: { + KMSEncryptionConfig: { + AWSKMSKeyARN: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition" + }, + ":kms:", + { + Ref: "AWS::Region" + }, + ":", + { + Ref: "AWS::AccountId" + }, + ":alias/aws/s3" + ] + ] + } } - }); + }, + RoleARN: "role_arn" + } + }); }); diff --git a/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-defaults.test.ts b/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-defaults.test.ts index fa77d5605..4b5ea9f1d 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-defaults.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-defaults.test.ts @@ -19,25 +19,25 @@ import { overrideProps } from '../lib/utils'; import '@aws-cdk/assert/jest'; test('snapshot test kinesisstream default params', () => { - const stack = new Stack(); - new kinesis.Stream(stack, 'KinesisStream', defaults.DefaultStreamProps); - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + const stack = new Stack(); + new kinesis.Stream(stack, 'KinesisStream', defaults.DefaultStreamProps); + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); test('test kinesisstream override RetentionPeriodHours', () => { - const stack = new Stack(); + const stack = new Stack(); - const defaultProps = defaults.DefaultStreamProps; + const defaultProps = defaults.DefaultStreamProps; - const inProps: kinesis.StreamProps = { - retentionPeriod: Duration.hours(48) - }; + const inProps: kinesis.StreamProps = { + retentionPeriod: Duration.hours(48) + }; - const outProps = overrideProps(defaultProps, inProps); + const outProps = overrideProps(defaultProps, inProps); - new kinesis.Stream(stack, 'KinesisStream', outProps); + new kinesis.Stream(stack, 'KinesisStream', outProps); - expect(stack).toHaveResource("AWS::Kinesis::Stream", { - RetentionPeriodHours: 48 - }); + expect(stack).toHaveResource("AWS::Kinesis::Stream", { + RetentionPeriodHours: 48 + }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-helper.test.ts index 180c2a5e8..982abac16 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/kinesis-streams-helper.test.ts @@ -22,21 +22,21 @@ import '@aws-cdk/assert/jest'; // Test minimal deployment with no properties // -------------------------------------------------------------- test('Test minimal deployment with no properties', () => { - // Stack - const stack = new Stack(); - // Helper declaration - defaults.buildKinesisStream(stack, {}); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { - Type: "AWS::Kinesis::Stream", - Properties: { - StreamEncryption: { - EncryptionType: "KMS" - } - } - }, ResourcePart.CompleteDefinition); + // Stack + const stack = new Stack(); + // Helper declaration + defaults.buildKinesisStream(stack, {}); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { + Type: "AWS::Kinesis::Stream", + Properties: { + StreamEncryption: { + EncryptionType: "KMS" + } + } + }, ResourcePart.CompleteDefinition); }); // -------------------------------------------------------------- @@ -49,21 +49,21 @@ test('Test deployment w/ custom properties', () => { const encKey = defaults.buildEncryptionKey(stack); // Helper declaration defaults.buildKinesisStream(stack, { - kinesisStreamProps: { - streamName: 'myCustomKinesisStream', - encryption: kinesis.StreamEncryption.KMS, - encryptionKey: encKey - } + kinesisStreamProps: { + streamName: 'myCustomKinesisStream', + encryption: kinesis.StreamEncryption.KMS, + encryptionKey: encKey + } }); // Assertion 1 expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); // Assertion 2 expect(stack).toHaveResource('AWS::Kinesis::Stream', { - Name: 'myCustomKinesisStream' + Name: 'myCustomKinesisStream' }); // Assertion 3 expect(stack).toHaveResource('AWS::KMS::Key', { - EnableKeyRotation: true + EnableKeyRotation: true }); }); diff --git a/source/patterns/@aws-solutions-constructs/core/test/kms-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/kms-helper.test.ts index dc3b79fe9..1e9a44fa6 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/kms-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/kms-helper.test.ts @@ -21,19 +21,19 @@ import '@aws-cdk/assert/jest'; // Test minimal deployment with no properties // -------------------------------------------------------------- test('Test minimal deployment with no properties', () => { - // Stack - const stack = new Stack(); - // Helper declaration - defaults.buildEncryptionKey(stack); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResourceLike('AWS::KMS::Key', { - Type: "AWS::KMS::Key", - Properties: { - EnableKeyRotation: true - } - }, ResourcePart.CompleteDefinition); + // Stack + const stack = new Stack(); + // Helper declaration + defaults.buildEncryptionKey(stack); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResourceLike('AWS::KMS::Key', { + Type: "AWS::KMS::Key", + Properties: { + EnableKeyRotation: true + } + }, ResourcePart.CompleteDefinition); }); // -------------------------------------------------------------- @@ -50,9 +50,9 @@ test('Test minimal deployment with custom properties', () => { expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); // Assertion 2 expect(stack).toHaveResourceLike('AWS::KMS::Key', { - Type: "AWS::KMS::Key", - Properties: { - EnableKeyRotation: false - } - }, ResourcePart.CompleteDefinition); + Type: "AWS::KMS::Key", + Properties: { + EnableKeyRotation: false + } + }, ResourcePart.CompleteDefinition); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/test/lambda-event-source.test.ts b/source/patterns/@aws-solutions-constructs/core/test/lambda-event-source.test.ts index aedf3fd65..71f0bf405 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/lambda-event-source.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/lambda-event-source.test.ts @@ -142,7 +142,7 @@ test('test sqsDlqQueueProps override', () => { }); expect(stack).toHaveResource("AWS::SQS::Queue", { - QueueName: "hello-world", - VisibilityTimeout: 50 + QueueName: "hello-world", + VisibilityTimeout: 50 }); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/core/test/lambda-func.test.ts b/source/patterns/@aws-solutions-constructs/core/test/lambda-helper.test.ts similarity index 88% rename from source/patterns/@aws-solutions-constructs/core/test/lambda-func.test.ts rename to source/patterns/@aws-solutions-constructs/core/test/lambda-helper.test.ts index 6ac5b925a..290dfa6b1 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/lambda-func.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/lambda-helper.test.ts @@ -197,6 +197,25 @@ test("test buildLambdaFunction with deploy = true", () => { }); }); +test("test buildLambdaFunction with existing Lambda function (no VPC)", () => { + const stack = new Stack(); + + const inProps: lambda.FunctionProps = { + code: lambda.Code.fromAsset(`${__dirname}/lambda-test`), + runtime: lambda.Runtime.NODEJS_12_X, + handler: "index.handler", + }; + + const newFunction = new lambda.Function(stack, "existingFunction", inProps); + + const construct = defaults.buildLambdaFunction(stack, { + existingLambdaObj: newFunction + }); + + expect(construct).toBe(newFunction); + +}); + test("test buildLambdaFunction with FunctionProps", () => { const stack = new Stack(); @@ -286,3 +305,22 @@ test("test buildLambdaFunction when Lambda properties includes a VPC", () => { }, }); }); + +test("Test for error if VPC in arguments AND in Lambda Function properties", () => { + const stack = new Stack(); + + const fakeVpc = new ec2.Vpc(stack, "vpc", {}); + + const lambdaFunctionProps: lambda.FunctionProps = { + runtime: lambda.Runtime.NODEJS_12_X, + handler: "index.handler", + code: lambda.Code.fromAsset(`${__dirname}/lambda`), + vpc: fakeVpc, + }; + + const app = () => { + defaults.deployLambdaFunction(stack, lambdaFunctionProps, undefined, fakeVpc); + }; + + expect(app).toThrowError(); +}); diff --git a/source/patterns/@aws-solutions-constructs/core/test/s3-bucket-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/s3-bucket-helper.test.ts index a3497ca9f..a8cd7a4b4 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/s3-bucket-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/s3-bucket-helper.test.ts @@ -27,7 +27,7 @@ test('s3 bucket with default params', () => { test('s3 bucket with default params and bucket names', () => { const stack = new Stack(); const s3BucketProps: s3.BucketProps = { - bucketName: 'my-bucket' + bucketName: 'my-bucket' }; defaults.buildS3Bucket(stack, { bucketProps: s3BucketProps @@ -81,11 +81,11 @@ test('s3 bucket with life cycle policy', () => { lifecycleRules: [{ expiration: Duration.days(365), transitions: [{ - storageClass: StorageClass.INFREQUENT_ACCESS, - transitionAfter: Duration.days(30) + storageClass: StorageClass.INFREQUENT_ACCESS, + transitionAfter: Duration.days(30) }, { - storageClass: StorageClass.GLACIER, - transitionAfter: Duration.days(90) + storageClass: StorageClass.GLACIER, + transitionAfter: Duration.days(90) }] }] } @@ -114,24 +114,24 @@ test('s3 bucket with life cycle policy', () => { }); test('s3 bucket with access logging configured', () => { - const stack = new Stack(); - const mybucket = new Bucket(stack, 'mybucket', { - serverAccessLogsBucket: new Bucket(stack, 'myaccesslogbucket', {}) - }); + const stack = new Stack(); + const mybucket = new Bucket(stack, 'mybucket', { + serverAccessLogsBucket: new Bucket(stack, 'myaccesslogbucket', {}) + }); - defaults.buildS3Bucket(stack, { - bucketProps: { - serverAccessLogsBucket: mybucket - } - }); + defaults.buildS3Bucket(stack, { + bucketProps: { + serverAccessLogsBucket: mybucket + } + }); - expectCDK(stack).to(haveResource("AWS::S3::Bucket", { - LoggingConfiguration: { - DestinationBucketName: { - Ref: "mybucket160F8132" - } - }, - })); + expectCDK(stack).to(haveResource("AWS::S3::Bucket", { + LoggingConfiguration: { + DestinationBucketName: { + Ref: "mybucket160F8132" + } + }, + })); }); test('Check S3 Bucket policy', () => { diff --git a/source/patterns/@aws-solutions-constructs/core/test/s3-bucket.test.ts b/source/patterns/@aws-solutions-constructs/core/test/s3-bucket.test.ts index 49fe2ee5b..078d56345 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/s3-bucket.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/s3-bucket.test.ts @@ -26,8 +26,8 @@ test('s3 bucket with default params', () => { /** Default Life Cycle policy to transition older versions to Glacier after 90 days */ const lifecycleRules: s3.LifecycleRule[] = [{ noncurrentVersionTransitions: [{ - storageClass: StorageClass.GLACIER, - transitionAfter: Duration.days(90) + storageClass: StorageClass.GLACIER, + transitionAfter: Duration.days(90) }] }]; diff --git a/source/patterns/@aws-solutions-constructs/core/test/sagemaker-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/sagemaker-helper.test.ts index 1e3e9caf9..4a467aa22 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/sagemaker-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/sagemaker-helper.test.ts @@ -23,60 +23,60 @@ import '@aws-cdk/assert/jest'; // Test minimal deployment with no properties // -------------------------------------------------------------- test('Test minimal deployment with no properties', () => { - // Stack - const stack = new Stack(); - const sagemakerRole = new iam.Role(stack, "SagemakerRole", { - assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), - }); + // Stack + const stack = new Stack(); + const sagemakerRole = new iam.Role(stack, "SagemakerRole", { + assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), + }); // Build SageMaker Notebook Instance - defaults.buildSagemakerNotebook(stack, { - role: sagemakerRole, - }); - // Assertion - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + defaults.buildSagemakerNotebook(stack, { + role: sagemakerRole, + }); + // Assertion + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment with VPC // -------------------------------------------------------------- test('Test deployment with VPC', () => { - // Stack - const stack = new Stack(); - const sagemakerRole = new iam.Role(stack, "SagemakerRole", { - assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), - }); - let sagemaker; - let vpc; - let sg; + // Stack + const stack = new Stack(); + const sagemakerRole = new iam.Role(stack, "SagemakerRole", { + assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), + }); + let sagemaker; + let vpc; + let sg; - // Build SageMaker Notebook Instance - [sagemaker, vpc, sg] = defaults.buildSagemakerNotebook(stack, { - role: sagemakerRole, - }); - // Assertion - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - expect(vpc?.privateSubnets.length).toEqual(2); - expect(vpc?.publicSubnets.length).toEqual(2); - expect(sagemaker.instanceType).toEqual('ml.t2.medium'); - expect(sg).toBeInstanceOf(ec2.SecurityGroup); + // Build SageMaker Notebook Instance + [sagemaker, vpc, sg] = defaults.buildSagemakerNotebook(stack, { + role: sagemakerRole, + }); + // Assertion + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + expect(vpc?.privateSubnets.length).toEqual(2); + expect(vpc?.publicSubnets.length).toEqual(2); + expect(sagemaker.instanceType).toEqual('ml.t2.medium'); + expect(sg).toBeInstanceOf(ec2.SecurityGroup); }); // -------------------------------------------------------------- // Test deployment witout VPC // -------------------------------------------------------------- test('Test deployment w/o VPC', () => { - // Stack - const stack = new Stack(); - const sagemakerRole = new iam.Role(stack, "SagemakerRole", { - assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), - }); + // Stack + const stack = new Stack(); + const sagemakerRole = new iam.Role(stack, "SagemakerRole", { + assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), + }); // Build SageMaker Notebook Instance - defaults.buildSagemakerNotebook(stack, { - role: sagemakerRole, - deployInsideVpc: false - }); - // Assertion - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + defaults.buildSagemakerNotebook(stack, { + role: sagemakerRole, + deployInsideVpc: false + }); + // Assertion + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); @@ -84,27 +84,27 @@ test('Test deployment w/o VPC', () => { // Test deployment in existing VPC // -------------------------------------------------------------- test('Test deployment w/ existing VPC', () => { - // Stack - const stack = new Stack(); - const sagemakerRole = new iam.Role(stack, "SagemakerRole", { - assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), - }); + // Stack + const stack = new Stack(); + const sagemakerRole = new iam.Role(stack, "SagemakerRole", { + assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), + }); // Build SageMaker Notebook Instance - defaults.buildSagemakerNotebook(stack, { - role: sagemakerRole, - deployInsideVpc: true, - sagemakerNotebookProps: { - subnetId: 'subnet-deadbeef', - securityGroupIds: ['sg-deadbeef'] - } - }); - expect(stack).toHaveResource("AWS::SageMaker::NotebookInstance", { - DirectInternetAccess: "Disabled", - SecurityGroupIds: [ - "sg-deadbeef" - ], - SubnetId: "subnet-deadbeef" - }); + defaults.buildSagemakerNotebook(stack, { + role: sagemakerRole, + deployInsideVpc: true, + sagemakerNotebookProps: { + subnetId: 'subnet-deadbeef', + securityGroupIds: ['sg-deadbeef'] + } + }); + expect(stack).toHaveResource("AWS::SageMaker::NotebookInstance", { + DirectInternetAccess: "Disabled", + SecurityGroupIds: [ + "sg-deadbeef" + ], + SubnetId: "subnet-deadbeef" + }); }); @@ -112,50 +112,50 @@ test('Test deployment w/ existing VPC', () => { // Test deployment with override // -------------------------------------------------------------- test('Test deployment w/ override', () => { - // Stack - const stack = new Stack(); - const sagemakerRole = new iam.Role(stack, "SagemakerRole", { - assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), - }); - const key = new kms.Key(stack, 'MyEncryptionKey'); - // Build SageMaker Notebook Instance - defaults.buildSagemakerNotebook(stack, { - role: sagemakerRole, - sagemakerNotebookProps: { - instanceType: 'ml.c4.2xlarge', - kmsKeyId: key.keyArn - } - }); - expect(stack).toHaveResource("AWS::SageMaker::NotebookInstance", { - DirectInternetAccess: "Disabled", - InstanceType: "ml.c4.2xlarge", - KmsKeyId: { - "Fn::GetAtt": [ - "MyEncryptionKeyD795679F", - "Arn" - ] - } - }); + // Stack + const stack = new Stack(); + const sagemakerRole = new iam.Role(stack, "SagemakerRole", { + assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), + }); + const key = new kms.Key(stack, 'MyEncryptionKey'); + // Build SageMaker Notebook Instance + defaults.buildSagemakerNotebook(stack, { + role: sagemakerRole, + sagemakerNotebookProps: { + instanceType: 'ml.c4.2xlarge', + kmsKeyId: key.keyArn + } + }); + expect(stack).toHaveResource("AWS::SageMaker::NotebookInstance", { + DirectInternetAccess: "Disabled", + InstanceType: "ml.c4.2xlarge", + KmsKeyId: { + "Fn::GetAtt": [ + "MyEncryptionKeyD795679F", + "Arn" + ] + } + }); }); // -------------------------------------------------------------- // Test exception // -------------------------------------------------------------- test('Test exception', () => { - // Stack - const stack = new Stack(); - const sagemakerRole = new iam.Role(stack, "SagemakerRole", { - assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), - }); + // Stack + const stack = new Stack(); + const sagemakerRole = new iam.Role(stack, "SagemakerRole", { + assumedBy: new iam.ServicePrincipal("sagemaker.amazonaws.com"), + }); - expect(() => { - // Build SageMaker Notebook Instance - defaults.buildSagemakerNotebook(stack, { - role: sagemakerRole, - deployInsideVpc: true, - sagemakerNotebookProps: { - subnetId: 'subnet-deadbeef', - } - }); - }).toThrowError(); + expect(() => { + // Build SageMaker Notebook Instance + defaults.buildSagemakerNotebook(stack, { + role: sagemakerRole, + deployInsideVpc: true, + sagemakerNotebookProps: { + subnetId: 'subnet-deadbeef', + } + }); + }).toThrowError(); }); diff --git a/source/patterns/@aws-solutions-constructs/core/test/sns-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/sns-helper.test.ts index e1b250225..729ae072c 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/sns-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/sns-helper.test.ts @@ -21,35 +21,35 @@ import '@aws-cdk/assert/jest'; // Test deployment with no properties using AWS Managed KMS Key // -------------------------------------------------------------- test('Test deployment with no properties using AWS Managed KMS Key', () => { - // Stack - const stack = new Stack(); - // Helper declaration - defaults.buildTopic(stack, {}); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); - // Assertion 2 - expect(stack).toHaveResource("AWS::SNS::Topic", { - KmsMasterKeyId: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition" - }, - ":kms:", - { - Ref: "AWS::Region" - }, - ":", - { - Ref: "AWS::AccountId" - }, - ":alias/aws/sns" - ] + // Stack + const stack = new Stack(); + // Helper declaration + defaults.buildTopic(stack, {}); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Assertion 2 + expect(stack).toHaveResource("AWS::SNS::Topic", { + KmsMasterKeyId: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition" + }, + ":kms:", + { + Ref: "AWS::Region" + }, + ":", + { + Ref: "AWS::AccountId" + }, + ":alias/aws/sns" ] - } - }); + ] + } + }); }); // -------------------------------------------------------------- @@ -60,16 +60,16 @@ test('Test deployment without imported encryption key', () => { const stack = new Stack(); // Helper declaration defaults.buildTopic(stack, { - topicProps: { - topicName: "custom-topic" - }, - enableEncryptionWithCustomerManagedKey: true + topicProps: { + topicName: "custom-topic" + }, + enableEncryptionWithCustomerManagedKey: true }); // Assertion 1 expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); // Assertion 2 expect(stack).toHaveResource("AWS::SNS::Topic", { - TopicName: "custom-topic" + TopicName: "custom-topic" }); // Assertion 3 expect(stack).toHaveResource("AWS::KMS::Key", { @@ -87,11 +87,11 @@ test('Test deployment w/ imported encryption key', () => { const key = defaults.buildEncryptionKey(stack); // Helper declaration defaults.buildTopic(stack, { - topicProps: { - topicName: "custom-topic" - }, - enableEncryptionWithCustomerManagedKey: true, - encryptionKey: key + topicProps: { + topicName: "custom-topic" + }, + enableEncryptionWithCustomerManagedKey: true, + encryptionKey: key }); // Assertion 1 expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); @@ -108,81 +108,81 @@ test('Test deployment w/ imported encryption key', () => { }); test('Check SNS Topic policy', () => { - const stack = new Stack(); - defaults.buildTopic(stack, {}); + const stack = new Stack(); + defaults.buildTopic(stack, {}); - expectCDK(stack).to(haveResource("AWS::SNS::TopicPolicy", { - PolicyDocument: { - Statement: [ - { - Action: [ - "SNS:Publish", - "SNS:RemovePermission", - "SNS:SetTopicAttributes", - "SNS:DeleteTopic", - "SNS:ListSubscriptionsByTopic", - "SNS:GetTopicAttributes", - "SNS:Receive", - "SNS:AddPermission", - "SNS:Subscribe" - ], - Condition: { - StringEquals: { - "AWS:SourceOwner": { - Ref: "AWS::AccountId" - } + expectCDK(stack).to(haveResource("AWS::SNS::TopicPolicy", { + PolicyDocument: { + Statement: [ + { + Action: [ + "SNS:Publish", + "SNS:RemovePermission", + "SNS:SetTopicAttributes", + "SNS:DeleteTopic", + "SNS:ListSubscriptionsByTopic", + "SNS:GetTopicAttributes", + "SNS:Receive", + "SNS:AddPermission", + "SNS:Subscribe" + ], + Condition: { + StringEquals: { + "AWS:SourceOwner": { + Ref: "AWS::AccountId" } - }, - Effect: "Allow", - Principal: { - AWS: { - "Fn::Join": [ - "", - [ - "arn:", - { - Ref: "AWS::Partition" - }, - ":iam::", - { - Ref: "AWS::AccountId" - }, - ":root" - ] + } + }, + Effect: "Allow", + Principal: { + AWS: { + "Fn::Join": [ + "", + [ + "arn:", + { + Ref: "AWS::Partition" + }, + ":iam::", + { + Ref: "AWS::AccountId" + }, + ":root" ] - } - }, - Resource: { - Ref: "SnsTopic2C1570A4" - }, - Sid: "TopicOwnerOnlyAccess" + ] + } }, - { - Action: [ - "SNS:Publish", - "SNS:RemovePermission", - "SNS:SetTopicAttributes", - "SNS:DeleteTopic", - "SNS:ListSubscriptionsByTopic", - "SNS:GetTopicAttributes", - "SNS:Receive", - "SNS:AddPermission", - "SNS:Subscribe" - ], - Condition: { - Bool: { - "aws:SecureTransport": "false" - } - }, - Effect: "Deny", - Principal: "*", - Resource: { - Ref: "SnsTopic2C1570A4" - }, - Sid: "HttpsOnly" - } - ], - Version: "2012-10-17" - }, - })); - }); \ No newline at end of file + Resource: { + Ref: "SnsTopic2C1570A4" + }, + Sid: "TopicOwnerOnlyAccess" + }, + { + Action: [ + "SNS:Publish", + "SNS:RemovePermission", + "SNS:SetTopicAttributes", + "SNS:DeleteTopic", + "SNS:ListSubscriptionsByTopic", + "SNS:GetTopicAttributes", + "SNS:Receive", + "SNS:AddPermission", + "SNS:Subscribe" + ], + Condition: { + Bool: { + "aws:SecureTransport": "false" + } + }, + Effect: "Deny", + Principal: "*", + Resource: { + Ref: "SnsTopic2C1570A4" + }, + Sid: "HttpsOnly" + } + ], + Version: "2012-10-17" + }, + })); +}); \ No newline at end of file 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 442a9865a..ddaee8210 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 @@ -22,58 +22,58 @@ import * as sqs from '@aws-cdk/aws-sqs'; // Test minimal deployment with no properties // -------------------------------------------------------------- test('Test minimal deployment with no properties', () => { - // Stack - const stack = new Stack(); - // Helper declaration - defaults.buildQueue(stack, 'primary-queue', {}); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper declaration + defaults.buildQueue(stack, 'primary-queue', {}); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ custom properties // -------------------------------------------------------------- test('Test deployment w/ custom properties', () => { - // Stack - const stack = new Stack(); - // Helper setup - const encKey = defaults.buildEncryptionKey(stack); - // Helper declaration - defaults.buildQueue(stack, 'primary-queue', { - queueProps: { - queueName: "custom-queue-props", - encryption: sqs.QueueEncryption.KMS, - encryptionMasterKey: encKey - } - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Helper setup + const encKey = defaults.buildEncryptionKey(stack); + // Helper declaration + defaults.buildQueue(stack, 'primary-queue', { + queueProps: { + queueName: "custom-queue-props", + encryption: sqs.QueueEncryption.KMS, + encryptionMasterKey: encKey + } + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test dead letter queue deployment/configuration // -------------------------------------------------------------- test('Test dead letter queue deployment/configuration', () => { - // Stack - const stack = new Stack(); - // Helper setup - const encKey = defaults.buildEncryptionKey(stack); - // const [dlq] = defaults.buildQueue(stack, 'dead-letter-queue', {}); - const dlqi = defaults.buildDeadLetterQueue(stack, { - deployDeadLetterQueue: true, - maxReceiveCount: 3 - }); + // Stack + const stack = new Stack(); + // Helper setup + const encKey = defaults.buildEncryptionKey(stack); + // const [dlq] = defaults.buildQueue(stack, 'dead-letter-queue', {}); + const dlqi = defaults.buildDeadLetterQueue(stack, { + deployDeadLetterQueue: true, + maxReceiveCount: 3 + }); // Helper declaration - defaults.buildQueue(stack, 'primary-queue', { - queueProps: { - queueName: "not-the-dead-letter-queue-props", - encryption: sqs.QueueEncryption.KMS, - encryptionMasterKey: encKey - }, - deadLetterQueue: dlqi - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + defaults.buildQueue(stack, 'primary-queue', { + queueProps: { + queueName: "not-the-dead-letter-queue-props", + encryption: sqs.QueueEncryption.KMS, + encryptionMasterKey: encKey + }, + deadLetterQueue: dlqi + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- @@ -86,16 +86,16 @@ test('Test dead letter queue deployment/configuration w/o mrc', () => { const encKey = defaults.buildEncryptionKey(stack); // const [dlq] = defaults.buildQueue(stack, 'dead-letter-queue', {}); const dlqi = defaults.buildDeadLetterQueue(stack, { - deployDeadLetterQueue: true + deployDeadLetterQueue: true }); // Helper declaration defaults.buildQueue(stack, 'primary-queue', { - queueProps: { - queueName: "not-the-dead-letter-queue-props", - encryption: sqs.QueueEncryption.KMS, - encryptionMasterKey: encKey - }, - deadLetterQueue: dlqi + queueProps: { + queueName: "not-the-dead-letter-queue-props", + encryption: sqs.QueueEncryption.KMS, + encryptionMasterKey: encKey + }, + deadLetterQueue: dlqi }); // Assertion 1 expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); @@ -115,7 +115,7 @@ test('Test existingQueueObj', () => { }); // Helper declaration defaults.buildQueue(stack, 'primary-queue', { - existingQueueObj: existingQueue + existingQueueObj: existingQueue }); // Assertion 1 expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); diff --git a/source/patterns/@aws-solutions-constructs/core/test/step-function-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/step-function-helper.test.ts index b333cfe95..dbd80b5fb 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/step-function-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/step-function-helper.test.ts @@ -23,132 +23,132 @@ import { LogGroup } from "@aws-cdk/aws-logs"; // Test minimal deployment with no properties // -------------------------------------------------------------- test('Test minimal deployment with no properties', () => { - // Stack - const stack = new Stack(); - // Step function definition - const startState = new sfn.Pass(stack, 'StartState'); - // Build state machine - defaults.buildStateMachine(stack, { - definition: startState - }); - // Assertion 1 - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Step function definition + const startState = new sfn.Pass(stack, 'StartState'); + // Build state machine + defaults.buildStateMachine(stack, { + definition: startState + }); + // Assertion 1 + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ custom properties // -------------------------------------------------------------- test('Test deployment w/ custom properties', () => { - // Stack - const stack = new Stack(); - // Step function definition - const startState = new sfn.Pass(stack, 'StartState'); - // Build state machine - defaults.buildStateMachine(stack, { - definition: startState, - stateMachineName: 'myStateMachine' - }); - // Assertion - expect(stack).toHaveResource("AWS::StepFunctions::StateMachine", { - StateMachineName: "myStateMachine" - }); + // Stack + const stack = new Stack(); + // Step function definition + const startState = new sfn.Pass(stack, 'StartState'); + // Build state machine + defaults.buildStateMachine(stack, { + definition: startState, + stateMachineName: 'myStateMachine' + }); + // Assertion + expect(stack).toHaveResource("AWS::StepFunctions::StateMachine", { + StateMachineName: "myStateMachine" + }); }); // -------------------------------------------------------------- // Test deployment w/ logging enabled // -------------------------------------------------------------- test('Test deployment w/ logging enabled', () => { - // Stack - const stack = new Stack(); - // Step function definition - const startState = new sfn.Pass(stack, 'StartState'); - // Log group - const logGroup = new LogGroup(stack, 'myLogGroup', defaults.DefaultLogGroupProps()); - // Build state machine - defaults.buildStateMachine(stack, { - definition: startState, - logs: { - destination: logGroup, - level: sfn.LogLevel.FATAL - } - }); - // Assertion - expect(stack).toHaveResource("AWS::StepFunctions::StateMachine", { - LoggingConfiguration: { - Destinations: [{ - CloudWatchLogsLogGroup: { - LogGroupArn: { - "Fn::GetAtt": [ - "myLogGroup46524CAB", - "Arn" - ] - } - } - }], - Level: 'FATAL' + // Stack + const stack = new Stack(); + // Step function definition + const startState = new sfn.Pass(stack, 'StartState'); + // Log group + const logGroup = new LogGroup(stack, 'myLogGroup', defaults.DefaultLogGroupProps()); + // Build state machine + defaults.buildStateMachine(stack, { + definition: startState, + logs: { + destination: logGroup, + level: sfn.LogLevel.FATAL + } + }); + // Assertion + expect(stack).toHaveResource("AWS::StepFunctions::StateMachine", { + LoggingConfiguration: { + Destinations: [{ + CloudWatchLogsLogGroup: { + LogGroupArn: { + "Fn::GetAtt": [ + "myLogGroup46524CAB", + "Arn" + ] + } } - }); + }], + Level: 'FATAL' + } + }); }); // -------------------------------------------------------------- // Check default Cloudwatch perissions // -------------------------------------------------------------- test('Test deployment w/ logging enabled', () => { - // Stack - const stack = new Stack(); - // Step function definition - const startState = new sfn.Pass(stack, 'StartState'); - // Build state machine - defaults.buildStateMachine(stack, { - definition: startState - }); - // Assertion - expect(stack).toHaveResource("AWS::IAM::Policy", { - 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" - }, - ":*" - ] + // Stack + const stack = new Stack(); + // Step function definition + const startState = new sfn.Pass(stack, 'StartState'); + // Build state machine + defaults.buildStateMachine(stack, { + definition: startState + }); + // Assertion + expect(stack).toHaveResource("AWS::IAM::Policy", { + 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" - } - }); + } + ], + Version: "2012-10-17" + } + }); }); // -------------------------------------------------------------- @@ -161,7 +161,7 @@ test('Count State Machine CW Alarms', () => { const startState = new sfn.Pass(stack, 'StartState'); // Build state machine const [sm] = defaults.buildStateMachine(stack, { - definition: startState + definition: startState }); const cwList = defaults.buildStepFunctionCWAlarms(stack, sm); diff --git a/source/patterns/@aws-solutions-constructs/core/test/vpc-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/vpc-helper.test.ts index 2b07e8e55..0fa54305a 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/vpc-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/vpc-helper.test.ts @@ -13,54 +13,224 @@ import { Stack } from "@aws-cdk/core"; import * as defaults from '../'; +import * as ec2 from '@aws-cdk/aws-ec2'; import { SynthUtils } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; +import { AddAwsServiceEndpoint, ServiceEndpointTypes } from "../lib/vpc-helper"; // -------------------------------------------------------------- // Test minimal deployment with no properties // -------------------------------------------------------------- test('Test minimal deployment with no properties', () => { - // Stack - const stack = new Stack(); - // Build VPC - defaults.buildVpc(stack); - // Assertion - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Build VPC + defaults.buildVpc(stack); + // Assertion + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- // Test deployment w/ custom CIDR // -------------------------------------------------------------- test('Test deployment w/ custom CIDR', () => { - // Stack - const stack = new Stack(); - // Build VPC - defaults.buildVpc(stack, { - vpcProps: { - cidr: '172.168.0.0/16' - } - }); - // Assertion - expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + // Stack + const stack = new Stack(); + // Build VPC + defaults.buildVpc(stack, { + userVpcProps: { + cidr: '172.168.0.0/16' + } + }); + // Assertion + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); }); // -------------------------------------------------------------- -// Test deployment w/ custom properties -// -------------------------------------------------------------- -test('Test deployment w/ custom properties', () => { - // Stack - const stack = new Stack(); - // Build VPC - defaults.buildVpc(stack, { - vpcProps: { - enableDnsHostnames: false, - enableDnsSupport: false, - cidr: '172.168.0.0/16' - } - }); - expect(stack).toHaveResource("AWS::EC2::VPC", { - CidrBlock: "172.168.0.0/16", - EnableDnsHostnames: false, - EnableDnsSupport: false - }); -}); \ No newline at end of file +// Test deployment w/ user provided custom properties +// -------------------------------------------------------------- +test("Test deployment w/ user provided custom properties", () => { + // Stack + const stack = new Stack(); + // Build VPC + defaults.buildVpc(stack, { + userVpcProps: { + enableDnsHostnames: false, + enableDnsSupport: false, + cidr: '172.168.0.0/16' + } + }); + expect(stack).toHaveResource("AWS::EC2::VPC", { + CidrBlock: "172.168.0.0/16", + EnableDnsHostnames: false, + EnableDnsSupport: false + }); +}); + +// -------------------------------------------------------------- +// Test deployment w/ construct provided custom properties +// -------------------------------------------------------------- +test("Test deployment w/ construct provided custom properties", () => { + // Stack + const stack = new Stack(); + // Build VPC + defaults.buildVpc(stack, { + constructVpcProps: { + enableDnsHostnames: true, + enableDnsSupport: true, + cidr: "172.168.0.0/16", + }, + }); + expect(stack).toHaveResource("AWS::EC2::VPC", { + CidrBlock: "172.168.0.0/16", + EnableDnsHostnames: true, + EnableDnsSupport: true, + }); +}); + +// -------------------------------------------------------------- +// Test deployment w/ construct and user provided custom properties +// -------------------------------------------------------------- +test("Test deployment w/ construct and user provided custom properties", () => { + // Stack + const stack = new Stack(); + // Build VPC + defaults.buildVpc(stack, { + userVpcProps: { + enableDnsHostnames: false, + enableDnsSupport: false, + cidr: "10.0.0.0/16", + }, + constructVpcProps: { + enableDnsHostnames: false, + enableDnsSupport: false, + cidr: "172.168.0.0/16", + }, + }); + expect(stack).toHaveResource("AWS::EC2::VPC", { + CidrBlock: "172.168.0.0/16", + EnableDnsHostnames: false, + EnableDnsSupport: false, + }); +}); + +// -------------------------------------------------------------- +// Test priority of default, user and construct properties +// -------------------------------------------------------------- +test("Test deployment w/ construct and user provided custom properties", () => { + + // Stack + const stack = new Stack(); + // Build VPC + const v = defaults.buildVpc(stack, { + userVpcProps: { + enableDnsHostnames: false, + enableDnsSupport: false, + cidr: "10.0.0.0/16", + }, + constructVpcProps: { + enableDnsHostnames: true, + enableDnsSupport: true, + natGateways: 0, + subnetConfiguration: [ + { + cidrMask: 18, + name: "isolated", + subnetType: ec2.SubnetType.ISOLATED, + }, + ], + }, + }); + AddAwsServiceEndpoint(stack, v, defaults.ServiceEndpointTypes.SQS); + + // Expect 2 isolated subnets (usual error condition is 2 public/2 private) + expect(stack).toCountResources("AWS::EC2::Subnet", 2); + expect(stack).toCountResources("AWS::EC2::InternetGateway", 0); +}); + +// -------------------------------------------------------------- +// Test deployment w/ existing VPC provided +// -------------------------------------------------------------- +test("Test deployment w/ existing VPC provided", () => { + // Stack + const stack = new Stack(); + // Build VPC + const testExistingVpc = defaults.buildVpc(stack, { + constructVpcProps: { + enableDnsHostnames: false, + enableDnsSupport: false, + cidr: "172.168.0.0/16", + }, + }); + + const newVpc = defaults.buildVpc(stack, { + existingVpc: testExistingVpc, + }); + + expect(newVpc).toBe(testExistingVpc); +}); + +// -------------------------------------------------------------- +// Test adding Gateway Endpoint +// -------------------------------------------------------------- +test("Test adding Gateway Endpoint", () => { + // Stack + const stack = new Stack(); + // Build VPC + const testVpc = defaults.buildVpc(stack); + + AddAwsServiceEndpoint(stack, testVpc, ServiceEndpointTypes.DYNAMODB); + + // Assertion + expect(stack).toHaveResource("AWS::EC2::VPCEndpoint", { + VpcEndpointType: "Gateway", + }); +}); + +// -------------------------------------------------------------- +// Test adding Interface Endpoint +// -------------------------------------------------------------- +test("Test adding Interface Endpoint", () => { + // Stack + const stack = new Stack(); + // Build VPC + const testVpc = defaults.buildVpc(stack); + + AddAwsServiceEndpoint(stack, testVpc, ServiceEndpointTypes.SNS); + + // Assertion + expect(stack).toHaveResource("AWS::EC2::VPCEndpoint", { + VpcEndpointType: "Interface", + }); +}); + +// -------------------------------------------------------------- +// Test adding a second Endpoint of same service +// -------------------------------------------------------------- +test("Test adding a second Endpoint of same service", () => { + // Stack + const stack = new Stack(); + // Build VPC + const testVpc = defaults.buildVpc(stack); + + AddAwsServiceEndpoint(stack, testVpc, ServiceEndpointTypes.SNS); + + // Assertion + expect(stack).toCountResources("AWS::EC2::VPCEndpoint", 1); +}); + +// -------------------------------------------------------------- +// Test adding bad Endpoint +// -------------------------------------------------------------- +test("Test adding bad Endpoint", () => { + // Stack + const stack = new Stack(); + // Build VPC + const testVpc = defaults.buildVpc(stack); + + const app = () => { + AddAwsServiceEndpoint(stack, testVpc, "string" as ServiceEndpointTypes); + }; + // Assertion + expect(app).toThrowError(); +}); diff --git a/source/patterns/@aws-solutions-constructs/eslintrc.yml b/source/patterns/@aws-solutions-constructs/eslintrc.yml index 6806f7be5..6dbd48011 100644 --- a/source/patterns/@aws-solutions-constructs/eslintrc.yml +++ b/source/patterns/@aws-solutions-constructs/eslintrc.yml @@ -47,3 +47,7 @@ rules: 'license-header/header': - error - ../license-header.js + + 'indent': + - error + - 2 diff --git a/source/patterns/@aws-solutions-constructs/tslint.yaml b/source/patterns/@aws-solutions-constructs/tslint.yaml index 5226a9ae3..0ff7c217c 100644 --- a/source/patterns/@aws-solutions-constructs/tslint.yaml +++ b/source/patterns/@aws-solutions-constructs/tslint.yaml @@ -1,5 +1,9 @@ extends: "tslint:recommended" rules: + # Once we enforce indent rules, function declarations and invocations + # that span multiple lines are indented 2 spaces and not aligned + align: false + semicolon: [true, "always", "ignore-interfaces"] # Due to VSCode syntax highlighting we're unlikely to do this wrong, and it gets annoying @@ -58,5 +62,3 @@ rules: # Turning off class member ordering member-ordering: false - - diff --git a/source/tools/cdk-integ-tools/package.json b/source/tools/cdk-integ-tools/package.json index 93a2c6cae..463e17f59 100644 --- a/source/tools/cdk-integ-tools/package.json +++ b/source/tools/cdk-integ-tools/package.json @@ -46,4 +46,4 @@ "engines": { "node": ">= 10.3.0" } -} \ No newline at end of file +}