Merge pull request #1974 from johnewart/sns
Initial SNS topic / subscription support
This commit is contained in:
commit
8764205bcf
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/awslabs/aws-sdk-go/service/route53"
|
"github.com/awslabs/aws-sdk-go/service/route53"
|
||||||
"github.com/awslabs/aws-sdk-go/service/s3"
|
"github.com/awslabs/aws-sdk-go/service/s3"
|
||||||
"github.com/awslabs/aws-sdk-go/service/sqs"
|
"github.com/awslabs/aws-sdk-go/service/sqs"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -37,6 +38,7 @@ type AWSClient struct {
|
||||||
autoscalingconn *autoscaling.AutoScaling
|
autoscalingconn *autoscaling.AutoScaling
|
||||||
s3conn *s3.S3
|
s3conn *s3.S3
|
||||||
sqsconn *sqs.SQS
|
sqsconn *sqs.SQS
|
||||||
|
snsconn *sns.SNS
|
||||||
r53conn *route53.Route53
|
r53conn *route53.Route53
|
||||||
region string
|
region string
|
||||||
rdsconn *rds.RDS
|
rdsconn *rds.RDS
|
||||||
|
@ -89,6 +91,9 @@ func (c *Config) Client() (interface{}, error) {
|
||||||
log.Println("[INFO] Initializing SQS connection")
|
log.Println("[INFO] Initializing SQS connection")
|
||||||
client.sqsconn = sqs.New(awsConfig)
|
client.sqsconn = sqs.New(awsConfig)
|
||||||
|
|
||||||
|
log.Println("[INFO] Initializing SNS connection")
|
||||||
|
client.snsconn = sns.New(awsConfig)
|
||||||
|
|
||||||
log.Println("[INFO] Initializing RDS Connection")
|
log.Println("[INFO] Initializing RDS Connection")
|
||||||
client.rdsconn = rds.New(awsConfig)
|
client.rdsconn = rds.New(awsConfig)
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,8 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_security_group": resourceAwsSecurityGroup(),
|
"aws_security_group": resourceAwsSecurityGroup(),
|
||||||
"aws_security_group_rule": resourceAwsSecurityGroupRule(),
|
"aws_security_group_rule": resourceAwsSecurityGroupRule(),
|
||||||
"aws_sqs_queue": resourceAwsSqsQueue(),
|
"aws_sqs_queue": resourceAwsSqsQueue(),
|
||||||
|
"aws_sns_topic": resourceAwsSnsTopic(),
|
||||||
|
"aws_sns_topic_subscription": resourceAwsSnsTopicSubscription(),
|
||||||
"aws_subnet": resourceAwsSubnet(),
|
"aws_subnet": resourceAwsSubnet(),
|
||||||
"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
|
"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
|
||||||
"aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(),
|
"aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(),
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mutable attributes
|
||||||
|
var SNSAttributeMap = map[string]string{
|
||||||
|
"display_name" : "DisplayName",
|
||||||
|
"policy" : "Policy",
|
||||||
|
"delivery_policy": "DeliveryPolicy",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func resourceAwsSnsTopic() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsSnsTopicCreate,
|
||||||
|
Read: resourceAwsSnsTopicRead,
|
||||||
|
Update: resourceAwsSnsTopicUpdate,
|
||||||
|
Delete: resourceAwsSnsTopicDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"display_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"policy": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"delivery_policy": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
name := d.Get("name").(string)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] SNS create topic: %s", name)
|
||||||
|
|
||||||
|
req := &sns.CreateTopicInput{
|
||||||
|
Name: aws.String(name),
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := snsconn.CreateTopic(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error creating SNS topic: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(*output.TopicARN)
|
||||||
|
|
||||||
|
// Write the ARN to the 'arn' field for export
|
||||||
|
d.Set("arn", *output.TopicARN)
|
||||||
|
|
||||||
|
return resourceAwsSnsTopicUpdate(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
resource := *resourceAwsSnsTopic()
|
||||||
|
|
||||||
|
for k, _ := range resource.Schema {
|
||||||
|
if attrKey, ok := SNSAttributeMap[k]; ok {
|
||||||
|
if d.HasChange(k) {
|
||||||
|
log.Printf("[DEBUG] Updating %s", attrKey)
|
||||||
|
_, n := d.GetChange(k)
|
||||||
|
// Ignore an empty policy
|
||||||
|
if !(k == "policy" && n == "") {
|
||||||
|
// Make API call to update attributes
|
||||||
|
req := &sns.SetTopicAttributesInput{
|
||||||
|
TopicARN: aws.String(d.Id()),
|
||||||
|
AttributeName: aws.String(attrKey),
|
||||||
|
AttributeValue: aws.String(n.(string)),
|
||||||
|
}
|
||||||
|
snsconn.SetTopicAttributes(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceAwsSnsTopicRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
attributeOutput, err := snsconn.GetTopicAttributes(&sns.GetTopicAttributesInput{
|
||||||
|
TopicARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if attributeOutput.Attributes != nil && len(*attributeOutput.Attributes) > 0 {
|
||||||
|
attrmap := *attributeOutput.Attributes
|
||||||
|
resource := *resourceAwsSnsTopic()
|
||||||
|
// iKey = internal struct key, oKey = AWS Attribute Map key
|
||||||
|
for iKey, oKey := range SNSAttributeMap {
|
||||||
|
log.Printf("[DEBUG] Updating %s => %s", iKey, oKey)
|
||||||
|
|
||||||
|
if attrmap[oKey] != nil {
|
||||||
|
// Some of the fetched attributes are stateful properties such as
|
||||||
|
// the number of subscriptions, the owner, etc. skip those
|
||||||
|
if resource.Schema[iKey] != nil {
|
||||||
|
value := *attrmap[oKey]
|
||||||
|
log.Printf("[DEBUG] Updating %s => %s -> %s", iKey, oKey, value)
|
||||||
|
d.Set(iKey, *attrmap[oKey])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] SNS Delete Topic: %s", d.Id())
|
||||||
|
_, err := snsconn.DeleteTopic(&sns.DeleteTopicInput{
|
||||||
|
TopicARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,181 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscription() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsSnsTopicSubscriptionCreate,
|
||||||
|
Read: resourceAwsSnsTopicSubscriptionRead,
|
||||||
|
Update: resourceAwsSnsTopicSubscriptionUpdate,
|
||||||
|
Delete: resourceAwsSnsTopicSubscriptionDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"protocol": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"endpoint": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"topic_arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"delivery_policy": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"raw_message_delivery": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
Default: false,
|
||||||
|
},
|
||||||
|
"arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscriptionCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
if(d.Get("protocol") == "email") {
|
||||||
|
return fmt.Errorf("Email endpoints are not supported!")
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := subscribeToSNSTopic(d, snsconn)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("New subscription ARN: %s", *output.SubscriptionARN)
|
||||||
|
d.SetId(*output.SubscriptionARN)
|
||||||
|
|
||||||
|
// Write the ARN to the 'arn' field for export
|
||||||
|
d.Set("arn", *output.SubscriptionARN)
|
||||||
|
|
||||||
|
return resourceAwsSnsTopicSubscriptionUpdate(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
// If any changes happened, un-subscribe and re-subscribe
|
||||||
|
if d.HasChange("protocol") || d.HasChange("endpoint") || d.HasChange("topic_arn") {
|
||||||
|
log.Printf("[DEBUG] Updating subscription %s", d.Id())
|
||||||
|
// Unsubscribe
|
||||||
|
_, err := snsconn.Unsubscribe(&sns.UnsubscribeInput{
|
||||||
|
SubscriptionARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error unsubscribing from SNS topic: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-subscribe and set id
|
||||||
|
output, err := subscribeToSNSTopic(d, snsconn)
|
||||||
|
d.SetId(*output.SubscriptionARN)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("raw_message_delivery") {
|
||||||
|
_, n := d.GetChange("raw_message_delivery")
|
||||||
|
|
||||||
|
attrValue := "false"
|
||||||
|
|
||||||
|
if n.(bool) {
|
||||||
|
attrValue = "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &sns.SetSubscriptionAttributesInput{
|
||||||
|
SubscriptionARN: aws.String(d.Id()),
|
||||||
|
AttributeName: aws.String("RawMessageDelivery"),
|
||||||
|
AttributeValue: aws.String(attrValue),
|
||||||
|
}
|
||||||
|
_, err := snsconn.SetSubscriptionAttributes(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to set raw message delivery attribute on subscription")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceAwsSnsTopicSubscriptionRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscriptionRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Loading subscription %s", d.Id())
|
||||||
|
|
||||||
|
attributeOutput, err := snsconn.GetSubscriptionAttributes(&sns.GetSubscriptionAttributesInput{
|
||||||
|
SubscriptionARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if attributeOutput.Attributes != nil && len(*attributeOutput.Attributes) > 0 {
|
||||||
|
attrHash := *attributeOutput.Attributes
|
||||||
|
log.Printf("[DEBUG] raw message delivery: %s", *attrHash["RawMessageDelivery"])
|
||||||
|
if *attrHash["RawMessageDelivery"] == "true" {
|
||||||
|
d.Set("raw_message_delivery", true)
|
||||||
|
} else {
|
||||||
|
d.Set("raw_message_delivery", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscriptionDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] SNS delete topic subscription: %s", d.Id())
|
||||||
|
_, err := snsconn.Unsubscribe(&sns.UnsubscribeInput{
|
||||||
|
SubscriptionARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribeToSNSTopic(d *schema.ResourceData, snsconn *sns.SNS) (output *sns.SubscribeOutput, err error) {
|
||||||
|
protocol := d.Get("protocol").(string)
|
||||||
|
endpoint := d.Get("endpoint").(string)
|
||||||
|
topic_arn := d.Get("topic_arn").(string)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] SNS create topic subscription: %s (%s) @ '%s'", endpoint, protocol, topic_arn)
|
||||||
|
|
||||||
|
req := &sns.SubscribeInput{
|
||||||
|
Protocol: aws.String(protocol),
|
||||||
|
Endpoint: aws.String(endpoint),
|
||||||
|
TopicARN: aws.String(topic_arn),
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err = snsconn.Subscribe(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error creating SNS topic: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Created new subscription!")
|
||||||
|
return output, nil
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSSNSTopicSubscription(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSSNSTopicSubscriptionDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSSNSTopicSubscriptionConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSSNSTopicExists("aws_sns_topic.test_topic"),
|
||||||
|
testAccCheckAWSSNSTopicSubscriptionExists("aws_sns_topic_subscription.test_subscription"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAccCheckAWSSNSTopicSubscriptionDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).snsconn
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "aws_sns_topic" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find key pair
|
||||||
|
req := &sns.GetSubscriptionAttributesInput{
|
||||||
|
SubscriptionARN: aws.String(rs.Primary.ID),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_, err := conn.GetSubscriptionAttributes(req)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Subscription still exists, can't continue.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the error is an API error, not something else
|
||||||
|
_, ok := err.(awserr.Error)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAccCheckAWSSNSTopicSubscriptionExists(n string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No SNS subscription with that ARN exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).snsconn
|
||||||
|
|
||||||
|
params := &sns.GetSubscriptionAttributesInput{
|
||||||
|
SubscriptionARN: aws.String(rs.Primary.ID),
|
||||||
|
}
|
||||||
|
_, err := conn.GetSubscriptionAttributes(params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccAWSSNSTopicSubscriptionConfig = `
|
||||||
|
resource "aws_sns_topic" "test_topic" {
|
||||||
|
name = "terraform-test-topic"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_sqs_queue" "test_queue" {
|
||||||
|
name = "terraform-subscription-test-queue"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_sns_topic_subscription" "test_subscription" {
|
||||||
|
topic_arn = "${aws_sns_topic.test_topic.arn}"
|
||||||
|
protocol = "sqs"
|
||||||
|
endpoint = "${aws_sqs_queue.test_queue.arn}"
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,89 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSSNSTopic(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSSNSTopicDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSSNSTopicConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSSNSTopicExists("aws_sns_topic.test_topic"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAccCheckAWSSNSTopicDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).snsconn
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "aws_sns_topic" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the topic exists by fetching its attributes
|
||||||
|
params := &sns.GetTopicAttributesInput{
|
||||||
|
TopicARN: aws.String(rs.Primary.ID),
|
||||||
|
}
|
||||||
|
_, err := conn.GetTopicAttributes(params)
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Topic exists when it should be destroyed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the error is an API error, not something else
|
||||||
|
_, ok := err.(awserr.Error)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAccCheckAWSSNSTopicExists(n string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No SNS topic with that ARN exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).snsconn
|
||||||
|
|
||||||
|
params := &sns.GetTopicAttributesInput{
|
||||||
|
TopicARN: aws.String(rs.Primary.ID),
|
||||||
|
}
|
||||||
|
_, err := conn.GetTopicAttributes(params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccAWSSNSTopicConfig = `
|
||||||
|
resource "aws_sns_topic" "test_topic" {
|
||||||
|
name = "terraform-test-topic"
|
||||||
|
}
|
||||||
|
`
|
|
@ -19,6 +19,7 @@ var AttributeMap = map[string]string{
|
||||||
"visibility_timeout_seconds": "VisibilityTimeout",
|
"visibility_timeout_seconds": "VisibilityTimeout",
|
||||||
"policy": "Policy",
|
"policy": "Policy",
|
||||||
"redrive_policy": "RedrivePolicy",
|
"redrive_policy": "RedrivePolicy",
|
||||||
|
"arn": "QueueArn",
|
||||||
}
|
}
|
||||||
|
|
||||||
// A number of these are marked as computed because if you don't
|
// A number of these are marked as computed because if you don't
|
||||||
|
@ -70,6 +71,10 @@ func resourceAwsSqsQueue() *schema.Resource {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
|
"arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +159,7 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
QueueURL: aws.String(d.Id()),
|
QueueURL: aws.String(d.Id()),
|
||||||
AttributeNames: []*string{aws.String("All")},
|
AttributeNames: []*string{aws.String("All")},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: sns_topic"
|
||||||
|
sidebar_current: "docs-aws-resource-sns-topic"
|
||||||
|
description: |-
|
||||||
|
Provides an SNS topic resource.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_sns\_topic
|
||||||
|
|
||||||
|
Provides an SNS topic resource
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_sns_topic" "user_updates" {
|
||||||
|
name = "user-updates-topic"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The friendly name for the SNS topic
|
||||||
|
* `policy` - (Optional) The fully-formed AWS policy as JSON
|
||||||
|
* `delivery_policy` - (Optional) The SNS delivery policy
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The ARN of the SNS topic
|
||||||
|
* `arn` - The ARN of the SNS topic, as a more obvious property (clone of id)
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: sns_topic_subscription"
|
||||||
|
sidebar_current: "docs-aws-resource-sns-topic-subscription"
|
||||||
|
description: |-
|
||||||
|
Provides a resource for subscribing to SNS topics.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_sns\_topic\_subscription
|
||||||
|
|
||||||
|
Provides a resource for subscribing to SNS topics. Requires that an SNS topic exist for the subscription to attach to.
|
||||||
|
This resource allows you to automatically place messages sent to SNS topics in SQS queues, send them as HTTP(S) POST requests
|
||||||
|
to a given endpoint, send SMS messages, or notify devices / applications. The most likely use case for Terraform users will
|
||||||
|
probably be SQS queues.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
You can directly supply a topic and ARN by hand in the `topic_arn` property along with the queue ARN:
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_sns_topic_subscription" "user_updates_sqs_target" {
|
||||||
|
topic_arn = "arn:aws:sns:us-west-2:432981146916:user-updates-topic"
|
||||||
|
protocol = "sqs"
|
||||||
|
endpoint = "arn:aws:sqs:us-west-2:432981146916:terraform-queue-too"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively you can use the ARN properties of a managed SNS topic and SQS queue:
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_sns_topic" "user_updates" {
|
||||||
|
name = "user-updates-topic"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_sqs_queue" "user_updates_queue" {
|
||||||
|
name = "user-updates-queue"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_sns_topic_subscription" "user_updates_sqs_target" {
|
||||||
|
topic_arn = "${aws_sns_topic.user_updates.arn}"
|
||||||
|
protocol = "sqs"
|
||||||
|
endpoint = "${aws_sqs_queue.user_updates_queue.arn}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `topic_arn` - (Required) The ARN of the SNS topic to subscribe to
|
||||||
|
* `protocol` - (Required) The protocol to use. The possible values for this are: `sqs`, `http`, `https`, `sms`, or `application`. (`email` is an option but unsupported, see below)
|
||||||
|
* `endpoint` - (Required) The endpoint to send data to, the contents will vary with the protocol. (see below for more information)
|
||||||
|
* `raw_message_delivery` - (Optional) Boolean indicating whether or not to enable raw message delivery (the original message is directly passed, not wrapped in JSON with the original message in the message property).
|
||||||
|
|
||||||
|
### Protocols supported
|
||||||
|
|
||||||
|
Supported SNS protocols include:
|
||||||
|
|
||||||
|
* `http` -- delivery of JSON-encoded message via HTTP POST
|
||||||
|
* `https` -- delivery of JSON-encoded message via HTTPS POST
|
||||||
|
* `sms` -- delivery of message via SMS
|
||||||
|
* `sqs` -- delivery of JSON-encoded message to an Amazon SQS queue
|
||||||
|
* `application` -- delivery of JSON-encoded message to an EndpointArn for a mobile app and device
|
||||||
|
|
||||||
|
Unsupported protocols include the following:
|
||||||
|
|
||||||
|
* `email` -- delivery of message via SMTP
|
||||||
|
* `email-json` -- delivery of JSON-encoded message via SMTP
|
||||||
|
|
||||||
|
These are unsupported because the email address needs to be authorized and does not generate an ARN until the target email address has been validated. This breaks
|
||||||
|
the Terraform model and as a result are not currently supported.
|
||||||
|
|
||||||
|
### Specifying endpoints
|
||||||
|
|
||||||
|
Endpoints have different format requirements according to the protocol that is chosen.
|
||||||
|
|
||||||
|
* HTTP/HTTPS endpoints will require a URL to POST data to
|
||||||
|
* SMS endpoints are mobile numbers that are capable of receiving an SMS
|
||||||
|
* SQS endpoints come in the form of the SQS queue's ARN (not the URL of the queue) e.g: `arn:aws:sqs:us-west-2:432981146916:terraform-queue-too`
|
||||||
|
* Application endpoints are also the endpoint ARN for the mobile app and device.
|
||||||
|
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The ARN of the subscription
|
||||||
|
* `topic_arn` - The ARN of the topic the subscription belongs to
|
||||||
|
* `protocol` - The protocol being used
|
||||||
|
* `endpoint` - The full endpoint to send data to (SQS ARN, HTTP(S) URL, Application ARN, SMS number, etc.)
|
||||||
|
* `arn` - The ARN of the subscription stored as a more user-friendly property
|
||||||
|
|
|
@ -11,7 +11,7 @@ description: |-
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
resource "aws_sqs_queue" "terrform_queue" {
|
resource "aws_sqs_queue" "terraform_queue" {
|
||||||
name = "terraform-example-queue"
|
name = "terraform-example-queue"
|
||||||
delay_seconds = 90
|
delay_seconds = 90
|
||||||
max_message_size = 2048
|
max_message_size = 2048
|
||||||
|
@ -35,4 +35,5 @@ The following arguments are supported:
|
||||||
|
|
||||||
The following attributes are exported:
|
The following attributes are exported:
|
||||||
|
|
||||||
* `id` - The URL for the created Amazon SQS queue.
|
* `id` - The URL for the created Amazon SQS queue.
|
||||||
|
* `arn` - The ARN of the SQS queue
|
|
@ -152,6 +152,14 @@
|
||||||
<a href="/docs/providers/aws/r/s3_bucket.html">aws_s3_bucket</a>
|
<a href="/docs/providers/aws/r/s3_bucket.html">aws_s3_bucket</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-sns-topic") %>>
|
||||||
|
<a href="/docs/providers/aws/r/sns_topic.html">aws_sns_topic</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-sns-topic-subscription") %>>
|
||||||
|
<a href="/docs/providers/aws/r/sns_topic_subscription.html">aws_sns_topic_subscription</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-security-group") %>>
|
<li<%= sidebar_current("docs-aws-resource-security-group") %>>
|
||||||
<a href="/docs/providers/aws/r/security_group.html">aws_security_group</a>
|
<a href="/docs/providers/aws/r/security_group.html">aws_security_group</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue