github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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: resourceAwsDbEventSubscriptionImport,
    23  		},
    24  		Schema: map[string]*schema.Schema{
    25  			"name": {
    26  				Type:         schema.TypeString,
    27  				Required:     true,
    28  				ForceNew:     true,
    29  				ValidateFunc: validateDbEventSubscriptionName,
    30  			},
    31  			"sns_topic": {
    32  				Type:     schema.TypeString,
    33  				Required: true,
    34  			},
    35  			"event_categories": {
    36  				Type:     schema.TypeSet,
    37  				Optional: true,
    38  				Elem:     &schema.Schema{Type: schema.TypeString},
    39  				Set:      schema.HashString,
    40  			},
    41  			"source_ids": {
    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": {
    50  				Type:     schema.TypeString,
    51  				Optional: true,
    52  			},
    53  			"enabled": {
    54  				Type:     schema.TypeBool,
    55  				Optional: true,
    56  				Default:  true,
    57  			},
    58  			"customer_aws_id": {
    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  }