github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/builtin/providers/aws/resource_aws_sns_topic_policy.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "time" 8 9 "github.com/hashicorp/terraform/helper/resource" 10 "github.com/hashicorp/terraform/helper/schema" 11 12 "github.com/aws/aws-sdk-go/aws" 13 "github.com/aws/aws-sdk-go/aws/awserr" 14 "github.com/aws/aws-sdk-go/service/sns" 15 ) 16 17 func resourceAwsSnsTopicPolicy() *schema.Resource { 18 return &schema.Resource{ 19 Create: resourceAwsSnsTopicPolicyUpsert, 20 Read: resourceAwsSnsTopicPolicyRead, 21 Update: resourceAwsSnsTopicPolicyUpsert, 22 Delete: resourceAwsSnsTopicPolicyDelete, 23 24 Schema: map[string]*schema.Schema{ 25 "arn": { 26 Type: schema.TypeString, 27 Required: true, 28 ForceNew: true, 29 }, 30 "policy": { 31 Type: schema.TypeString, 32 Required: true, 33 DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, 34 }, 35 }, 36 } 37 } 38 39 func resourceAwsSnsTopicPolicyUpsert(d *schema.ResourceData, meta interface{}) error { 40 arn := d.Get("arn").(string) 41 req := sns.SetTopicAttributesInput{ 42 TopicArn: aws.String(arn), 43 AttributeName: aws.String("Policy"), 44 AttributeValue: aws.String(d.Get("policy").(string)), 45 } 46 47 d.SetId(arn) 48 49 // Retry the update in the event of an eventually consistent style of 50 // error, where say an IAM resource is successfully created but not 51 // actually available. See https://github.com/hashicorp/terraform/issues/3660 52 log.Printf("[DEBUG] Updating SNS Topic Policy: %s", req) 53 stateConf := &resource.StateChangeConf{ 54 Pending: []string{"retrying"}, 55 Target: []string{"success"}, 56 Refresh: resourceAwsSNSUpdateRefreshFunc(meta, req), 57 Timeout: 3 * time.Minute, 58 MinTimeout: 3 * time.Second, 59 } 60 _, err := stateConf.WaitForState() 61 if err != nil { 62 return err 63 } 64 65 return resourceAwsSnsTopicPolicyRead(d, meta) 66 } 67 68 func resourceAwsSnsTopicPolicyRead(d *schema.ResourceData, meta interface{}) error { 69 snsconn := meta.(*AWSClient).snsconn 70 71 attributeOutput, err := snsconn.GetTopicAttributes(&sns.GetTopicAttributesInput{ 72 TopicArn: aws.String(d.Id()), 73 }) 74 if err != nil { 75 if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NotFound" { 76 log.Printf("[WARN] SNS Topic (%s) not found, error code (404)", d.Id()) 77 d.SetId("") 78 return nil 79 } 80 81 return err 82 } 83 84 if attributeOutput.Attributes == nil { 85 log.Printf("[WARN] SNS Topic (%q) attributes not found (nil)", d.Id()) 86 d.SetId("") 87 return nil 88 } 89 attrmap := attributeOutput.Attributes 90 91 policy, ok := attrmap["Policy"] 92 if !ok { 93 log.Printf("[WARN] SNS Topic (%q) policy not found in attributes", d.Id()) 94 d.SetId("") 95 return nil 96 } 97 98 d.Set("policy", policy) 99 100 return nil 101 } 102 103 func resourceAwsSnsTopicPolicyDelete(d *schema.ResourceData, meta interface{}) error { 104 accountId, err := getAccountIdFromSnsTopicArn(d.Id()) 105 if err != nil { 106 return err 107 } 108 109 req := sns.SetTopicAttributesInput{ 110 TopicArn: aws.String(d.Id()), 111 AttributeName: aws.String("Policy"), 112 // It is impossible to delete a policy or set to empty 113 // (confirmed by AWS Support representative) 114 // so we instead set it back to the default one 115 AttributeValue: aws.String(buildDefaultSnsTopicPolicy(d.Id(), accountId)), 116 } 117 118 // Retry the update in the event of an eventually consistent style of 119 // error, where say an IAM resource is successfully created but not 120 // actually available. See https://github.com/hashicorp/terraform/issues/3660 121 log.Printf("[DEBUG] Resetting SNS Topic Policy to default: %s", req) 122 stateConf := &resource.StateChangeConf{ 123 Pending: []string{"retrying"}, 124 Target: []string{"success"}, 125 Refresh: resourceAwsSNSUpdateRefreshFunc(meta, req), 126 Timeout: 3 * time.Minute, 127 MinTimeout: 3 * time.Second, 128 } 129 _, err = stateConf.WaitForState() 130 if err != nil { 131 return err 132 } 133 return nil 134 } 135 136 func getAccountIdFromSnsTopicArn(arn string) (string, error) { 137 // arn:aws:sns:us-west-2:123456789012:test-new 138 re := regexp.MustCompile("^arn:aws:sns:[^:]+:([0-9]{12}):.+") 139 matches := re.FindStringSubmatch(arn) 140 if len(matches) != 2 { 141 return "", fmt.Errorf("Unable to get account ID from ARN (%q)", arn) 142 } 143 return matches[1], nil 144 } 145 146 func buildDefaultSnsTopicPolicy(topicArn, accountId string) string { 147 return fmt.Sprintf(`{ 148 "Version": "2008-10-17", 149 "Id": "__default_policy_ID", 150 "Statement": [ 151 { 152 "Sid": "__default_statement_ID", 153 "Effect": "Allow", 154 "Principal": { 155 "AWS": "*" 156 }, 157 "Action": [ 158 "SNS:GetTopicAttributes", 159 "SNS:SetTopicAttributes", 160 "SNS:AddPermission", 161 "SNS:RemovePermission", 162 "SNS:DeleteTopic", 163 "SNS:Subscribe", 164 "SNS:ListSubscriptionsByTopic", 165 "SNS:Publish", 166 "SNS:Receive" 167 ], 168 "Resource": "%s", 169 "Condition": { 170 "StringEquals": { 171 "AWS:SourceOwner": "%s" 172 } 173 } 174 } 175 ] 176 }`, topicArn, accountId) 177 }