diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-fargate/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-alb-fargate/lib/index.ts index 9a4311279..21f461272 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-fargate/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-alb-fargate/lib/index.ts @@ -207,7 +207,7 @@ export class AlbToFargate extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -218,6 +218,8 @@ export class AlbToFargate extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } // Add the Fargate Service to the // to the ALB Listener we set up earlier diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-fargate/test/alb-fargate.test.ts b/source/patterns/@aws-solutions-constructs/aws-alb-fargate/test/alb-fargate.test.ts index 4a5b24156..cc725ff05 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-fargate/test/alb-fargate.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-alb-fargate/test/alb-fargate.test.ts @@ -130,7 +130,7 @@ test('Test existing load balancer, vpc, service', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -145,8 +145,8 @@ test('Test existing load balancer, vpc, service', () => { const testProps: AlbToFargateProps = { existingVpc, publicApi: true, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingLoadBalancerObj: existingAlb, listenerProps: { protocol: 'HTTP' diff --git a/source/patterns/@aws-solutions-constructs/aws-alb-fargate/test/integ.all-existing-private-http.ts b/source/patterns/@aws-solutions-constructs/aws-alb-fargate/test/integ.all-existing-private-http.ts index c256ca754..574bb6fc1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-alb-fargate/test/integ.all-existing-private-http.ts +++ b/source/patterns/@aws-solutions-constructs/aws-alb-fargate/test/integ.all-existing-private-http.ts @@ -30,7 +30,7 @@ const image = ecs.ContainerImage.fromRegistry('nginx'); const testExistingVpc = defaults.getTestVpc(stack); -const [testService, testContainer] = defaults.CreateFargateService(stack, +const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', testExistingVpc, undefined, @@ -48,8 +48,8 @@ const existingAlb = new elb.ApplicationLoadBalancer(stack, 'test-alb', { const testProps: AlbToFargateProps = { existingVpc: testExistingVpc, publicApi: true, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingLoadBalancerObj: existingAlb, listenerProps: { protocol: 'HTTP' diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/lib/index.ts index ee134bcc2..59ace2c14 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-dynamodb/lib/index.ts @@ -239,15 +239,18 @@ export class ApiGatewayToDynamoDB extends Construct { // Since we are only invoking this function with an existing Table or tableProps, // (not a table interface), we know that the implementation will always return - // a Table object and we can safely cast away the optional aspect of the type. - this.dynamoTable = defaults.buildDynamoDBTable(this, { + // a Table object and we can force assignment to the dynamoTable property. + const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(this, { existingTableObj: props.existingTableObj, dynamoTableProps: props.dynamoTableProps - })[1] as dynamodb.Table; + }); + this.dynamoTable = buildDynamoDBTableResponse.tableObject!; // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, - props.apiGatewayProps, props.logGroupProps); + const globalRestApiResponse = defaults.GlobalRestApi(this, props.apiGatewayProps, props.logGroupProps); + this.apiGateway = globalRestApiResponse.api; + this.apiGatewayCloudWatchRole = globalRestApiResponse.role; + this.apiGatewayLogGroup = globalRestApiResponse.logGroup; // Setup the API Gateway role this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { 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 7ea0bda50..14f09e23c 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 @@ -144,8 +144,10 @@ export class ApiGatewayToIot extends Construct { } // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, - this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, extraApiGwProps, props.logGroupProps); + const globalRestApiResponse = defaults.GlobalRestApi(this, extraApiGwProps, props.logGroupProps); + this.apiGateway = globalRestApiResponse.api; + this.apiGatewayCloudWatchRole = globalRestApiResponse.role; + this.apiGatewayLogGroup = globalRestApiResponse.logGroup; // Validate the Query Params const requestValidatorProps: api.RequestValidatorProps = { 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 8257676c6..52f389453 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 @@ -146,8 +146,10 @@ export class ApiGatewayToKinesisStreams extends Construct { }); // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, - props.apiGatewayProps, props.logGroupProps); + const globalRestApiResponse = defaults.GlobalRestApi(this, props.apiGatewayProps, props.logGroupProps); + this.apiGateway = globalRestApiResponse.api; + this.apiGatewayCloudWatchRole = globalRestApiResponse.role; + this.apiGatewayLogGroup = globalRestApiResponse.logGroup; // Setup the API Gateway role this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { 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 6d5f37f14..6a69f86d8 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 @@ -78,7 +78,9 @@ export class ApiGatewayToLambda extends Construct { }); // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, - this.apiGatewayLogGroup] = defaults.GlobalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps, props.logGroupProps); + const globalRestApiResponse = defaults.GlobalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps, props.logGroupProps); + this.apiGateway = globalRestApiResponse.api; + this.apiGatewayCloudWatchRole = globalRestApiResponse.role; + this.apiGatewayLogGroup = globalRestApiResponse.group; } } \ 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 a40992851..0ff4b0628 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 @@ -103,8 +103,10 @@ export class ApiGatewayToSageMakerEndpoint extends Construct { defaults.CheckProps(props); // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, - props.apiGatewayProps, props.logGroupProps); + const globalRestApiResponse = defaults.GlobalRestApi(this, props.apiGatewayProps, props.logGroupProps); + this.apiGateway = globalRestApiResponse.api; + this.apiGatewayCloudWatchRole = globalRestApiResponse.role; + this.apiGatewayLogGroup = globalRestApiResponse.logGroup; // Setup the API Gateway role if (props.apiGatewayExecutionRole !== undefined) { 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 164f2d44e..1b4d00221 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 @@ -223,7 +223,7 @@ export class ApiGatewayToSqs extends Construct { }); // Setup the queue - [this.sqsQueue] = defaults.buildQueue(this, 'queue', { + const buildQueueResponse = defaults.buildQueue(this, 'queue', { existingQueueObj: props.existingQueueObj, queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue, @@ -231,10 +231,13 @@ export class ApiGatewayToSqs extends Construct { encryptionKey: props.encryptionKey, encryptionKeyProps: props.encryptionKeyProps }); + this.sqsQueue = buildQueueResponse.queue; // Setup the API Gateway - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = defaults.GlobalRestApi(this, - props.apiGatewayProps, props.logGroupProps); + const globalRestApiResponse = defaults.GlobalRestApi(this, props.apiGatewayProps, props.logGroupProps); + this.apiGateway = globalRestApiResponse.api; + this.apiGatewayCloudWatchRole = globalRestApiResponse.role; + this.apiGatewayLogGroup = globalRestApiResponse.logGroup; // Setup the API Gateway role this.apiGatewayRole = new iam.Role(this, 'api-gateway-role', { diff --git a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.existing-queue.ts b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.existing-queue.ts index 15dd4281a..b063631a0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.existing-queue.ts +++ b/source/patterns/@aws-solutions-constructs/aws-apigateway-sqs/test/integ.existing-queue.ts @@ -21,10 +21,10 @@ const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); stack.templateOptions.description = 'Integration Test for aws-apigateway-sqs'; -const [existingQueueObj] = buildQueue(stack, 'existing-queue', {}); +const buildQueueResponse = buildQueue(stack, 'existing-queue', {}); new ApiGatewayToSqs(stack, 'test-api-gateway-sqs-existing-queue', { - existingQueueObj + existingQueueObj: buildQueueResponse.queue }); // Synth 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 536f3c5fe..6af19fa39 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 @@ -111,8 +111,10 @@ export class CloudFrontToApiGatewayToLambda extends Construct { lambdaFunctionProps: props.lambdaFunctionProps }); - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = - defaults.RegionalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps, props.logGroupProps); + const regionalLambdaRestApiResponse = defaults.RegionalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps, props.logGroupProps); + this.apiGateway = regionalLambdaRestApiResponse.api; + this.apiGatewayCloudWatchRole = regionalLambdaRestApiResponse.role; + this.apiGatewayLogGroup = regionalLambdaRestApiResponse.group; this.apiGateway.methods.forEach((apiMethod) => { // Override the API Gateway Authorization Type from AWS_IAM to NONE 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 16b0474c9..3deb82336 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 @@ -83,14 +83,16 @@ export class CloudFrontToApiGateway extends Construct { this.apiGateway = props.existingApiGatewayObj; - [this.cloudFrontWebDistribution, this.cloudFrontFunction, this.cloudFrontLoggingBucket] = - defaults.CloudFrontDistributionForApiGateway( - this, - props.existingApiGatewayObj, - props.cloudFrontDistributionProps, - props.insertHttpSecurityHeaders, - props.cloudFrontLoggingBucketProps, - props.responseHeadersPolicyProps - ); + const cloudFrontDistributionForApiGatewayResponse = defaults.CloudFrontDistributionForApiGateway( + this, + props.existingApiGatewayObj, + props.cloudFrontDistributionProps, + props.insertHttpSecurityHeaders, + props.cloudFrontLoggingBucketProps, + props.responseHeadersPolicyProps + ); + this.cloudFrontWebDistribution = cloudFrontDistributionForApiGatewayResponse.distribution; + this.cloudFrontFunction = cloudFrontDistributionForApiGatewayResponse.cloudfrontFunction; + this.cloudFrontLoggingBucket = cloudFrontDistributionForApiGatewayResponse.loggingBucket; } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/integ.customCloudfrontLoggingBucket.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/integ.customCloudfrontLoggingBucket.ts index 44683dab2..7acca56f6 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/integ.customCloudfrontLoggingBucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/integ.customCloudfrontLoggingBucket.ts @@ -33,9 +33,9 @@ const inProps: lambda.FunctionProps = { const func = defaults.deployLambdaFunction(stack, inProps); -const [_api] = defaults.RegionalLambdaRestApi(stack, func); +const regionalLambdaRestApiResponse = defaults.RegionalLambdaRestApi(stack, func); -_api.methods.forEach((apiMethod) => { +regionalLambdaRestApiResponse.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') { @@ -52,7 +52,7 @@ _api.methods.forEach((apiMethod) => { }); new CloudFrontToApiGateway(stack, 'cf-apigw', { - existingApiGatewayObj: _api, + existingApiGatewayObj: regionalLambdaRestApiResponse.api, cloudFrontLoggingBucketProps: { removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, 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 bc6442b3f..4ec959b9d 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 @@ -32,9 +32,9 @@ const inProps: lambda.FunctionProps = { const func = defaults.deployLambdaFunction(stack, inProps); -const [_api] = defaults.RegionalLambdaRestApi(stack, func); +const regionalLambdaRestApiResponse = defaults.RegionalLambdaRestApi(stack, func); -_api.methods.forEach((apiMethod) => { +regionalLambdaRestApiResponse.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') { @@ -51,7 +51,7 @@ _api.methods.forEach((apiMethod) => { }); new CloudFrontToApiGateway(stack, 'test-cloudfront-apigateway', { - existingApiGatewayObj: _api, + existingApiGatewayObj: regionalLambdaRestApiResponse.api, cloudFrontLoggingBucketProps: { removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts index 7889d164c..27e70bba8 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-apigateway/test/test.cloudfront-apigateway.test.ts @@ -29,10 +29,10 @@ function deploy(stack: cdk.Stack) { const func = defaults.deployLambdaFunction(stack, inProps); - const [api] = defaults.RegionalLambdaRestApi(stack, func); + const regionalLambdaRestApiResponse = defaults.RegionalLambdaRestApi(stack, func); return new CloudFrontToApiGateway(stack, 'test-cloudfront-apigateway', { - existingApiGatewayObj: api + existingApiGatewayObj: regionalLambdaRestApiResponse.api }); } @@ -172,8 +172,8 @@ function createApi() { const func = defaults.deployLambdaFunction(stack, inProps); - const [api] = defaults.RegionalLambdaRestApi(stack, func); - return {stack, api}; + const regionalLambdaRestApiResponse = defaults.RegionalLambdaRestApi(stack, func); + return {stack, api: regionalLambdaRestApiResponse.api}; } // -------------------------------------------------------------- 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 22f37912e..e8b4c4fbd 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 @@ -142,14 +142,17 @@ export class CloudFrontToMediaStore extends Construct { this.mediaStoreContainer = defaults.MediaStoreContainer(this, mediaStoreProps); } - [this.cloudFrontWebDistribution, this.cloudFrontLoggingBucket, this.cloudFrontOriginRequestPolicy, this.cloudFrontFunction] - = defaults.CloudFrontDistributionForMediaStore( - this, - this.mediaStoreContainer, - cloudFrontDistributionProps, - props.insertHttpSecurityHeaders, - props.cloudFrontLoggingBucketProps, - props.responseHeadersPolicyProps - ); + const DistributionResponse = defaults.CloudFrontDistributionForMediaStore( + this, + this.mediaStoreContainer, + cloudFrontDistributionProps, + props.insertHttpSecurityHeaders, + props.cloudFrontLoggingBucketProps, + props.responseHeadersPolicyProps + ); + this.cloudFrontWebDistribution = DistributionResponse.distribution; + this.cloudFrontLoggingBucket = DistributionResponse.loggingBucket; + this.cloudFrontOriginRequestPolicy = DistributionResponse.requestPolicy; + this.cloudFrontFunction = DistributionResponse.cloudfrontFunction; } } 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 ef578688d..2758e3987 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 @@ -111,11 +111,12 @@ export class CloudFrontToS3 extends Construct { let bucket: s3.IBucket; if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps: props.bucketProps, loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs }); + this.s3Bucket = buildS3BucketResponse.bucket; bucket = this.s3Bucket; } else { bucket = props.existingBucketObj; @@ -123,16 +124,18 @@ export class CloudFrontToS3 extends Construct { this.s3BucketInterface = bucket; - [this.cloudFrontWebDistribution, this.cloudFrontFunction, this.cloudFrontLoggingBucket] = - defaults.CloudFrontDistributionForS3( - this, - this.s3BucketInterface, - props.cloudFrontDistributionProps, - props.insertHttpSecurityHeaders, - props.originPath, - props.cloudFrontLoggingBucketProps, - props.responseHeadersPolicyProps - ); + const cloudFrontDistributionForS3Response = defaults.CloudFrontDistributionForS3( + this, + this.s3BucketInterface, + props.cloudFrontDistributionProps, + props.insertHttpSecurityHeaders, + props.originPath, + props.cloudFrontLoggingBucketProps, + props.responseHeadersPolicyProps + ); + this.cloudFrontWebDistribution = cloudFrontDistributionForS3Response.distribution; + this.cloudFrontFunction = cloudFrontDistributionForS3Response.cloudfrontFunction; + this.cloudFrontLoggingBucket = cloudFrontDistributionForS3Response.loggingBucket; } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/lib/index.ts index 83b83d6f9..efd18bc1f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cognito-apigateway-lambda/lib/index.ts @@ -105,8 +105,11 @@ export class CognitoToApiGatewayToLambda extends Construct { existingLambdaObj: props.existingLambdaObj, lambdaFunctionProps: props.lambdaFunctionProps }); - [this.apiGateway, this.apiGatewayCloudWatchRole, this.apiGatewayLogGroup] = - defaults.GlobalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps, props.logGroupProps); + const globalLambdaRestApiResponse = defaults.GlobalLambdaRestApi(this, this.lambdaFunction, props.apiGatewayProps, props.logGroupProps); + this.apiGateway = globalLambdaRestApiResponse.api; + this.apiGatewayCloudWatchRole = globalLambdaRestApiResponse.role; + this.apiGatewayLogGroup = globalLambdaRestApiResponse.group; + this.userPool = defaults.buildUserPool(this, props.cognitoUserPoolProps); this.userPoolClient = defaults.buildUserPoolClient(this, this.userPool, props.cognitoUserPoolClientProps); diff --git a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/lib/index.ts index 1214ff77b..af0077d73 100644 --- a/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-dynamodbstreams-lambda/lib/index.ts @@ -89,10 +89,12 @@ export class DynamoDBStreamsToLambda extends Construct { lambdaFunctionProps: props.lambdaFunctionProps }); - [this.dynamoTableInterface, this.dynamoTable] = defaults.buildDynamoDBTableWithStream(this, { + const buildDynamoDBTableWithStreamResponse = defaults.buildDynamoDBTableWithStream(this, { dynamoTableProps: props.dynamoTableProps, existingTableInterface: props.existingTableInterface }); + this.dynamoTableInterface = buildDynamoDBTableWithStreamResponse.tableInterface; + this.dynamoTable = buildDynamoDBTableWithStreamResponse.tableObject; // Grant DynamoDB Stream read perimssion for lambda function this.dynamoTableInterface.grantStreamRead(this.lambdaFunction.grantPrincipal); diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/lib/index.ts index d323c3185..4f4c50a05 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/lib/index.ts @@ -96,7 +96,7 @@ export class EventbridgeToSns extends Construct { } // Setup the sns topic. - [this.snsTopic, this.encryptionKey] = defaults.buildTopic(this, { + const buildTopicResponse = defaults.buildTopic(this, { existingTopicObj: props.existingTopicObj, topicProps: props.topicProps, enableEncryptionWithCustomerManagedKey: enableEncryptionParam, @@ -104,6 +104,8 @@ export class EventbridgeToSns extends Construct { encryptionKeyProps: props.encryptionKeyProps }); + this.snsTopic = buildTopicResponse.topic; + this.encryptionKey = buildTopicResponse.key; // Setup the event rule target as sns topic. const topicEventTarget: events.IRuleTarget = { bind: () => ({ diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/test/eventbridge-sns-topic.test.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/test/eventbridge-sns-topic.test.ts index cb4ddc1d3..696c22ee6 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/test/eventbridge-sns-topic.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sns/test/eventbridge-sns-topic.test.ts @@ -13,6 +13,7 @@ import * as cdk from "aws-cdk-lib"; import * as events from "aws-cdk-lib/aws-events"; +import * as sns from "aws-cdk-lib/aws-sns"; import * as defaults from '@aws-solutions-constructs/core'; import '@aws-cdk/assert/jest'; import { EventbridgeToSns, EventbridgeToSnsProps } from "../lib"; @@ -40,7 +41,10 @@ function deployStackWithNewEventBus(stack: cdk.Stack) { test('check if the event rule has permission/policy in place in sns for it to be able to publish to the topic', () => { const stack = new cdk.Stack(); - deployNewStack(stack); + const testConstruct = deployNewStack(stack); + + expect(testConstruct.snsTopic).toBeDefined(); + expect(testConstruct.encryptionKey).toBeDefined(); expect(stack).toHaveResource('AWS::SNS::TopicPolicy', { PolicyDocument: { Statement: [ @@ -359,4 +363,22 @@ test('Topic is encrypted with AWS-managed KMS key when enableEncryptionWithCusto ] } }); +}); + +test('Properties correctly set when unencrypted existing topic is provided', () => { + const stack = new cdk.Stack(); + const existingTopicObj = new sns.Topic(stack, 'Topic', { + topicName: 'existing-topic-name' + }); + + const props: EventbridgeToSnsProps = { + existingTopicObj, + eventRuleProps: { + schedule: events.Schedule.rate(cdk.Duration.minutes(5)) + } + }; + const testConstruct = new EventbridgeToSns(stack, 'test', props); + + expect(testConstruct.snsTopic).toBeDefined(); + expect(testConstruct.encryptionKey).not.toBeDefined(); }); \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/lib/index.ts index 0032c8b9c..9d9aae2a8 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/lib/index.ts @@ -133,7 +133,7 @@ export class EventbridgeToSqs extends Construct { } // Setup the queue - [this.sqsQueue, this.encryptionKey] = defaults.buildQueue(this, 'queue', { + const buildQueueResponse = defaults.buildQueue(this, 'queue', { existingQueueObj: props.existingQueueObj, queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue, @@ -141,6 +141,8 @@ export class EventbridgeToSqs extends Construct { encryptionKey: props.encryptionKey, encryptionKeyProps: props.encryptionKeyProps }); + this.sqsQueue = buildQueueResponse.queue; + this.encryptionKey = buildQueueResponse.key; const sqsEventTarget: events.IRuleTarget = { bind: () => ({ diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/test/eventbridge-sqs-queue.test.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/test/eventbridge-sqs-queue.test.ts index 96f4bc49b..34ae5e017 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/test/eventbridge-sqs-queue.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-sqs/test/eventbridge-sqs-queue.test.ts @@ -40,7 +40,11 @@ function deployStackWithNewEventBus(stack: cdk.Stack) { test('check the sqs queue properties', () => { const stack = new cdk.Stack(); - deployNewStack(stack); + const buildQueueResponse = deployNewStack(stack); + + expect(buildQueueResponse.sqsQueue).toBeDefined(); + expect(buildQueueResponse.encryptionKey).toBeDefined(); + expect(stack).toHaveResource('AWS::SQS::Queue', { KmsMasterKeyId: { "Fn::GetAtt": [ @@ -73,7 +77,10 @@ test('check the sqs queue properties with existing KMS key', () => { encryptionKey: key }; - new EventbridgeToSqs(stack, 'test-eventbridge-sqs', props); + const buildQueueResponse = new EventbridgeToSqs(stack, 'test-eventbridge-sqs', props); + + expect(buildQueueResponse.sqsQueue).toBeDefined(); + expect(buildQueueResponse.encryptionKey).toBeDefined(); expect(stack).toHaveResource('AWS::SQS::Queue', { KmsMasterKeyId: { diff --git a/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/lib/index.ts index d3051f1aa..01b91451b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-eventbridge-stepfunctions/lib/index.ts @@ -81,8 +81,10 @@ export class EventbridgeToStepfunctions extends Construct { super(scope, id); defaults.CheckProps(props); - [this.stateMachine, this.stateMachineLogGroup] = defaults.buildStateMachine(this, props.stateMachineProps, + const buildStateMachineResponse = defaults.buildStateMachine(this, props.stateMachineProps, props.logGroupProps); + this.stateMachine = buildStateMachineResponse.stateMachine; + this.stateMachineLogGroup = buildStateMachineResponse.logGroup; // Create an IAM role for Events to start the State Machine const eventsRole = new iam.Role(this, 'EventsRuleRole', { diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts index 66939b645..270b479c9 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/lib/index.ts @@ -164,7 +164,7 @@ export class FargateToDynamoDB extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -175,12 +175,16 @@ export class FargateToDynamoDB extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } - [this.dynamoTableInterface, this.dynamoTable] = defaults.buildDynamoDBTable(this, { + const response = defaults.buildDynamoDBTable(this, { dynamoTableProps: props.dynamoTableProps, existingTableInterface: props.existingTableInterface }); + this.dynamoTableInterface = response.tableInterface; + this.dynamoTable = response.tableObject; // Add the requested or default table permissions if (props.tablePermissions) { diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/test/fargate-dynamodb.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/test/fargate-dynamodb.test.ts index 2d8a8651b..e52397d0f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/test/fargate-dynamodb.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/test/fargate-dynamodb.test.ts @@ -347,7 +347,7 @@ test('Existing service/new table, public API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -359,8 +359,8 @@ test('Existing service/new table, public API, existing VPC', () => { const construct = new FargateToDynamoDB(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, tableArnEnvironmentVariableName: customArn, tableEnvironmentVariableName: customName, @@ -497,7 +497,7 @@ test('Existing service/existing table, private API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -517,8 +517,8 @@ test('Existing service/existing table, private API, existing VPC', () => { const construct = new FargateToDynamoDB(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, tablePermissions: 'Write', existingTableInterface: existingTable @@ -640,7 +640,7 @@ test('test error invalid table permission', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -661,8 +661,8 @@ test('test error invalid table permission', () => { const app = () => { new FargateToDynamoDB(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, tablePermissions: 'reed', existingTableInterface: existingTable diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/test/integ.existing-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/test/integ.existing-resources.ts index a2aada18c..264489203 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/test/integ.existing-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-dynamodb/test/integ.existing-resources.ts @@ -26,11 +26,11 @@ const stack = new Stack(app, generateIntegStackName(__filename), { stack.templateOptions.description = 'Integration Test with existing VPC and Service and Table'; const existingVpc = getTestVpc(stack); -const [ existingTable ] = defaults.buildDynamoDBTable(stack, {}); +const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, {}); const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -43,9 +43,9 @@ const [testService, testContainer] = CreateFargateService(stack, const constructProps: FargateToDynamoDBProps = { publicApi: true, existingVpc, - existingTableInterface: existingTable, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingTableInterface: buildDynamoDBTableResponse.tableObject, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, tableArnEnvironmentVariableName: 'CUSTOM_ARN', tableEnvironmentVariableName: 'CUSTOM_NAME' }; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/lib/index.ts index 376a7aece..346e89f6e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/lib/index.ts @@ -149,7 +149,7 @@ export class FargateToEventbridge extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -160,6 +160,8 @@ export class FargateToEventbridge extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } this.eventBus = defaults.buildEventBus(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/fargate-eventbridge.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/fargate-eventbridge.test.ts index 40045e7bf..1ac19bacb 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/fargate-eventbridge.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/fargate-eventbridge.test.ts @@ -76,7 +76,7 @@ test('Check for an existing service', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, { clusterName }, @@ -88,8 +88,8 @@ test('Check for an existing service', () => { new FargateToEventbridge(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, }); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/integ.existing-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/integ.existing-resources.ts index c15741d51..5efbcaa67 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/integ.existing-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-eventbridge/test/integ.existing-resources.ts @@ -28,7 +28,7 @@ stack.templateOptions.description = 'Integration Test with existing VPC, Service const existingVpc = getTestVpc(stack); const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -44,8 +44,8 @@ const testProps: FargateToEventbridgeProps = { publicApi: true, existingVpc, existingEventBusInterface: existingEventBus, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, eventBusEnvironmentVariableName: 'CUSTOM_ARN', }; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/lib/index.ts index 01c62ab3f..4595e58ac 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/lib/index.ts @@ -146,7 +146,7 @@ export class FargateToKinesisFirehose extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -157,6 +157,8 @@ export class FargateToKinesisFirehose extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } this.kinesisFirehose = props.existingKinesisFirehose; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/test/aws-fargate-kinesisfirehose.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/test/aws-fargate-kinesisfirehose.test.ts index 83d26ac86..2191cf13b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/test/aws-fargate-kinesisfirehose.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/test/aws-fargate-kinesisfirehose.test.ts @@ -668,7 +668,7 @@ test('Construct uses existingFargateServiceObject when provided', () => { const existingVpc = defaults.getTestVpc(stack); - const [existingFargateServiceObject, existingContainerDefinitionObject] = defaults.CreateFargateService(stack, 'test-existing-fargate-service', + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test-existing-fargate-service', existingVpc, { clusterName: 'my-cluster' }, defaults.fakeEcrRepoArn, @@ -682,8 +682,8 @@ test('Construct uses existingFargateServiceObject when provided', () => { publicApi: false, existingVpc, existingKinesisFirehose: destination.kinesisFirehose, - existingFargateServiceObject, - existingContainerDefinitionObject + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition }); expect(stack).toCountResources('AWS::ECS::Cluster', 1); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/test/integ.existingFargateService.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/test/integ.existingFargateService.ts index 97161a1bd..2c020c87d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/test/integ.existingFargateService.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisfirehose/test/integ.existingFargateService.ts @@ -27,7 +27,7 @@ const image = ecs.ContainerImage.fromRegistry('nginx'); const destination = GetTestFirehoseDestination(stack, 'destination-firehose'); -const [existingFargateServiceObject, existingContainerDefinitionObject] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -40,8 +40,8 @@ const [existingFargateServiceObject, existingContainerDefinitionObject] = Create new FargateToKinesisFirehose(stack, 'test-fargate-kinesisstreams', { publicApi: true, existingVpc, - existingFargateServiceObject, - existingContainerDefinitionObject, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingKinesisFirehose: destination.kinesisFirehose }); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/lib/index.ts index 3da292938..64eee4a29 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/lib/index.ts @@ -170,7 +170,7 @@ export class FargateToKinesisStreams extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -181,6 +181,8 @@ export class FargateToKinesisStreams extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } // Setup the Kinesis Stream diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/fargate-kinesisstreams.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/fargate-kinesisstreams.test.ts index f07066f93..6e864825c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/fargate-kinesisstreams.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/fargate-kinesisstreams.test.ts @@ -573,7 +573,7 @@ test('Construct uses existingFargateServiceObject when provided', () => { const existingVpc = defaults.getTestVpc(stack); - const [existingFargateServiceObject, existingContainerDefinitionObject] = defaults.CreateFargateService(stack, 'test-existing-fargate-service', + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test-existing-fargate-service', existingVpc, { clusterName: 'my-cluster' }, defaults.fakeEcrRepoArn, @@ -586,8 +586,8 @@ test('Construct uses existingFargateServiceObject when provided', () => { new FargateToKinesisStreams(stack, 'test-fargate-kinesisstreams', { publicApi: false, existingVpc, - existingFargateServiceObject, - existingContainerDefinitionObject + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition }); expect(stack).toCountResources('AWS::ECS::Cluster', 1); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/integ.existingFargateService.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/integ.existingFargateService.ts index 0a82d8ccc..82cc70c70 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/integ.existingFargateService.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-kinesisstreams/test/integ.existingFargateService.ts @@ -24,7 +24,7 @@ const existingVpc = getTestVpc(stack); const image = ecs.ContainerImage.fromRegistry('nginx'); -const [existingFargateServiceObject, existingContainerDefinitionObject] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -37,8 +37,8 @@ const [existingFargateServiceObject, existingContainerDefinitionObject] = Create new FargateToKinesisStreams(stack, 'test-fargate-kinesisstreams', { publicApi: true, existingVpc, - existingFargateServiceObject, - existingContainerDefinitionObject + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition }); app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/lib/index.ts index 7f17e9078..7013befbd 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/lib/index.ts @@ -160,7 +160,7 @@ export class FargateToOpenSearch extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -171,6 +171,8 @@ export class FargateToOpenSearch extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } let cognitoAuthorizedRole: iam.Role; @@ -194,7 +196,9 @@ export class FargateToOpenSearch extends Construct { securityGroupIds }; - [this.openSearchDomain, this.openSearchRole] = defaults.buildOpenSearch(this, buildOpenSearchProps); + const buildOpenSearchResponse = defaults.buildOpenSearch(this, buildOpenSearchProps); + this.openSearchDomain = buildOpenSearchResponse.domain; + this.openSearchRole = buildOpenSearchResponse.role; if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { this.cloudWatchAlarms = defaults.buildOpenSearchCWAlarms(this); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/fargate-opensearch.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/fargate-opensearch.test.ts index 7d125bd9b..ed72a6738 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/fargate-opensearch.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/fargate-opensearch.test.ts @@ -549,7 +549,7 @@ test('Existing service/new domain, public API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -561,8 +561,8 @@ test('Existing service/new domain, public API, existing VPC', () => { new FargateToOpenSearch(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, openSearchDomainName: DOMAIN_NAME }); @@ -631,7 +631,7 @@ test('Existing service/new domain, private API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -643,8 +643,8 @@ test('Existing service/new domain, private API, existing VPC', () => { new FargateToOpenSearch(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, openSearchDomainName: DOMAIN_NAME }); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/integ.existing-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/integ.existing-resources.ts index b1d8561d9..8d6cf0643 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/integ.existing-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-opensearch/test/integ.existing-resources.ts @@ -28,7 +28,7 @@ stack.templateOptions.description = 'Integration Test with existing VPC, Service const existingVpc = getTestVpc(stack); const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -43,8 +43,8 @@ const testProps: FargateToOpenSearchProps = { existingVpc, openSearchDomainName: 'solution-constructs', cognitoDomainName: 'cogn-solution-constructs', - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, domainEndpointEnvironmentVariableName: 'CUSTOM_NAME', }; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts index 2baa7eb40..78463e6de 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/lib/index.ts @@ -177,7 +177,7 @@ export class FargateToS3 extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -188,17 +188,21 @@ export class FargateToS3 extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } // Setup the S3 Bucket let bucket: s3.IBucket; if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps: props.bucketProps, loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs }); + this.s3Bucket = buildS3BucketResponse.bucket; + this.s3LoggingBucket = buildS3BucketResponse.loggingBucket; bucket = this.s3Bucket; } else { bucket = props.existingBucketObj; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/test/fargate-s3.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/test/fargate-s3.test.ts index a410706b5..0d67afe39 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/test/fargate-s3.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/test/fargate-s3.test.ts @@ -434,7 +434,7 @@ test('Existing service/new bucket, public API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -446,8 +446,8 @@ test('Existing service/new bucket, public API, existing VPC', () => { new FargateToS3(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, bucketArnEnvironmentVariableName: customArn, bucketEnvironmentVariableName: customName, @@ -577,7 +577,7 @@ test('Existing service/existing bucket, private API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -593,8 +593,8 @@ test('Existing service/existing bucket, private API, existing VPC', () => { new FargateToS3(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, existingBucketObj: existingBucket, bucketPermissions: ['Write'] diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/test/integ.existing-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/test/integ.existing-resources.ts index 7f3802be7..e36f264e0 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-s3/test/integ.existing-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-s3/test/integ.existing-resources.ts @@ -33,7 +33,7 @@ const existingBucket = defaults.CreateScrapBucket(stack, { const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -47,8 +47,8 @@ const testProps: FargateToS3Props = { publicApi: true, existingVpc, existingBucketObj: existingBucket, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, bucketArnEnvironmentVariableName: 'CUSTOM_ARN', bucketEnvironmentVariableName: 'CUSTOM_NAME', bucketPermissions: ['Read', 'Write', 'Delete'], diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts index b183f0032..6e31f2a47 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/lib/index.ts @@ -158,7 +158,7 @@ export class FargateToSecretsmanager extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -169,6 +169,8 @@ export class FargateToSecretsmanager extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } if (props.existingSecretObj) { diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/fargate-secretsmanager.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/fargate-secretsmanager.test.ts index 0c0832573..13a58657d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/fargate-secretsmanager.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/fargate-secretsmanager.test.ts @@ -373,7 +373,7 @@ test('Existing service/new secret, public API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -385,8 +385,8 @@ test('Existing service/new secret, public API, existing VPC', () => { new FargateToSecretsmanager(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, secretEnvironmentVariableName: envName, secretProps: { @@ -499,7 +499,7 @@ test('Existing service/existing secret, private API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -515,8 +515,8 @@ test('Existing service/existing secret, private API, existing VPC', () => { new FargateToSecretsmanager(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, existingSecretObj }); @@ -614,7 +614,7 @@ test('Test error invalid secret permission', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -629,8 +629,8 @@ test('Test error invalid secret permission', () => { const app = () => { new FargateToSecretsmanager(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, grantWriteAccess: 'reed', existingSecretObj diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/integ.existing-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/integ.existing-resources.ts index 04d318e4c..0d18b520d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/integ.existing-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-secretsmanager/test/integ.existing-resources.ts @@ -30,7 +30,7 @@ const existingSecretObj = defaults.buildSecretsManagerSecret(stack, 'secret', {} const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -44,8 +44,8 @@ const constructProps: FargateToSecretsmanagerProps = { publicApi: true, existingVpc, existingSecretObj, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, }; new FargateToSecretsmanager(stack, 'test-construct', constructProps); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts index cb92c915b..c588a63ea 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/lib/index.ts @@ -170,7 +170,7 @@ export class FargateToSns extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -181,10 +181,12 @@ export class FargateToSns extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } // Setup the SNS topic - [this.snsTopic] = defaults.buildTopic(this, { + const buildTopicResponse = defaults.buildTopic(this, { existingTopicObj: props.existingTopicObject, topicProps: props.topicProps, enableEncryptionWithCustomerManagedKey: props.enableEncryptionWithCustomerManagedKey, @@ -192,6 +194,7 @@ export class FargateToSns extends Construct { encryptionKeyProps: props.encryptionKeyProps }); + this.snsTopic = buildTopicResponse.topic; this.snsTopic.grantPublish(this.service.taskDefinition.taskRole); const topicArnEnvironmentVariableName = props.topicArnEnvironmentVariableName || 'SNS_TOPIC_ARN'; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/test/fargate-sns.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/test/fargate-sns.test.ts index a53bdd7f9..271dcaf4b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/test/fargate-sns.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/test/fargate-sns.test.ts @@ -32,7 +32,7 @@ test('New service/new topic, public API, new VPC', () => { const serviceName = "custom-service-name"; const topicName = "custom-topic-name"; - new FargateToSns(stack, 'test-construct', { + const testConstruct = new FargateToSns(stack, 'test-construct', { publicApi, ecrRepositoryArn: defaults.fakeEcrRepoArn, vpcProps: { ipAddresses: ec2.IpAddresses.cidr('172.0.0.0/16') }, @@ -43,6 +43,7 @@ test('New service/new topic, public API, new VPC', () => { topicProps: { topicName }, }); + expect(testConstruct.snsTopic).toBeDefined(); expect(stack).toHaveResourceLike("AWS::ECS::Service", { LaunchType: 'FARGATE', DesiredCount: 2, @@ -196,7 +197,7 @@ test('Existing service/new topic, public API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -208,8 +209,8 @@ test('Existing service/new topic, public API, existing VPC', () => { new FargateToSns(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, topicArnEnvironmentVariableName: 'CUSTOM_ARN', topicNameEnvironmentVariableName: 'CUSTOM_NAME', @@ -285,7 +286,7 @@ test('Existing service/existing topic, private API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -301,8 +302,8 @@ test('Existing service/existing topic, private API, existing VPC', () => { new FargateToSns(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, existingTopicObject: existingTopic }); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/test/integ.existing-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/test/integ.existing-resources.ts index a3a66e3d1..4743214fa 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sns/test/integ.existing-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sns/test/integ.existing-resources.ts @@ -31,7 +31,7 @@ addCfnSuppressRules(existingTopic, [ { id: "W47", reason: "Stub topic for placeh const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -45,8 +45,8 @@ const testProps: FargateToSnsProps = { publicApi: true, existingVpc, existingTopicObject: existingTopic, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, topicArnEnvironmentVariableName: 'CUSTOM_ARN', topicNameEnvironmentVariableName: 'CUSTOM_NAME', }; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts index 8a521ecec..98cb0c95a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/lib/index.ts @@ -199,7 +199,7 @@ export class FargateToSqs extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -210,6 +210,8 @@ export class FargateToSqs extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } // Setup the dead letter queue, if applicable @@ -221,7 +223,7 @@ export class FargateToSqs extends Construct { }); // Setup the SQS Queue - [this.sqsQueue] = defaults.buildQueue(this, `${id}-queue`, { + const buildQueueResponse = defaults.buildQueue(this, `${id}-queue`, { queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue, existingQueueObj: props.existingQueueObj, @@ -229,6 +231,7 @@ export class FargateToSqs extends Construct { encryptionKey: props.encryptionKey, encryptionKeyProps: props.encryptionKeyProps }); + this.sqsQueue = buildQueueResponse.queue; // Enable message send and receive permissions for Fargate service by default if (props.queuePermissions) { diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/test/fargate-sqs.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/test/fargate-sqs.test.ts index 0b5690957..7814ad769 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/test/fargate-sqs.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/test/fargate-sqs.test.ts @@ -299,7 +299,7 @@ test('Existing service/new queue, public API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -311,8 +311,8 @@ test('Existing service/new queue, public API, existing VPC', () => { new FargateToSqs(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, queueUrlEnvironmentVariableName: customVariableName, queueArnEnvironmentVariableName: customArnName, @@ -401,7 +401,7 @@ test('Existing service/existing queue, private API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -417,8 +417,8 @@ test('Existing service/existing queue, private API, existing VPC', () => { new FargateToSqs(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, existingQueueObj: existingQueue }); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/test/integ.existing-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/test/integ.existing-resources.ts index 78c196ef3..7f04e60d2 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/test/integ.existing-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-sqs/test/integ.existing-resources.ts @@ -33,7 +33,7 @@ const existingQueue = new sqs.Queue(stack, 'test-queue', { const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -47,8 +47,8 @@ const testProps: FargateToSqsProps = { publicApi: true, existingVpc, existingQueueObj: existingQueue, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, queueUrlEnvironmentVariableName: 'CUSTOM_NAME', queuePermissions: ['Write', 'Read'] }; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts index 09d1b177b..3ba4a6a9f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/lib/index.ts @@ -157,7 +157,7 @@ export class FargateToSsmstringparameter extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -168,6 +168,8 @@ export class FargateToSsmstringparameter extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } // Setup the SSM String parameter diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/test/fargate-ssmstringparameter.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/test/fargate-ssmstringparameter.test.ts index f17adc0e8..739026732 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/test/fargate-ssmstringparameter.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/test/fargate-ssmstringparameter.test.ts @@ -461,7 +461,7 @@ test('Existing service/new parameter store, public API, existing VPC', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -473,8 +473,8 @@ test('Existing service/new parameter store, public API, existing VPC', () => { new FargateToSsmstringparameter(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, stringParameterEnvironmentVariableName: customName, stringParameterProps: { @@ -628,7 +628,7 @@ test('Existing service/existing parameter store, private API, existing VPC', () const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -642,8 +642,8 @@ test('Existing service/existing parameter store, private API, existing VPC', () new FargateToSsmstringparameter(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, existingStringParameterObj: existingParameterStore }); @@ -763,7 +763,7 @@ test('Test error invalid string parameter permission', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -778,8 +778,8 @@ test('Test error invalid string parameter permission', () => { const app = () => { new FargateToSsmstringparameter(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, stringParameterPermissions: 'reed', existingStringParameterObj @@ -795,7 +795,7 @@ test('Test error no existing object or prop provided', () => { const existingVpc = defaults.getTestVpc(stack, publicApi); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -808,8 +808,8 @@ test('Test error no existing object or prop provided', () => { const app = () => { new FargateToSsmstringparameter(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, }); }; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/test/integ.existing-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/test/integ.existing-resources.ts index f2d32288f..2e4afa201 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/test/integ.existing-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-ssmstringparameter/test/integ.existing-resources.ts @@ -35,7 +35,7 @@ const existingStringParameterObj = new ssm.StringParameter(stack, 'Parameter', { const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = CreateFargateService(stack, +const createFargateServiceResponse = CreateFargateService(stack, 'test', existingVpc, undefined, @@ -49,8 +49,8 @@ const constructProps: FargateToSsmstringparameterProps = { publicApi: true, existingVpc, existingStringParameterObj, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, stringParameterEnvironmentVariableName: 'CUSTOM_NAME', stringParameterPermissions: "readwrite" }; diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts index 3dd5ba873..3ae716eea 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/lib/index.ts @@ -155,7 +155,7 @@ export class FargateToStepfunctions extends Construct { // CheckFargateProps confirms that the container is provided this.container = props.existingContainerDefinitionObject!; } else { - [this.service, this.container] = defaults.CreateFargateService( + const createFargateServiceResponse = defaults.CreateFargateService( scope, id, this.vpc, @@ -166,10 +166,14 @@ export class FargateToStepfunctions extends Construct { props.containerDefinitionProps, props.fargateServiceProps ); + this.service = createFargateServiceResponse.service; + this.container = createFargateServiceResponse.containerDefinition; } - [this.stateMachine, this.stateMachineLogGroup] = defaults.buildStateMachine(this, props.stateMachineProps, + const buildStateMachineResponse = defaults.buildStateMachine(this, props.stateMachineProps, props.logGroupProps); + this.stateMachine = buildStateMachineResponse.stateMachine; + this.stateMachineLogGroup = buildStateMachineResponse.logGroup; this.stateMachine.grantStartExecution(this.service.taskDefinition.taskRole); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/fargate-stepfunctions.test.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/fargate-stepfunctions.test.ts index 762c9c36d..6e6518e80 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/fargate-stepfunctions.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/fargate-stepfunctions.test.ts @@ -63,7 +63,7 @@ test('Check for an existing service', () => { const existingVpc = defaults.getTestVpc(stack); - const [testService, testContainer] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, { clusterName }, @@ -75,8 +75,8 @@ test('Check for an existing service', () => { new FargateToStepfunctions(stack, 'test-construct', { publicApi, - existingFargateServiceObject: testService, - existingContainerDefinitionObject: testContainer, + existingFargateServiceObject: createFargateServiceResponse.service, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, existingVpc, stateMachineProps: testStateMachineProps(stack) }); diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.ts index 39d1b3c30..7fbc9bd56 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.new-resources.ts @@ -29,7 +29,7 @@ const existingVpc = defaults.getTestVpc(stack); const startState = new stepfunctions.Pass(stack, 'StartState'); const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = defaults.CreateFargateService(stack, +const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -45,8 +45,8 @@ const constructProps: FargateToStepfunctionsProps = { stateMachineProps: { definition: startState }, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, stateMachineEnvironmentVariableName: 'CUSTOM_NAME', logGroupProps: { removalPolicy: RemovalPolicy.DESTROY diff --git a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.ts b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.ts index 2aaed3376..d42018563 100644 --- a/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.ts +++ b/source/patterns/@aws-solutions-constructs/aws-fargate-stepfunctions/test/integ.no-cloudwatch-alarms.ts @@ -29,7 +29,7 @@ const existingVpc = defaults.getTestVpc(stack); const startState = new stepfunctions.Pass(stack, 'StartState'); const image = ecs.ContainerImage.fromRegistry('nginx'); -const [testService, testContainer] = defaults.CreateFargateService(stack, +const createFargateServiceResponse = defaults.CreateFargateService(stack, 'test', existingVpc, undefined, @@ -45,8 +45,8 @@ const constructProps: FargateToStepfunctionsProps = { stateMachineProps: { definition: startState }, - existingContainerDefinitionObject: testContainer, - existingFargateServiceObject: testService, + existingContainerDefinitionObject: createFargateServiceResponse.containerDefinition, + existingFargateServiceObject: createFargateServiceResponse.service, createCloudWatchAlarms: false, logGroupProps: { removalPolicy: RemovalPolicy.DESTROY diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts index f5d7b58f5..51e6e278b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-s3/lib/index.ts @@ -81,11 +81,13 @@ export class IotToS3 extends Construct { // Setup S3 Bucket if (!props.existingBucketInterface) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps: props.bucketProps, loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs }); + this.s3Bucket = buildS3BucketResponse.bucket; + this.s3LoggingBucket = buildS3BucketResponse.loggingBucket; this.s3BucketInterface = this.s3Bucket; } else { this.s3BucketInterface = props.existingBucketInterface; diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-s3/test/integ.iot-s3-existing-bucket.ts b/source/patterns/@aws-solutions-constructs/aws-iot-s3/test/integ.iot-s3-existing-bucket.ts index aba431997..e164a84f1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-s3/test/integ.iot-s3-existing-bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-s3/test/integ.iot-s3-existing-bucket.ts @@ -21,9 +21,7 @@ import { BucketEncryption } from "aws-cdk-lib/aws-s3"; const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); -let existingBucketObj; - -[existingBucketObj] = defaults.buildS3Bucket(stack, { +const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { removalPolicy: RemovalPolicy.DESTROY, encryption: BucketEncryption.KMS_MANAGED, @@ -39,11 +37,11 @@ const props: IotToS3Props = { actions: [] } }, - existingBucketInterface: existingBucketObj, + existingBucketInterface: buildS3BucketResponse.bucket, s3Key: 'test/${timestamp()}' }; -defaults.addCfnSuppressRules(existingBucketObj, [ +defaults.addCfnSuppressRules(buildS3BucketResponse.bucket, [ { id: 'W35', reason: 'This S3 bucket is created for unit/ integration testing purposes only.' }, ]); diff --git a/source/patterns/@aws-solutions-constructs/aws-iot-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-iot-sqs/lib/index.ts index 6837a3b32..13a46e435 100644 --- a/source/patterns/@aws-solutions-constructs/aws-iot-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-iot-sqs/lib/index.ts @@ -119,7 +119,7 @@ export class IotToSqs extends Construct { } // Setup the queue - [this.sqsQueue, this.encryptionKey] = defaults.buildQueue(this, 'queue', { + const buildQueueResponse = defaults.buildQueue(this, 'queue', { existingQueueObj: props.existingQueueObj, queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue, @@ -127,6 +127,8 @@ export class IotToSqs extends Construct { encryptionKey: props.encryptionKey, encryptionKeyProps: props.encryptionKeyProps }); + this.sqsQueue = buildQueueResponse.queue; + this.encryptionKey = buildQueueResponse.key; if (this.sqsQueue.fifo) { throw new Error('The IoT SQS action doesn\'t support Amazon SQS FIFO (First-In-First-Out) queues'); 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 f7160f043..90925fb2e 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 @@ -103,11 +103,13 @@ export class KinesisFirehoseToS3 extends Construct { bucketProps; // Setup logging S3 Bucket - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps, loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs, }); + this.s3Bucket = buildS3BucketResponse.bucket; + this.s3LoggingBucket = buildS3BucketResponse.loggingBucket; bucket = this.s3Bucket; } else { diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts index d683332e7..daa211c06 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/lib/index.ts @@ -211,7 +211,7 @@ export class KinesisstreamsToGluejob extends Construct { }); } - [this.glueJob, this.glueJobRole, this.outputBucket] = defaults.buildGlueJob(this, { + const buildGlueJobResponse = defaults.buildGlueJob(this, { existingCfnJob: props.existingGlueJob, glueJobProps: props.glueJobProps, table: this.table!, @@ -219,6 +219,11 @@ export class KinesisstreamsToGluejob extends Construct { outputDataStore: props.outputDataStore!, etlCodeAsset: props.etlCodeAsset }); + this.glueJob = buildGlueJobResponse.job; + this.glueJobRole = buildGlueJobResponse.role; + // We refactored the array of anonymous values out of the helper functions, but it was exposed in the + // construct interface, so we need to recreate it. + this.outputBucket = buildGlueJobResponse.bucket ? [ buildGlueJobResponse.bucket, buildGlueJobResponse.loggingBucket] : undefined; this.glueJobRole = this.buildRolePolicy(scope, id, this.database, this.table, this.glueJob, this.glueJobRole); diff --git a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/test/test.kinesisstream-gluejob.test.ts b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/test/test.kinesisstream-gluejob.test.ts index 1c4e0283d..7496793f4 100644 --- a/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/test/test.kinesisstream-gluejob.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-kinesisstreams-gluejob/test/test.kinesisstream-gluejob.test.ts @@ -13,6 +13,7 @@ import * as path from "path"; import * as s3assets from "aws-cdk-lib/aws-s3-assets"; +import * as s3 from "aws-cdk-lib/aws-s3"; import { ResourcePart } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import { CfnDatabase, CfnJob } from 'aws-cdk-lib/aws-glue'; @@ -22,9 +23,6 @@ import * as defaults from '@aws-solutions-constructs/core'; import { SinkStoreType } from '@aws-solutions-constructs/core'; import { KinesisstreamsToGluejob, KinesisstreamsToGluejobProps } from '../lib'; -// -------------------------------------------------------------- -// Pattern minimal deployment -// -------------------------------------------------------------- test('Pattern minimal deployment', () => { // Initial setup const stack = new Stack(); @@ -59,6 +57,10 @@ test('Pattern minimal deployment', () => { const construct = new KinesisstreamsToGluejob(stack, id, props); + expect(construct.outputBucket).toBeDefined(); + expect(construct.outputBucket![0]).toBeDefined(); + expect(construct.outputBucket![1]).toBeDefined(); + // check for role creation expect(stack).toHaveResourceLike('AWS::IAM::Role', { Properties: { @@ -268,9 +270,6 @@ test('Pattern minimal deployment', () => { expect(construct.cloudwatchAlarms).toBeDefined(); }); -// -------------------------------------------------------------- -// Test if existing Glue Job is provided -// -------------------------------------------------------------- test('Test if existing Glue Job is provided', () => { // Initial setup const stack = new Stack(); @@ -285,7 +284,7 @@ test('Test if existing Glue Job is provided', () => { securityConfiguration: 'testSecConfig' }); - new KinesisstreamsToGluejob(stack, 'test-kinesisstreams-lambda', { + const construct = new KinesisstreamsToGluejob(stack, 'test-kinesisstreams-lambda', { existingGlueJob: existingCfnJob, fieldSchema: [{ name: "id", @@ -306,6 +305,8 @@ test('Test if existing Glue Job is provided', () => { }], }); + expect(construct.outputBucket).not.toBeDefined(); + // check for Kinesis Stream expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', { Properties: { @@ -320,9 +321,6 @@ test('Test if existing Glue Job is provided', () => { }, ResourcePart.CompleteDefinition); }); -// -------------------------------------------------------------- -// Test if existing S3 bucket location for script is provided -// -------------------------------------------------------------- test('When S3 bucket location for script exists', () => { // Initial setup const stack = new Stack(); @@ -356,7 +354,12 @@ test('When S3 bucket location for script exists', () => { datastoreType: SinkStoreType.S3 } }; - new KinesisstreamsToGluejob(stack, 'test-kinesisstreams-lambda', props); + const construct = new KinesisstreamsToGluejob(stack, 'test-kinesisstreams-lambda', props); + + expect(construct.outputBucket).toBeDefined(); + expect(construct.outputBucket![0]).toBeDefined(); + expect(construct.outputBucket![1]).toBeDefined(); + expect(stack).toHaveResourceLike('AWS::Glue::Job', { Type: 'AWS::Glue::Job', Properties: { @@ -369,9 +372,6 @@ test('When S3 bucket location for script exists', () => { }, ResourcePart.CompleteDefinition); }); -// -------------------------------------------------------------- -// Test when the construct is supplied with an existing stream -// -------------------------------------------------------------- test('create glue job with existing kinesis stream', () => { const stack = new Stack(); const _kinesisStream = new Stream(stack, 'FakeStream', { @@ -422,9 +422,6 @@ test('create glue job with existing kinesis stream', () => { }, ResourcePart.CompleteDefinition); }); -// -------------------------------------------------------------- -// Test if no script loocation is provided -// -------------------------------------------------------------- test('Do not pass s3ObjectUrlForScript or scriptLocationPath, error out', () => { const stack = new Stack(); try { @@ -463,9 +460,6 @@ test('Do not pass s3ObjectUrlForScript or scriptLocationPath, error out', () => } }); -// -------------------------------------------------------------- -// Test when neither CfnTable nor Table schem structure is provided -// -------------------------------------------------------------- test('Do not pass fieldSchame or table (CfnTable), error out', () => { const stack = new Stack(); @@ -488,9 +482,6 @@ test('Do not pass fieldSchame or table (CfnTable), error out', () => { } }); -// -------------------------------------------------------------- -// Provide a database and table -// -------------------------------------------------------------- test('When database and table are provided', () => { // Initial setup const stack = new Stack(); @@ -527,7 +518,12 @@ test('When database and table are provided', () => { comment: "Some value associated with the record" }], 'kinesis', { STREAM_NAME: 'testStream' }) }; - new KinesisstreamsToGluejob(stack, 'test-kinesisstreams-lambda', props); + const construct = new KinesisstreamsToGluejob(stack, 'test-kinesisstreams-lambda', props); + + expect(construct.outputBucket).toBeDefined(); + expect(construct.outputBucket![0]).toBeDefined(); + expect(construct.outputBucket![1]).toBeDefined(); + expect(stack).toHaveResourceLike('AWS::Glue::Database', { Type: "AWS::Glue::Database", Properties: { @@ -539,9 +535,6 @@ test('When database and table are provided', () => { }, ResourcePart.CompleteDefinition); }); -// -------------------------------------------------------------- -// When database and table are not provided & cloudwatch alarms set to false -// -------------------------------------------------------------- test('When database and table are not provided & cloudwatch alarms set to false', () => { // Initial setup const stack = new Stack(); @@ -573,6 +566,11 @@ test('When database and table are not provided & cloudwatch alarms set to false' }] }; const construct = new KinesisstreamsToGluejob(stack, 'test-kinesisstreams-lambda', props); + + expect(construct.outputBucket).toBeDefined(); + expect(construct.outputBucket![0]).toBeDefined(); + expect(construct.outputBucket![1]).toBeDefined(); + expect(stack).toHaveResourceLike('AWS::Glue::Database', { Type: "AWS::Glue::Database", Properties: { @@ -713,6 +711,10 @@ test('When Asset for local file is defined', () => { const id = 'test-kinesisstreams-lambda'; const construct = new KinesisstreamsToGluejob(stack, id, props); + expect(construct.outputBucket).toBeDefined(); + expect(construct.outputBucket![0]).toBeDefined(); + expect(construct.outputBucket![1]).toBeDefined(); + // Check for properties expect(construct.database).toBeDefined(); expect(construct.glueJob).toBeDefined(); @@ -812,4 +814,50 @@ test('When Asset for local file is defined', () => { WorkerType: "G.1X" } }, ResourcePart.CompleteDefinition); -}); \ No newline at end of file +}); + +test('Check properties when output bucket is provided', () => { + // Initial setup + const stack = new Stack(); + + const outputBucket = new s3.Bucket(stack, 'output-bucket'); + + const props: KinesisstreamsToGluejobProps = { + glueJobProps: { + command: { + name: 'glueetl', + pythonVersion: '3', + scriptLocation: 's3://fakebucket/fakefolder/fakefolder/fakefile.py' + } + }, + fieldSchema: [{ + name: "id", + type: "int", + comment: "Identifier for the record" + }, { + name: "name", + type: "string", + comment: "The name of the record" + }, { + name: "type", + type: "string", + comment: "The type of the record" + }, { + name: "numericvalue", + type: "int", + comment: "Some value associated with the record" + }], + outputDataStore: { + existingS3OutputBucket: outputBucket, + datastoreType: SinkStoreType.S3 + } + }; + + const id = 'test-kinesisstreams-lambda'; + + const construct = new KinesisstreamsToGluejob(stack, id, props); + + expect(construct.outputBucket).toBeDefined(); + expect(construct.outputBucket![0]).toBeDefined(); + expect(construct.outputBucket![1]).not.toBeDefined(); +}); 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 b46444b4d..73cfa2d0e 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 @@ -125,10 +125,11 @@ export class LambdaToDynamoDB extends Construct { // Since we are only invoking this function with an existing Table or tableProps, // (not a table interface), we know that the implementation will always return // a Table object and we can safely cast away the optional aspect of the type. - this.dynamoTable = defaults.buildDynamoDBTable(this, { + const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(this, { dynamoTableProps: props.dynamoTableProps, existingTableObj: props.existingTableObj - })[1] as dynamodb.Table; + }); + this.dynamoTable = buildDynamoDBTableResponse.tableObject!; // Configure environment variables const tableEnvironmentVariableName = props.tableEnvironmentVariableName || 'DDB_TABLE_NAME'; 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 3cfd339ef..dffaf3625 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 @@ -162,7 +162,9 @@ export class LambdaToElasticSearchAndKibana extends Construct { buildElasticSearchProps.securityGroupIds = securityGroupIds; } - [this.elasticsearchDomain, this.elasticsearchRole] = defaults.buildElasticSearch(this, buildElasticSearchProps); + const buildElasticSearchResponse = defaults.buildElasticSearch(this, buildElasticSearchProps); + this.elasticsearchDomain = buildElasticSearchResponse.domain; + this.elasticsearchRole = buildElasticSearchResponse.role; // Add ES Domain to lambda environment variable const domainEndpointEnvironmentVariableName = props.domainEndpointEnvironmentVariableName || 'DOMAIN_ENDPOINT'; diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/lib/index.ts index 7657145e7..af3bee054 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-opensearch/lib/index.ts @@ -160,7 +160,9 @@ export class LambdaToOpenSearch extends Construct { securityGroupIds }; - [this.openSearchDomain, this.openSearchRole] = defaults.buildOpenSearch(this, buildOpenSearchProps); + const buildOpenSearchResponse = defaults.buildOpenSearch(this, buildOpenSearchProps); + this.openSearchDomain = buildOpenSearchResponse.domain; + this.openSearchRole = buildOpenSearchResponse.role; if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) { this.cloudWatchAlarms = defaults.buildOpenSearchCWAlarms(this); 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 605f81d1a..4b8cec0ac 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 @@ -140,11 +140,14 @@ export class LambdaToS3 extends Construct { // Setup S3 Bucket if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps: props.bucketProps, loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs }); + this.s3Bucket = buildS3BucketResponse.bucket; + this.s3LoggingBucket = buildS3BucketResponse.loggingBucket; + bucket = this.s3Bucket; } else { bucket = props.existingBucketObj; diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts index 009949b0a..a59c19713 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/lib/index.ts @@ -130,13 +130,16 @@ export class LambdaToSagemakerEndpoint extends Construct { } // Build SageMaker Endpoint (inclduing SageMaker's Endpoint Configuration and Model) - [this.sagemakerEndpoint, this.sagemakerEndpointConfig, this.sagemakerModel] = defaults.BuildSagemakerEndpoint( + const buildSagemakerEndpointResponse = defaults.BuildSagemakerEndpoint( this, { ...props, vpc: this.vpc, } ); + this.sagemakerEndpoint = buildSagemakerEndpointResponse.endpoint; + this.sagemakerEndpointConfig = buildSagemakerEndpointResponse.endpointConfig; + this.sagemakerModel = buildSagemakerEndpointResponse.model; // Setup the Lambda function this.lambdaFunction = defaults.buildLambdaFunction(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/aws-lambda-sagemakerendpoint.test.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/aws-lambda-sagemakerendpoint.test.ts index 52a13eb79..8a5a13f90 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/aws-lambda-sagemakerendpoint.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/aws-lambda-sagemakerendpoint.test.ts @@ -474,7 +474,7 @@ test('Test getter methods: new Lambda function, existingSagemakerendpointObj (no // Initial Setup const stack = new Stack(); - const [sagemakerEndpoint] = defaults.deploySagemakerEndpoint(stack, { + const deploySagemakerEndpointResponse = defaults.deploySagemakerEndpoint(stack, { modelProps: { primaryContainer: { image: '.dkr.ecr..amazonaws.com/linear-learner:latest', @@ -484,7 +484,7 @@ test('Test getter methods: new Lambda function, existingSagemakerendpointObj (no }); const constructProps: LambdaToSagemakerEndpointProps = { - existingSagemakerEndpointObj: sagemakerEndpoint, + existingSagemakerEndpointObj: deploySagemakerEndpointResponse.endpoint, lambdaFunctionProps: { runtime: lambda.Runtime.PYTHON_3_8, code: lambda.Code.fromAsset(`${__dirname}/lambda`), @@ -509,7 +509,7 @@ test('Test getter methods: new Lambda function, existingSagemakerendpointObj and // Initial Setup const stack = new Stack(); - const [sagemakerEndpoint] = defaults.deploySagemakerEndpoint(stack, { + const deploySagemakerEndpointResponse = defaults.deploySagemakerEndpoint(stack, { modelProps: { primaryContainer: { image: '.dkr.ecr..amazonaws.com/linear-learner:latest', @@ -519,7 +519,7 @@ test('Test getter methods: new Lambda function, existingSagemakerendpointObj and }); const constructProps: LambdaToSagemakerEndpointProps = { - existingSagemakerEndpointObj: sagemakerEndpoint, + existingSagemakerEndpointObj: deploySagemakerEndpointResponse.endpoint, lambdaFunctionProps: { runtime: lambda.Runtime.PYTHON_3_8, code: lambda.Code.fromAsset(`${__dirname}/lambda`), @@ -546,7 +546,7 @@ test('Test lambda function custom environment variable', () => { const stack = new Stack(); // Helper declaration - const [sagemakerEndpoint] = defaults.deploySagemakerEndpoint(stack, { + const deploySagemakerEndpointResponse = defaults.deploySagemakerEndpoint(stack, { modelProps: { primaryContainer: { image: '.dkr.ecr..amazonaws.com/linear-learner:latest', @@ -555,7 +555,7 @@ test('Test lambda function custom environment variable', () => { }, }); new LambdaToSagemakerEndpoint(stack, 'test-lambda-sagemaker', { - existingSagemakerEndpointObj: sagemakerEndpoint, + existingSagemakerEndpointObj: deploySagemakerEndpointResponse.endpoint, lambdaFunctionProps: { runtime: lambda.Runtime.PYTHON_3_8, handler: 'index.handler', diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.deployFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.deployFunction.ts index 132581940..8c9ca32ab 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.deployFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.deployFunction.ts @@ -23,13 +23,13 @@ const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); stack.templateOptions.description = 'Integration Test for aws-lambda-sagemakerendpoint'; -const [containerMap, modelAsset ] = getSagemakerModel(stack); +const getSagemakerModelResponse = getSagemakerModel(stack); const constructProps: LambdaToSagemakerEndpointProps = { modelProps: { primaryContainer: { - image: containerMap.findInMap(Stack.of(stack).region, "containerArn"), - modelDataUrl: modelAsset.s3ObjectUrl + image: getSagemakerModelResponse.mapping.findInMap(Stack.of(stack).region, "containerArn"), + modelDataUrl: getSagemakerModelResponse.asset.s3ObjectUrl }, }, lambdaFunctionProps: { @@ -43,7 +43,7 @@ const constructProps: LambdaToSagemakerEndpointProps = { const lambdaToSagemakerConstruct = new LambdaToSagemakerEndpoint(stack, 'test-lambda-sagemaker', constructProps); -lambdaToSagemakerConstruct.node.addDependency(modelAsset); +lambdaToSagemakerConstruct.node.addDependency(getSagemakerModelResponse.asset); // Synth app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.existingFunction.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.existingFunction.ts index 2aa25e66e..9f661901b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.existingFunction.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.existingFunction.ts @@ -33,13 +33,13 @@ const fn = defaults.deployLambdaFunction(stack, { memorySize: 128, }); -const [containerMap, modelAsset ] = getSagemakerModel(stack); +const getSagemakerModelResponse = getSagemakerModel(stack); const constructProps: LambdaToSagemakerEndpointProps = { modelProps: { primaryContainer: { - image: containerMap.findInMap(Stack.of(stack).region, "containerArn"), - modelDataUrl: modelAsset.s3ObjectUrl + image: getSagemakerModelResponse.mapping.findInMap(Stack.of(stack).region, "containerArn"), + modelDataUrl: getSagemakerModelResponse.asset.s3ObjectUrl }, }, existingLambdaObj: fn, @@ -48,7 +48,7 @@ const constructProps: LambdaToSagemakerEndpointProps = { // Fix names and construct IDs const lambdaToSagemakerConstruct = new LambdaToSagemakerEndpoint(stack, 'test-lambda-sagemaker', constructProps); -lambdaToSagemakerConstruct.node.addDependency(modelAsset); +lambdaToSagemakerConstruct.node.addDependency(getSagemakerModelResponse.asset); // Synth app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.existingSageMakerEndpoint.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.existingSageMakerEndpoint.ts index d597e6dea..c63a0aeac 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.existingSageMakerEndpoint.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/integ.existingSageMakerEndpoint.ts @@ -24,23 +24,23 @@ const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); stack.templateOptions.description = 'Integration Test for aws-lambda-sagemakerendpoint'; -const [containerMap, modelAsset ] = getSagemakerModel(stack); +const getSagemakerModelResponse = getSagemakerModel(stack); -const [sagemakerEndpoint, endpointConfig, model] = defaults.deploySagemakerEndpoint(stack, { +const deploySagemakerEndpointResponse = defaults.deploySagemakerEndpoint(stack, { modelProps: { primaryContainer: { - image: containerMap.findInMap(Stack.of(stack).region, "containerArn"), - modelDataUrl: modelAsset.s3ObjectUrl + image: getSagemakerModelResponse.mapping.findInMap(Stack.of(stack).region, "containerArn"), + modelDataUrl: getSagemakerModelResponse.asset.s3ObjectUrl }, }, }); -sagemakerEndpoint.node.addDependency(modelAsset); -endpointConfig?.node.addDependency(modelAsset); -model?.node.addDependency(modelAsset); +deploySagemakerEndpointResponse.endpoint.node.addDependency(getSagemakerModelResponse.asset); +deploySagemakerEndpointResponse.endpointConfig?.node.addDependency(getSagemakerModelResponse.asset); +deploySagemakerEndpointResponse.model?.node.addDependency(getSagemakerModelResponse.asset); const constructProps: LambdaToSagemakerEndpointProps = { - existingSagemakerEndpointObj: sagemakerEndpoint, + existingSagemakerEndpointObj: deploySagemakerEndpointResponse.endpoint, lambdaFunctionProps: { runtime: lambda.Runtime.PYTHON_3_8, code: lambda.Code.fromAsset(`${__dirname}/lambda`), @@ -52,7 +52,7 @@ const constructProps: LambdaToSagemakerEndpointProps = { const lambdaToSagemakerConstruct = new LambdaToSagemakerEndpoint(stack, 'test-lambda-sagemaker', constructProps); -lambdaToSagemakerConstruct.node.addDependency(modelAsset); +lambdaToSagemakerConstruct.node.addDependency(getSagemakerModelResponse.asset); // Synth app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/test-helper.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/test-helper.ts index 494a7b8d6..2b8693959 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/test-helper.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-sagemakerendpoint/test/test-helper.ts @@ -14,9 +14,14 @@ import * as s3a from 'aws-cdk-lib/aws-s3-assets'; import { Stack, CfnMapping } from 'aws-cdk-lib'; +export interface GetSagemakerModelResponse { + readonly mapping: CfnMapping, + readonly asset: s3a.Asset, +} + // linear learner ECR images can be found here: // https://github.com/awsdocs/amazon-sagemaker-developer-guide/blob/master/doc_source/sagemaker-algo-docker-registry-paths.md -export function getSagemakerModel(stack: Stack): [CfnMapping, s3a.Asset ] { +export function getSagemakerModel(stack: Stack): GetSagemakerModelResponse { const containerMap = new CfnMapping(stack, 'mappings', { mapping: { @@ -90,6 +95,6 @@ export function getSagemakerModel(stack: Stack): [CfnMapping, s3a.Asset ] { path: 'model/model.tar.gz', }); - return [containerMap, modelAsset]; + return { mapping: containerMap, asset: modelAsset }; } \ 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 7f5812b11..eb3072a10 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 @@ -137,7 +137,7 @@ export class LambdaToSns extends Construct { }); // Setup the SNS topic - [this.snsTopic] = defaults.buildTopic(this, { + const buildTopicResponse = defaults.buildTopic(this, { existingTopicObj: props.existingTopicObj, topicProps: props.topicProps, enableEncryptionWithCustomerManagedKey: props.enableEncryptionWithCustomerManagedKey, @@ -145,6 +145,7 @@ export class LambdaToSns extends Construct { encryptionKeyProps: props.encryptionKeyProps }); + this.snsTopic = buildTopicResponse.topic; // Configure environment variables const topicArnEnvironmentVariableName = props.topicArnEnvironmentVariableName || 'SNS_TOPIC_ARN'; this.lambdaFunction.addEnvironment(topicArnEnvironmentVariableName, this.snsTopic.topicArn); 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 df4736307..251d496c4 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 @@ -28,7 +28,7 @@ test('Test deployment with new Lambda function', () => { // Stack const stack = new Stack(); // Helper declaration - new LambdaToSns(stack, 'lambda-to-sns-stack', { + const testConstruct = new LambdaToSns(stack, 'lambda-to-sns-stack', { lambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_14_X, handler: 'index.handler', @@ -39,6 +39,7 @@ test('Test deployment with new Lambda function', () => { } }); + expect(testConstruct.snsTopic).toBeDefined(); expect(stack).toHaveResourceLike("AWS::Lambda::Function", { Environment: { Variables: { 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 e1e535e73..b436bdb9f 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 @@ -24,7 +24,7 @@ const stack = new Stack(app, generateIntegStackName(__filename)); stack.templateOptions.description = 'Integration Test for aws-lambda-sqs-lambda'; // Definitions -const [existingQueue] = defaults.buildQueue(stack, 'existing-sqs-queue', {}); +const buildQueueResponse = defaults.buildQueue(stack, 'existing-sqs-queue', {}); const props: LambdaToSqsToLambdaProps = { producerLambdaFunctionProps: { @@ -32,7 +32,7 @@ const props: LambdaToSqsToLambdaProps = { handler: 'index.handler', code: lambda.Code.fromAsset(`${__dirname}/lambda/producer-function`) }, - existingQueueObj: existingQueue, + existingQueueObj: buildQueueResponse.queue, consumerLambdaFunctionProps: { runtime: lambda.Runtime.NODEJS_14_X, handler: 'index.handler', 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 e33ccf8ae..9454d568f 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 @@ -198,7 +198,7 @@ test('Test deployment w/ existing queue', () => { // Stack const stack = new Stack(); // Define existing resources - const [existingQueue] = defaults.buildQueue(stack, 'existing-queue', { + const buildQueueResponse = defaults.buildQueue(stack, 'existing-queue', { queueProps: { queueName: 'existing-queue' } @@ -217,7 +217,7 @@ test('Test deployment w/ existing queue', () => { code: lambda.Code.fromAsset(`${__dirname}/lambda/consumer-function`), functionName: 'consumer-function' }, - existingQueueObj: existingQueue + existingQueueObj: buildQueueResponse.queue }; new LambdaToSqsToLambda(stack, 'lambda-sqs-lambda', props); 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 74392933d..cfa860bb0 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 @@ -163,7 +163,7 @@ export class LambdaToSqs extends Construct { }); // Setup the queue - [this.sqsQueue] = defaults.buildQueue(this, 'queue', { + const buildQueueResponse = defaults.buildQueue(this, 'queue', { existingQueueObj: props.existingQueueObj, queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue, @@ -171,6 +171,7 @@ export class LambdaToSqs extends Construct { encryptionKey: props.encryptionKey, encryptionKeyProps: props.encryptionKeyProps }); + this.sqsQueue = buildQueueResponse.queue; // Configure environment variables const queueEnvironmentVariableName = props.queueEnvironmentVariableName || 'SQS_QUEUE_URL'; diff --git a/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts index a068e2a0b..9f6406460 100644 --- a/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-lambda-stepfunctions/lib/index.ts @@ -119,8 +119,10 @@ export class LambdaToStepfunctions extends Construct { } // Setup the state machine - [this.stateMachine, this.stateMachineLogGroup] = defaults.buildStateMachine(this, props.stateMachineProps, + const buildStateMachineResponse = defaults.buildStateMachine(this, props.stateMachineProps, props.logGroupProps); + this.stateMachine = buildStateMachineResponse.stateMachine; + this.stateMachineLogGroup = buildStateMachineResponse.logGroup; // Setup the Lambda function this.lambdaFunction = defaults.buildLambdaFunction(this, { diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/test/integ.dummyTest.ts b/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/test/integ.dummyTest.ts index dea5546d8..2c4610575 100644 --- a/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/test/integ.dummyTest.ts +++ b/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/test/integ.dummyTest.ts @@ -29,8 +29,8 @@ stack.templateOptions.description = 'Dummy Integration Test for aws-route53-apig // and will need to be regenerated. // Create dummy integ with at least one resource to pass CFN scan -const [restApi] = defaults.RegionalRestApi(stack); -restApi.root.addMethod('GET'); +const regionalRestApiResponse = defaults.RegionalRestApi(stack); +regionalRestApiResponse.api.root.addMethod('GET'); // Synth app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/test/test.route53-apigateway.test.ts b/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/test/test.route53-apigateway.test.ts index a5dba8602..9f240dd0e 100755 --- a/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/test/test.route53-apigateway.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-route53-apigateway/test/test.route53-apigateway.test.ts @@ -25,8 +25,8 @@ function deployApi( stack: cdk.Stack, publicApi: boolean ) { - const [restApi] = defaults.RegionalRestApi(stack); - restApi.root.addMethod('GET'); + const regionalRestApiResponse = defaults.RegionalRestApi(stack); + regionalRestApiResponse.api.root.addMethod('GET'); const domainName = "www.test-example.com"; @@ -62,7 +62,7 @@ function deployApi( const props: Route53ToApiGatewayProps = { publicApi, existingHostedZoneInterface: newZone, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, existingCertificateInterface: certificate, }; @@ -90,7 +90,7 @@ test("Test for default params construct props", () => { test("Test for errors when creating a private hosted zone", () => { // Initial Setup const stack = new cdk.Stack(); - const [restApi] = defaults.RegionalRestApi(stack); + const regionalRestApiResponse = defaults.RegionalRestApi(stack); const domainName = "www.test-example.com"; const vpc = defaults.buildVpc(stack, { @@ -116,7 +116,7 @@ test("Test for errors when creating a private hosted zone", () => { let app = () => new Route53ToApiGateway(stack, "api-stack1", { publicApi: true, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, existingCertificateInterface: certificate }); // Assertion 1 @@ -127,7 +127,7 @@ test("Test for errors when creating a private hosted zone", () => { app = () => new Route53ToApiGateway(stack, "api-stack2", { publicApi: false, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, existingCertificateInterface: certificate }); @@ -143,7 +143,7 @@ test("Test for errors when creating a private hosted zone", () => { zoneName: "test-example.com", vpc, }, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, existingCertificateInterface: certificate }); @@ -157,7 +157,7 @@ test("Test for errors when creating a private hosted zone", () => { publicApi: false, existingHostedZoneInterface: newZone, existingVpc: vpc, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, existingCertificateInterface: certificate }); @@ -170,7 +170,7 @@ test("Test for errors when creating a private hosted zone", () => { new Route53ToApiGateway(stack, "api-stack5", { publicApi: false, existingHostedZoneInterface: newZone, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, privateHostedZoneProps: { domainName: "test-example.com" }, @@ -188,7 +188,7 @@ test("Test for errors when creating a private hosted zone", () => { privateHostedZoneProps: { domainName: "test.example.com" }, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, existingCertificateInterface: certificate }); @@ -203,7 +203,7 @@ test("Test for errors when creating a private hosted zone", () => { privateHostedZoneProps: { zoneName: "test.example.com" }, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, existingCertificateInterface: certificate }); @@ -219,8 +219,8 @@ test("Test for errors when creating a private hosted zone", () => { test("Test for providing private hosted zone props", () => { // Initial Setup const stack = new cdk.Stack(); - const [restApi] = defaults.RegionalRestApi(stack); - restApi.root.addMethod('GET'); + const regionalRestApiResponse = defaults.RegionalRestApi(stack); + regionalRestApiResponse.api.root.addMethod('GET'); const domainName = "www.private-zone.com"; @@ -241,7 +241,7 @@ test("Test for providing private hosted zone props", () => { new Route53ToApiGateway(stack, "api-stack1", { publicApi: false, - existingApiGatewayInterface: restApi, + existingApiGatewayInterface: regionalRestApiResponse.api, privateHostedZoneProps: { zoneName: domainName, }, 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 732044169..d9e25271b 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 @@ -94,11 +94,14 @@ export class S3ToLambda extends Construct { }); if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps: props.bucketProps, loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs }); + this.s3Bucket = buildS3BucketResponse.bucket; + this.s3LoggingBucket = buildS3BucketResponse.loggingBucket; + bucket = this.s3Bucket; } else { bucket = props.existingBucketObj; diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sns/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sns/lib/index.ts index 52b25e11c..807a3fc14 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sns/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sns/lib/index.ts @@ -131,18 +131,21 @@ export class S3ToSns extends Construct { // Setup the S3 bucket if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps: props.bucketProps, loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs }); + this.s3Bucket = buildS3BucketResponse.bucket; + this.s3LoggingBucket = buildS3BucketResponse.loggingBucket; + this.s3BucketInterface = this.s3Bucket; } else { this.s3BucketInterface = props.existingBucketObj; } // Setup the topic - [this.snsTopic, this.encryptionKey] = defaults.buildTopic(this, { + const buildTopicResponse = defaults.buildTopic(this, { existingTopicObj: props.existingTopicObj, existingTopicEncryptionKey: props.existingTopicEncryptionKey, topicProps: props.topicProps, @@ -151,6 +154,8 @@ export class S3ToSns extends Construct { encryptionKeyProps: props.encryptionKeyProps }); + this.snsTopic = buildTopicResponse.topic; + this.encryptionKey = buildTopicResponse.key; // Setup the S3 bucket event types const s3EventTypes = props.s3EventTypes ?? defaults.defaultS3NotificationEventTypes; diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sns/test/integ.existingSnsTopic.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sns/test/integ.existingSnsTopic.ts index 23d88ea3d..2aa47961c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sns/test/integ.existingSnsTopic.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sns/test/integ.existingSnsTopic.ts @@ -21,12 +21,12 @@ const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); const existingTopicEncryptionKey = defaults.buildEncryptionKey(stack, {}); -const [ existingTopicObj ] = defaults.buildTopic(stack, { +const buildTopicResponse = defaults.buildTopic(stack, { encryptionKey: existingTopicEncryptionKey }); new S3ToSns(stack, 'test-s3-sns', { - existingTopicObj, + existingTopicObj: buildTopicResponse.topic, existingTopicEncryptionKey, bucketProps: { removalPolicy: RemovalPolicy.DESTROY diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sns/test/test.s3-sns.test.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sns/test/test.s3-sns.test.ts index 94e38ae93..779373f7b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sns/test/test.s3-sns.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sns/test/test.s3-sns.test.ts @@ -51,13 +51,13 @@ test('construct creates default event notification', () => { test('construct uses existingBucketObj property', () => { const stack = new Stack(); - const [ existingBucketObj ] = defaults.buildS3Bucket(stack, { + const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { bucketName: 'existing-bucket-name' } }); new S3ToSns(stack, 'test-s3-sns', { - existingBucketObj + existingBucketObj: buildS3BucketResponse.bucket }); expect(stack).toHaveResourceLike("AWS::S3::Bucket", { @@ -70,18 +70,20 @@ test('construct uses existing topic and key', () => { const cmk = defaults.buildEncryptionKey(stack, { description: 'existing-key-description' }); - const [ existingTopicObj ] = defaults.buildTopic(stack, { + const buildTopicResponse = defaults.buildTopic(stack, { encryptionKey: cmk, topicProps: { topicName: 'existing-topic-name' } }); - new S3ToSns(stack, 'test-s3-sns', { - existingTopicObj, + const testConstruct = new S3ToSns(stack, 'test-s3-sns', { + existingTopicObj: buildTopicResponse.topic, existingTopicEncryptionKey: cmk }); + expect(testConstruct.snsTopic).toBeDefined(); + expect(testConstruct.encryptionKey).toBeDefined(); expect(stack).toHaveResourceLike("AWS::SNS::Topic", { TopicName: 'existing-topic-name' }); @@ -232,10 +234,12 @@ test('Construct does not override unencrypted topic when passed in existingTopic topicName: 'existing-topic-name' }); - new S3ToSns(stack, 'test-s3-sns', { + const testConstruct = new S3ToSns(stack, 'test-s3-sns', { existingTopicObj }); + expect(testConstruct.snsTopic).toBeDefined(); + expect(testConstruct.encryptionKey).not.toBeDefined(); expect(stack).toCountResources('AWS::KMS::Key', 0); expect(stack).toCountResources('AWS::SNS::Topic', 1); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts index e6a705576..e64fe714b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts @@ -146,11 +146,14 @@ export class S3ToSqs extends Construct { // Setup the S3 bucket if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps: props.bucketProps, loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs }); + this.s3Bucket = buildS3BucketResponse.bucket; + this.s3LoggingBucket = buildS3BucketResponse.loggingBucket; + bucket = this.s3Bucket; } else { bucket = props.existingBucketObj; @@ -166,7 +169,7 @@ export class S3ToSqs extends Construct { maxReceiveCount: props.maxReceiveCount }); // Setup the queue - [this.sqsQueue, this.encryptionKey] = defaults.buildQueue(this, 'queue', { + const buildQueueResponse = defaults.buildQueue(this, 'queue', { existingQueueObj: props.existingQueueObj, queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue, @@ -174,6 +177,8 @@ export class S3ToSqs extends Construct { encryptionKey: props.encryptionKey, encryptionKeyProps: props.encryptionKeyProps }); + this.sqsQueue = buildQueueResponse.queue; + this.encryptionKey = buildQueueResponse.key; // Setup the S3 bucket event types let s3EventTypes; diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingQueue.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingQueue.ts index ef54bdea1..b726a9c10 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingQueue.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingQueue.ts @@ -22,12 +22,12 @@ const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); -const [myQueue] = defaults.buildQueue(stack, 'test-existing-queue', { +const buildQueueResponse = defaults.buildQueue(stack, 'test-existing-queue', { enableEncryptionWithCustomerManagedKey: true }); const props: S3ToSqsProps = { - existingQueueObj: myQueue, + existingQueueObj: buildQueueResponse.queue, bucketProps: { removalPolicy: RemovalPolicy.DESTROY, }, diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingS3Bucket.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingS3Bucket.ts index 1263d99ed..ad381b56a 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingS3Bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingS3Bucket.ts @@ -21,12 +21,12 @@ const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); -const [myBucket] = defaults.buildS3Bucket(stack, { bucketProps: { removalPolicy: RemovalPolicy.DESTROY }, }); +const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { removalPolicy: RemovalPolicy.DESTROY }, }); // Currently there is no way to customize the logging bucket, so this // test will leave a bucket behind const props: S3ToSqsProps = { - existingBucketObj: myBucket, + existingBucketObj: buildS3BucketResponse.bucket, }; new S3ToSqs(stack, 'test-s3-sqs', props); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/test.s3-sqs.test.ts b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/test.s3-sqs.test.ts index 870cf1c0a..b60b9a39d 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/test.s3-sqs.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/test.s3-sqs.test.ts @@ -84,9 +84,9 @@ test('Test deployment w/ existing Bucket', () => { const stack = new Stack(); // Helper declaration - const [myBucket] = defaults.buildS3Bucket(stack, {}); + const buildS3BucketResponse = defaults.buildS3Bucket(stack, {}); new S3ToSqs(stack, 'test-s3-sqs', { - existingBucketObj: myBucket + existingBucketObj: buildS3BucketResponse.bucket }); // Assertion 1 expect(stack).toHaveResource("Custom::S3BucketNotifications", { diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts index fbafcd04d..098f00fce 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts @@ -111,11 +111,14 @@ export class S3ToStepfunctions extends Construct { } if (!props.existingBucketObj) { - [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { + const buildS3BucketResponse = defaults.buildS3Bucket(this, { bucketProps: defaults.consolidateProps({}, props.bucketProps, { eventBridgeEnabled: true }), loggingBucketProps: props.loggingBucketProps, logS3AccessLogs: props.logS3AccessLogs }); + this.s3Bucket = buildS3BucketResponse.bucket; + this.s3LoggingBucket = buildS3BucketResponse.loggingBucket; + bucket = this.s3Bucket; // Suppress cfn-nag rules that generate warns for S3 bucket notification CDK resources 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 56ddeed37..86ff8ea10 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 @@ -94,7 +94,7 @@ export class SnsToLambda extends Construct { }); // Setup the SNS topic - [this.snsTopic] = defaults.buildTopic(this, { + const buildTopicResponse = defaults.buildTopic(this, { existingTopicObj: props.existingTopicObj, topicProps: props.topicProps, enableEncryptionWithCustomerManagedKey: props.enableEncryptionWithCustomerManagedKey, @@ -102,6 +102,8 @@ export class SnsToLambda extends Construct { encryptionKeyProps: props.encryptionKeyProps }); + this.snsTopic = buildTopicResponse.topic; + this.lambdaFunction.addEventSource(new SnsEventSource(this.snsTopic)); } } \ No newline at end of file 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 db02f8919..142c719e4 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 @@ -139,24 +139,27 @@ export class SnsToSqs extends Construct { // Setup the SNS topic if (!props.existingTopicObj) { // If an existingTopicObj was not specified create new topic - [this.snsTopic, this.encryptionKey] = defaults.buildTopic(this, { + const buildTopicResponse = defaults.buildTopic(this, { topicProps: props.topicProps, enableEncryptionWithCustomerManagedKey: enableEncryptionParam, encryptionKey: encryptionKeyParam }); + this.snsTopic = buildTopicResponse.topic; + this.encryptionKey = buildTopicResponse.key; } else { // If an existingTopicObj was specified utilize the provided topic this.snsTopic = props.existingTopicObj; } // Setup the queue - [this.sqsQueue] = defaults.buildQueue(this, 'queue', { + const buildQueueResponse = defaults.buildQueue(this, 'queue', { existingQueueObj: props.existingQueueObj, queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue, enableEncryptionWithCustomerManagedKey: enableEncryptionParam, encryptionKey: encryptionKeyParam }); + this.sqsQueue = buildQueueResponse.queue; // Setup the SQS queue subscription to the SNS topic this.snsTopic.addSubscription(new subscriptions.SqsSubscription(this.sqsQueue, props.sqsSubscriptionProps)); 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 6b87ac679..8f493bef1 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 @@ -27,8 +27,10 @@ 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); + const testConstruct = new SnsToSqs(stack, 'test-sns-sqs', props); + expect(testConstruct.snsTopic).toBeDefined(); + expect(testConstruct.encryptionKey).toBeDefined(); // Assertion 2 expect(stack).toHaveResource("AWS::SNS::Topic", { KmsMasterKeyId: { @@ -467,4 +469,21 @@ test('Construct uses queueProps.encryptionMasterKey when specified', () => { ] } }); +}); + +test('Construct does not override unencrypted topic when passed in existingTopicObj prop', () => { + const stack = new Stack(); + + const existingTopicObj = new sns.Topic(stack, 'Topic', { + topicName: 'existing-topic-name' + }); + + const props: SnsToSqsProps = { + existingTopicObj, + }; + + const testConstruct = new SnsToSqs(stack, 'test-sns-sqs', props); + + expect(testConstruct.snsTopic).toBeDefined(); + expect(testConstruct.encryptionKey).not.toBeDefined(); }); \ No newline at end of file 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 a04670b10..9d8093255 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 @@ -128,7 +128,7 @@ export class SqsToLambda extends Construct { }); // Setup the queue - [this.sqsQueue] = defaults.buildQueue(this, 'queue', { + const buildQueueResponse = defaults.buildQueue(this, 'queue', { existingQueueObj: props.existingQueueObj, queueProps: props.queueProps, deadLetterQueue: this.deadLetterQueue, @@ -136,6 +136,7 @@ export class SqsToLambda extends Construct { encryptionKey: props.encryptionKey, encryptionKeyProps: props.encryptionKeyProps }); + this.sqsQueue = buildQueueResponse.queue; // Setup the event source mapping this.lambdaFunction.addEventSource(new SqsEventSource(this.sqsQueue, props.sqsEventSourceProps)); 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 fbd8f9b63..a4a1f0982 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/apigateway-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/apigateway-helper.ts @@ -15,7 +15,7 @@ import * as logs from 'aws-cdk-lib/aws-logs'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as cdk from 'aws-cdk-lib'; -import * as api from 'aws-cdk-lib/aws-apigateway'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as apiDefaults from './apigateway-defaults'; import { buildLogGroup } from './cloudwatch-log-group-helper'; @@ -27,9 +27,9 @@ import { Construct } from 'constructs'; /** * Create and configures access logging for API Gateway resources. * @param scope - the construct to which the access logging capabilities should be attached to. - * @param _api - an existing api.RestApi or api.LambdaRestApi. + * @param api - an existing api.RestApi or api.LambdaRestApi. */ -function configureCloudwatchRoleForApi(scope: Construct, _api: api.RestApi): iam.Role { +function configureCloudwatchRoleForApi(scope: Construct, api: apigateway.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'), @@ -51,14 +51,14 @@ function configureCloudwatchRoleForApi(scope: Construct, _api: api.RestApi): iam } }); // 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', { + const CfnApi = api.node.findChild('Resource') as apigateway.CfnRestApi; + const cfnAccount: apigateway.CfnAccount = new apigateway.CfnAccount(scope, 'LambdaRestApiAccount', { cloudWatchRoleArn: restApiCloudwatchRole.roleArn }); cfnAccount.addDependency(CfnApi); // Suppress Cfn Nag warning for APIG - const deployment: api.CfnDeployment = _api.latestDeployment?.node.findChild('Resource') as api.CfnDeployment; + const deployment: apigateway.CfnDeployment = api.latestDeployment?.node.findChild('Resource') as apigateway.CfnDeployment; addCfnSuppressRules(deployment, [ { id: 'W45', @@ -70,14 +70,19 @@ function configureCloudwatchRoleForApi(scope: Construct, _api: api.RestApi): iam return restApiCloudwatchRole; } +interface ConfigureLambdaRestApiResponse { + api: apigateway.RestApi, + role?: iam.Role +} + /** * Creates and configures an api.LambdaRestApi. * @param scope - the construct to which the LambdaRestApi should be attached to. * @param defaultApiGatewayProps - the default properties for the LambdaRestApi. * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ -function configureLambdaRestApi(scope: Construct, defaultApiGatewayProps: api.LambdaRestApiProps, - apiGatewayProps?: api.LambdaRestApiProps): [api.RestApi, iam.Role | undefined] { +function configureLambdaRestApi(scope: Construct, defaultApiGatewayProps: apigateway.LambdaRestApiProps, + apiGatewayProps?: apigateway.LambdaRestApiProps): ConfigureLambdaRestApiResponse { // API Gateway doesn't allow both endpointTypes and endpointConfiguration, check whether endPointTypes exists if (apiGatewayProps?.endpointTypes) { @@ -85,41 +90,42 @@ function configureLambdaRestApi(scope: Construct, defaultApiGatewayProps: api.La } // Define the API object - let _api: api.RestApi; + let api: apigateway.RestApi; if (apiGatewayProps) { // If property overrides have been provided, incorporate them and deploy - const _apiGatewayProps = consolidateProps(defaultApiGatewayProps, apiGatewayProps, { cloudWatchRole: false }); - _api = new api.LambdaRestApi(scope, 'LambdaRestApi', _apiGatewayProps); + const consolidatedApiGatewayProps = consolidateProps(defaultApiGatewayProps, apiGatewayProps, { cloudWatchRole: false }); + api = new apigateway.LambdaRestApi(scope, 'LambdaRestApi', consolidatedApiGatewayProps); } else { // If no property overrides, deploy using the default configuration - _api = new api.LambdaRestApi(scope, 'LambdaRestApi', defaultApiGatewayProps); + api = new apigateway.LambdaRestApi(scope, 'LambdaRestApi', defaultApiGatewayProps); } // Configure API access logging - let cwRole; - - if (apiGatewayProps?.cloudWatchRole !== false) { - cwRole = configureCloudwatchRoleForApi(scope, _api); - } + const cwRole = (apiGatewayProps?.cloudWatchRole !== false) ? configureCloudwatchRoleForApi(scope, api) : undefined; // Configure Usage Plan - const usagePlanProps: api.UsagePlanProps = { + const usagePlanProps: apigateway.UsagePlanProps = { apiStages: [{ - api: _api, - stage: _api.deploymentStage + api, + stage: api.deploymentStage }] }; - const plan = _api.addUsagePlan('UsagePlan', usagePlanProps); + const plan = api.addUsagePlan('UsagePlan', usagePlanProps); // If requireApiKey param is set to true, create a api key & associate to Usage Plan if (apiGatewayProps?.defaultMethodOptions?.apiKeyRequired === true) { // Configure Usage Plan with API Key - const key = _api.addApiKey('ApiKey'); + const key = api.addApiKey('ApiKey'); plan.addApiKey(key); } // Return the API and CW Role - return [_api, cwRole]; + return { api, role: cwRole}; +} + +interface ConfigureRestApiResponse { + api: apigateway.RestApi, + role?: iam.Role } /** @@ -128,46 +134,49 @@ function configureLambdaRestApi(scope: Construct, defaultApiGatewayProps: api.La * @param defaultApiGatewayProps - the default properties for the RestApi. * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ -function configureRestApi(scope: Construct, defaultApiGatewayProps: api.RestApiProps, - apiGatewayProps?: api.RestApiProps): [api.RestApi, iam.Role | undefined] { +function configureRestApi(scope: Construct, defaultApiGatewayProps: apigateway.RestApiProps, + apiGatewayProps?: apigateway.RestApiProps): ConfigureRestApiResponse { // 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; - - const _apiGatewayProps = consolidateProps(defaultApiGatewayProps, apiGatewayProps, { cloudWatchRole: false }); - _api = new api.RestApi(scope, 'RestApi', _apiGatewayProps); + const consolidatedApiGatewayProps = consolidateProps(defaultApiGatewayProps, apiGatewayProps, { cloudWatchRole: false }); + const api = new apigateway.RestApi(scope, 'RestApi', consolidatedApiGatewayProps); let cwRole; // Configure API access logging if (apiGatewayProps?.cloudWatchRole !== false) { - cwRole = configureCloudwatchRoleForApi(scope, _api); + cwRole = configureCloudwatchRoleForApi(scope, api); } // Configure Usage Plan - const usagePlanProps: api.UsagePlanProps = { + const usagePlanProps: apigateway.UsagePlanProps = { apiStages: [{ - api: _api, - stage: _api.deploymentStage + api, + stage: api.deploymentStage }] }; - const plan = _api.addUsagePlan('UsagePlan', usagePlanProps); + const plan = api.addUsagePlan('UsagePlan', usagePlanProps); // If requireApiKey param is set to true, create a api key & associate to Usage Plan if (apiGatewayProps?.defaultMethodOptions?.apiKeyRequired === true) { // Configure Usage Plan with API Key - const key = _api.addApiKey('ApiKey'); + const key = api.addApiKey('ApiKey'); plan.addApiKey(key); } // Return the API and CW Role - return [_api, cwRole]; + return { api, role: cwRole }; +} + +export interface GlobalLambdaRestApiResponse { + readonly api: apigateway.RestApi, + readonly role?: iam.Role, + readonly group: logs.LogGroup } /** @@ -177,29 +186,41 @@ function configureRestApi(scope: Construct, defaultApiGatewayProps: api.RestApiP * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ export function GlobalLambdaRestApi(scope: Construct, _existingLambdaObj: lambda.Function, - apiGatewayProps?: api.LambdaRestApiProps, logGroupProps?: logs.LogGroupProps): [api.RestApi, iam.Role | undefined, logs.LogGroup] { + apiGatewayProps?: apigateway.LambdaRestApiProps, logGroupProps?: logs.LogGroupProps): GlobalLambdaRestApiResponse { // Configure log group for API Gateway AccessLogging const logGroup = buildLogGroup(scope, 'ApiAccessLogGroup', logGroupProps); const defaultProps = apiDefaults.DefaultGlobalLambdaRestApiProps(_existingLambdaObj, logGroup); - const [restApi, apiCWRole] = configureLambdaRestApi(scope, defaultProps, apiGatewayProps); - return [restApi, apiCWRole, logGroup]; + const configureLambdaRestApiResponse = configureLambdaRestApi(scope, defaultProps, apiGatewayProps); + return { api: configureLambdaRestApiResponse.api, role: configureLambdaRestApiResponse.role, group: logGroup}; +} + +export interface RegionalLambdaRestApiResponse { + readonly api: apigateway.RestApi, + readonly role?: iam.Role, + readonly group: logs.LogGroup, } /** * Builds and returns a regional api.RestApi designed to be used with an AWS Lambda function. * @param scope - the construct to which the RestApi should be attached to. - * @param _existingLambdaObj - an existing AWS Lambda function. + * @param existingLambdaObj - an existing AWS Lambda function. * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ -export function RegionalLambdaRestApi(scope: Construct, _existingLambdaObj: lambda.Function, - apiGatewayProps?: api.LambdaRestApiProps, logGroupProps?: logs.LogGroupProps): [api.RestApi, iam.Role | undefined, logs.LogGroup] { +export function RegionalLambdaRestApi(scope: Construct, existingLambdaObj: lambda.Function, + apiGatewayProps?: apigateway.LambdaRestApiProps, logGroupProps?: logs.LogGroupProps): RegionalLambdaRestApiResponse { // Configure log group for API Gateway AccessLogging const logGroup = buildLogGroup(scope, 'ApiAccessLogGroup', logGroupProps); - const defaultProps = apiDefaults.DefaultRegionalLambdaRestApiProps(_existingLambdaObj, logGroup); - const [restApi, apiCWRole] = configureLambdaRestApi(scope, defaultProps, apiGatewayProps); - return [restApi, apiCWRole, logGroup]; + const defaultProps = apiDefaults.DefaultRegionalLambdaRestApiProps(existingLambdaObj, logGroup); + const configureLambdaRestApiResponse = configureLambdaRestApi(scope, defaultProps, apiGatewayProps); + return { api: configureLambdaRestApiResponse.api, role: configureLambdaRestApiResponse.role, group: logGroup}; +} + +export interface GlobalRestApiResponse { + readonly api: apigateway.RestApi, + readonly role?: iam.Role, + readonly logGroup: logs.LogGroup, } /** @@ -207,14 +228,20 @@ export function RegionalLambdaRestApi(scope: Construct, _existingLambdaObj: lamb * @param scope - the construct to which the RestApi should be attached to. * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ -export function GlobalRestApi(scope: Construct, apiGatewayProps?: api.RestApiProps, - logGroupProps?: logs.LogGroupProps): [api.RestApi, iam.Role | undefined, logs.LogGroup] { +export function GlobalRestApi(scope: Construct, apiGatewayProps?: apigateway.RestApiProps, + logGroupProps?: logs.LogGroupProps): GlobalRestApiResponse { // Configure log group for API Gateway AccessLogging const logGroup = buildLogGroup(scope, 'ApiAccessLogGroup', logGroupProps); const defaultProps = apiDefaults.DefaultGlobalRestApiProps(logGroup); - const [restApi, apiCWRole] = configureRestApi(scope, defaultProps, apiGatewayProps); - return [restApi, apiCWRole, logGroup]; + const configureRestApiResponse = configureRestApi(scope, defaultProps, apiGatewayProps); + return { api: configureRestApiResponse.api, role: configureRestApiResponse.role, logGroup }; +} + +export interface RegionalRestApiResponse { + readonly api: apigateway.RestApi, + readonly role?: iam.Role, + readonly logGroup: logs.LogGroup, } /** @@ -222,34 +249,34 @@ export function GlobalRestApi(scope: Construct, apiGatewayProps?: api.RestApiPro * @param scope - the construct to which the RestApi should be attached to. * @param apiGatewayProps - (optional) user-specified properties to override the default properties. */ -export function RegionalRestApi(scope: Construct, apiGatewayProps?: api.RestApiProps, - logGroupProps?: logs.LogGroupProps): [api.RestApi, iam.Role | undefined, logs.LogGroup] { +export function RegionalRestApi(scope: Construct, apiGatewayProps?: apigateway.RestApiProps, + logGroupProps?: logs.LogGroupProps): RegionalRestApiResponse { // Configure log group for API Gateway AccessLogging const logGroup = buildLogGroup(scope, 'ApiAccessLogGroup', logGroupProps); const defaultProps = apiDefaults.DefaultRegionalRestApiProps(logGroup); - const [restApi, apiCWRole] = configureRestApi(scope, defaultProps, apiGatewayProps); - return [restApi, apiCWRole, logGroup]; + const configureRestApiResponse = configureRestApi(scope, defaultProps, apiGatewayProps); + return { api: configureRestApiResponse.api, role: configureRestApiResponse.role, logGroup }; } export interface AddProxyMethodToApiResourceInputParams { readonly service: string, readonly action?: string, readonly path?: string, - readonly apiResource: api.IResource, + readonly apiResource: apigateway.IResource, readonly apiMethod: string, readonly apiGatewayRole: IRole, readonly requestTemplate: string, readonly additionalRequestTemplates?: { [contentType: string]: string; }, readonly integrationResponses?: cdk.aws_apigateway.IntegrationResponse[], readonly contentType?: string, - readonly requestValidator?: api.IRequestValidator, - readonly requestModel?: { [contentType: string]: api.IModel; }, - readonly awsIntegrationProps?: api.AwsIntegrationProps | any, - readonly methodOptions?: api.MethodOptions + readonly requestValidator?: apigateway.IRequestValidator, + readonly requestModel?: { [contentType: string]: apigateway.IModel; }, + readonly awsIntegrationProps?: apigateway.AwsIntegrationProps | any, + readonly methodOptions?: apigateway.MethodOptions } -export function addProxyMethodToApiResource(params: AddProxyMethodToApiResourceInputParams): api.Method { +export function addProxyMethodToApiResource(params: AddProxyMethodToApiResourceInputParams): apigateway.Method { // Make sure the user hasn't also specified the application/json content-type in the additionalRequestTemplates optional property if (params.additionalRequestTemplates && 'application/json' in params.additionalRequestTemplates) { throw new Error(`Request Template for the application/json content-type must be specified in the requestTemplate property and not in the additionalRequestTemplates property `); @@ -263,11 +290,11 @@ export function addProxyMethodToApiResource(params: AddProxyMethodToApiResourceI // Use user-provided integration responses, otherwise fallback to the default ones we provide. const integrationResponses = params.integrationResponses ?? apiDefaults.DefaultIntegrationResponses(); - let baseProps: api.AwsIntegrationProps = { + let baseProps: apigateway.AwsIntegrationProps = { service: params.service, integrationHttpMethod: "POST", options: { - passthroughBehavior: api.PassthroughBehavior.NEVER, + passthroughBehavior: apigateway.PassthroughBehavior.NEVER, credentialsRole: params.apiGatewayRole, requestParameters: { "integration.request.header.Content-Type": params.contentType ? params.contentType : "'application/json'" @@ -297,7 +324,7 @@ export function addProxyMethodToApiResource(params: AddProxyMethodToApiResourceI let apiGatewayIntegration; const newProps = consolidateProps(baseProps, params.awsIntegrationProps); - apiGatewayIntegration = new api.AwsIntegration(newProps); + apiGatewayIntegration = new apigateway.AwsIntegration(newProps); const defaultMethodOptions = { methodResponses: [ @@ -318,11 +345,7 @@ export function addProxyMethodToApiResource(params: AddProxyMethodToApiResourceI requestModels: params.requestModel }; - let apiMethod; - // Setup the API Gateway method const overridenProps = consolidateProps(defaultMethodOptions, params.methodOptions); - apiMethod = params.apiResource.addMethod(params.apiMethod, apiGatewayIntegration, overridenProps); - - return apiMethod; + return params.apiResource.addMethod(params.apiMethod, apiGatewayIntegration, overridenProps); } \ 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 b0d48fd6c..934b1d1a5 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 @@ -62,13 +62,19 @@ function defaultCloudfrontFunction(scope: Construct): cloudfront.Function { }); } +export interface CloudFrontDistributionForApiGatewayResponse { + readonly distribution: cloudfront.Distribution, + readonly cloudfrontFunction?: cloudfront.Function, + readonly loggingBucket?: s3.Bucket +} + export function CloudFrontDistributionForApiGateway(scope: Construct, apiEndPoint: api.RestApi, cloudFrontDistributionProps?: cloudfront.DistributionProps | any, httpSecurityHeaders: boolean = true, cloudFrontLoggingBucketProps?: s3.BucketProps, responseHeadersPolicyProps?: cloudfront.ResponseHeadersPolicyProps -): [cloudfront.Distribution, cloudfront.Function?, s3.Bucket?] { +): CloudFrontDistributionForApiGatewayResponse { const cloudfrontFunction = getCloudfrontFunction(httpSecurityHeaders, scope); @@ -86,7 +92,13 @@ export function CloudFrontDistributionForApiGateway(scope: Construct, const cfDistribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); updateSecurityPolicy(cfDistribution); - return [cfDistribution, cloudfrontFunction, loggingBucket]; + return { distribution: cfDistribution, cloudfrontFunction, loggingBucket}; +} + +export interface CloudFrontDistributionForS3Response { + readonly distribution: cloudfront.Distribution, + readonly loggingBucket?: s3.Bucket, + readonly cloudfrontFunction?: cloudfront.Function, } export function CloudFrontDistributionForS3( @@ -97,7 +109,7 @@ export function CloudFrontDistributionForS3( originPath?: string, cloudFrontLoggingBucketProps?: s3.BucketProps, responseHeadersPolicyProps?: cloudfront.ResponseHeadersPolicyProps -): [cloudfront.Distribution, cloudfront.Function?, s3.Bucket?] { +): CloudFrontDistributionForS3Response { const cloudfrontFunction = getCloudfrontFunction(httpSecurityHeaders, scope); const loggingBucket = getLoggingBucket(cloudFrontDistributionProps, scope, cloudFrontLoggingBucketProps); @@ -126,7 +138,14 @@ export function CloudFrontDistributionForS3( } ]); } - return [cfDistribution, cloudfrontFunction, loggingBucket]; + return { distribution: cfDistribution, cloudfrontFunction, loggingBucket}; +} + +export interface CloudFrontDistributionForMediaStoreResponse { + readonly distribution: cloudfront.Distribution, + readonly loggingBucket?: s3.Bucket, + readonly requestPolicy: cloudfront.OriginRequestPolicy, + readonly cloudfrontFunction?: cloudfront.Function } export function CloudFrontDistributionForMediaStore(scope: Construct, @@ -135,8 +154,7 @@ export function CloudFrontDistributionForMediaStore(scope: Construct, httpSecurityHeaders: boolean = true, cloudFrontLoggingBucketProps?: s3.BucketProps, responseHeadersPolicyProps?: cloudfront.ResponseHeadersPolicyProps -): [cloudfront.Distribution, - s3.Bucket | undefined, cloudfront.OriginRequestPolicy, cloudfront.Function?] { +): CloudFrontDistributionForMediaStoreResponse { let originRequestPolicy: cloudfront.OriginRequestPolicy; @@ -190,7 +208,7 @@ export function CloudFrontDistributionForMediaStore(scope: Construct, const cfDistribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); updateSecurityPolicy(cfDistribution); - return [cfDistribution, loggingBucket, originRequestPolicy, cloudfrontFunction]; + return { distribution: cfDistribution, loggingBucket, requestPolicy: originRequestPolicy, cloudfrontFunction }; } export function CloudFrontOriginAccessIdentity(scope: Construct, comment?: string) { 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 d614be6b1..862de8aa5 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 @@ -56,18 +56,23 @@ export interface BuildDynamoDBTableWithStreamProps { readonly existingTableInterface?: dynamodb.ITable } -export function buildDynamoDBTable(scope: Construct, props: BuildDynamoDBTableProps): [dynamodb.ITable, dynamodb.Table?] { +export interface BuildDynamoDBTableResponse { + readonly tableInterface: dynamodb.ITable, + readonly tableObject?: dynamodb.Table, +} + +export function buildDynamoDBTable(scope: Construct, props: BuildDynamoDBTableProps): BuildDynamoDBTableResponse { checkTableProps(props); // Conditional DynamoDB Table creation if (props.existingTableObj) { - return [props.existingTableObj, props.existingTableObj]; + return { tableInterface: props.existingTableObj, tableObject: props.existingTableObj }; } else if (props.existingTableInterface) { - return [props.existingTableInterface, undefined]; + return { tableInterface: props.existingTableInterface }; } else { const consolidatedTableProps = consolidateProps(DefaultTableProps, props.dynamoTableProps); const newTable = new dynamodb.Table(scope, 'DynamoTable', consolidatedTableProps); - return [newTable, newTable]; + return { tableInterface: newTable, tableObject: newTable }; } } @@ -95,15 +100,20 @@ export function checkTableProps(props: BuildDynamoDBTableProps) { } } -export function buildDynamoDBTableWithStream(scope: Construct, props: BuildDynamoDBTableWithStreamProps): [dynamodb.ITable, dynamodb.Table?] { +export interface BuildDynamoDBTableWithStreamResponse { + readonly tableInterface: dynamodb.ITable, + readonly tableObject?: dynamodb.Table, +} + +export function buildDynamoDBTableWithStream(scope: Construct, props: BuildDynamoDBTableWithStreamProps): BuildDynamoDBTableWithStreamResponse { // Conditional DynamoDB Table creation if (!props.existingTableInterface) { // Set the default props for DynamoDB table const dynamoTableProps = consolidateProps(DefaultTableWithStreamProps, props.dynamoTableProps); const dynamoTable: dynamodb.Table = new dynamodb.Table(scope, 'DynamoTable', dynamoTableProps); - return [dynamoTable as dynamodb.ITable, dynamoTable]; + return { tableInterface: dynamoTable, tableObject: dynamoTable }; } else { - return [props.existingTableInterface, undefined]; + return { tableInterface: props.existingTableInterface }; } } 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 4fea8d207..122820650 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/elasticsearch-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/elasticsearch-helper.ts @@ -36,7 +36,12 @@ export interface BuildElasticSearchProps { readonly securityGroupIds?: string[] } -export function buildElasticSearch(scope: Construct, props: BuildElasticSearchProps): [elasticsearch.CfnDomain, iam.Role] { +export interface BuildElasticSearchResponse { + readonly domain: elasticsearch.CfnDomain, + readonly role: iam.Role +} + +export function buildElasticSearch(scope: Construct, props: BuildElasticSearchProps): BuildElasticSearchResponse { let subnetIds: string[] = []; const constructDrivenProps: any = {}; @@ -83,7 +88,7 @@ export function buildElasticSearch(scope: Construct, props: BuildElasticSearchPr }, ]); - return [esDomain, cognitoKibanaConfigureRole]; + return { domain: esDomain, role: cognitoKibanaConfigureRole }; } export function buildElasticSearchCWAlarms(scope: Construct): cloudwatch.Alarm[] { diff --git a/source/patterns/@aws-solutions-constructs/core/lib/fargate-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/fargate-helper.ts index 10396281a..555b9fc18 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/fargate-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/fargate-helper.ts @@ -18,6 +18,11 @@ import * as ecr from "aws-cdk-lib/aws-ecr"; import * as defaults from ".."; import { overrideProps } from ".."; +export interface CreateFargateServiceResponse { + readonly service: ecs.FargateService, + readonly containerDefinition: ecs.ContainerDefinition +} + export function CreateFargateService( scope: Construct, id: string, @@ -28,7 +33,7 @@ export function CreateFargateService( clientFargateTaskDefinitionProps?: ecs.FargateTaskDefinitionProps | any, clientContainerDefinitionProps?: ecs.ContainerDefinitionProps | any, clientFargateServiceProps?: ecs.FargateServiceProps | any -): [ecs.FargateService, ecs.ContainerDefinition] { +): CreateFargateServiceResponse { defaults.AddAwsServiceEndpoint( scope, constructVpc, @@ -70,13 +75,15 @@ export function CreateFargateService( // Create the Fargate Service let newContainerDefinition; - [constructFargateServiceDefinitionProps.taskDefinition, newContainerDefinition] = CreateTaskDefinition( + const createTaskDefinitionResponse = CreateTaskDefinition( scope, id, clientFargateTaskDefinitionProps, clientContainerDefinitionProps, constructContainerDefintionProps ); + constructFargateServiceDefinitionProps.taskDefinition = createTaskDefinitionResponse.taskDefinition; + newContainerDefinition = createTaskDefinitionResponse.containerDefinition; if (!clientFargateServiceProps?.vpcSubnets) { if (constructVpc.isolatedSubnets.length) { @@ -127,7 +134,7 @@ export function CreateFargateService( fargateServiceProps, ); - return [newService, newContainerDefinition]; + return { service: newService, containerDefinition: newContainerDefinition }; } function CreateCluster( @@ -164,13 +171,18 @@ function CreateImage( } } +interface CreateTaskDefinitionResponse { + taskDefinition: ecs.FargateTaskDefinition + containerDefinition: ecs.ContainerDefinition +} + function CreateTaskDefinition( scope: Construct, id: string, clientFargateTaskDefinitionProps?: ecs.FargateTaskDefinitionProps, clientContainerDefinitionProps?: ecs.ContainerDefinitionProps, constructContainerDefinitionProps?: ecs.ContainerDefinitionProps -): [ecs.FargateTaskDefinition, ecs.ContainerDefinition] { +): CreateTaskDefinitionResponse { const taskDefinitionProps = defaults.consolidateProps( defaults.DefaultFargateTaskDefinitionProps(), clientFargateTaskDefinitionProps @@ -190,7 +202,7 @@ function CreateTaskDefinition( constructContainerDefinitionProps, ); const containerDefinition = taskDefinition.addContainer(`${id}-container`, containerDefinitionProps); - return [taskDefinition, containerDefinition]; + return { taskDefinition, containerDefinition }; } export function CheckFargateProps(props: any) { diff --git a/source/patterns/@aws-solutions-constructs/core/lib/glue-job-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/glue-job-helper.ts index 12d65ee93..ff5a3b9f1 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/glue-job-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/glue-job-helper.ts @@ -19,6 +19,7 @@ import { Aws, IResolvable } from 'aws-cdk-lib'; import * as s3assets from "aws-cdk-lib/aws-s3-assets"; import * as defaults from '../'; import { overrideProps } from './utils'; +import { BuildS3BucketResponse } from '../'; /** * Enumeration of data store types that could include S3, DynamoDB, DocumentDB, RDS or Redshift. Current @@ -86,7 +87,14 @@ export interface BuildGlueJobProps { readonly etlCodeAsset?: s3assets.Asset; } -export function buildGlueJob(scope: Construct, props: BuildGlueJobProps): [glue.CfnJob, IRole, [Bucket, (Bucket | undefined)?]?] { +export interface BuildGlueJobResponse { + readonly job: glue.CfnJob, + readonly role: IRole, + readonly bucket?: Bucket, + readonly loggingBucket?: Bucket, +} + +export function buildGlueJob(scope: Construct, props: BuildGlueJobProps): BuildGlueJobResponse { if (!props.existingCfnJob) { if (props.glueJobProps) { if (props.glueJobProps.glueVersion === '2.0' && props.glueJobProps.maxCapacity) { @@ -99,30 +107,43 @@ export function buildGlueJob(scope: Construct, props: BuildGlueJobProps): [glue. 'it is recommended to use "WorkerType" or "NumberOfWorkers"'); } - return deployGlueJob(scope, props.glueJobProps, props.database!, props.table!, props.outputDataStore!, props.etlCodeAsset); + const deployGlueJobResponse = + deployGlueJob(scope, props.glueJobProps, props.database!, props.table!, props.outputDataStore!, props.etlCodeAsset); + return { + job: deployGlueJobResponse.job, + role: deployGlueJobResponse.role, + bucket: deployGlueJobResponse.bucket, + loggingBucket: deployGlueJobResponse.loggingBucket }; } else { throw Error('Either glueJobProps or existingCfnJob is required'); } } else { - return [props.existingCfnJob, Role.fromRoleArn(scope, 'ExistingRole', props.existingCfnJob.role)]; + return { job: props.existingCfnJob, role: Role.fromRoleArn(scope, 'ExistingRole', props.existingCfnJob.role)}; } } +export interface DeployGlueJobResponse { + readonly job: glue.CfnJob, + readonly role: IRole, + readonly bucket?: Bucket, + readonly loggingBucket?: Bucket, +} + export function deployGlueJob(scope: Construct, glueJobProps: glue.CfnJobProps, database: glue.CfnDatabase, table: glue.CfnTable, - outputDataStore: SinkDataStoreProps, etlCodeAsset?: s3assets.Asset): [glue.CfnJob, IRole, [Bucket, (Bucket | undefined)?]] { + outputDataStore: SinkDataStoreProps, etlCodeAsset?: s3assets.Asset): DeployGlueJobResponse { - let _glueSecurityConfigName: string; + let glueSecurityConfigName: string; if (glueJobProps.securityConfiguration === undefined) { - _glueSecurityConfigName = 'ETLJobSecurityConfig'; - const _glueKMSKey = `arn:${Aws.PARTITION}:kms:${Aws.REGION}:${Aws.ACCOUNT_ID}:alias/aws/glue`; + glueSecurityConfigName = 'ETLJobSecurityConfig'; + const glueKMSKey = `arn:${Aws.PARTITION}:kms:${Aws.REGION}:${Aws.ACCOUNT_ID}:alias/aws/glue`; new glue.CfnSecurityConfiguration(scope, 'GlueSecurityConfig', { - name: _glueSecurityConfigName, + name: glueSecurityConfigName, encryptionConfiguration: { jobBookmarksEncryption: { jobBookmarksEncryptionMode: 'CSE-KMS', - kmsKeyArn: _glueKMSKey + kmsKeyArn: glueKMSKey }, s3Encryptions: [{ s3EncryptionMode: 'SSE-S3' @@ -130,10 +151,10 @@ export function deployGlueJob(scope: Construct, glueJobProps: glue.CfnJobProps, } }); } else { - _glueSecurityConfigName = glueJobProps.securityConfiguration; + glueSecurityConfigName = glueJobProps.securityConfiguration; } - const _glueJobPolicy = new Policy(scope, 'LogPolicy', { + const glueJobPolicy = new Policy(scope, 'LogPolicy', { statements: [ new PolicyStatement({ effect: Effect.ALLOW, @@ -143,57 +164,54 @@ export function deployGlueJob(scope: Construct, glueJobProps: glue.CfnJobProps, ] }); - let _jobRole: IRole; - if (glueJobProps.role) { - _jobRole = Role.fromRoleArn(scope, 'JobRole', glueJobProps.role); - } else { - _jobRole = defaults.createGlueJobRole(scope); - } + const jobRole = glueJobProps.role ? + Role.fromRoleArn(scope, 'JobRole', glueJobProps.role) : + defaults.createGlueJobRole(scope); - _glueJobPolicy.attachToRole(_jobRole); + glueJobPolicy.attachToRole(jobRole); - let _outputLocation: [ Bucket, Bucket? ]; + let outputLocation: BuildS3BucketResponse; if (outputDataStore !== undefined && outputDataStore.datastoreType === SinkStoreType.S3) { if (outputDataStore.existingS3OutputBucket !== undefined) { - _outputLocation = [ outputDataStore.existingS3OutputBucket, undefined ]; + outputLocation = { bucket: outputDataStore.existingS3OutputBucket }; } else { - _outputLocation = defaults.buildS3Bucket(scope, { bucketProps: outputDataStore.outputBucketProps } ); + outputLocation = defaults.buildS3Bucket(scope, { bucketProps: outputDataStore.outputBucketProps } ); } } else { - _outputLocation = defaults.buildS3Bucket(scope, {}); + outputLocation = defaults.buildS3Bucket(scope, {}); } - _outputLocation[0].grantReadWrite(_jobRole); + outputLocation.bucket.grantReadWrite(jobRole); - const _jobArgumentsList = { + const jobArgumentsList = { "--enable-metrics" : true, "--enable-continuous-cloudwatch-log" : true, "--database_name": database.ref, "--table_name": table.ref, ...((outputDataStore === undefined || (outputDataStore && outputDataStore.datastoreType === SinkStoreType.S3)) && - { '--output_path' : `s3a://${_outputLocation[0].bucketName}/output/` }), + { '--output_path' : `s3a://${outputLocation.bucket.bucketName}/output/` }), ...glueJobProps.defaultArguments }; - const _newGlueJobProps: glue.CfnJobProps = overrideProps(defaults.DefaultGlueJobProps(_jobRole!, glueJobProps, - _glueSecurityConfigName, _jobArgumentsList, etlCodeAsset), glueJobProps); + const newGlueJobProps: glue.CfnJobProps = overrideProps(defaults.DefaultGlueJobProps(jobRole!, glueJobProps, + glueSecurityConfigName, jobArgumentsList, etlCodeAsset), glueJobProps); if (etlCodeAsset) { - etlCodeAsset.grantRead(_jobRole); + etlCodeAsset.grantRead(jobRole); } else { // create CDK Bucket instance from S3 url and grant read access to Glue Job's service principal - if (isJobCommandProperty(_newGlueJobProps.command)) { - if (!_newGlueJobProps.command.scriptLocation) { + if (isJobCommandProperty(newGlueJobProps.command)) { + if (!newGlueJobProps.command.scriptLocation) { throw Error('Script location has to be provided as an s3 Url location. Script location cannot be empty'); } - const _scriptLocation = _newGlueJobProps.command.scriptLocation; + const scriptLocation = newGlueJobProps.command.scriptLocation; - const _scriptBucketLocation: IBucket = Bucket.fromBucketArn(scope, 'ScriptLocaiton', getS3ArnfromS3Url(_scriptLocation!)); - _scriptBucketLocation.grantRead(_jobRole); + const scriptBucketLocation: IBucket = Bucket.fromBucketArn(scope, 'ScriptLocaiton', getS3ArnfromS3Url(scriptLocation!)); + scriptBucketLocation.grantRead(jobRole); } } - const _glueJob: glue.CfnJob = new glue.CfnJob(scope, 'KinesisETLJob', _newGlueJobProps); - return [_glueJob, _jobRole, _outputLocation]; + const glueJob: glue.CfnJob = new glue.CfnJob(scope, 'KinesisETLJob', newGlueJobProps); + return { job: glueJob, role: jobRole, bucket: outputLocation.bucket, loggingBucket: outputLocation.loggingBucket }; } /** 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 09d411e32..9e66e5c94 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 @@ -39,12 +39,12 @@ export function DynamoEventSourceProps(scope: Construct, _dynamoEventSourceProps if (_dynamoEventSourceProps === undefined || _dynamoEventSourceProps?.deploySqsDlqQueue === undefined || _dynamoEventSourceProps.deploySqsDlqQueue) { - const [sqsQueue] = buildQueue(scope, 'SqsDlqQueue', { + const buildQueueResponse = buildQueue(scope, 'SqsDlqQueue', { queueProps: _dynamoEventSourceProps?.sqsDlqQueueProps }); extraProps = { - onFailure: new SqsDlq(sqsQueue), + onFailure: new SqsDlq(buildQueueResponse.queue), }; } @@ -74,12 +74,12 @@ export function KinesisEventSourceProps(scope: Construct, _kinesisEventSourcePro if (_kinesisEventSourceProps === undefined || _kinesisEventSourceProps?.deploySqsDlqQueue === undefined || _kinesisEventSourceProps.deploySqsDlqQueue) { - const [sqsQueue] = buildQueue(scope, 'SqsDlqQueue', { + const buildQueueResponse = buildQueue(scope, 'SqsDlqQueue', { queueProps: _kinesisEventSourceProps?.sqsDlqQueueProps }); extraProps = { - onFailure: new SqsDlq(sqsQueue), + onFailure: new SqsDlq(buildQueueResponse.queue), }; } diff --git a/source/patterns/@aws-solutions-constructs/core/lib/opensearch-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/opensearch-helper.ts index b710a9865..a91b93781 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/opensearch-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/opensearch-helper.ts @@ -36,7 +36,12 @@ export interface BuildOpenSearchProps { readonly securityGroupIds?: string[] } -export function buildOpenSearch(scope: Construct, props: BuildOpenSearchProps): [opensearch.CfnDomain, iam.Role] { +export interface BuildOpenSearchResponse { + readonly domain: opensearch.CfnDomain, + readonly role: iam.Role +} + +export function buildOpenSearch(scope: Construct, props: BuildOpenSearchProps): BuildOpenSearchResponse { let subnetIds: string[] = []; const constructDrivenProps: any = {}; @@ -82,7 +87,7 @@ export function buildOpenSearch(scope: Construct, props: BuildOpenSearchProps): }, ]); - return [opensearchDomain, cognitoDashboardConfigureRole]; + return { domain: opensearchDomain, role: cognitoDashboardConfigureRole }; } export function buildOpenSearchCWAlarms(scope: Construct): cloudwatch.Alarm[] { 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 f06285460..548e43301 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 @@ -96,9 +96,14 @@ export function createAlbLoggingBucket(scope: Construct, return loggingBucket; } +export interface BuildS3BucketResponse { + readonly bucket: s3.Bucket, + readonly loggingBucket?: s3.Bucket +} + export function buildS3Bucket(scope: Construct, props: BuildS3BucketProps, - bucketId?: string): [s3.Bucket, s3.Bucket?] { + bucketId?: string): BuildS3BucketResponse { /** Default Life Cycle policy to transition older versions to Glacier after 90 days */ const lifecycleRules: s3.LifecycleRule[] = [{ @@ -141,7 +146,7 @@ export function buildS3Bucket(scope: Construct, const s3Bucket: s3.Bucket = new s3.Bucket(scope, _bucketId, customBucketProps ); - return [s3Bucket, loggingBucket]; + return { bucket: s3Bucket, loggingBucket }; } export function addCfnNagS3BucketNotificationRulesToSuppress(stackRoot: cdk.Stack, logicalId: string) { 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 ff10a9a9d..743c62669 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sagemaker-helper.ts @@ -58,9 +58,9 @@ export interface BuildSagemakerNotebookProps { readonly role: iam.Role; } -function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { +function addPermissions(role: iam.Role, props?: BuildSagemakerEndpointProps) { // Grant permissions to NoteBookInstance for creating and training the model - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ resources: [`arn:${Aws.PARTITION}:sagemaker:${Aws.REGION}:${Aws.ACCOUNT_ID}:*`], actions: [ @@ -81,7 +81,7 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { ); // Grant CloudWatch Logging permissions - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:/aws/sagemaker/*`], actions: [ @@ -96,7 +96,7 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { // To place the Sagemaker endpoint in a VPC if (props && props.vpc) { - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ resources: ['*'], actions: [ @@ -118,7 +118,7 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { // To create a Sagemaker model using Bring-Your-Own-Model (BYOM) algorith image // The image URL is specified in the modelProps - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ resources: [`arn:${cdk.Aws.PARTITION}:ecr:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:repository/*`], actions: [ @@ -132,7 +132,7 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { ); // Add GetAuthorizationToken (it can not be bound to resources other than *) - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ resources: ['*'], actions: ['ecr:GetAuthorizationToken'], @@ -145,7 +145,7 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { const acceleratorType = (props.endpointConfigProps ?.productionVariants as sagemaker.CfnEndpointConfig.ProductionVariantProperty[])[0].acceleratorType; if (acceleratorType !== undefined) { - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ resources: ['*'], actions: ['elastic-inference:Connect'], @@ -155,7 +155,7 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { } // add kms permissions - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ // the kmsKeyId in the endpointConfigProps can be any of the following formats: // Key ID: 1234abcd-12ab-34cd-56ef-1234567890ab @@ -172,7 +172,7 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { ); // Add S3 permissions to get Model artifact, put data capture files, etc. - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ actions: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject', 's3:ListBucket'], resources: ['arn:aws:s3:::*'], @@ -180,17 +180,17 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { ); // Grant GetRole permissions to the Sagemaker service - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ - resources: [_role.roleArn], + resources: [role.roleArn], actions: ['iam:GetRole'], }) ); // Grant PassRole permissions to the Sagemaker service - _role.addToPolicy( + role.addToPolicy( new iam.PolicyStatement({ - resources: [_role.roleArn], + resources: [role.roleArn], actions: ['iam:PassRole'], conditions: { StringLike: { 'iam:PassedToService': 'sagemaker.amazonaws.com' }, @@ -201,7 +201,7 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { // Add CFN NAG uppress to allow for "Resource": "*" for ENI access in VPC, // ECR authorization token for custom model images, and elastic inference // Add CFN NAG for Complex Role because Sagmaker needs permissions to access several services - const roleDefaultPolicy = _role.node.tryFindChild('DefaultPolicy')?.node.findChild('Resource') as iam.CfnPolicy; + const roleDefaultPolicy = role.node.tryFindChild('DefaultPolicy')?.node.findChild('Resource') as iam.CfnPolicy; addCfnSuppressRules(roleDefaultPolicy, [ { id: 'W12', @@ -214,10 +214,16 @@ function addPermissions(_role: iam.Role, props?: BuildSagemakerEndpointProps) { ]); } +export interface BuildSagemakerNotebookResponse { + readonly notebook: sagemaker.CfnNotebookInstance, + readonly vpc?: ec2.IVpc, + readonly securityGroup?: ec2.SecurityGroup +} + export function buildSagemakerNotebook( scope: Construct, props: BuildSagemakerNotebookProps -): [sagemaker.CfnNotebookInstance, ec2.IVpc?, ec2.SecurityGroup?] { +): BuildSagemakerNotebookResponse { // Setup the notebook properties let sagemakerNotebookProps; let vpcInstance; @@ -287,13 +293,13 @@ export function buildSagemakerNotebook( sagemakerNotebookProps ); if (vpcInstance) { - return [sagemakerInstance, vpcInstance, securityGroup]; + return { notebook: sagemakerInstance, vpc: vpcInstance, securityGroup }; } else { - return [sagemakerInstance]; + return { notebook: sagemakerInstance }; } } else { // Return existing notebook object - return [props.existingNotebookObj]; + return { notebook: props.existingNotebookObj }; } } @@ -330,28 +336,40 @@ export interface BuildSagemakerEndpointProps { readonly vpc?: ec2.IVpc; } +export interface BuildSagemakerEndpointResponse { + readonly endpoint: sagemaker.CfnEndpoint, + readonly endpointConfig?: sagemaker.CfnEndpointConfig, + readonly model?: sagemaker.CfnModel +} + export function BuildSagemakerEndpoint( scope: Construct, props: BuildSagemakerEndpointProps -): [sagemaker.CfnEndpoint, sagemaker.CfnEndpointConfig?, sagemaker.CfnModel?] { +): BuildSagemakerEndpointResponse { /** Conditional Sagemaker endpoint creation */ if (!props.existingSagemakerEndpointObj) { if (props.modelProps) { - /** return [endpoint, endpointConfig, model] */ - return deploySagemakerEndpoint(scope, props); + const deploySagemakerEndpointResponse = deploySagemakerEndpoint(scope, props); + return { ...deploySagemakerEndpointResponse }; } else { throw Error('Either existingSagemakerEndpointObj or at least modelProps is required'); } } else { /** Otherwise, return [endpoint] */ - return [props.existingSagemakerEndpointObj]; + return { endpoint: props.existingSagemakerEndpointObj }; } } +export interface DeploySagemakerEndpointResponse { + readonly endpoint: sagemaker.CfnEndpoint, + readonly endpointConfig?: sagemaker.CfnEndpointConfig, + readonly model?: sagemaker.CfnModel +} + export function deploySagemakerEndpoint( scope: Construct, props: BuildSagemakerEndpointProps -): [sagemaker.CfnEndpoint, sagemaker.CfnEndpointConfig?, sagemaker.CfnModel?] { +): DeploySagemakerEndpointResponse { let model: sagemaker.CfnModel; let endpointConfig: sagemaker.CfnEndpointConfig; let endpoint: sagemaker.CfnEndpoint; @@ -386,7 +404,7 @@ export function deploySagemakerEndpoint( // Add dependency on EndpointConfig endpoint.addDependency(endpointConfig); - return [endpoint, endpointConfig, model]; + return { endpoint, endpointConfig, model }; } else { throw Error('You need to provide at least modelProps to create Sagemaker Endpoint'); } 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 904d51d05..6cc262fdb 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sns-helper.ts @@ -126,7 +126,12 @@ function applySecureTopicPolicy(topic: sns.Topic): void { ); } -export function buildTopic(scope: Construct, props: BuildTopicProps): [sns.Topic, kms.Key?] { +export interface BuildTopicResponse { + readonly topic: sns.Topic, + readonly key?: kms.Key +} + +export function buildTopic(scope: Construct, props: BuildTopicProps): BuildTopicResponse { if (!props.existingTopicObj) { // Setup the topic properties const snsTopicProps = consolidateProps(DefaultSnsTopicProps, props.topicProps); @@ -151,8 +156,8 @@ export function buildTopic(scope: Construct, props: BuildTopicProps): [sns.Topic applySecureTopicPolicy(topic); - return [topic, snsTopicProps.masterKey]; + return { topic, key: snsTopicProps.masterKey }; } else { - return [props.existingTopicObj, props.existingTopicEncryptionKey]; + return { topic: props.existingTopicObj, key: props.existingTopicEncryptionKey }; } } 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 7ba6b4d2b..4ada7f9cf 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/sqs-helper.ts @@ -62,7 +62,12 @@ export interface BuildQueueProps { readonly encryptionKeyProps?: kms.KeyProps; } -export function buildQueue(scope: Construct, id: string, props: BuildQueueProps): [sqs.Queue, kms.IKey?] { +export interface BuildQueueResponse { + readonly queue: sqs.Queue, + readonly key?: kms.IKey +} + +export function buildQueue(scope: Construct, id: string, props: BuildQueueProps): BuildQueueResponse { if ((props.queueProps?.encryptionMasterKey || props.encryptionKey || props.encryptionKeyProps) && props.enableEncryptionWithCustomerManagedKey === true) { @@ -103,10 +108,10 @@ export function buildQueue(scope: Construct, id: string, props: BuildQueueProps) applySecureQueuePolicy(queue); // Return the queue - return [queue, queue.encryptionMasterKey]; + return { queue, key: queue.encryptionMasterKey }; } else { // If an existingQueueObj is specified, return that object as the queue to be used - return [props.existingQueueObj]; + return { queue: props.existingQueueObj }; } } @@ -140,7 +145,7 @@ export interface BuildDeadLetterQueueProps { export function buildDeadLetterQueue(scope: Construct, props: BuildDeadLetterQueueProps): sqs.DeadLetterQueue | undefined { if (!props.existingQueueObj && (props.deployDeadLetterQueue || props.deployDeadLetterQueue === undefined)) { // Create the Dead Letter Queue - const [dlq] = buildQueue(scope, 'deadLetterQueue', { + const buildQueueResponse = buildQueue(scope, 'deadLetterQueue', { queueProps: props.deadLetterQueueProps }); @@ -149,7 +154,7 @@ export function buildDeadLetterQueue(scope: Construct, props: BuildDeadLetterQue // Setup the Dead Letter Queue interface const dlqInterface: sqs.DeadLetterQueue = { maxReceiveCount: mrc, - queue: dlq + queue: buildQueueResponse.queue }; // Return the dead letter queue interface 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 ec6a3b662..64397129a 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 @@ -23,21 +23,25 @@ import { buildLogGroup } from './cloudwatch-log-group-helper'; // Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate import { Construct } from 'constructs'; +export interface BuildStateMachineResponse { + readonly stateMachine: sfn.StateMachine, + readonly logGroup: logs.ILogGroup +} /** * Builds and returns a StateMachine. * @param scope - the construct to which the StateMachine should be attached to. * @param stateMachineProps - user-specified properties to override the default properties. */ export function buildStateMachine(scope: Construct, stateMachineProps: sfn.StateMachineProps, - logGroupProps?: logs.LogGroupProps): [sfn.StateMachine, logs.ILogGroup] { + logGroupProps?: logs.LogGroupProps): BuildStateMachineResponse { let logGroup: logs.ILogGroup; - let _smProps; + let consolidatedStateMachineProps; // If they sent a logGroup in stateMachineProps if (stateMachineProps.logs?.destination) { logGroup = stateMachineProps.logs?.destination; - _smProps = stateMachineProps; + consolidatedStateMachineProps = stateMachineProps; } else { // Three possibilities // 1) logGroupProps not provided - create logGroupProps with just logGroupName @@ -65,12 +69,12 @@ export function buildStateMachine(scope: Construct, stateMachineProps: sfn.State logGroup = buildLogGroup(scope, 'StateMachineLogGroup', consolidatedLogGroupProps); // Override the defaults with the user provided props - _smProps = overrideProps(smDefaults.DefaultStateMachineProps(logGroup), stateMachineProps); + consolidatedStateMachineProps = 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 newStateMachine = new sfn.StateMachine(scope, 'StateMachine', consolidatedStateMachineProps); + const role = newStateMachine.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 @@ -92,7 +96,7 @@ export function buildStateMachine(scope: Construct, stateMachineProps: sfn.State ]); // Add a new policy with logging permissions for the given cloudwatch log group - _sm.addToRolePolicy(new iam.PolicyStatement({ + newStateMachine.addToRolePolicy(new iam.PolicyStatement({ actions: [ 'logs:PutResourcePolicy', 'logs:DescribeResourcePolicies', @@ -101,7 +105,7 @@ export function buildStateMachine(scope: Construct, stateMachineProps: sfn.State resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:*`] })); - return [_sm, logGroup]; + return { stateMachine: newStateMachine, logGroup }; } export function buildStepFunctionCWAlarms(scope: Construct, sm: sfn.StateMachine): cloudwatch.Alarm[] { diff --git a/source/patterns/@aws-solutions-constructs/core/test/alb-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/alb-helper.test.ts index a1e409434..b57f6bb93 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/alb-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/alb-helper.test.ts @@ -543,13 +543,13 @@ function CreateTestFunction(stack: Stack, id: string): lambda.Function { } function CreateTestFargateService(stack: Stack, id: string, vpc: ec2.IVpc): ecs.FargateService { - const [svc] = defaults.CreateFargateService(stack, + const createFargateServiceResponse = defaults.CreateFargateService(stack, `${id}-fg-svc`, vpc, undefined, 'arn:aws:ecr:us-east-1:123456789012:repository/fake-repo', 'latest'); - return svc; + return createFargateServiceResponse.service; } function CreateTestListener(stack: Stack, id: string, alb: elb.ApplicationLoadBalancer) { 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 50745fa5f..f3f9311eb 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 @@ -32,9 +32,9 @@ function deployRegionalApiGateway(stack: Stack) { } function setupRestApi(stack: Stack, apiProps?: any): void { - const [restApi] = defaults.GlobalRestApi(stack, apiProps); + const globalRestApiResponse = defaults.GlobalRestApi(stack, apiProps); // Setup the API Gateway resource - const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('api-gateway-resource'); // Setup the API Gateway Integration const apiGatewayIntegration = new api.AwsIntegration({ service: "sqs", @@ -234,7 +234,7 @@ test('Test default RestApi deployment for Cloudwatch loggroup', () => { test('Test addMethodToApiResource with action', () => { const stack = new Stack(); - const [restApi] = defaults.GlobalRestApi(stack); + const globalRestApiResponse = defaults.GlobalRestApi(stack); // Setup the API Gateway role const apiGatewayRole = new iam.Role(stack, 'api-gateway-role', { @@ -242,7 +242,7 @@ test('Test addMethodToApiResource with action', () => { }); // Setup the API Gateway resource - const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('api-gateway-resource'); const getRequestTemplate = "{}"; // Add Method @@ -281,7 +281,7 @@ test('Test addMethodToApiResource with action', () => { test('Test default RestApi w/ request model and validator', () => { const stack = new Stack(); - const [restApi] = defaults.GlobalRestApi(stack); + const globalRestApiResponse = defaults.GlobalRestApi(stack); // Setup the API Gateway role const apiGatewayRole = new iam.Role(stack, 'api-gateway-role', { @@ -289,9 +289,9 @@ test('Test default RestApi w/ request model and validator', () => { }); // Setup the API Gateway resource - const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('api-gateway-resource'); - const validator = restApi.addRequestValidator('default-validator', { + const validator = globalRestApiResponse.api.addRequestValidator('default-validator', { requestValidatorName: 'default-validator', validateRequestBody: true }); @@ -324,7 +324,7 @@ test('Test default RestApi w/ request model and validator', () => { test('Test for RegionalRestApiGateway', () => { const stack = new Stack(); - const [regionalApi] = defaults.RegionalRestApi(stack, { + const regionalRestApiResponse = defaults.RegionalRestApi(stack, { restApiName: "HelloWorld-RegionalApi" }); // Setup the API Gateway role @@ -333,7 +333,7 @@ test('Test for RegionalRestApiGateway', () => { }); // Setup the API Gateway resource - const apiGatewayResource = regionalApi.root.addResource('hello'); + const apiGatewayResource = regionalRestApiResponse.api.root.addResource('hello'); defaults.addProxyMethodToApiResource( { @@ -401,7 +401,7 @@ test('Test for Exception while overriding LambdaRestApiProps using endPointTypes test('Test for Integration Request Props Override', () => { const stack = new Stack(); - const [regionalApi] = defaults.RegionalRestApi(stack); + const regionalRestApiResponse = defaults.RegionalRestApi(stack); // Setup the API Gateway role const apiGatewayRole = new iam.Role(stack, 'api-gateway-role', { @@ -409,7 +409,7 @@ test('Test for Integration Request Props Override', () => { }); // Setup the API Gateway resource - const apiGatewayResource = regionalApi.root.addResource('hello'); + const apiGatewayResource = regionalRestApiResponse.api.root.addResource('hello'); const integReqParams = {'integration.request.path.topic-level-1': "'method.request.path.topic-level-1'"}; const integResp: api.IntegrationResponse[] = [ { @@ -496,7 +496,7 @@ test('Test for Integration Request Props Override', () => { test('Test for Method Request Props Override', () => { const stack = new Stack(); - const [globalApi] = defaults.GlobalRestApi(stack); + const globalRestApiResponse = defaults.GlobalRestApi(stack); // Setup the API Gateway role const apiGatewayRole = new iam.Role(stack, 'api-gateway-role', { @@ -504,7 +504,7 @@ test('Test for Method Request Props Override', () => { }); // Setup the API Gateway resource - const apiGatewayResource = globalApi.root.addResource('hello'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('hello'); const methodReqParams = {'method.request.path.topic-level-1': true}; const methodResp: api.MethodResponse[] = [ { @@ -584,7 +584,7 @@ test('Test for Method Request Props Override', () => { // ----------------------------------------------------------------------- test('Test for ApiKey creation using restApiProps', () => { const stack = new Stack(); - const [globalRestApi] = defaults.GlobalRestApi(stack, { + const globalRestApiResponse = defaults.GlobalRestApi(stack, { defaultMethodOptions: { apiKeyRequired: true } @@ -596,7 +596,7 @@ test('Test for ApiKey creation using restApiProps', () => { }); // Setup the API Gateway resource - const apiGatewayResource = globalRestApi.root.addResource('hello'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('hello'); defaults.addProxyMethodToApiResource( { @@ -654,7 +654,7 @@ test('Test for ApiKey creation using lambdaApiProps', () => { test('Additional request templates can be specified on addMethodToApiResource method', () => { const stack = new Stack(); - const [ restApi ] = defaults.GlobalRestApi(stack); + const globalRestApiResponse = defaults.GlobalRestApi(stack); // Setup the API Gateway role const apiGatewayRole = new iam.Role(stack, 'api-gateway-role', { @@ -662,7 +662,7 @@ test('Additional request templates can be specified on addMethodToApiResource me }); // Setup the API Gateway resource - const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('api-gateway-resource'); const requestTemplate = '{}'; const additionalRequestTemplates = { 'text/plain': 'additional-request-template' @@ -692,7 +692,7 @@ test('Additional request templates can be specified on addMethodToApiResource me test('Default integration responses are used on addMethodToApiResource method', () => { const stack = new Stack(); - const [ restApi ] = defaults.GlobalRestApi(stack); + const globalRestApiResponse = defaults.GlobalRestApi(stack); // Setup the API Gateway role const apiGatewayRole = new iam.Role(stack, 'api-gateway-role', { @@ -700,7 +700,7 @@ test('Default integration responses are used on addMethodToApiResource method', }); // Setup the API Gateway resource - const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('api-gateway-resource'); // Add Method defaults.addProxyMethodToApiResource({ @@ -733,7 +733,7 @@ test('Default integration responses are used on addMethodToApiResource method', test('Can override integration responses on addMethodToApiResource method', () => { const stack = new Stack(); - const [ restApi ] = defaults.GlobalRestApi(stack); + const globalRestApiResponse = defaults.GlobalRestApi(stack); // Setup the API Gateway role const apiGatewayRole = new iam.Role(stack, 'api-gateway-role', { @@ -741,7 +741,7 @@ test('Can override integration responses on addMethodToApiResource method', () = }); // Setup the API Gateway resource - const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('api-gateway-resource'); // Add Method defaults.addProxyMethodToApiResource({ @@ -778,13 +778,13 @@ test('Can override integration responses on addMethodToApiResource method', () = test('Specifying application/json content-type in additionalRequestTemplates property throws an error', () => { const stack = new Stack(); - const [ restApi ] = defaults.GlobalRestApi(stack); + const globalRestApiResponse = defaults.GlobalRestApi(stack); const apiGatewayRole = new iam.Role(stack, 'api-gateway-role', { assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com') }); - const apiGatewayResource = restApi.root.addResource('api-gateway-resource'); + const apiGatewayResource = globalRestApiResponse.api.root.addResource('api-gateway-resource'); const app = () => { defaults.addProxyMethodToApiResource({ diff --git a/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-api-gateway-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-api-gateway-helper.test.ts index c59709c0a..54d0a38e5 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-api-gateway-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-api-gateway-helper.test.ts @@ -29,7 +29,7 @@ test('test cloudfront for Api Gateway with user provided logging bucket', () => const inProps: lambda.FunctionProps = { code: lambda.Code.fromAsset(`${__dirname}/lambda-test`), - runtime: lambda.Runtime.PYTHON_3_6, + runtime: lambda.Runtime.PYTHON_3_9, handler: 'index.handler' }; @@ -147,7 +147,7 @@ test('test cloudfront for Api Gateway override properties', () => { const inProps: lambda.FunctionProps = { code: lambda.Code.fromAsset(`${__dirname}/lambda-test`), - runtime: lambda.Runtime.PYTHON_3_6, + runtime: lambda.Runtime.PYTHON_3_9, handler: 'index.handler' }; 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 fc1beee0c..0a5d02f82 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 @@ -25,8 +25,8 @@ import * as acm from 'aws-cdk-lib/aws-certificatemanager'; test('check bucket policy metadata', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); - CloudFrontDistributionForS3(stack, sourceBucket); + const buildS3BucketResponse = buildS3Bucket(stack, {}); + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket); expect(stack).toHaveResource('AWS::S3::BucketPolicy', { Metadata: { cfn_nag: { @@ -43,8 +43,8 @@ test('check bucket policy metadata', () => { test('check bucket metadata', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); - CloudFrontDistributionForS3(stack, sourceBucket); + const buildS3BucketResponse = buildS3Bucket(stack, {}); + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket); expect(stack).toHaveResource('AWS::S3::Bucket', { Metadata: { cfn_nag: { @@ -61,8 +61,8 @@ test('check bucket metadata', () => { test('test cloudfront check bucket policy', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); - CloudFrontDistributionForS3(stack, sourceBucket); + const buildS3BucketResponse = buildS3Bucket(stack, {}); + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket); expect(stack).toHaveResourceLike("AWS::S3::BucketPolicy", { PolicyDocument: { @@ -135,9 +135,9 @@ test('test cloudfront check bucket policy', () => { test('test cloudfront with no security headers ', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); + const buildS3BucketResponse = buildS3Bucket(stack, {}); - CloudFrontDistributionForS3(stack, sourceBucket, {}, false); + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket, {}, false); expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { DistributionConfig: { @@ -189,7 +189,7 @@ test('test cloudfront with no security headers ', () => { test('test cloudfront override cloudfront logging bucket ', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); + const buildS3BucketResponse = buildS3Bucket(stack, {}); const logBucket = new Bucket(stack, 'loggingbucket'); const myprops = { @@ -197,7 +197,7 @@ test('test cloudfront override cloudfront logging bucket ', () => { logBucket }; - CloudFrontDistributionForS3(stack, sourceBucket, myprops); + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket, myprops); expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { DistributionConfig: { @@ -260,17 +260,17 @@ test('test cloudfront override cloudfront logging bucket ', () => { test('test cloudfront override properties', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); + const buildS3BucketResponse = buildS3Bucket(stack, {}); const props: cloudfront.DistributionProps = { defaultBehavior: { - origin: new origins.S3Origin(sourceBucket, { originPath: '/testPath' }), + origin: new origins.S3Origin(buildS3BucketResponse.bucket, { originPath: '/testPath' }), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS }, }; - CloudFrontDistributionForS3(stack, sourceBucket, props); + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket, props); expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { DistributionConfig: { @@ -348,14 +348,14 @@ test('test cloudfront override properties', () => { test('test override cloudfront with custom cloudfront function', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); + const buildS3BucketResponse = buildS3Bucket(stack, {}); // custom cloudfront function const cloudfrontFunction = new cloudfront.Function(stack, "MyFunction", { code: cloudfront.FunctionCode.fromInline("exports.handler = (event, context, callback) => {}") }); - CloudFrontDistributionForS3(stack, sourceBucket, { + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket, { defaultBehavior: { functionAssociations: [ { @@ -427,7 +427,7 @@ test('test override cloudfront with custom cloudfront function', () => { test('test override cloudfront replace custom lambda@edge', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); + const buildS3BucketResponse = buildS3Bucket(stack, {}); // custom lambda@edg function const handler = new lambda.Function(stack, 'SomeHandler', { @@ -441,7 +441,7 @@ test('test override cloudfront replace custom lambda@edge', () => { lambda: handler, }); - CloudFrontDistributionForS3(stack, sourceBucket, { + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket, { defaultBehavior: { edgeLambdas: [ { @@ -513,7 +513,7 @@ test('test override cloudfront replace custom lambda@edge', () => { test('test cloudfront override cloudfront custom domain names ', () => { const stack = new Stack(); - const [sourceBucket] = buildS3Bucket(stack, {}); + const buildS3BucketResponse = buildS3Bucket(stack, {}); const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/11112222-3333-1234-1234-123456789012'); const myprops = { @@ -521,7 +521,7 @@ test('test cloudfront override cloudfront custom domain names ', () => { certificate }; - CloudFrontDistributionForS3(stack, sourceBucket, myprops); + CloudFrontDistributionForS3(stack, buildS3BucketResponse.bucket, myprops); expect(stack).toHaveResourceLike("AWS::CloudFront::Distribution", { DistributionConfig: { 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 3a964677b..9b172f1d7 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 @@ -159,10 +159,13 @@ test('test buildDynamoDBTable with existingTableObj', () => { const existingTableObj = new dynamodb.Table(stack, 'DynamoTable', tableProps); - defaults.buildDynamoDBTable(stack, { + const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, { existingTableObj }); + expect(buildDynamoDBTableResponse.tableInterface).toBeDefined(); + expect(buildDynamoDBTableResponse.tableObject).toBeDefined(); + expectCDK(stack).to(haveResource('AWS::DynamoDB::Table', { KeySchema: [ { @@ -183,7 +186,10 @@ test('test buildDynamoDBTable with existingTableObj', () => { test('test buildDynamoDBTable without any arguments', () => { const stack = new Stack(); - defaults.buildDynamoDBTable(stack, {}); + const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, {}); + + expect(buildDynamoDBTableResponse.tableInterface).toBeDefined(); + expect(buildDynamoDBTableResponse.tableObject).toBeDefined(); expectCDK(stack).to(haveResource('AWS::DynamoDB::Table', { KeySchema: [ @@ -216,10 +222,13 @@ test('test buildDynamoDBTable with TableProps', () => { } }; - defaults.buildDynamoDBTable(stack, { + const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, { dynamoTableProps }); + expect(buildDynamoDBTableResponse.tableInterface).toBeDefined(); + expect(buildDynamoDBTableResponse.tableObject).toBeDefined(); + expectCDK(stack).to(haveResource('AWS::DynamoDB::Table', { KeySchema: [ { @@ -248,10 +257,13 @@ test('test buildDynamoDBTableWithStream with TableProps', () => { stream: dynamodb.StreamViewType.NEW_IMAGE }; - defaults.buildDynamoDBTableWithStream(stack, { + const response = defaults.buildDynamoDBTableWithStream(stack, { dynamoTableProps }); + expect(response.tableInterface).toBeDefined(); + expect(response.tableObject).toBeDefined(); + expectCDK(stack).to(haveResource('AWS::DynamoDB::Table', { KeySchema: [ { @@ -271,7 +283,10 @@ test('test buildDynamoDBTableWithStream with TableProps', () => { test('test buildDynamoDBTableWithStream without any arguments', () => { const stack = new Stack(); - defaults.buildDynamoDBTableWithStream(stack, {}); + const response = defaults.buildDynamoDBTableWithStream(stack, {}); + + expect(response.tableInterface).toBeDefined(); + expect(response.tableObject).toBeDefined(); expectCDK(stack).to(haveResource('AWS::DynamoDB::Table', { KeySchema: [ @@ -312,10 +327,13 @@ test('test buildDynamoDBTableWithStream with existingTableObj', () => { const existingTableInterface = new dynamodb.Table(stack, 'DynamoTable', tableProps); - defaults.buildDynamoDBTableWithStream(stack, { + const response = defaults.buildDynamoDBTableWithStream(stack, { existingTableInterface }); + expect(response.tableInterface).toBeDefined(); + expect(response.tableObject).not.toBeDefined(); + expectCDK(stack).to(haveResource('AWS::DynamoDB::Table', { KeySchema: [ { @@ -345,10 +363,13 @@ test('test buildDynamoDBTable with existingTableInterface', () => { const existingTableInterface = new dynamodb.Table(stack, 'DynamoTable', tableProps); - defaults.buildDynamoDBTable(stack, { + const buildDynamoDBTableResponse = defaults.buildDynamoDBTable(stack, { existingTableInterface }); + expect(buildDynamoDBTableResponse.tableInterface).toBeDefined(); + expect(buildDynamoDBTableResponse.tableObject).not.toBeDefined(); + expectCDK(stack).to(haveResource('AWS::DynamoDB::Table', { KeySchema: [ { 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 4991b4ab6..22d9ea139 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 @@ -15,11 +15,10 @@ import { Stack } from 'aws-cdk-lib'; import * as elasticsearch from 'aws-cdk-lib/aws-elasticsearch'; import * as defaults from '../index'; import '@aws-cdk/assert/jest'; -import * as iam from 'aws-cdk-lib/aws-iam'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; function deployES(stack: Stack, domainName: string, clientDomainProps?: elasticsearch.CfnDomainProps, - lambdaRoleARN?: string, vpc?: ec2.IVpc): [elasticsearch.CfnDomain, iam.Role] { + lambdaRoleARN?: string, vpc?: ec2.IVpc): defaults.BuildElasticSearchResponse { const userpool = defaults.buildUserPool(stack); const userpoolclient = defaults.buildUserPoolClient(stack, userpool, { userPoolClientName: 'test', @@ -60,12 +59,15 @@ test('Test override SnapshotOptions for buildElasticSearch', () => { env: { account: "123456789012", region: 'us-east-1' }, }); - deployES(stack, 'test-domain', { + const buildElasticSearchResponse = deployES(stack, 'test-domain', { snapshotOptions: { automatedSnapshotStartHour: 5 } }); + expect(buildElasticSearchResponse.domain).toBeDefined(); + expect(buildElasticSearchResponse.role).toBeDefined(); + expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { AccessPolicies: { Statement: [ @@ -149,7 +151,7 @@ test('Test VPC with 1 AZ, Zone Awareness Disabled', () => { const vpc = defaults.getTestVpc(stack, false); - deployES(stack, 'test-domain', { + const buildElasticSearchResponse = deployES(stack, 'test-domain', { elasticsearchClusterConfig: { dedicatedMasterEnabled: true, dedicatedMasterCount: 3, @@ -158,6 +160,9 @@ test('Test VPC with 1 AZ, Zone Awareness Disabled', () => { } }, undefined, vpc); + expect(buildElasticSearchResponse.domain).toBeDefined(); + expect(buildElasticSearchResponse.role).toBeDefined(); + expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { DomainName: "test-domain", ElasticsearchClusterConfig: { @@ -176,7 +181,10 @@ test('Test VPC with 2 AZ, Zone Awareness Enabled', () => { const vpc: ec2.IVpc = defaults.getTestVpc(stack, false); - deployES(stack, 'test-domain', {}, undefined, vpc); + const buildElasticSearchResponse = deployES(stack, 'test-domain', {}, undefined, vpc); + + expect(buildElasticSearchResponse.domain).toBeDefined(); + expect(buildElasticSearchResponse.role).toBeDefined(); expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { DomainName: "test-domain", @@ -198,7 +206,10 @@ test('Test VPC with 3 AZ, Zone Awareness Enabled', () => { const vpc: ec2.IVpc = defaults.getTestVpc(stack); - deployES(stack, 'test-domain', {}, undefined, vpc); + const buildElasticSearchResponse = deployES(stack, 'test-domain', {}, undefined, vpc); + + expect(buildElasticSearchResponse.domain).toBeDefined(); + expect(buildElasticSearchResponse.role).toBeDefined(); expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { DomainName: "test-domain", @@ -232,7 +243,10 @@ test('Test deployment with an existing private VPC', () => { ] }); - deployES(stack, 'test-domain', {}, undefined, vpc); + const buildElasticSearchResponse = deployES(stack, 'test-domain', {}, undefined, vpc); + + expect(buildElasticSearchResponse.domain).toBeDefined(); + expect(buildElasticSearchResponse.role).toBeDefined(); expect(stack).toHaveResourceLike('AWS::Elasticsearch::Domain', { DomainName: "test-domain", @@ -274,10 +288,13 @@ test('Test override ES version for buildElasticSearch', () => { env: { account: "123456789012", region: 'us-east-1' }, }); - deployES(stack, 'test-domain', { + const response = deployES(stack, 'test-domain', { elasticsearchVersion: '7.0' }); + expect(response.domain).toBeDefined(); + expect(response.role).toBeDefined(); + expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { AccessPolicies: { Statement: [ @@ -360,7 +377,10 @@ test('Test ES with lambdaRoleARN', () => { env: { account: "123456789012", region: 'us-east-1' }, }); - deployES(stack, 'test-domain', {}, 'arn:aws:us-east-1:mylambdaRoleARN'); + const buildElasticSearchResponse = deployES(stack, 'test-domain', {}, 'arn:aws:us-east-1:mylambdaRoleARN'); + + expect(buildElasticSearchResponse.domain).toBeDefined(); + expect(buildElasticSearchResponse.role).toBeDefined(); expect(stack).toHaveResource('AWS::Elasticsearch::Domain', { AccessPolicies: { @@ -444,7 +464,10 @@ test('Test ES with lambdaRoleARN', () => { test('Count ES CW Alarms', () => { const stack = new Stack(); - deployES(stack, 'test-domain'); + const buildElasticSearchResponse = deployES(stack, 'test-domain'); + expect(buildElasticSearchResponse.domain).toBeDefined(); + expect(buildElasticSearchResponse.role).toBeDefined(); + const cwList = defaults.buildElasticSearchCWAlarms(stack); expect(cwList.length).toEqual(9); diff --git a/source/patterns/@aws-solutions-constructs/core/test/fargate-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/fargate-helper.test.ts index d9bdf7c24..3c60635ae 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/fargate-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/fargate-helper.test.ts @@ -23,12 +23,15 @@ test('Test with all defaults', () => { const stack = new Stack(); const testVpc = defaults.getTestVpc(stack); - CreateFargateService(stack, + const createFargateServiceResponse = CreateFargateService(stack, 'test', testVpc, undefined, defaults.fakeEcrRepoArn); + expect(createFargateServiceResponse.containerDefinition).toBeDefined(); + expect(createFargateServiceResponse.service).toBeDefined(); + expect(stack).toHaveResource("AWS::ECS::Service", { Cluster: { Ref: "testclusterDF8B0D19" diff --git a/source/patterns/@aws-solutions-constructs/core/test/glue-job-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/glue-job-helper.test.ts index 473673144..5e8c0a15e 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/glue-job-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/glue-job-helper.test.ts @@ -27,33 +27,33 @@ test('Test deployment with role creation', () => { // Stack const stack = new Stack(); - const _jobRole = new Role(stack, 'CustomETLJobRole', { + const jobRole = new Role(stack, 'CustomETLJobRole', { assumedBy: new ServicePrincipal('glue.amazonaws.com') }); - const cfnJobProps: CfnJobProps = defaults.DefaultGlueJobProps(_jobRole, { + const cfnJobProps: CfnJobProps = defaults.DefaultGlueJobProps(jobRole, { command: { name: 'glueetl', pythonVersion: '3', scriptLocation: 's3://fakescriptlocation/fakebucket', }, - role: _jobRole.roleArn + role: jobRole.roleArn }, 'testETLJob', {}); - const _database = defaults.createGlueDatabase(stack, defaults.DefaultGlueDatabaseProps()); + const database = defaults.createGlueDatabase(stack, defaults.DefaultGlueDatabaseProps()); - const _glueJob = defaults.buildGlueJob(stack, { + const glueJob = defaults.buildGlueJob(stack, { glueJobProps: cfnJobProps, - database: _database, - table: defaults.createGlueTable(stack, _database, undefined, [{ + database, + table: defaults.createGlueTable(stack, database, undefined, [{ name: "id", type: "int", comment: "" }], 'kinesis', {STREAM_NAME: 'testStream'}) }); - expect(_glueJob[2]?.[0]).toBeDefined(); - expect(_glueJob[2]?.[0]).toBeInstanceOf(Bucket); + expect(glueJob.bucket).toBeDefined(); + expect(glueJob.bucket).toBeInstanceOf(Bucket); expect(stack).toHaveResourceLike('AWS::Glue::Job', { Type: "AWS::Glue::Job", Properties: { @@ -82,7 +82,7 @@ test('Test deployment with role creation', () => { test('Create a Glue Job outside the construct', () => { // Stack const stack = new Stack(); - const _existingCfnJob = new CfnJob(stack, 'ExistingJob', { + const existingCfnJob = new CfnJob(stack, 'ExistingJob', { command: { name: 'pythonshell', pythonVersion: '2', @@ -99,22 +99,23 @@ test('Create a Glue Job outside the construct', () => { workerType: 'Standard' }); - const _database = defaults.createGlueDatabase(stack, defaults.DefaultGlueDatabaseProps()); + const database = defaults.createGlueDatabase(stack, defaults.DefaultGlueDatabaseProps()); - const _glueJob = defaults.buildGlueJob(stack, { - existingCfnJob: _existingCfnJob, + const glueJob = defaults.buildGlueJob(stack, { + existingCfnJob, outputDataStore: { datastoreType: defaults.SinkStoreType.S3 }, - database: _database, - table: defaults.createGlueTable(stack, _database, undefined, [{ + database, + table: defaults.createGlueTable(stack, database, undefined, [{ name: "id", type: "int", comment: "" }], 'kinesis', {STREAM_NAME: 'testStream'}) }); - expect(_glueJob[2]).not.toBeDefined(); + expect(glueJob.bucket).not.toBeDefined(); + expect(glueJob.loggingBucket).not.toBeDefined(); expect(stack).toHaveResourceLike('AWS::Glue::Job', { Type: "AWS::Glue::Job", Properties: { @@ -144,11 +145,11 @@ test('Create a Glue Job outside the construct', () => { test('Test custom deployment properties', () => { // Stack const stack = new Stack(); - const _commandName = 'glueetl'; + const commandName = 'glueetl'; const cfnJobProps: CfnJobProps = { command: { - name: _commandName, + name: commandName, pythonVersion: '3', scriptLocation: 's3://existingfakelocation/existingScript' }, @@ -161,15 +162,15 @@ test('Test custom deployment properties', () => { workerType: 'Standard' }; - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { glueJobProps: cfnJobProps, outputDataStore: { datastoreType: defaults.SinkStoreType.S3 }, - database: _database, - table: defaults.createGlueTable(stack, _database, undefined, [{ + database, + table: defaults.createGlueTable(stack, database, undefined, [{ name: "id", type: "int", comment: "" @@ -257,13 +258,13 @@ test('Test custom deployment properties', () => { test('Do no supply glueJobProps or existingCfnJob and error out', () => { const stack = new Stack(); try { - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { outputDataStore: { datastoreType: defaults.SinkStoreType.S3 }, - database: _database, - table: defaults.createGlueTable(stack, _database, defaults.DefaultGlueTableProps(_database, [{ + database, + table: defaults.createGlueTable(stack, database, defaults.DefaultGlueTableProps(database, [{ name: "id", type: "int", comment: "" @@ -280,25 +281,25 @@ test('Do no supply glueJobProps or existingCfnJob and error out', () => { test('Test deployment with role creation', () => { // Stack const stack = new Stack(); - const _jobID = 'glueetl'; + const jobID = 'glueetl'; const cfnJobProps = { command: { - name: _jobID, + name: jobID, pythonVersion: '3', scriptLocation: 's3://fakelocation/script' } }; - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { glueJobProps: cfnJobProps, outputDataStore: { datastoreType: defaults.SinkStoreType.S3 }, - database: _database, - table: defaults.createGlueTable(stack, _database, undefined, [{ + database, + table: defaults.createGlueTable(stack, database, undefined, [{ name: "id", type: "int", comment: "" @@ -328,17 +329,17 @@ test('Test deployment with role creation', () => { test('Test deployment with role creation', () => { // Stack const stack = new Stack(); - const _jobID = 'glueetl'; + const jobID = 'glueetl'; const cfnJobProps = { command: { - name: _jobID, + name: jobID, pythonVersion: '3', scriptLocation: 's3://fakelocation/script' } }; - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { glueJobProps: cfnJobProps, @@ -351,8 +352,8 @@ test('Test deployment with role creation', () => { removalPolicy: RemovalPolicy.DESTROY }) }, - database: _database, - table: defaults.createGlueTable(stack, _database, undefined, [{ + database, + table: defaults.createGlueTable(stack, database, undefined, [{ name: "id", type: "int", comment: "" @@ -381,16 +382,16 @@ test('Test deployment with role creation', () => { test('Test deployment with role creation', () => { // Stack const stack = new Stack(); - const _jobID = 'glueetl'; + const jobID = 'glueetl'; const cfnJobProps = { command: { - name: _jobID, + name: jobID, pythonVersion: '3' } }; - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); try { defaults.buildGlueJob(stack, { glueJobProps: cfnJobProps, @@ -400,8 +401,8 @@ test('Test deployment with role creation', () => { versioned: false }) }, - database: _database, - table: defaults.createGlueTable(stack, _database, undefined, [{ + database, + table: defaults.createGlueTable(stack, database, undefined, [{ name: "id", type: "int", comment: "" @@ -421,11 +422,11 @@ test('Test deployment with role creation', () => { test('Test for incorrect Job Command property', () => { const stack = new Stack(); try { - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { glueJobProps: {}, - database: _database, - table: defaults.createGlueTable(stack, _database, undefined, [{ + database, + table: defaults.createGlueTable(stack, database, undefined, [{ name: "id", type: "int", comment: "" @@ -442,15 +443,15 @@ test('Test for incorrect Job Command property', () => { test('check for JobCommandProperty type', () => { const stack = new Stack(); try { - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { glueJobProps: { command: { fakekey: 'fakevalue' } }, - database: _database, - table: defaults.createGlueTable(stack, _database, undefined, [{ + database, + table: defaults.createGlueTable(stack, database, undefined, [{ name: "id", type: "int", comment: "" @@ -467,13 +468,13 @@ test('check for JobCommandProperty type', () => { test('GlueJob configuration with glueVersion 2.0 should not support maxCapacity and error out', () => { const stack = new Stack(); try { - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { outputDataStore: { datastoreType: defaults.SinkStoreType.S3 }, - database: _database, - table: defaults.createGlueTable(stack, _database, defaults.DefaultGlueTableProps(_database, [{ + database, + table: defaults.createGlueTable(stack, database, defaults.DefaultGlueTableProps(database, [{ name: "id", type: "int", comment: "" @@ -494,13 +495,13 @@ test('GlueJob configuration with glueVersion 2.0 should not support maxCapacity test('Cannot use maxCapacity and WorkerType, so error out', () => { const stack = new Stack(); try { - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { outputDataStore: { datastoreType: defaults.SinkStoreType.S3 }, - database: _database, - table: defaults.createGlueTable(stack, _database, defaults.DefaultGlueTableProps(_database, [{ + database, + table: defaults.createGlueTable(stack, database, defaults.DefaultGlueTableProps(database, [{ name: "id", type: "int", comment: "" @@ -523,13 +524,13 @@ test('Cannot use maxCapacity and WorkerType, so error out', () => { test('Cannot use maxCapacity and WorkerType, so error out', () => { const stack = new Stack(); try { - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { outputDataStore: { datastoreType: defaults.SinkStoreType.S3 }, - database: _database, - table: defaults.createGlueTable(stack, _database, defaults.DefaultGlueTableProps(_database, [{ + database, + table: defaults.createGlueTable(stack, database, defaults.DefaultGlueTableProps(database, [{ name: "id", type: "int", comment: "" @@ -552,13 +553,13 @@ test('Cannot use maxCapacity and WorkerType, so error out', () => { test('Cannot use maxCapacity and WorkerType, so error out', () => { const stack = new Stack(); try { - const _database = defaults.createGlueDatabase(stack); + const database = defaults.createGlueDatabase(stack); defaults.buildGlueJob(stack, { outputDataStore: { datastoreType: defaults.SinkStoreType.S3 }, - database: _database, - table: defaults.createGlueTable(stack, _database, defaults.DefaultGlueTableProps(_database, [{ + database, + table: defaults.createGlueTable(stack, database, defaults.DefaultGlueTableProps(database, [{ name: "id", type: "int", comment: "" diff --git a/source/patterns/@aws-solutions-constructs/core/test/input-validation.test.ts b/source/patterns/@aws-solutions-constructs/core/test/input-validation.test.ts index c963ac049..37db0fbe9 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/input-validation.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/input-validation.test.ts @@ -410,10 +410,10 @@ test('Test fail SageMaker endpoint check', () => { }, }; - const [endpoint] = BuildSagemakerEndpoint(stack, { modelProps }); + const buildSagemakerEndpointResponse = BuildSagemakerEndpoint(stack, { modelProps }); const props: defaults.VerifiedProps = { - existingSagemakerEndpointObj: endpoint, + existingSagemakerEndpointObj: buildSagemakerEndpointResponse.endpoint, endpointProps: { endpointConfigName: 'placeholder' } diff --git a/source/patterns/@aws-solutions-constructs/core/test/opensearch-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/opensearch-helper.test.ts index 909fe1299..0a3c3bb5a 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/opensearch-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/opensearch-helper.test.ts @@ -15,11 +15,11 @@ import { Stack } from 'aws-cdk-lib'; import * as opensearch from 'aws-cdk-lib/aws-opensearchservice'; import * as defaults from '../index'; import '@aws-cdk/assert/jest'; -import * as iam from 'aws-cdk-lib/aws-iam'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import { BuildOpenSearchResponse } from '../index'; -function deployOpenSearch(stack: Stack, openSearchDomainName: string, clientDomainProps?: opensearch.CfnDomainProps, - lambdaRoleARN?: string, vpc?: ec2.IVpc): [opensearch.CfnDomain, iam.Role] { +function buildTestOpenSearchDomain(stack: Stack, openSearchDomainName: string, clientDomainProps?: opensearch.CfnDomainProps, + lambdaRoleARN?: string, vpc?: ec2.IVpc): BuildOpenSearchResponse { const userpool = defaults.buildUserPool(stack); const userpoolclient = defaults.buildUserPoolClient(stack, userpool, { userPoolClientName: 'test', @@ -53,12 +53,14 @@ function deployStack() { test('Test override SnapshotOptions for buildOpenSearch', () => { const stack = deployStack(); - deployOpenSearch(stack, 'test-domain', { + const buildOpenSearchResponse = buildTestOpenSearchDomain(stack, 'test-domain', { snapshotOptions: { automatedSnapshotStartHour: 5 } }); + expect(buildOpenSearchResponse.domain).toBeDefined(); + expect(buildOpenSearchResponse.role).toBeDefined(); expect(stack).toHaveResource('AWS::OpenSearchService::Domain', { AccessPolicies: { Statement: [ @@ -140,7 +142,7 @@ test('Test VPC with 1 AZ, Zone Awareness Disabled', () => { const vpc = defaults.getTestVpc(stack, false); - deployOpenSearch(stack, 'test-domain', { + buildTestOpenSearchDomain(stack, 'test-domain', { clusterConfig: { dedicatedMasterEnabled: true, dedicatedMasterCount: 3, @@ -167,8 +169,10 @@ test('Test VPC with 2 AZ, Zone Awareness Enabled', () => { const vpc: ec2.IVpc = defaults.getTestVpc(stack, false); - deployOpenSearch(stack, 'test-domain', {}, undefined, vpc); + const buildOpenSearchResponse = buildTestOpenSearchDomain(stack, 'test-domain', {}, undefined, vpc); + expect(buildOpenSearchResponse.domain).toBeDefined(); + expect(buildOpenSearchResponse.role).toBeDefined(); expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { DomainName: "test-domain", ClusterConfig: { @@ -187,7 +191,7 @@ test('Test VPC with 3 AZ, Zone Awareness Enabled', () => { const vpc: ec2.IVpc = defaults.getTestVpc(stack); - deployOpenSearch(stack, 'test-domain', {}, undefined, vpc); + buildTestOpenSearchDomain(stack, 'test-domain', {}, undefined, vpc); expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { DomainName: "test-domain", @@ -219,7 +223,7 @@ test('Test deployment with an existing private VPC', () => { ] }); - deployOpenSearch(stack, 'test-domain', {}, undefined, vpc); + buildTestOpenSearchDomain(stack, 'test-domain', {}, undefined, vpc); expect(stack).toHaveResourceLike('AWS::OpenSearchService::Domain', { DomainName: "test-domain", @@ -248,7 +252,7 @@ test('Test error thrown with no private subnet configurations', () => { }); const app = () => { - deployOpenSearch(stack, 'test-domain', {}, undefined, vpc); + buildTestOpenSearchDomain(stack, 'test-domain', {}, undefined, vpc); }; expect(app).toThrowError('Error - No isolated or private subnets available in VPC'); @@ -257,7 +261,7 @@ test('Test error thrown with no private subnet configurations', () => { test('Test engine version override for buildOpenSearch', () => { const stack = deployStack(); - deployOpenSearch(stack, 'test-domain', { + buildTestOpenSearchDomain(stack, 'test-domain', { engineVersion: 'OpenSearch_1.0' }); @@ -341,8 +345,10 @@ test('Test engine version override for buildOpenSearch', () => { test('Test deployment with lambdaRoleARN', () => { const stack = deployStack(); - deployOpenSearch(stack, 'test-domain', {}, 'arn:aws:us-east-1:mylambdaRoleARN'); + const buildOpenSearchResponse = buildTestOpenSearchDomain(stack, 'test-domain', {}, 'arn:aws:us-east-1:mylambdaRoleARN'); + expect(buildOpenSearchResponse.domain).toBeDefined(); + expect(buildOpenSearchResponse.role).toBeDefined(); expect(stack).toHaveResource('AWS::OpenSearchService::Domain', { AccessPolicies: { Statement: [ @@ -425,7 +431,7 @@ test('Test deployment with lambdaRoleARN', () => { test('Count OpenSearch CloudWatch alarms', () => { const stack = new Stack(); - deployOpenSearch(stack, 'test-domain'); + buildTestOpenSearchDomain(stack, 'test-domain'); const cwList = defaults.buildOpenSearchCWAlarms(stack); expect(cwList.length).toEqual(9); 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 372b1c635..1e158f5cd 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 @@ -15,7 +15,6 @@ import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert import { Duration, Stack, RemovalPolicy } from 'aws-cdk-lib'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as s3n from 'aws-cdk-lib/aws-s3-notifications'; -import * as sqs from 'aws-cdk-lib/aws-sqs'; import * as defaults from '../index'; import '@aws-cdk/assert/jest'; import { Bucket, StorageClass } from 'aws-cdk-lib/aws-s3'; @@ -33,7 +32,10 @@ test('check exception for Missing existingBucketObj from props for deploy = fals test('s3 bucket with bucketId', () => { const stack = new Stack(); - defaults.buildS3Bucket(stack, {}, 'my'); + const buildS3BucketResponse = defaults.buildS3Bucket(stack, {}, 'my'); + + expect(buildS3BucketResponse.bucket).toBeDefined(); + expect(buildS3BucketResponse.loggingBucket).toBeDefined(); expectCDK(stack).to(haveResource("AWS::S3::Bucket", { LoggingConfiguration: { @@ -47,12 +49,15 @@ test('s3 bucket with bucketId', () => { test('s3 bucket with bucketProps', () => { const stack = new Stack(); - defaults.buildS3Bucket(stack, { + const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { bucketName: 'mybucket' } }); + expect(buildS3BucketResponse.bucket).toBeDefined(); + expect(buildS3BucketResponse.loggingBucket).toBeDefined(); + expectCDK(stack).to(haveResource("AWS::S3::Bucket", { BucketName: "mybucket" })); @@ -61,7 +66,10 @@ test('s3 bucket with bucketProps', () => { test('s3 bucket with default props', () => { const stack = new Stack(); - defaults.buildS3Bucket(stack, {}); + const buildS3BucketResponse = defaults.buildS3Bucket(stack, {}); + + expect(buildS3BucketResponse.bucket).toBeDefined(); + expect(buildS3BucketResponse.loggingBucket).toBeDefined(); expectCDK(stack).to(haveResource("AWS::S3::Bucket", { BucketEncryption: { @@ -88,7 +96,7 @@ test('s3 bucket with default props', () => { test('s3 bucket with life cycle policy', () => { const stack = new Stack(); - defaults.buildS3Bucket(stack, { + const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { lifecycleRules: [{ expiration: Duration.days(365), @@ -103,6 +111,9 @@ test('s3 bucket with life cycle policy', () => { } }); + expect(buildS3BucketResponse.bucket).toBeDefined(); + expect(buildS3BucketResponse.loggingBucket).toBeDefined(); + expectCDK(stack).to(haveResource("AWS::S3::Bucket", { LifecycleConfiguration: { Rules: [ @@ -131,12 +142,16 @@ test('s3 bucket with access logging configured', () => { serverAccessLogsBucket: new Bucket(stack, 'myaccesslogbucket', {}) }); - defaults.buildS3Bucket(stack, { + const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { serverAccessLogsBucket: mybucket } }); + expect(buildS3BucketResponse.bucket).toBeDefined(); + // This value should be populated, entered Issue 907 + // expect(response.loggingBucket).toBeDefined(); + expectCDK(stack).to(haveResource("AWS::S3::Bucket", { LoggingConfiguration: { DestinationBucketName: { @@ -201,7 +216,7 @@ test('s3 bucket with LoggingBucket and versioning turned off', () => { serverAccessLogsBucket: new Bucket(stack, 'myaccesslogbucket', {}) }); - defaults.buildS3Bucket(stack, { + const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { serverAccessLogsBucket: mybucket, serverAccessLogsPrefix: 'access-logs', @@ -209,6 +224,10 @@ test('s3 bucket with LoggingBucket and versioning turned off', () => { } }); + expect(buildS3BucketResponse.bucket).toBeDefined(); + // The line below fails, this appears to be a bug. Entered Issue 906 + // expect(response.loggingBucket).toBeDefined(); + expectCDK(stack).to(haveResource("AWS::S3::Bucket", { BucketEncryption: { ServerSideEncryptionConfiguration: [ @@ -237,13 +256,16 @@ test('s3 bucket with LoggingBucket and versioning turned off', () => { test('s3 bucket versioning turned off', () => { const stack = new Stack(); - defaults.buildS3Bucket(stack, { + const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { serverAccessLogsPrefix: 'access-logs', versioned: false } }); + expect(buildS3BucketResponse.bucket).toBeDefined(); + expect(buildS3BucketResponse.loggingBucket).toBeDefined(); + expectCDK(stack).to(haveResource("AWS::S3::Bucket", { BucketEncryption: { ServerSideEncryptionConfiguration: [ @@ -272,13 +294,16 @@ test('s3 bucket versioning turned off', () => { test('s3 bucket with LoggingBucket and auto delete objects', () => { const stack = new Stack(); - defaults.buildS3Bucket(stack, { + const buildS3BucketResponse = defaults.buildS3Bucket(stack, { loggingBucketProps: { removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true } }); + expect(buildS3BucketResponse.bucket).toBeDefined(); + expect(buildS3BucketResponse.loggingBucket).toBeDefined(); + expectCDK(stack).to(haveResource("AWS::S3::Bucket", { AccessControl: "LogDeliveryWrite" })); @@ -299,12 +324,15 @@ test('s3 bucket with LoggingBucket and auto delete objects', () => { test('s3 bucket versioning turned on', () => { const stack = new Stack(); - defaults.buildS3Bucket(stack, { + const buildS3BucketResponse = defaults.buildS3Bucket(stack, { bucketProps: { serverAccessLogsPrefix: 'access-logs', } }); + expect(buildS3BucketResponse.bucket).toBeDefined(); + expect(buildS3BucketResponse.loggingBucket).toBeDefined(); + expectCDK(stack).to(haveResource("AWS::S3::Bucket", { BucketEncryption: { ServerSideEncryptionConfiguration: [ @@ -348,11 +376,9 @@ test('s3 bucket versioning turned on', () => { test('Suppress cfn-nag warning for s3 bucket notification', () => { const stack = new Stack(); - let queue: sqs.Queue; - let bucket: s3.Bucket; - [bucket] = defaults.buildS3Bucket(stack, {}); - [queue] = defaults.buildQueue(stack, "S3BucketNotificationQueue", {}); - bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.SqsDestination(queue)); + const buildS3BucketResponse = defaults.buildS3Bucket(stack, {}); + const buildQueueResponse = defaults.buildQueue(stack, "S3BucketNotificationQueue", {}); + buildS3BucketResponse.bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.SqsDestination(buildQueueResponse.queue)); defaults.addCfnNagS3BucketNotificationRulesToSuppress(stack, "BucketNotificationsHandler050a0587b7544547bf325f094a3db834"); expectCDK(stack).to(haveResource("AWS::Lambda::Function", { @@ -407,4 +433,20 @@ test('test s3Bucket removalPolicy override', () => { UpdateReplacePolicy: "Delete", DeletionPolicy: "Delete" }, ResourcePart.CompleteDefinition); -}); \ No newline at end of file +}); + +test('s3 bucket with logging turned off', () => { + const stack = new Stack(); + + const respbuildS3BucketResponsense = defaults.buildS3Bucket(stack, { + logS3AccessLogs: false, + }); + + expect(respbuildS3BucketResponsense.bucket).toBeDefined(); + expect(respbuildS3BucketResponsense.loggingBucket).not.toBeDefined(); + + expect(stack).not.toHaveResourceLike("AWS::S3::Bucket", { + LoggingConfiguration: { + }, + }); +}); 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 614a5a745..146c642f6 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 @@ -18,33 +18,42 @@ import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as defaults from '../'; import '@aws-cdk/assert/jest'; -// -------------------------------------------------------------- -// 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; // Build Sagemaker Notebook Instance - [sagemaker, vpc, sg] = defaults.buildSagemakerNotebook(stack, { + const buildSagemakerNotebookResponse = defaults.buildSagemakerNotebook(stack, { role: sagemakerRole, }); // Assertion - expect(vpc?.privateSubnets.length).toEqual(2); - expect(vpc?.publicSubnets.length).toEqual(2); - expect(sagemaker.instanceType).toEqual('ml.t2.medium'); - expect(sg).toBeInstanceOf(ec2.SecurityGroup); + expect(buildSagemakerNotebookResponse.vpc?.privateSubnets.length).toEqual(2); + expect(buildSagemakerNotebookResponse.vpc?.publicSubnets.length).toEqual(2); + expect(buildSagemakerNotebookResponse.notebook.instanceType).toEqual('ml.t2.medium'); + expect(buildSagemakerNotebookResponse.securityGroup).toBeInstanceOf(ec2.SecurityGroup); +}); + +test('Test deployment without VPC', () => { + // Stack + const stack = new Stack(); + const sagemakerRole = new iam.Role(stack, 'SagemakerRole', { + assumedBy: new iam.ServicePrincipal('sagemaker.amazonaws.com'), + }); + + // Build Sagemaker Notebook Instance + const buildSagemakerNotebookResponse = defaults.buildSagemakerNotebook(stack, { + role: sagemakerRole, + deployInsideVpc: false, + }); + // Assertion + expect(buildSagemakerNotebookResponse.vpc).not.toBeDefined(); + expect(buildSagemakerNotebookResponse.notebook).toBeDefined(); + expect(buildSagemakerNotebookResponse.securityGroup).not.toBeDefined(); }); -// -------------------------------------------------------------- -// Test deployment in existing VPC -// -------------------------------------------------------------- test('Test deployment w/ existing VPC', () => { // Stack const stack = new Stack(); @@ -52,7 +61,7 @@ test('Test deployment w/ existing VPC', () => { assumedBy: new iam.ServicePrincipal('sagemaker.amazonaws.com'), }); // Build Sagemaker Notebook Instance - defaults.buildSagemakerNotebook(stack, { + const buildSagemakerNotebookResponse = defaults.buildSagemakerNotebook(stack, { role: sagemakerRole, deployInsideVpc: true, sagemakerNotebookProps: { @@ -60,6 +69,11 @@ test('Test deployment w/ existing VPC', () => { securityGroupIds: ['sg-deadbeef'], }, }); + + expect(buildSagemakerNotebookResponse.notebook).toBeDefined(); + expect(buildSagemakerNotebookResponse.vpc).not.toBeDefined(); + expect(buildSagemakerNotebookResponse.securityGroup).not.toBeDefined(); + expect(stack).toHaveResource('AWS::SageMaker::NotebookInstance', { DirectInternetAccess: 'Disabled', SecurityGroupIds: ['sg-deadbeef'], @@ -67,9 +81,6 @@ test('Test deployment w/ existing VPC', () => { }); }); -// -------------------------------------------------------------- -// Test deployment with override -// -------------------------------------------------------------- test('Test deployment w/ override', () => { // Stack const stack = new Stack(); @@ -94,9 +105,6 @@ test('Test deployment w/ override', () => { }); }); -// -------------------------------------------------------------- -// Test exception -// -------------------------------------------------------------- test('Test exception', () => { // Stack const stack = new Stack(); @@ -116,9 +124,6 @@ test('Test exception', () => { }).toThrowError(); }); -// --------------------------------------------------------------- -// Test exception for not providing primaryContainer in modelProps -// --------------------------------------------------------------- test('Test exception for not providing primaryContainer in modelProps', () => { // Stack const stack = new Stack(); @@ -133,9 +138,6 @@ test('Test exception for not providing primaryContainer in modelProps', () => { expect(app).toThrowError(); }); -// ------------------------------------------------------------------------- -// Test exception for not providing modelProps -// ------------------------------------------------------------------------- test('Test exception for not providing modelProps', () => { // Stack const stack = new Stack(); @@ -156,9 +158,6 @@ test('Test exception for not providing modelProps', () => { expect(app).toThrowError(); }); -// ------------------------------------------------------------------------- -// Test exception for not providing modelProps or existingSagemkaerObj -// ------------------------------------------------------------------------- test('Test exception for not providing modelProps or existingSagemkaerObj', () => { // Stack const stack = new Stack(); @@ -179,9 +178,6 @@ test('Test exception for not providing modelProps or existingSagemkaerObj', () = expect(app).toThrowError(); }); -// ----------------------------------------------------------------------------------------- -// Test exception for not providing private or isolated subnets in an existing vpc -// ----------------------------------------------------------------------------------------- test('Test exception for not providing private or isolated subnets in an existing vpc', () => { // Stack const stack = new Stack(); 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 cbdcd1070..b1b1e9407 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 @@ -27,8 +27,10 @@ test('Test deployment with no properties using AWS Managed KMS Key', () => { // Stack const stack = new Stack(); // Helper declaration - defaults.buildTopic(stack, {}); + const buildTopicResponse = defaults.buildTopic(stack, {}); + expect(buildTopicResponse.topic).toBeDefined(); + expect(buildTopicResponse.key).toBeDefined(); expect(stack).toHaveResource("AWS::SNS::Topic", { KmsMasterKeyId: { "Fn::Join": [ @@ -85,7 +87,7 @@ test('Test deployment w/ imported encryption key', () => { // Generate KMS Key const key = defaults.buildEncryptionKey(stack); // Helper declaration - defaults.buildTopic(stack, { + const buildTopicResponse = defaults.buildTopic(stack, { topicProps: { topicName: "custom-topic" }, @@ -93,6 +95,9 @@ test('Test deployment w/ imported encryption key', () => { encryptionKey: key }); + expect(buildTopicResponse.topic).toBeDefined(); + expect(buildTopicResponse.key).toBeDefined(); + expect(stack).toHaveResource("AWS::SNS::Topic", { KmsMasterKeyId: { "Fn::GetAtt": [ @@ -288,11 +293,13 @@ test('existing unencrypted topic is not overridden with defaults', () => { const topic = new sns.Topic(stack, 'Topic'); - defaults.buildTopic(stack, { + const buildBuildTopicResponse = defaults.buildTopic(stack, { existingTopicObj: topic, }); + expect(buildBuildTopicResponse.topic).toBeDefined(); + expect(buildBuildTopicResponse.key).not.toBeDefined(); // Make sure the construct did not create any other topics and that no keys exist expect(stack).toCountResources('AWS::KMS::Key', 0); expect(stack).toCountResources('AWS::SNS::Topic', 1); -}); \ 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 3bbf4d644..e995e16ad 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 @@ -20,9 +20,6 @@ import { buildDeadLetterQueue, buildQueue } from "../lib/sqs-helper"; import * as kms from 'aws-cdk-lib/aws-kms'; import { expectKmsKeyAttachedToCorrectResource } from "../"; -// -------------------------------------------------------------- -// Test deployment w/ imported encryption key -// -------------------------------------------------------------- test('Test deployment w/ encryptionMasterKey set on queueProps', () => { const stack = new Stack(); @@ -39,9 +36,6 @@ test('Test deployment w/ encryptionMasterKey set on queueProps', () => { expectKmsKeyAttachedToCorrectResource(stack, 'AWS::SQS::Queue', 'kms-key-description'); }); -// -------------------------------------------------------------- -// Test deployment w/ imported encryption key -// -------------------------------------------------------------- test('Test deployment w/ imported encryption key', () => { // Stack const stack = new Stack(); @@ -62,9 +56,6 @@ test('Test deployment w/ imported encryption key', () => { }); }); -// -------------------------------------------------------------- -// Test deployment without imported encryption key -// -------------------------------------------------------------- test('Test deployment without imported encryption key', () => { // Stack const stack = new Stack(); @@ -81,14 +72,11 @@ test('Test deployment without imported encryption key', () => { }); }); -// -------------------------------------------------------------- -// Test deployment w/ construct created encryption key -// -------------------------------------------------------------- test('Test deployment w/ construct created encryption key', () => { // Stack const stack = new Stack(); // Helper declaration - const [queue, key] = defaults.buildQueue(stack, 'existing-queue', { + const buildQueueResponse = defaults.buildQueue(stack, 'existing-queue', { queueProps: { queueName: 'existing-queue' }, @@ -101,8 +89,8 @@ test('Test deployment w/ construct created encryption key', () => { expect(stack).toHaveResource("AWS::KMS::Key", { EnableKeyRotation: true }); - expect(queue).toBeDefined(); - expect(key).toBeDefined(); + expect(buildQueueResponse.queue).toBeDefined(); + expect(buildQueueResponse.key).toBeDefined(); }); test('Test DLQ when existing Queue Provided', () => { @@ -161,14 +149,15 @@ test('Test returning an existing Queue', () => { queueName: testQueueName }); - const [returnedQueue] = defaults.buildQueue(stack, 'newQueue', { + const buildQueueResponse = defaults.buildQueue(stack, 'newQueue', { existingQueueObj: existingQueue }); expect(stack).toHaveResourceLike("AWS::SQS::Queue", { QueueName: testQueueName, }); - expect(existingQueue.queueName).toEqual(returnedQueue.queueName); + expect(existingQueue.queueName).toEqual(buildQueueResponse.queue.queueName); + expect(buildQueueResponse.key).not.toBeDefined(); }); test('Test creating a queue with a DLQ', () => { @@ -176,19 +165,19 @@ test('Test creating a queue with a DLQ', () => { const dlqInterface = buildDeadLetterQueue(stack, {}); - const [newQueue] = buildQueue(stack, 'new-queue', { + const buildQueueResponse = buildQueue(stack, 'new-queue', { deadLetterQueue: dlqInterface }); expect(stack).toCountResources("AWS::SQS::Queue", 2); - expect(newQueue).toBeDefined(); - expect(newQueue.deadLetterQueue).toBeDefined(); + expect(buildQueueResponse.queue).toBeDefined(); + expect(buildQueueResponse.queue.deadLetterQueue).toBeDefined(); }); test('Test creating a FIFO queue', () => { const stack = new Stack(); - const [newFifoQueue] = buildQueue(stack, 'new-queue', { + const buildQueueResponse = buildQueue(stack, 'new-queue', { queueProps: { fifo: true } @@ -197,5 +186,5 @@ test('Test creating a FIFO queue', () => { expect(stack).toHaveResourceLike("AWS::SQS::Queue", { FifoQueue: true }); - expect(newFifoQueue.fifo).toBe(true); + expect(buildQueueResponse.queue.fifo).toBe(true); }); 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 de810003d..4b195bf09 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 @@ -27,11 +27,13 @@ test('Test deployment w/ custom properties', () => { // Step function definition const startState = new sfn.Pass(stack, 'StartState'); // Build state machine - defaults.buildStateMachine(stack, { + const buildStateMachineResponse = defaults.buildStateMachine(stack, { definition: startState, stateMachineName: 'myStateMachine' }); // Assertion + expect(buildStateMachineResponse.stateMachine).toBeDefined(); + expect(buildStateMachineResponse.stateMachine).toBeDefined(); expect(stack).toCountResources("AWS::Logs::LogGroup", 1); expect(stack).toHaveResource("AWS::StepFunctions::StateMachine", { @@ -52,7 +54,7 @@ test('Test deployment w/ logging enabled', () => { const logGroup = buildLogGroup(stack, 'StateMachineLogGroup'); // Build state machine - defaults.buildStateMachine(stack, { + const buildStateMachineResponse = defaults.buildStateMachine(stack, { definition: startState, logs: { destination: logGroup, @@ -61,6 +63,8 @@ test('Test deployment w/ logging enabled', () => { }); // Assertion expect(stack).toCountResources("AWS::Logs::LogGroup", 1); + expect(buildStateMachineResponse.stateMachine).toBeDefined(); + expect(buildStateMachineResponse.stateMachine).toBeDefined(); expect(stack).toHaveResource("AWS::StepFunctions::StateMachine", { LoggingConfiguration: { @@ -88,10 +92,12 @@ test('Check default Cloudwatch permissions', () => { // Step function definition const startState = new sfn.Pass(stack, 'StartState'); // Build state machine - defaults.buildStateMachine(stack, { + const buildStateMachineResponse = defaults.buildStateMachine(stack, { definition: startState }); // Assertion + expect(buildStateMachineResponse.stateMachine).toBeDefined(); + expect(buildStateMachineResponse.stateMachine).toBeDefined(); expect(stack).toHaveResource("AWS::IAM::Policy", { PolicyDocument: { Statement: [ @@ -149,10 +155,12 @@ test('Count State Machine CW Alarms', () => { // Step function definition const startState = new sfn.Pass(stack, 'StartState'); // Build state machine - const [sm] = defaults.buildStateMachine(stack, { + const buildStateMachineResponse = defaults.buildStateMachine(stack, { definition: startState }); - const cwList = defaults.buildStepFunctionCWAlarms(stack, sm); + const cwList = defaults.buildStepFunctionCWAlarms(stack, buildStateMachineResponse.stateMachine); + expect(buildStateMachineResponse.stateMachine).toBeDefined(); + expect(buildStateMachineResponse.stateMachine).toBeDefined(); expect(cwList.length).toEqual(3); }); \ No newline at end of file