github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_rds_cluster.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"regexp"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/aws/awserr"
    12  	"github.com/aws/aws-sdk-go/service/rds"
    13  	"github.com/hashicorp/terraform/helper/resource"
    14  	"github.com/hashicorp/terraform/helper/schema"
    15  )
    16  
    17  func resourceAwsRDSCluster() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAwsRDSClusterCreate,
    20  		Read:   resourceAwsRDSClusterRead,
    21  		Update: resourceAwsRDSClusterUpdate,
    22  		Delete: resourceAwsRDSClusterDelete,
    23  		Importer: &schema.ResourceImporter{
    24  			State: resourceAwsRdsClusterImport,
    25  		},
    26  
    27  		Schema: map[string]*schema.Schema{
    28  
    29  			"availability_zones": {
    30  				Type:     schema.TypeSet,
    31  				Elem:     &schema.Schema{Type: schema.TypeString},
    32  				Optional: true,
    33  				ForceNew: true,
    34  				Computed: true,
    35  				Set:      schema.HashString,
    36  			},
    37  
    38  			"cluster_identifier": {
    39  				Type:          schema.TypeString,
    40  				Optional:      true,
    41  				Computed:      true,
    42  				ForceNew:      true,
    43  				ConflictsWith: []string{"cluster_identifier_prefix"},
    44  				ValidateFunc:  validateRdsIdentifier,
    45  			},
    46  			"cluster_identifier_prefix": {
    47  				Type:         schema.TypeString,
    48  				Optional:     true,
    49  				Computed:     true,
    50  				ForceNew:     true,
    51  				ValidateFunc: validateRdsIdentifierPrefix,
    52  			},
    53  
    54  			"cluster_members": {
    55  				Type:     schema.TypeSet,
    56  				Elem:     &schema.Schema{Type: schema.TypeString},
    57  				Optional: true,
    58  				Computed: true,
    59  				Set:      schema.HashString,
    60  			},
    61  
    62  			"database_name": {
    63  				Type:     schema.TypeString,
    64  				Optional: true,
    65  				Computed: true,
    66  				ForceNew: true,
    67  			},
    68  
    69  			"db_subnet_group_name": {
    70  				Type:     schema.TypeString,
    71  				Optional: true,
    72  				ForceNew: true,
    73  				Computed: true,
    74  			},
    75  
    76  			"db_cluster_parameter_group_name": {
    77  				Type:     schema.TypeString,
    78  				Optional: true,
    79  				Computed: true,
    80  			},
    81  
    82  			"endpoint": {
    83  				Type:     schema.TypeString,
    84  				Computed: true,
    85  			},
    86  
    87  			"reader_endpoint": {
    88  				Type:     schema.TypeString,
    89  				Computed: true,
    90  			},
    91  
    92  			"engine": {
    93  				Type:     schema.TypeString,
    94  				Computed: true,
    95  			},
    96  
    97  			"storage_encrypted": {
    98  				Type:     schema.TypeBool,
    99  				Optional: true,
   100  				Default:  false,
   101  				ForceNew: true,
   102  			},
   103  
   104  			"final_snapshot_identifier": {
   105  				Type:     schema.TypeString,
   106  				Optional: true,
   107  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   108  					value := v.(string)
   109  					if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   110  						es = append(es, fmt.Errorf(
   111  							"only alphanumeric characters and hyphens allowed in %q", k))
   112  					}
   113  					if regexp.MustCompile(`--`).MatchString(value) {
   114  						es = append(es, fmt.Errorf("%q cannot contain two consecutive hyphens", k))
   115  					}
   116  					if regexp.MustCompile(`-$`).MatchString(value) {
   117  						es = append(es, fmt.Errorf("%q cannot end in a hyphen", k))
   118  					}
   119  					return
   120  				},
   121  			},
   122  
   123  			"skip_final_snapshot": {
   124  				Type:     schema.TypeBool,
   125  				Optional: true,
   126  				Default:  false,
   127  			},
   128  
   129  			"master_username": {
   130  				Type:     schema.TypeString,
   131  				Computed: true,
   132  				Optional: true,
   133  				ForceNew: true,
   134  			},
   135  
   136  			"master_password": {
   137  				Type:      schema.TypeString,
   138  				Optional:  true,
   139  				Sensitive: true,
   140  			},
   141  
   142  			"snapshot_identifier": {
   143  				Type:     schema.TypeString,
   144  				Computed: false,
   145  				Optional: true,
   146  				Elem:     &schema.Schema{Type: schema.TypeString},
   147  			},
   148  
   149  			"port": {
   150  				Type:     schema.TypeInt,
   151  				Optional: true,
   152  				Computed: true,
   153  			},
   154  
   155  			// apply_immediately is used to determine when the update modifications
   156  			// take place.
   157  			// See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
   158  			"apply_immediately": {
   159  				Type:     schema.TypeBool,
   160  				Optional: true,
   161  				Computed: true,
   162  			},
   163  
   164  			"vpc_security_group_ids": {
   165  				Type:     schema.TypeSet,
   166  				Optional: true,
   167  				Computed: true,
   168  				Elem:     &schema.Schema{Type: schema.TypeString},
   169  				Set:      schema.HashString,
   170  			},
   171  
   172  			"preferred_backup_window": {
   173  				Type:         schema.TypeString,
   174  				Optional:     true,
   175  				Computed:     true,
   176  				ValidateFunc: validateOnceADayWindowFormat,
   177  			},
   178  
   179  			"preferred_maintenance_window": {
   180  				Type:     schema.TypeString,
   181  				Optional: true,
   182  				Computed: true,
   183  				StateFunc: func(val interface{}) string {
   184  					if val == nil {
   185  						return ""
   186  					}
   187  					return strings.ToLower(val.(string))
   188  				},
   189  				ValidateFunc: validateOnceAWeekWindowFormat,
   190  			},
   191  
   192  			"backup_retention_period": {
   193  				Type:     schema.TypeInt,
   194  				Optional: true,
   195  				Default:  1,
   196  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   197  					value := v.(int)
   198  					if value > 35 {
   199  						es = append(es, fmt.Errorf(
   200  							"backup retention period cannot be more than 35 days"))
   201  					}
   202  					return
   203  				},
   204  			},
   205  
   206  			"kms_key_id": {
   207  				Type:         schema.TypeString,
   208  				Optional:     true,
   209  				Computed:     true,
   210  				ForceNew:     true,
   211  				ValidateFunc: validateArn,
   212  			},
   213  
   214  			"replication_source_identifier": {
   215  				Type:     schema.TypeString,
   216  				Optional: true,
   217  			},
   218  
   219  			"tags": tagsSchema(),
   220  		},
   221  	}
   222  }
   223  
   224  func resourceAwsRdsClusterImport(
   225  	d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
   226  	// Neither skip_final_snapshot nor final_snapshot_identifier can be fetched
   227  	// from any API call, so we need to default skip_final_snapshot to true so
   228  	// that final_snapshot_identifier is not required
   229  	d.Set("skip_final_snapshot", true)
   230  	return []*schema.ResourceData{d}, nil
   231  }
   232  
   233  func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error {
   234  	conn := meta.(*AWSClient).rdsconn
   235  	tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
   236  
   237  	var identifier string
   238  	if v, ok := d.GetOk("cluster_identifier"); ok {
   239  		identifier = v.(string)
   240  	} else {
   241  		if v, ok := d.GetOk("cluster_identifier_prefix"); ok {
   242  			identifier = resource.PrefixedUniqueId(v.(string))
   243  		} else {
   244  			identifier = resource.PrefixedUniqueId("tf-")
   245  		}
   246  
   247  		d.Set("cluster_identifier", identifier)
   248  	}
   249  
   250  	if _, ok := d.GetOk("snapshot_identifier"); ok {
   251  		opts := rds.RestoreDBClusterFromSnapshotInput{
   252  			DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)),
   253  			SnapshotIdentifier:  aws.String(d.Get("snapshot_identifier").(string)),
   254  			Engine:              aws.String("aurora"),
   255  			Tags:                tags,
   256  		}
   257  
   258  		if attr := d.Get("availability_zones").(*schema.Set); attr.Len() > 0 {
   259  			opts.AvailabilityZones = expandStringList(attr.List())
   260  		}
   261  
   262  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   263  			opts.DBSubnetGroupName = aws.String(attr.(string))
   264  		}
   265  
   266  		if attr, ok := d.GetOk("database_name"); ok {
   267  			opts.DatabaseName = aws.String(attr.(string))
   268  		}
   269  
   270  		if attr, ok := d.GetOk("option_group_name"); ok {
   271  			opts.OptionGroupName = aws.String(attr.(string))
   272  		}
   273  
   274  		if attr, ok := d.GetOk("port"); ok {
   275  			opts.Port = aws.Int64(int64(attr.(int)))
   276  		}
   277  
   278  		var sgUpdate bool
   279  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   280  			sgUpdate = true
   281  			opts.VpcSecurityGroupIds = expandStringList(attr.List())
   282  		}
   283  
   284  		log.Printf("[DEBUG] RDS Cluster restore from snapshot configuration: %s", opts)
   285  		_, err := conn.RestoreDBClusterFromSnapshot(&opts)
   286  		if err != nil {
   287  			return fmt.Errorf("Error creating RDS Cluster: %s", err)
   288  		}
   289  
   290  		if sgUpdate {
   291  			log.Printf("[INFO] RDS Cluster is restoring from snapshot with default security, but custom security should be set, will now update after snapshot is restored!")
   292  
   293  			d.SetId(d.Get("cluster_identifier").(string))
   294  
   295  			log.Printf("[INFO] RDS Cluster Instance ID: %s", d.Id())
   296  
   297  			log.Println("[INFO] Waiting for RDS Cluster to be available")
   298  
   299  			stateConf := &resource.StateChangeConf{
   300  				Pending:    []string{"creating", "backing-up", "modifying"},
   301  				Target:     []string{"available"},
   302  				Refresh:    resourceAwsRDSClusterStateRefreshFunc(d, meta),
   303  				Timeout:    120 * time.Minute,
   304  				MinTimeout: 3 * time.Second,
   305  				Delay:      30 * time.Second, // Wait 30 secs before starting
   306  			}
   307  
   308  			// Wait, catching any errors
   309  			_, err := stateConf.WaitForState()
   310  			if err != nil {
   311  				return err
   312  			}
   313  
   314  			err = resourceAwsRDSClusterInstanceUpdate(d, meta)
   315  			if err != nil {
   316  				return err
   317  			}
   318  		}
   319  	} else if _, ok := d.GetOk("replication_source_identifier"); ok {
   320  		createOpts := &rds.CreateDBClusterInput{
   321  			DBClusterIdentifier:         aws.String(d.Get("cluster_identifier").(string)),
   322  			Engine:                      aws.String("aurora"),
   323  			StorageEncrypted:            aws.Bool(d.Get("storage_encrypted").(bool)),
   324  			ReplicationSourceIdentifier: aws.String(d.Get("replication_source_identifier").(string)),
   325  			Tags: tags,
   326  		}
   327  
   328  		if attr, ok := d.GetOk("port"); ok {
   329  			createOpts.Port = aws.Int64(int64(attr.(int)))
   330  		}
   331  
   332  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   333  			createOpts.DBSubnetGroupName = aws.String(attr.(string))
   334  		}
   335  
   336  		if attr, ok := d.GetOk("db_cluster_parameter_group_name"); ok {
   337  			createOpts.DBClusterParameterGroupName = aws.String(attr.(string))
   338  		}
   339  
   340  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   341  			createOpts.VpcSecurityGroupIds = expandStringList(attr.List())
   342  		}
   343  
   344  		if attr := d.Get("availability_zones").(*schema.Set); attr.Len() > 0 {
   345  			createOpts.AvailabilityZones = expandStringList(attr.List())
   346  		}
   347  
   348  		if v, ok := d.GetOk("backup_retention_period"); ok {
   349  			createOpts.BackupRetentionPeriod = aws.Int64(int64(v.(int)))
   350  		}
   351  
   352  		if v, ok := d.GetOk("preferred_backup_window"); ok {
   353  			createOpts.PreferredBackupWindow = aws.String(v.(string))
   354  		}
   355  
   356  		if v, ok := d.GetOk("preferred_maintenance_window"); ok {
   357  			createOpts.PreferredMaintenanceWindow = aws.String(v.(string))
   358  		}
   359  
   360  		if attr, ok := d.GetOk("kms_key_id"); ok {
   361  			createOpts.KmsKeyId = aws.String(attr.(string))
   362  		}
   363  
   364  		log.Printf("[DEBUG] Create RDS Cluster as read replica: %s", createOpts)
   365  		resp, err := conn.CreateDBCluster(createOpts)
   366  		if err != nil {
   367  			log.Printf("[ERROR] Error creating RDS Cluster: %s", err)
   368  			return err
   369  		}
   370  
   371  		log.Printf("[DEBUG]: RDS Cluster create response: %s", resp)
   372  
   373  	} else {
   374  		if _, ok := d.GetOk("master_password"); !ok {
   375  			return fmt.Errorf(`provider.aws: aws_rds_cluster: %s: "master_password": required field is not set`, d.Get("database_name").(string))
   376  		}
   377  
   378  		if _, ok := d.GetOk("master_username"); !ok {
   379  			return fmt.Errorf(`provider.aws: aws_rds_cluster: %s: "master_username": required field is not set`, d.Get("database_name").(string))
   380  		}
   381  
   382  		createOpts := &rds.CreateDBClusterInput{
   383  			DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)),
   384  			Engine:              aws.String("aurora"),
   385  			MasterUserPassword:  aws.String(d.Get("master_password").(string)),
   386  			MasterUsername:      aws.String(d.Get("master_username").(string)),
   387  			StorageEncrypted:    aws.Bool(d.Get("storage_encrypted").(bool)),
   388  			Tags:                tags,
   389  		}
   390  
   391  		if v := d.Get("database_name"); v.(string) != "" {
   392  			createOpts.DatabaseName = aws.String(v.(string))
   393  		}
   394  
   395  		if attr, ok := d.GetOk("port"); ok {
   396  			createOpts.Port = aws.Int64(int64(attr.(int)))
   397  		}
   398  
   399  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   400  			createOpts.DBSubnetGroupName = aws.String(attr.(string))
   401  		}
   402  
   403  		if attr, ok := d.GetOk("db_cluster_parameter_group_name"); ok {
   404  			createOpts.DBClusterParameterGroupName = aws.String(attr.(string))
   405  		}
   406  
   407  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   408  			createOpts.VpcSecurityGroupIds = expandStringList(attr.List())
   409  		}
   410  
   411  		if attr := d.Get("availability_zones").(*schema.Set); attr.Len() > 0 {
   412  			createOpts.AvailabilityZones = expandStringList(attr.List())
   413  		}
   414  
   415  		if v, ok := d.GetOk("backup_retention_period"); ok {
   416  			createOpts.BackupRetentionPeriod = aws.Int64(int64(v.(int)))
   417  		}
   418  
   419  		if v, ok := d.GetOk("preferred_backup_window"); ok {
   420  			createOpts.PreferredBackupWindow = aws.String(v.(string))
   421  		}
   422  
   423  		if v, ok := d.GetOk("preferred_maintenance_window"); ok {
   424  			createOpts.PreferredMaintenanceWindow = aws.String(v.(string))
   425  		}
   426  
   427  		if attr, ok := d.GetOk("kms_key_id"); ok {
   428  			createOpts.KmsKeyId = aws.String(attr.(string))
   429  		}
   430  
   431  		log.Printf("[DEBUG] RDS Cluster create options: %s", createOpts)
   432  		resp, err := conn.CreateDBCluster(createOpts)
   433  		if err != nil {
   434  			log.Printf("[ERROR] Error creating RDS Cluster: %s", err)
   435  			return err
   436  		}
   437  
   438  		log.Printf("[DEBUG]: RDS Cluster create response: %s", resp)
   439  	}
   440  
   441  	d.SetId(d.Get("cluster_identifier").(string))
   442  
   443  	log.Printf("[INFO] RDS Cluster ID: %s", d.Id())
   444  
   445  	log.Println(
   446  		"[INFO] Waiting for RDS Cluster to be available")
   447  
   448  	stateConf := &resource.StateChangeConf{
   449  		Pending:    []string{"creating", "backing-up", "modifying"},
   450  		Target:     []string{"available"},
   451  		Refresh:    resourceAwsRDSClusterStateRefreshFunc(d, meta),
   452  		Timeout:    120 * time.Minute,
   453  		MinTimeout: 3 * time.Second,
   454  	}
   455  
   456  	// Wait, catching any errors
   457  	_, err := stateConf.WaitForState()
   458  	if err != nil {
   459  		return fmt.Errorf("[WARN] Error waiting for RDS Cluster state to be \"available\": %s", err)
   460  	}
   461  
   462  	return resourceAwsRDSClusterRead(d, meta)
   463  }
   464  
   465  func resourceAwsRDSClusterRead(d *schema.ResourceData, meta interface{}) error {
   466  	conn := meta.(*AWSClient).rdsconn
   467  
   468  	resp, err := conn.DescribeDBClusters(&rds.DescribeDBClustersInput{
   469  		DBClusterIdentifier: aws.String(d.Id()),
   470  	})
   471  
   472  	if err != nil {
   473  		if awsErr, ok := err.(awserr.Error); ok {
   474  			if "DBClusterNotFoundFault" == awsErr.Code() {
   475  				d.SetId("")
   476  				log.Printf("[DEBUG] RDS Cluster (%s) not found", d.Id())
   477  				return nil
   478  			}
   479  		}
   480  		log.Printf("[DEBUG] Error describing RDS Cluster (%s)", d.Id())
   481  		return err
   482  	}
   483  
   484  	var dbc *rds.DBCluster
   485  	for _, c := range resp.DBClusters {
   486  		if *c.DBClusterIdentifier == d.Id() {
   487  			dbc = c
   488  		}
   489  	}
   490  
   491  	if dbc == nil {
   492  		log.Printf("[WARN] RDS Cluster (%s) not found", d.Id())
   493  		d.SetId("")
   494  		return nil
   495  	}
   496  
   497  	if err := d.Set("availability_zones", aws.StringValueSlice(dbc.AvailabilityZones)); err != nil {
   498  		return fmt.Errorf("[DEBUG] Error saving AvailabilityZones to state for RDS Cluster (%s): %s", d.Id(), err)
   499  	}
   500  
   501  	// Only set the DatabaseName if it is not nil. There is a known API bug where
   502  	// RDS accepts a DatabaseName but does not return it, causing a perpetual
   503  	// diff.
   504  	//	See https://github.com/hashicorp/terraform/issues/4671 for backstory
   505  	if dbc.DatabaseName != nil {
   506  		d.Set("database_name", dbc.DatabaseName)
   507  	}
   508  
   509  	d.Set("cluster_identifier", dbc.DBClusterIdentifier)
   510  	d.Set("db_subnet_group_name", dbc.DBSubnetGroup)
   511  	d.Set("db_cluster_parameter_group_name", dbc.DBClusterParameterGroup)
   512  	d.Set("endpoint", dbc.Endpoint)
   513  	d.Set("engine", dbc.Engine)
   514  	d.Set("master_username", dbc.MasterUsername)
   515  	d.Set("port", dbc.Port)
   516  	d.Set("storage_encrypted", dbc.StorageEncrypted)
   517  	d.Set("backup_retention_period", dbc.BackupRetentionPeriod)
   518  	d.Set("preferred_backup_window", dbc.PreferredBackupWindow)
   519  	d.Set("preferred_maintenance_window", dbc.PreferredMaintenanceWindow)
   520  	d.Set("kms_key_id", dbc.KmsKeyId)
   521  	d.Set("reader_endpoint", dbc.ReaderEndpoint)
   522  	d.Set("replication_source_identifier", dbc.ReplicationSourceIdentifier)
   523  
   524  	var vpcg []string
   525  	for _, g := range dbc.VpcSecurityGroups {
   526  		vpcg = append(vpcg, *g.VpcSecurityGroupId)
   527  	}
   528  	if err := d.Set("vpc_security_group_ids", vpcg); err != nil {
   529  		return fmt.Errorf("[DEBUG] Error saving VPC Security Group IDs to state for RDS Cluster (%s): %s", d.Id(), err)
   530  	}
   531  
   532  	var cm []string
   533  	for _, m := range dbc.DBClusterMembers {
   534  		cm = append(cm, *m.DBInstanceIdentifier)
   535  	}
   536  	if err := d.Set("cluster_members", cm); err != nil {
   537  		return fmt.Errorf("[DEBUG] Error saving RDS Cluster Members to state for RDS Cluster (%s): %s", d.Id(), err)
   538  	}
   539  
   540  	// Fetch and save tags
   541  	arn, err := buildRDSClusterARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region)
   542  	if err != nil {
   543  		log.Printf("[DEBUG] Error building ARN for RDS Cluster (%s), not setting Tags", *dbc.DBClusterIdentifier)
   544  	} else {
   545  		if err := saveTagsRDS(conn, d, arn); err != nil {
   546  			log.Printf("[WARN] Failed to save tags for RDS Cluster (%s): %s", *dbc.DBClusterIdentifier, err)
   547  		}
   548  	}
   549  
   550  	return nil
   551  }
   552  
   553  func resourceAwsRDSClusterUpdate(d *schema.ResourceData, meta interface{}) error {
   554  	conn := meta.(*AWSClient).rdsconn
   555  	requestUpdate := false
   556  
   557  	req := &rds.ModifyDBClusterInput{
   558  		ApplyImmediately:    aws.Bool(d.Get("apply_immediately").(bool)),
   559  		DBClusterIdentifier: aws.String(d.Id()),
   560  	}
   561  
   562  	if d.HasChange("master_password") {
   563  		req.MasterUserPassword = aws.String(d.Get("master_password").(string))
   564  		requestUpdate = true
   565  	}
   566  
   567  	if d.HasChange("vpc_security_group_ids") {
   568  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   569  			req.VpcSecurityGroupIds = expandStringList(attr.List())
   570  		} else {
   571  			req.VpcSecurityGroupIds = []*string{}
   572  		}
   573  		requestUpdate = true
   574  	}
   575  
   576  	if d.HasChange("preferred_backup_window") {
   577  		req.PreferredBackupWindow = aws.String(d.Get("preferred_backup_window").(string))
   578  		requestUpdate = true
   579  	}
   580  
   581  	if d.HasChange("preferred_maintenance_window") {
   582  		req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string))
   583  		requestUpdate = true
   584  	}
   585  
   586  	if d.HasChange("backup_retention_period") {
   587  		req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int)))
   588  		requestUpdate = true
   589  	}
   590  
   591  	if d.HasChange("db_cluster_parameter_group_name") {
   592  		d.SetPartial("db_cluster_parameter_group_name")
   593  		req.DBClusterParameterGroupName = aws.String(d.Get("db_cluster_parameter_group_name").(string))
   594  		requestUpdate = true
   595  	}
   596  
   597  	if requestUpdate {
   598  		_, err := conn.ModifyDBCluster(req)
   599  		if err != nil {
   600  			return fmt.Errorf("[WARN] Error modifying RDS Cluster (%s): %s", d.Id(), err)
   601  		}
   602  	}
   603  
   604  	if arn, err := buildRDSClusterARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region); err == nil {
   605  		if err := setTagsRDS(conn, d, arn); err != nil {
   606  			return err
   607  		} else {
   608  			d.SetPartial("tags")
   609  		}
   610  	}
   611  
   612  	return resourceAwsRDSClusterRead(d, meta)
   613  }
   614  
   615  func resourceAwsRDSClusterDelete(d *schema.ResourceData, meta interface{}) error {
   616  	conn := meta.(*AWSClient).rdsconn
   617  	log.Printf("[DEBUG] Destroying RDS Cluster (%s)", d.Id())
   618  
   619  	deleteOpts := rds.DeleteDBClusterInput{
   620  		DBClusterIdentifier: aws.String(d.Id()),
   621  	}
   622  
   623  	skipFinalSnapshot := d.Get("skip_final_snapshot").(bool)
   624  	deleteOpts.SkipFinalSnapshot = aws.Bool(skipFinalSnapshot)
   625  
   626  	if skipFinalSnapshot == false {
   627  		if name, present := d.GetOk("final_snapshot_identifier"); present {
   628  			deleteOpts.FinalDBSnapshotIdentifier = aws.String(name.(string))
   629  		} else {
   630  			return fmt.Errorf("RDS Cluster FinalSnapshotIdentifier is required when a final snapshot is required")
   631  		}
   632  	}
   633  
   634  	log.Printf("[DEBUG] RDS Cluster delete options: %s", deleteOpts)
   635  	_, err := conn.DeleteDBCluster(&deleteOpts)
   636  	if err != nil {
   637  		if awsErr, ok := err.(awserr.Error); ok {
   638  			if "InvalidDBClusterStateFault" == awsErr.Code() {
   639  				return fmt.Errorf("RDS Cluster cannot be deleted: %s", awsErr.Message())
   640  			}
   641  		}
   642  	}
   643  
   644  	stateConf := &resource.StateChangeConf{
   645  		Pending:    []string{"available", "deleting", "backing-up", "modifying"},
   646  		Target:     []string{"destroyed"},
   647  		Refresh:    resourceAwsRDSClusterStateRefreshFunc(d, meta),
   648  		Timeout:    15 * time.Minute,
   649  		MinTimeout: 3 * time.Second,
   650  	}
   651  
   652  	// Wait, catching any errors
   653  	_, err = stateConf.WaitForState()
   654  	if err != nil {
   655  		return fmt.Errorf("[WARN] Error deleting RDS Cluster (%s): %s", d.Id(), err)
   656  	}
   657  
   658  	return nil
   659  }
   660  
   661  func resourceAwsRDSClusterStateRefreshFunc(
   662  	d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
   663  	return func() (interface{}, string, error) {
   664  		conn := meta.(*AWSClient).rdsconn
   665  
   666  		resp, err := conn.DescribeDBClusters(&rds.DescribeDBClustersInput{
   667  			DBClusterIdentifier: aws.String(d.Id()),
   668  		})
   669  
   670  		if err != nil {
   671  			if awsErr, ok := err.(awserr.Error); ok {
   672  				if "DBClusterNotFoundFault" == awsErr.Code() {
   673  					return 42, "destroyed", nil
   674  				}
   675  			}
   676  			log.Printf("[WARN] Error on retrieving DB Cluster (%s) when waiting: %s", d.Id(), err)
   677  			return nil, "", err
   678  		}
   679  
   680  		var dbc *rds.DBCluster
   681  
   682  		for _, c := range resp.DBClusters {
   683  			if *c.DBClusterIdentifier == d.Id() {
   684  				dbc = c
   685  			}
   686  		}
   687  
   688  		if dbc == nil {
   689  			return 42, "destroyed", nil
   690  		}
   691  
   692  		if dbc.Status != nil {
   693  			log.Printf("[DEBUG] DB Cluster status (%s): %s", d.Id(), *dbc.Status)
   694  		}
   695  
   696  		return dbc, *dbc.Status, nil
   697  	}
   698  }
   699  
   700  func buildRDSClusterARN(identifier, partition, accountid, region string) (string, error) {
   701  	if partition == "" {
   702  		return "", fmt.Errorf("Unable to construct RDS Cluster ARN because of missing AWS partition")
   703  	}
   704  	if accountid == "" {
   705  		return "", fmt.Errorf("Unable to construct RDS Cluster ARN because of missing AWS Account ID")
   706  	}
   707  
   708  	arn := fmt.Sprintf("arn:%s:rds:%s:%s:cluster:%s", partition, region, accountid, identifier)
   709  	return arn, nil
   710  
   711  }