Skip to content
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

Added support for http/https endpoints that auto confirms SNS topic subscription. #4711

Merged
merged 6 commits into from
Feb 14, 2016

Conversation

srikalyan
Copy link
Contributor

Added support for http/https endpoints that auto confirms SNS topic subscription.

http and https SNS topic subscription endpoints require confirmation to set a valid arn otherwise
arn would be set to "pending confirmation". If the endpoints auto confirm then arn is set
asynchronously but if we try to create another subscription with same parameters then api returns
"pending subscription" as arn but does not create another a duplicate subscription. In order to
solve this we should be fetching the subscription list for the topic and identify the subscription
with same parameters i.e., protocol, topic_arn, endpoint and extract the subscription arn.

Following changes were made to support the http/https endpoints that auto confirms

  1. Added 3 extra parameters i.e.,

    1. endpoint_auto_confirms -> boolean indicates if end points auto confirms
    2. max_fetch_retries -> number of times to fetch subscription list for the topic to get the subscription arn
    3. fetch_retry_delay -> delay b/w fetch subscription list call as the confirmation is done asynchronously.

    With these parameters help added support http and https protocol based endpoints that auto confirm.

  2. Update website doc appropriately

…ubscription.

http and https SNS topic subscription endpoints require confirmation to set a valid arn otherwise
arn would be set to "pending confirmation". If the endpoints auto confirm then arn is set
asynchronously but if we try to create another subscription with same parameters then api returns
"pending subscription" as arn but does not create another a duplicate subscription. In order to
solve this we should be fetching the subscription list for the topic and identify the subscription
with same parameters i.e., protocol, topic_arn, endpoint and extract the subscription arn.

Following changes were made to support the http/https endpoints that auto confirms

1. Added 3 extra parameters i.e.,
   1. endpoint_auto_confirms -> boolean indicates if end points auto confirms
   2. max_fetch_retries -> number of times to fetch subscription list for the topic to get the subscription arn
   3. fetch_retry_delay -> delay b/w fetch subscription list call as the confirmation is done asynchronously.

  With these parameters help added support http and https protocol based endpoints that auto confirm.

2. Update website doc appropriately
max_fetch_retries := d.Get("max_fetch_retries").(int)
fetch_retry_delay := time.Duration(d.Get("fetch_retry_delay").(int))

