-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sns: support cross-region subscriptions #13707
Comments
Region
property in synthesized CloudFormation for resources AWS::SNS::SubscriptionRegion
property in synthesized AWS::SNS::Subscription
CloudFormation resource
Region
property in synthesized AWS::SNS::Subscription
CloudFormation resource
Is this truly a feature request? This functionality is already supported, albeit only through If I use the workaround of public class LambdaStack : Stack
{
public readonly IFunction Function;
internal LambdaStack(Construct scope, string id, StackProps props, SnsStack snsStack) : base(scope, id, props)
{
Function = new PythonFunction(this, "Function", new PythonFunctionProps
{
Entry = "src/CdkSnsCrossRegion/Function",
});
Topic.FromTopicArn(snsStack.Topic).AddSubscription(new LambdaSubscription(Function));
}
} I get the expected output {
"Type": "AWS::SNS::Subscription",
"Properties": {
"Protocol": "lambda",
"TopicArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":sns:us-east-1:XXXXXXXXXXXX:snssnstopic2f96c0ab8390dbda1164"
]
]
},
"Endpoint": {
"Fn::GetAtt": [
"Function76856677",
"Arn"
]
},
"Region": {
"Fn::Select": [
3,
{
"Fn::Split": [
":",
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":sns:us-east-1:XXXXXXXXXXXX:snssnstopic2f96c0ab8390dbda1164"
]
]
}
]
}
]
}
}
} Looking at the offending method: aws-cdk/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts Lines 50 to 56 in aa45ede
checking for The topic must be of type I'm fairly new to the CDK codebase, but an implementation such as below, seems to be more functionally correct. private regionFromArn(topic: sns.ITopic): string | undefined {
if (topic instanceof sns.Topic) {
// we know topic is not imported
// get the region of the stack that the topic was created in
const topicRegion = topic.stack.region;
// get the region of the stack that the function is being created in
const functionRegion = this.fn.stack.region;
// if the regions are not the same, we must provide the region of the topic
if (topicRegion !== functionRegion) {
return topicRegion;
}
// no need to specify region in subscription if topic is defined within the same region as the function.
return undefined;
}
// if topic is not an instanceof sns.Topic, assume it's an instance of sns.Import
// and get the region that it was defined/deployed in
return Stack.of(topic).parseArn(topic.topicArn).region;
} This way, even if we have a concrete Topic, we check its region to see if it is different from the region of the function. This supports multiple use-case patterns such as importing both the function and the topic, importing either, or neither. It will then appropriately return either the region of the topic, or I don't fully understand how tokens in the CDK work yet, so there may be a preferred alternative implementation, but I did write some unit tests to validate that this change did not break other functionality and does include the Region property for my use case. I haven't created a PR because there is already one open for this issue, but am willing to do so. I believe this change would also apply to the other subscription types such as SQS, as I believe this implementation originally came from a feature request for cross-region SNS subscriptions with SQS endpoints as a result of #4917 |
@robertd how do you believe this compares to your PR? The issue that I can see here is the use of the construct in environment-agnostic stacks, where the region will not be known at synth time and will be a tokenized value that can't be compared via '==='. We may be able to use intrinsics to do a bunch of template conditional logic but I'm not sure if that is doable for this case and would require some experimentation. @dillon-odonovan do you any details about use cases that may not be supported by the fix in the existing PR? |
Unless I'm missing something, this appears to be the only fix so far in the current PR (where 114 is the only line that changed): aws-cdk/packages/@aws-cdk/aws-sns/lib/subscription.ts Lines 108 to 116 in c634295
To me, this fix doesn't appear to change the behavior of the @MrArnoldPalmer So, with that being said, perhaps the guidance is that whenever a cross-region subscription is desired, the expectation is to import the resource via I looked into what the current behavior would be if given 2 environment-agnostic stacks a subscription was tried to be created in this manner: Test Case: test('subscription region property - two stacks where regions are not yet defined', () => {
const snsStack = new Stack();
const myTopic = new sns.Topic(snsStack, 'mytopic', {
topicName: 'MyTopic',
});
const subscriptionStack = new Stack();
const func = new lambda.Function(subscriptionStack, 'MyFunction', {
code: lambda.Code.fromInline('exports.handler = function(e, c, cb) { return cb() }'),
handler: 'index.handler',
runtime: lambda.Runtime.NODEJS_10_X,
});
myTopic.addSubscription(new subs.LambdaSubscription(func));
// note - I only had this be the expectation so that it would fail and I could see the generated CloudFormation
expect(subscriptionStack).toMatchTemplate({});
}); Result:
So I think this matches with what I think expected behavior would be if the stacks are both environment-agnostic and they are used in a cross-reference manner. To me, we could either raise an error similar to above if the subscription is tried to be created in a cross-reference manner (without importing via fromTopicArn), or we may be able to implement a similar fix to what I outlined above. If we are able to detect the former, then at that point it seems like we have all information to know how to correctly configure the subscription, and perhaps we should just do that. |
So this error is because the two stacks in the test have different I think I understand why the current change isn't what you were looking for but tell me this is correct. The current fix is defaulting to the region of the stack that the subscription is in when it should be the region of the topic being subscribed to. |
Yes, that's correct. The region needs to be relative to the topic not the subscription. |
So I wonder if we can just parse the region out of the topic arn, which we have access to here and always pass it. Or instead of |
…lambda (#17273) fixing cross region subscriptions to SQS and Lambda. This PR handles a couple different scenarios. This only applies to SNS topics that are instanceof sns.Topic, it does not apply to imported topics (sns.ITopic). The current behavior for imported topics will remain the same. 1. SNS Topic and subscriber (sqs or lambda) are created in separate stacks with explicit environment. In this case if the `region` is different between the two stacks then the topic region will be provided in the subscription. 2. SNS Topic and subscriber (sqs or lambda) are created in separate stacks, and _both_ are env agnostic (no explicit region is provided) In this case a region is not specified in the subscription resource, which means it is assumed that they are both created in the same region. The alternatives are to either throw an error telling the user to specify a region, or to create a CfnOutput with the topic region. Since it should be a rare occurrence for a user to be deploying a CDK app with multiple env agnostic stacks that are meant for different environments, I think the best option is to assume same region. 3. SNS Topic and subscriber (sqs or lambda) are created in separate stacks, and _one_ of them are env agnostic (no explicit region is provided) In this case if the SNS stack has an explicit environment then we will provide that in the subscription resource (assume that it is cross region). If the SNS stack is env agnostic then we will do nothing (assume they are created in the same region). fixes #7044,#13707 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
…lambda (aws#17273) fixing cross region subscriptions to SQS and Lambda. This PR handles a couple different scenarios. This only applies to SNS topics that are instanceof sns.Topic, it does not apply to imported topics (sns.ITopic). The current behavior for imported topics will remain the same. 1. SNS Topic and subscriber (sqs or lambda) are created in separate stacks with explicit environment. In this case if the `region` is different between the two stacks then the topic region will be provided in the subscription. 2. SNS Topic and subscriber (sqs or lambda) are created in separate stacks, and _both_ are env agnostic (no explicit region is provided) In this case a region is not specified in the subscription resource, which means it is assumed that they are both created in the same region. The alternatives are to either throw an error telling the user to specify a region, or to create a CfnOutput with the topic region. Since it should be a rare occurrence for a user to be deploying a CDK app with multiple env agnostic stacks that are meant for different environments, I think the best option is to assume same region. 3. SNS Topic and subscriber (sqs or lambda) are created in separate stacks, and _one_ of them are env agnostic (no explicit region is provided) In this case if the SNS stack has an explicit environment then we will provide that in the subscription resource (assume that it is cross region). If the SNS stack is env agnostic then we will do nothing (assume they are created in the same region). fixes aws#7044,aws#13707 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
This issue has not received any attention in 1 year. If you want to keep this issue open, please leave a comment below and auto-close will be canceled. |
When creating an SNS subscription in a region different from the SNS topic's region, there is a Region property in the CloudFormation resource that is not being set.
Reproduction Steps
What did you expect to happen?
Expected
Region
property to be set inAWS::SNS::Subscription
resource.What actually happened?
Region
property ofAWS::SNS::Subscription
is not set.Environment
Other
Possibly related:
#3842
#7044
I looked at the source and it seemed fine. Perhaps I'm missing something really obvious or the usage is incorrect?
This is 🐛 Bug Report
The text was updated successfully, but these errors were encountered: