github.com/mysza/terraform@v0.7.6-0.20161011024539-258005408b33/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  	arn := buildRDSEventSubscriptionARN(d.Get("customer_aws_id").(string), d.Id(), meta.(*AWSClient).region)
   159  	resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{
   160  		ResourceName: aws.String(arn),
   161  	})
   162  
   163  	if err != nil {
   164  		log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn)
   165  	}
   166  
   167  	var dt []*rds.Tag
   168  	if len(resp.TagList) > 0 {
   169  		dt = resp.TagList
   170  	}
   171  	d.Set("tags", tagsToMapRDS(dt))
   172  
   173  	return nil
   174  }
   175  
   176  func resourceAwsDbEventSubscriptionRetrieve(
   177  	name string, rdsconn *rds.RDS) (*rds.EventSubscription, error) {
   178  
   179  	request := &rds.DescribeEventSubscriptionsInput{
   180  		SubscriptionName: aws.String(name),
   181  	}
   182  
   183  	describeResp, err := rdsconn.DescribeEventSubscriptions(request)
   184  	if err != nil {
   185  		if rdserr, ok := err.(awserr.Error); ok && rdserr.Code() == "SubscriptionNotFound" {
   186  			log.Printf("[WARN] No RDS Event Subscription by name (%s) found", name)
   187  			return nil, nil
   188  		}
   189  		return nil, fmt.Errorf("Error reading RDS Event Subscription %s: %s", name, err)
   190  	}
   191  
   192  	if len(describeResp.EventSubscriptionsList) != 1 {
   193  		return nil, fmt.Errorf("Unable to find RDS Event Subscription: %#v", describeResp.EventSubscriptionsList)
   194  	}
   195  
   196  	return describeResp.EventSubscriptionsList[0], nil
   197  }
   198  
   199  func resourceAwsDbEventSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error {
   200  	rdsconn := meta.(*AWSClient).rdsconn
   201  
   202  	d.Partial(true)
   203  	requestUpdate := false
   204  
   205  	req := &rds.ModifyEventSubscriptionInput{
   206  		SubscriptionName: aws.String(d.Id()),
   207  	}
   208  
   209  	if d.HasChange("event_categories") {
   210  		eventCategoriesSet := d.Get("event_categories").(*schema.Set)
   211  		req.EventCategories = make([]*string, eventCategoriesSet.Len())
   212  		for i, eventCategory := range eventCategoriesSet.List() {
   213  			req.EventCategories[i] = aws.String(eventCategory.(string))
   214  		}
   215  		requestUpdate = true
   216  	}
   217  
   218  	if d.HasChange("enabled") {
   219  		req.Enabled = aws.Bool(d.Get("enabled").(bool))
   220  		requestUpdate = true
   221  	}
   222  
   223  	if d.HasChange("sns_topic") {
   224  		req.SnsTopicArn = aws.String(d.Get("sns_topic").(string))
   225  		requestUpdate = true
   226  	}
   227  
   228  	if d.HasChange("source_type") {
   229  		req.SourceType = aws.String(d.Get("source_type").(string))
   230  		requestUpdate = true
   231  	}
   232  
   233  	log.Printf("[DEBUG] Send RDS Event Subscription modification request: %#v", requestUpdate)
   234  	if requestUpdate {
   235  		log.Printf("[DEBUG] RDS Event Subscription modification request: %#v", req)
   236  		_, err := rdsconn.ModifyEventSubscription(req)
   237  		if err != nil {
   238  			return fmt.Errorf("Modifying RDS Event Subscription %s failed: %s", d.Id(), err)
   239  		}
   240  
   241  		log.Println(
   242  			"[INFO] Waiting for RDS Event Subscription modification to finish")
   243  
   244  		stateConf := &resource.StateChangeConf{
   245  			Pending:    []string{"modifying"},
   246  			Target:     []string{"active"},
   247  			Refresh:    resourceAwsDbEventSubscriptionRefreshFunc(d, meta.(*AWSClient).rdsconn),
   248  			Timeout:    40 * time.Minute,
   249  			MinTimeout: 10 * time.Second,
   250  			Delay:      30 * time.Second, // Wait 30 secs before starting
   251  		}
   252  
   253  		// Wait, catching any errors
   254  		_, err = stateConf.WaitForState()
   255  		if err != nil {
   256  			return fmt.Errorf("Modifying RDS Event Subscription %s failed: %s", d.Id(), err)
   257  		}
   258  		d.SetPartial("event_categories")
   259  		d.SetPartial("enabled")
   260  		d.SetPartial("sns_topic")
   261  		d.SetPartial("source_type")
   262  	}
   263  
   264  	arn := buildRDSEventSubscriptionARN(d.Get("customer_aws_id").(string), d.Id(), meta.(*AWSClient).region)
   265  	if err := setTagsRDS(rdsconn, d, arn); err != nil {
   266  		return err
   267  	} else {
   268  		d.SetPartial("tags")
   269  	}
   270  
   271  	if d.HasChange("source_ids") {
   272  		o, n := d.GetChange("source_ids")
   273  		if o == nil {
   274  			o = new(schema.Set)
   275  		}
   276  		if n == nil {
   277  			n = new(schema.Set)
   278  		}
   279  
   280  		os := o.(*schema.Set)
   281  		ns := n.(*schema.Set)
   282  		remove := expandStringList(os.Difference(ns).List())
   283  		add := expandStringList(ns.Difference(os).List())
   284  
   285  		if len(remove) > 0 {
   286  			for _, removing := range remove {
   287  				log.Printf("[INFO] Removing %s as a Source Identifier from %q", *removing, d.Id())
   288  				_, err := rdsconn.RemoveSourceIdentifierFromSubscription(&rds.RemoveSourceIdentifierFromSubscriptionInput{
   289  					SourceIdentifier: removing,
   290  					SubscriptionName: aws.String(d.Id()),
   291  				})
   292  				if err != nil {
   293  					return err
   294  				}
   295  			}
   296  		}
   297  
   298  		if len(add) > 0 {
   299  			for _, adding := range add {
   300  				log.Printf("[INFO] Adding %s as a Source Identifier to %q", *adding, d.Id())
   301  				_, err := rdsconn.AddSourceIdentifierToSubscription(&rds.AddSourceIdentifierToSubscriptionInput{
   302  					SourceIdentifier: adding,
   303  					SubscriptionName: aws.String(d.Id()),
   304  				})
   305  				if err != nil {
   306  					return err
   307  				}
   308  			}
   309  		}
   310  		d.SetPartial("source_ids")
   311  	}
   312  
   313  	d.Partial(false)
   314  
   315  	return nil
   316  }
   317  
   318  func resourceAwsDbEventSubscriptionDelete(d *schema.ResourceData, meta interface{}) error {
   319  	rdsconn := meta.(*AWSClient).rdsconn
   320  	deleteOpts := rds.DeleteEventSubscriptionInput{
   321  		SubscriptionName: aws.String(d.Id()),
   322  	}
   323  
   324  	if _, err := rdsconn.DeleteEventSubscription(&deleteOpts); err != nil {
   325  		rdserr, ok := err.(awserr.Error)
   326  		if !ok {
   327  			return fmt.Errorf("Error deleting RDS Event Subscription %s: %s", d.Id(), err)
   328  		}
   329  
   330  		if rdserr.Code() != "DBEventSubscriptionNotFoundFault" {
   331  			log.Printf("[WARN] RDS Event Subscription %s missing during delete", d.Id())
   332  			return fmt.Errorf("Error deleting RDS Event Subscription %s: %s", d.Id(), err)
   333  		}
   334  	}
   335  
   336  	stateConf := &resource.StateChangeConf{
   337  		Pending:    []string{"deleting"},
   338  		Target:     []string{},
   339  		Refresh:    resourceAwsDbEventSubscriptionRefreshFunc(d, meta.(*AWSClient).rdsconn),
   340  		Timeout:    40 * time.Minute,
   341  		MinTimeout: 10 * time.Second,
   342  		Delay:      30 * time.Second, // Wait 30 secs before starting
   343  	}
   344  	_, err := stateConf.WaitForState()
   345  	if err != nil {
   346  		return fmt.Errorf("Error deleting RDS Event Subscription %s: %s", d.Id(), err)
   347  	}
   348  	return err
   349  }
   350  
   351  func resourceAwsDbEventSubscriptionRefreshFunc(
   352  	d *schema.ResourceData,
   353  	rdsconn *rds.RDS) resource.StateRefreshFunc {
   354  
   355  	return func() (interface{}, string, error) {
   356  		sub, err := resourceAwsDbEventSubscriptionRetrieve(d.Get("name").(string), rdsconn)
   357  
   358  		if err != nil {
   359  			log.Printf("Error on retrieving DB Event Subscription when waiting: %s", err)
   360  			return nil, "", err
   361  		}
   362  
   363  		if sub == nil {
   364  			return nil, "", nil
   365  		}
   366  
   367  		if sub.Status != nil {
   368  			log.Printf("[DEBUG] DB Event Subscription status for %s: %s", d.Id(), *sub.Status)
   369  		}
   370  
   371  		return sub, *sub.Status, nil
   372  	}
   373  }
   374  
   375  func buildRDSEventSubscriptionARN(customerAwsId, subscriptionId, region string) string {
   376  	arn := fmt.Sprintf("arn:aws:rds:%s:%s:es:%s", region, customerAwsId, subscriptionId)
   377  	return arn
   378  }