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