if strings.Contains(protocol, "http") && !endpoint_auto_confirms {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like to move this to validateFunc but I need a function which can give me whole map. I need help on this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I see your point. This will be eventually possible after merging #3641 but I wouldn't want to block this PR on that.

The only suggestion I have regarding this is that we should rather be comparing protocols as IDs (i.e. (protocol == "http" || protocol == "https")), not arbitrary strings.

I almost thought on first sight you forgot about https.
Also there might be a new service in the future which will actually contain http in the name and that would make things even more confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree that there might be newer protocol which has .http. or .email. etc in it but then I saw logic around line 33 and thought that I should follow on the similar footsteps just to be consistent.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the logic around line 33 should be changed too then... if you want to do it, go ahead, but I won't push back on this PR if you won't. It would be nice to get it consistent (and only use equal sign).

@srikalyan
Copy link
Contributor Author

My golang skills are quite minimal (I did a quick turotial and added this PR) so please let me know if you see any problem or something needs to be updated.

Srikalyan Swayampakula added 2 commits January 18, 2016 14:00
"pending confirmation" such as "PendingConfirmation", "Pending Confirmation" etc.
@srikalyan
Copy link
Contributor Author

@packplusplus, thats what my intention was. Am I missing something to get this pulled?

@packplusplus
Copy link

/me is embarrassed

At the time I searched and didn't see a PR (I commented on the fork not the pr directly).

@srikalyan
Copy link
Contributor Author

@jen20, What is the usual turn around time for PRs?

@srikalyan
Copy link
Contributor Author

Guys any update on this?

@radeksimko
Copy link
Member

Hi @srikalyan
it would be nice to get this more automated somehow.

Can you provide any public examples of services which provide the auto-confirmation? I was hoping that Slack would be able to do this, but apparently not. 😢

From what I've read the SNS subscription confirmation works in a way that it requires the other end to call AWS API with a token that was sent to the provided HTTP(S) endpoint. This inherently means that the other end needs AWS access keys in order to call the API and confirm the subscription. These keys need to have the privilege to call Sns:ConfirmSubscription API method on that specific subscription ARN which would be created by Terraform.

Am I right?

@radeksimko radeksimko added the waiting-response An issue/pull request is waiting for a response from the community label Feb 10, 2016
@srikalyan
Copy link
Contributor Author

Hello @radeksimko,

There are quite a few public services that auto confirm subscription for e.g. Pagerduty. Cloud watch events can be sent via SNS topic to Pagerduty service which can call proper members.

As far as I can tell, we third party don't need AWS access keys and I definitely tested it with Pagerduty.

Hope I've answered your questions and please let me know if need anything else.

@radeksimko radeksimko removed the waiting-response An issue/pull request is waiting for a response from the community label Feb 11, 2016
@radeksimko
Copy link
Member

I see, thanks for the example, that's very helpful.

I searched thru AWS Docs again to find more details about this and found this page:
http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.html#SendMessageToHttp.prepare

I think we should add a link to the docs and probably also mention PagerDuty as an example e.g.:

  • endpoint_auto_confirms - (Optional) Boolean indicating whether the end point is capable of auto confirming subscription, e.g. PagerDuty (default is false)

I will give this a full review in couple of days.

@radeksimko radeksimko self-assigned this Feb 11, 2016
…ields added in the PR

and add the link to amazon describing the auto confirming subscription.
@srikalyan
Copy link
Contributor Author

@radeksimko,

I've updated the documentation as per your suggestion. Please let me know if you have any more suggestions for this PR.

"endpoint_auto_confirms": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
ForceNew: false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe ForceNew: false is a default behaviour so we shouldn't need to specify it here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which applies to the other 2 fields below too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point but almost all the schema elements have ForceNew: false, I guess they made a bad copy :). I will fix it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not everything you see elsewhere in the codebase is worth copying, yet many things do! 😃

@radeksimko
Copy link
Member

It is probably impossible to write a reliable acceptance test for this, unless we just hardcode a PagerDuty URL which would be generated manually I assume, so I won't insist on having one. 😃

I tried testing this manually with the following simple config:

resource "aws_sns_topic" "user_updates" {
  name = "cw-sns-topic"
}

resource "aws_sns_topic_subscription" "user_updates_sqs_target" {
    topic_arn = "${aws_sns_topic.user_updates.arn}"
    protocol  = "https"
    endpoint_auto_confirms = true
    endpoint  = "https://events.pagerduty.com/adapter/cloudwatch_sns/v1/*REDACTED*"
}

and in my first attempt Terraform crashed, here's the interesting part of the crash log:

panic: runtime error: invalid memory address or nil pointer dereference
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws: [signal 0xb code=0x1 addr=0x0 pc=0x1de3ee]
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws:
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws: goroutine 113 [running]:
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws: github.com/hashicorp/terraform/builtin/providers/aws.resourceAwsSnsTopicSubscriptionUpdate(0x821f92540, 0x96dfc0, 0x821d8e000, 0x0, 0x0)
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws:     /Users/radek/gopath/src/github.com/hashicorp/terraform/builtin/providers/aws/resource_aws_sns_topic_subscription.go:130 +0x8ce
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws: github.com/hashicorp/terraform/builtin/providers/aws.resourceAwsSnsTopicSubscriptionCreate(0x821f92540, 0x96dfc0, 0x821d8e000, 0x0, 0x0)
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws:     /Users/radek/gopath/src/github.com/hashicorp/terraform/builtin/providers/aws/resource_aws_sns_topic_subscription.go:110 +0x379
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws: github.com/hashicorp/terraform/helper/schema.(*Resource).Apply(0x821e75580, 0x821d2ef30, 0x822137840, 0x96dfc0, 0x821d8e000, 0x10101, 0x0, 0x0)
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws:     /Users/radek/gopath/src/github.com/hashicorp/terraform/helper/schema/resource.go:145 +0x28e
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws: github.com/hashicorp/terraform/helper/schema.(*Provider).Apply(0x821f17440, 0x821e33540, 0x821d2ef30, 0x822137840, 0x6d3055446e746f01, 0x0, 0x0)
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws:     /Users/radek/gopath/src/github.com/hashicorp/terraform/helper/schema/provider.go:162 +0x1ed
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws: github.com/hashicorp/terraform/rpc.(*ResourceProviderServer).Apply(0x82213a900, 0x8220d22a0, 0x822137b30, 0x0, 0x0)
2016/02/12 10:09:29 [DEBUG] terraform-provider-aws:     /Users/radek/gopath/src/github.com/hashicorp/terraform/rpc/resource_provider.go:323 +0x76

it looks like there was no ARN returned in the response from API.

on my second attempt I just hit timeout (I assume because PagerDuty didn't confirm the subscription in 3 secs):

* aws_sns_topic_subscription.user_updates_sqs_target: Endpoint (https://events.pagerduty.com/adapter/cloudwatch_sns/v1/*REDACTED*) did not autoconfirm the subscription for topic arn:aws:sns:us-west-2:*REDACTED*:cw-sns-topic

One way to get around the timeout issue is to use the resource.Retry with exponential backoff instead of for loop, as I mentioned above.

Would you mind making the modifications I mentioned?

@radeksimko radeksimko added the waiting-response An issue/pull request is waiting for a response from the community label Feb 12, 2016
@srikalyan
Copy link
Contributor Author

Yeah np. I will make them asap.

One question though, what did you mean when you said terraform crashed? Did you had any extra setting or is there a way that I can reproduce?

Thanks for helping me out :).

@radeksimko
Copy link
Member

One question though, what did you mean when you said terraform crashed? Did you had any extra setting or is there a way that I can reproduce?

Nope, no special settings, if there is nil-dereference, Terraform just crashes and prints out the stack trace.

In terms of reproduction I guess it may be tricky with the AWS API... if sometimes it returns A and minutes after it returns B. 😞 I guess you'll have to either rerun an example couple of times until you hit the problem or just trust my crash log above.

1. Used resource.Retry instead of custom solution
2. Removed unnecessary variables and added required variable to resource.Retry.
@srikalyan
Copy link
Contributor Author

@radeksimko,

I've made almost all the changes you have suggested except protocol contains check (as you have suggested it as optional ;). Also, I've tested it several times and could not reproduce the error stack trace :(.

Just curios though, what go version are you using?

I will keep an eye on it but It seems ok for now.

@radeksimko radeksimko removed the waiting-response An issue/pull request is waiting for a response from the community label Feb 12, 2016
@radeksimko
Copy link
Member

Thanks, this looks much better on the first sight!

I will give it another look during the weekend or next week.

@srikalyan
Copy link
Contributor Author

Thanks @radeksimko for all your help :).

@@ -178,6 +187,12 @@ func subscribeToSNSTopic(d *schema.ResourceData, snsconn *sns.SNS) (output *sns.
protocol := d.Get("protocol").(string)
endpoint := d.Get("endpoint").(string)
topic_arn := d.Get("topic_arn").(string)
endpoint_auto_confirms := d.Get("endpoint_auto_confirms").(bool)
confirmation_timeout_in_minutes := time.Duration(d.Get("confirmation_timeout_in_minutes").(int))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason for the time.Duration wrapper here? I think that keeping it as integer should be ok.
It has no functional effect as I see you're actually multiplying this variable below with time.Minutes, but the default representation of time.Duration are nanoseconds which makes the variable name wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I don't convert it then I get the follow error
mismatched types time.Duration and int
On the other hand, I see your concern that the variable does not make sense
I will change it to
confirmation_timeout_in_minutes := d.Get("confirmation_timeout_in_minutes").(int)
and use time.Duration(int(time.Minute) * confirmation_timeout_in_minutes)

I have few other options too but I think this makes most sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change it to
confirmation_timeout_in_minutes := d.Get("confirmation_timeout_in_minutes").(int)
and use time.Duration(int(time.Minute) * confirmation_timeout_in_minutes)

That's exactly what I had in mind. 👍

@radeksimko
Copy link
Member

Besides one nitpick about code readability I'd be happy to merge this. I tried rerunning my previous example and it worked aok.

Thanks for making all the modifications.

@radeksimko radeksimko added the waiting-response An issue/pull request is waiting for a response from the community label Feb 13, 2016
@radeksimko radeksimko removed the waiting-response An issue/pull request is waiting for a response from the community label Feb 13, 2016
radeksimko added a commit that referenced this pull request Feb 14, 2016
Added support for http/https endpoints that auto confirms SNS topic subscription.
@radeksimko radeksimko merged commit fdd9c3b into hashicorp:master Feb 14, 2016
@ghost
Copy link

ghost commented Apr 28, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Apr 28, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants