github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/aws/resource_aws_db_event_subscription.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/aws/awserr" 10 "github.com/aws/aws-sdk-go/service/rds" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/helper/schema" 13 ) 14 15 func resourceAwsDbEventSubscription() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceAwsDbEventSubscriptionCreate, 18 Read: resourceAwsDbEventSubscriptionRead, 19 Update: resourceAwsDbEventSubscriptionUpdate, 20 Delete: resourceAwsDbEventSubscriptionDelete, 21 Importer: &schema.ResourceImporter{ 22 State: schema.ImportStatePassthrough, 23 }, 24 Schema: map[string]*schema.Schema{ 25 "name": &schema.Schema{ 26 Type: schema.TypeString, 27 Required: true, 28 ForceNew: true, 29 ValidateFunc: validateDbEventSubscriptionName, 30 }, 31 "sns_topic": &schema.Schema{ 32 Type: schema.TypeString, 33 Required: true, 34 }, 35 "event_categories": &schema.Schema{ 36 Type: schema.TypeSet, 37 Optional: true, 38 Elem: &schema.Schema{Type: schema.TypeString}, 39 Set: schema.HashString, 40 }, 41 "source_ids": &schema.Schema{ 42 Type: schema.TypeSet, 43 Optional: true, 44 Elem: &schema.Schema{Type: schema.TypeString}, 45 Set: schema.HashString, 46 // ValidateFunc: validateDbEventSubscriptionSourceIds, 47 // requires source_type to be set, does not seem to be a way to validate this 48 }, 49 "source_type": &schema.Schema{ 50 Type: schema.TypeString, 51 Optional: true, 52 }, 53 "enabled": &schema.Schema{ 54 Type: schema.TypeBool, 55 Optional: true, 56 Default: true, 57 }, 58 "customer_aws_id": &schema.Schema{ 59 Type: schema.TypeString, 60 Computed: true, 61 }, 62 "tags": tagsSchema(), 63 }, 64 } 65 } 66 67 func resourceAwsDbEventSubscriptionCreate(d *schema.ResourceData, meta interface{}) error { 68 rdsconn := meta.(*AWSClient).rdsconn 69 name := d.Get("name").(string) 70 tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) 71 72 sourceIdsSet := d.Get("source_ids").(*schema.Set) 73 sourceIds := make([]*string, sourceIdsSet.Len()) 74 for i, sourceId := range sourceIdsSet.List() { 75 sourceIds[i] = aws.String(sourceId.(string)) 76 } 77 78 eventCategoriesSet := d.Get("event_categories").(*schema.Set) 79 eventCategories := make([]*string, eventCategoriesSet.Len()) 80 for i, eventCategory := range eventCategoriesSet.List() { 81 eventCategories[i] = aws.String(eventCategory.(string)) 82 } 83 84 request := &rds.CreateEventSubscriptionInput{ 85 SubscriptionName: aws.String(name), 86 SnsTopicArn: aws.String(d.Get("sns_topic").(string)), 87 Enabled: aws.Bool(d.Get("enabled").(bool)), 88 SourceIds: sourceIds, 89 SourceType: aws.String(d.Get("source_type").(string)), 90 EventCategories: eventCategories, 91 Tags: tags, 92 } 93 94 log.Println("[DEBUG] Create RDS Event Subscription:", request) 95 96 _, err := rdsconn.CreateEventSubscription(request) 97 if err != nil { 98 return fmt.Errorf("Error creating RDS Event Subscription %s: %s", name, err) 99 } 100 101 log.Println( 102 "[INFO] Waiting for RDS Event Subscription to be ready") 103 104 stateConf := &resource.StateChangeConf{ 105 Pending: []string{"creating"}, 106 Target: []string{"active"}, 107 Refresh: resourceAwsDbEventSubscriptionRefreshFunc(d, meta.(*AWSClient).rdsconn), 108 Timeout: 40 * time.Minute, 109 MinTimeout: 10 * time.Second, 110 Delay: 30 * time.Second, // Wait 30 secs before starting 111 } 112 113 // Wait, catching any errors 114 _, err = stateConf.WaitForState() 115 if err != nil { 116 return fmt.Errorf("Creating RDS Event Subscription %s failed: %s", d.Id(), err) 117 } 118 119 return resourceAwsDbEventSubscriptionRead(d, meta) 120 } 121 122 func resourceAwsDbEventSubscriptionRead(d *schema.ResourceData, meta interface{}) error { 123 sub, err := resourceAwsDbEventSubscriptionRetrieve(d.Get("name").(string), meta.(*AWSClient).rdsconn) 124 if err != nil { 125 return fmt.Errorf("Error retrieving RDS Event Subscription %s: %s", d.Id(), err) 126 } 127 if sub == nil { 128 d.SetId("") 129 return nil 130 } 131 132 d.SetId(*sub.CustSubscriptionId) 133 if err := d.Set("name", sub.CustSubscriptionId); err != nil { 134 return err 135 } 136 if err := d.Set("sns_topic", sub.SnsTopicArn); err != nil { 137 return err 138 } 139 if err := d.Set("source_type", sub.SourceType); err != nil { 140 return err 141 } 142 if err := d.Set("enabled", sub.Enabled); err != nil { 143 return err 144 } 145 if err := d.Set("source_ids", flattenStringList(sub.SourceIdsList)); err != nil { 146 return err 147 } 148 if err := d.Set("event_categories", flattenStringList(sub.EventCategoriesList)); err != nil { 149 return err 150 } 151 if err := d.Set("customer_aws_id", sub.CustomerAwsId); err != nil { 152 return err 153 } 154 155 // list tags for resource 156 // set tags 157 conn := meta.(*AWSClient).rdsconn 158 if arn, err := buildRDSEventSubscriptionARN(d.Get("customer_aws_id").(string), d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).region); err != nil { 159 log.Printf("[DEBUG] Error building ARN for RDS Event Subscription, not setting Tags for Event Subscription %s", *sub.CustSubscriptionId) 160 } else { 161 resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{ 162 ResourceName: aws.String(arn), 163 }) 164 165 if err != nil { 166 log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn) 167 } 168 169 var dt []*rds.Tag 170 if len(resp.TagList) > 0 { 171 dt = resp.TagList 172 } 173 d.Set("tags", tagsToMapRDS(dt)) 174 } 175 176 return nil 177 } 178 179 func resourceAwsDbEventSubscriptionRetrieve( 180 name string, rdsconn *rds.RDS) (*rds.EventSubscription, error) { 181 182 request := &rds.DescribeEventSubscriptionsInput{ 183 SubscriptionName: aws.String(name), 184 } 185 186 describeResp, err := rdsconn.DescribeEventSubscriptions(request) 187 if err != nil { 188 if rdserr, ok := err.(awserr.Error); ok && rdserr.Code() == "SubscriptionNotFound" { 189 log.Printf("[WARN] No RDS Event Subscription by name (%s) found", name) 190 return nil, nil 191 } 192 return nil, fmt.Errorf("Error reading RDS Event Subscription %s: %s", name, err) 193 } 194 195 if len(describeResp.EventSubscriptionsList) != 1 { 196 return nil, fmt.Errorf("Unable to find RDS Event Subscription: %#v", describeResp.EventSubscriptionsList) 197 } 198 199 return describeResp.EventSubscriptionsList[0], nil 200 } 201 202 func resourceAwsDbEventSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error { 203 rdsconn := meta.(*AWSClient).rdsconn 204 205 d.Partial(true) 206 requestUpdate := false 207 208 req := &rds.ModifyEventSubscriptionInput{ 209 SubscriptionName: aws.String(d.Id()), 210 } 211 212 if d.HasChange("event_categories") { 213 eventCategoriesSet := d.Get("event_categories").(*schema.Set) 214 req.EventCategories = make([]*string, eventCategoriesSet.Len()) 215 for i, eventCategory := range eventCategoriesSet.List() { 216 req.EventCategories[i] = aws.String(eventCategory.(string)) 217 } 218 requestUpdate = true 219 } 220 221 if d.HasChange("enabled") { 222 req.Enabled = aws.Bool(d.Get("enabled").(bool)) 223 requestUpdate = true 224 } 225 226 if d.HasChange("sns_topic") { 227 req.SnsTopicArn = aws.String(d.Get("sns_topic").(string)) 228 requestUpdate = true 229 } 230 231 if d.HasChange("source_type") { 232 req.SourceType = aws.String(d.Get("source_type").(string)) 233 requestUpdate = true 234 } 235 236 log.Printf("[DEBUG] Send RDS Event Subscription modification request: %#v", requestUpdate) 237 if requestUpdate { 238 log.Printf("[DEBUG] RDS Event Subscription modification request: %#v", req) 239 _, err := rdsconn.ModifyEventSubscription(req) 240 if err != nil { 241 return fmt.Errorf("Modifying RDS Event Subscription %s failed: %s", d.Id(), err) 242 } 243 244 log.Println( 245 "[INFO] Waiting for RDS Event Subscription modification to finish") 246 247 stateConf := &resource.StateChangeConf{ 248 Pending: []string{"modifying"}, 249 Target: []string{"active"}, 250 Refresh: resourceAwsDbEventSubscriptionRefreshFunc(d, meta.(*AWSClient).rdsconn), 251 Timeout: 40 * time.Minute, 252 MinTimeout: 10 * time.Second, 253 Delay: 30 * time.Second, // Wait 30 secs before starting 254 } 255 256 // Wait, catching any errors 257 _, err = stateConf.WaitForState() 258 if err != nil { 259 return fmt.Errorf("Modifying RDS Event Subscription %s failed: %s", d.Id(), err) 260 } 261 d.SetPartial("event_categories") 262 d.SetPartial("enabled") 263 d.SetPartial("sns_topic") 264 d.SetPartial("source_type") 265 } 266 267 if arn, err := buildRDSEventSubscriptionARN(d.Get("customer_aws_id").(string), d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).region); err == nil { 268 if err := setTagsRDS(rdsconn, d, arn); err != nil { 269 return err 270 } else { 271 d.SetPartial("tags") 272 } 273 } 274 275 if d.HasChange("source_ids") { 276 o, n := d.GetChange("source_ids") 277 if o == nil { 278 o = new(schema.Set) 279 } 280 if n == nil { 281 n = new(schema.Set) 282 } 283 284 os := o.(*schema.Set) 285 ns := n.(*schema.Set) 286 remove := expandStringList(os.Difference(ns).List()) 287 add := expandStringList(ns.Difference(os).List()) 288 289 if len(remove) > 0 { 290 for _, removing := range remove { 291 log.Printf("[INFO] Removing %s as a Source Identifier from %q", *removing, d.Id()) 292 _, err := rdsconn.RemoveSourceIdentifierFromSubscription(&rds.RemoveSourceIdentifierFromSubscriptionInput{ 293 SourceIdentifier: removing, 294 SubscriptionName: aws.String(d.Id()), 295 }) 296 if err != nil { 297 return err 298 } 299 } 300 } 301 302 if len(add) > 0 { 303 for _, adding := range add { 304 log.Printf("[INFO] Adding %s as a Source Identifier to %q", *adding, d.Id()) 305 _, err := rdsconn.AddSourceIdentifierToSubscription(&rds.AddSourceIdentifierToSubscriptionInput{ 306 SourceIdentifier: adding, 307 SubscriptionName: aws.String(d.Id()), 308 }) 309 if err != nil { 310 return err 311 } 312 } 313 } 314 d.SetPartial("source_ids") 315 } 316 317 d.Partial(false) 318 319 return nil 320 } 321 322 func resourceAwsDbEventSubscriptionDelete(d *schema.ResourceData, meta interface{}) error { 323 rdsconn := meta.(*AWSClient).rdsconn 324 deleteOpts := rds.DeleteEventSubscriptionInput{ 325 SubscriptionName: aws.String(d.Id()), 326 } 327 328 if _, err := rdsconn.DeleteEventSubscription(&deleteOpts); err != nil { 329 rdserr, ok := err.(awserr.Error) 330 if !ok { 331 return fmt.Errorf("Error deleting RDS Event Subscription %s: %s", d.Id(), err) 332 } 333 334 if rdserr.Code() != "DBEventSubscriptionNotFoundFault" { 335 log.Printf("[WARN] RDS Event Subscription %s missing during delete", d.Id()) 336 return fmt.Errorf("Error deleting RDS Event Subscription %s: %s", d.Id(), err) 337 } 338 } 339 340 stateConf := &resource.StateChangeConf{ 341 Pending: []string{"deleting"}, 342 Target: []string{}, 343 Refresh: resourceAwsDbEventSubscriptionRefreshFunc(d, meta.(*AWSClient).rdsconn), 344 Timeout: 40 * time.Minute, 345 MinTimeout: 10 * time.Second, 346 Delay: 30 * time.Second, // Wait 30 secs before starting 347 } 348 _, err := stateConf.WaitForState() 349 if err != nil { 350 return fmt.Errorf("Error deleting RDS Event Subscription %s: %s", d.Id(), err) 351 } 352 return err 353 } 354 355 func resourceAwsDbEventSubscriptionRefreshFunc( 356 d *schema.ResourceData, 357 rdsconn *rds.RDS) resource.StateRefreshFunc { 358 359 return func() (interface{}, string, error) { 360 sub, err := resourceAwsDbEventSubscriptionRetrieve(d.Get("name").(string), rdsconn) 361 362 if err != nil { 363 log.Printf("Error on retrieving DB Event Subscription when waiting: %s", err) 364 return nil, "", err 365 } 366 367 if sub == nil { 368 return nil, "", nil 369 } 370 371 if sub.Status != nil { 372 log.Printf("[DEBUG] DB Event Subscription status for %s: %s", d.Id(), *sub.Status) 373 } 374 375 return sub, *sub.Status, nil 376 } 377 } 378 379 func buildRDSEventSubscriptionARN(customerAwsId, subscriptionId, partition, region string) (string, error) { 380 if partition == "" { 381 return "", fmt.Errorf("Unable to construct RDS ARN because of missing AWS partition") 382 } 383 arn := fmt.Sprintf("arn:%s:rds:%s:%s:es:%s", partition, region, customerAwsId, subscriptionId) 384 return arn, nil 385 }