From 20c02f17819442a53518fd03ebe4a649974f4de2 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Wed, 29 Apr 2020 15:22:43 +0100 Subject: [PATCH 1/2] feat(sns-subscriptions): extend cross-region support to Lambda functions Extend the existing cross-region topic subscription for SQS to apply to Lambda. fixes #5734 --- .../aws-sns-subscriptions/lib/lambda.ts | 11 +++++++- .../aws-sns-subscriptions/test/subs.test.ts | 26 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts b/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts index 6e85ebe16b1d1..718a6db6ecd06 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts @@ -1,7 +1,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; -import { Construct } from '@aws-cdk/core'; +import { Construct, Stack } from '@aws-cdk/core'; import { SubscriptionProps } from './subscription'; /** @@ -35,6 +35,15 @@ export class LambdaSubscription implements sns.ITopicSubscription { endpoint: this.fn.functionArn, protocol: sns.SubscriptionProtocol.LAMBDA, filterPolicy: this.props.filterPolicy, + region: this.regionFromArn(topic), }; } + + private regionFromArn(topic: sns.ITopic): string | undefined { + // no need to specify `region` for topics defined within the same stack. + if (topic instanceof sns.Topic) { + return undefined; + } + return Stack.of(topic).parseArn(topic.topicArn).region; + } } diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts index 0d2d1181df63a..db2b8fc12b07c 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts @@ -739,9 +739,21 @@ test('with filter policy', () => { test('region property is present on an imported topic', () => { const imported = sns.Topic.fromTopicArn(stack, 'mytopic', 'arn:aws:sns:us-east-1:1234567890:mytopic'); const queue = new sqs.Queue(stack, 'myqueue'); + const func = new lambda.Function(stack, 'MyFunc', { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function(e, c, cb) { return cb() }'), + }); + imported.addSubscription(new subs.SqsSubscription(queue)); + imported.addSubscription(new subs.LambdaSubscription(func)); expect(stack).toHaveResource('AWS::SNS::Subscription', { + Protocol: 'sqs', + Region: 'us-east-1', + }); + expect(stack).toHaveResource('AWS::SNS::Subscription', { + Protocol: 'lambda', Region: 'us-east-1', }); }); @@ -750,9 +762,23 @@ test('region property on an imported topic as a parameter', () => { const topicArn = new CfnParameter(stack, 'topicArn'); const imported = sns.Topic.fromTopicArn(stack, 'mytopic', topicArn.valueAsString); const queue = new sqs.Queue(stack, 'myqueue'); + const func = new lambda.Function(stack, 'MyFunc', { + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function(e, c, cb) { return cb() }'), + }); + imported.addSubscription(new subs.SqsSubscription(queue)); + imported.addSubscription(new subs.LambdaSubscription(func)); expect(stack).toHaveResource('AWS::SNS::Subscription', { + Protocol: 'sqs', + Region: { + 'Fn::Select': [ 3, { 'Fn::Split': [ ':', { 'Ref': 'topicArn' } ] } ], + }, + }); + expect(stack).toHaveResource('AWS::SNS::Subscription', { + Protocol: 'lambda', Region: { 'Fn::Select': [ 3, { 'Fn::Split': [ ':', { 'Ref': 'topicArn' } ] } ], }, From 26714b80f75f3f4f00745060127611e257476018 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Wed, 29 Apr 2020 16:53:39 +0100 Subject: [PATCH 2/2] Separating out the Lambda tests into their own test cases, and updating the README --- .../@aws-cdk/aws-sns-subscriptions/README.md | 2 + .../aws-sns-subscriptions/test/subs.test.ts | 43 +++++++++++-------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/packages/@aws-cdk/aws-sns-subscriptions/README.md b/packages/@aws-cdk/aws-sns-subscriptions/README.md index 8f9c04bdb8274..a0d845d39714c 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/README.md +++ b/packages/@aws-cdk/aws-sns-subscriptions/README.md @@ -19,6 +19,8 @@ Subscriptions can be added to the following endpoints: * AWS Lambda * Email +Subscriptions to Amazon SQS and AWS Lambda can be added on topics across regions. + Create an Amazon SNS Topic to add subscriptions. ```ts diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts index db2b8fc12b07c..2b4a013ab22b4 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts @@ -736,49 +736,54 @@ test('with filter policy', () => { }); }); -test('region property is present on an imported topic', () => { +test('region property is present on an imported topic - sqs', () => { const imported = sns.Topic.fromTopicArn(stack, 'mytopic', 'arn:aws:sns:us-east-1:1234567890:mytopic'); const queue = new sqs.Queue(stack, 'myqueue'); + imported.addSubscription(new subs.SqsSubscription(queue)); + + expect(stack).toHaveResource('AWS::SNS::Subscription', { + Region: 'us-east-1', + }); +}); + +test('region property on an imported topic as a parameter - sqs', () => { + const topicArn = new CfnParameter(stack, 'topicArn'); + const imported = sns.Topic.fromTopicArn(stack, 'mytopic', topicArn.valueAsString); + const queue = new sqs.Queue(stack, 'myqueue'); + imported.addSubscription(new subs.SqsSubscription(queue)); + + expect(stack).toHaveResource('AWS::SNS::Subscription', { + Region: { + 'Fn::Select': [ 3, { 'Fn::Split': [ ':', { 'Ref': 'topicArn' } ] } ], + }, + }); +}); + +test('region property is present on an imported topic - lambda', () => { + const imported = sns.Topic.fromTopicArn(stack, 'mytopic', 'arn:aws:sns:us-east-1:1234567890:mytopic'); const func = new lambda.Function(stack, 'MyFunc', { runtime: lambda.Runtime.NODEJS_10_X, handler: 'index.handler', code: lambda.Code.fromInline('exports.handler = function(e, c, cb) { return cb() }'), }); - - imported.addSubscription(new subs.SqsSubscription(queue)); imported.addSubscription(new subs.LambdaSubscription(func)); expect(stack).toHaveResource('AWS::SNS::Subscription', { - Protocol: 'sqs', - Region: 'us-east-1', - }); - expect(stack).toHaveResource('AWS::SNS::Subscription', { - Protocol: 'lambda', Region: 'us-east-1', }); }); -test('region property on an imported topic as a parameter', () => { +test('region property on an imported topic as a parameter - lambda', () => { const topicArn = new CfnParameter(stack, 'topicArn'); const imported = sns.Topic.fromTopicArn(stack, 'mytopic', topicArn.valueAsString); - const queue = new sqs.Queue(stack, 'myqueue'); const func = new lambda.Function(stack, 'MyFunc', { runtime: lambda.Runtime.NODEJS_10_X, handler: 'index.handler', code: lambda.Code.fromInline('exports.handler = function(e, c, cb) { return cb() }'), }); - - imported.addSubscription(new subs.SqsSubscription(queue)); imported.addSubscription(new subs.LambdaSubscription(func)); expect(stack).toHaveResource('AWS::SNS::Subscription', { - Protocol: 'sqs', - Region: { - 'Fn::Select': [ 3, { 'Fn::Split': [ ':', { 'Ref': 'topicArn' } ] } ], - }, - }); - expect(stack).toHaveResource('AWS::SNS::Subscription', { - Protocol: 'lambda', Region: { 'Fn::Select': [ 3, { 'Fn::Split': [ ':', { 'Ref': 'topicArn' } ] } ], },