github.com/sathiyas/terraform@v0.6.9-0.20151210233947-3330da00b997/builtin/providers/aws/resource_aws_db_instance.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/iam"
    13  	"github.com/aws/aws-sdk-go/service/rds"
    14  
    15  	"github.com/hashicorp/terraform/helper/resource"
    16  	"github.com/hashicorp/terraform/helper/schema"
    17  )
    18  
    19  func resourceAwsDbInstance() *schema.Resource {
    20  	return &schema.Resource{
    21  		Create: resourceAwsDbInstanceCreate,
    22  		Read:   resourceAwsDbInstanceRead,
    23  		Update: resourceAwsDbInstanceUpdate,
    24  		Delete: resourceAwsDbInstanceDelete,
    25  
    26  		Schema: map[string]*schema.Schema{
    27  			"name": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Optional: true,
    30  				Computed: true,
    31  				ForceNew: true,
    32  			},
    33  
    34  			"arn": &schema.Schema{
    35  				Type:     schema.TypeString,
    36  				Computed: true,
    37  			},
    38  
    39  			"username": &schema.Schema{
    40  				Type:     schema.TypeString,
    41  				Required: true,
    42  				ForceNew: true,
    43  			},
    44  
    45  			"password": &schema.Schema{
    46  				Type:     schema.TypeString,
    47  				Required: true,
    48  			},
    49  
    50  			"engine": &schema.Schema{
    51  				Type:     schema.TypeString,
    52  				Required: true,
    53  				ForceNew: true,
    54  				StateFunc: func(v interface{}) string {
    55  					value := v.(string)
    56  					return strings.ToLower(value)
    57  				},
    58  			},
    59  
    60  			"engine_version": &schema.Schema{
    61  				Type:     schema.TypeString,
    62  				Optional: true,
    63  				Computed: true,
    64  			},
    65  
    66  			"storage_encrypted": &schema.Schema{
    67  				Type:     schema.TypeBool,
    68  				Optional: true,
    69  				ForceNew: true,
    70  			},
    71  
    72  			"allocated_storage": &schema.Schema{
    73  				Type:     schema.TypeInt,
    74  				Required: true,
    75  			},
    76  
    77  			"storage_type": &schema.Schema{
    78  				Type:     schema.TypeString,
    79  				Optional: true,
    80  				Computed: true,
    81  			},
    82  
    83  			"identifier": &schema.Schema{
    84  				Type:         schema.TypeString,
    85  				Required:     true,
    86  				ForceNew:     true,
    87  				ValidateFunc: validateRdsId,
    88  			},
    89  
    90  			"instance_class": &schema.Schema{
    91  				Type:     schema.TypeString,
    92  				Required: true,
    93  			},
    94  
    95  			"availability_zone": &schema.Schema{
    96  				Type:     schema.TypeString,
    97  				Optional: true,
    98  				Computed: true,
    99  				ForceNew: true,
   100  			},
   101  
   102  			"backup_retention_period": &schema.Schema{
   103  				Type:     schema.TypeInt,
   104  				Optional: true,
   105  				Computed: true,
   106  			},
   107  
   108  			"backup_window": &schema.Schema{
   109  				Type:     schema.TypeString,
   110  				Optional: true,
   111  				Computed: true,
   112  			},
   113  
   114  			"iops": &schema.Schema{
   115  				Type:     schema.TypeInt,
   116  				Optional: true,
   117  			},
   118  
   119  			"license_model": &schema.Schema{
   120  				Type:     schema.TypeString,
   121  				Optional: true,
   122  				Computed: true,
   123  			},
   124  
   125  			"maintenance_window": &schema.Schema{
   126  				Type:     schema.TypeString,
   127  				Optional: true,
   128  				Computed: true,
   129  				StateFunc: func(v interface{}) string {
   130  					if v != nil {
   131  						value := v.(string)
   132  						return strings.ToLower(value)
   133  					}
   134  					return ""
   135  				},
   136  			},
   137  
   138  			"multi_az": &schema.Schema{
   139  				Type:     schema.TypeBool,
   140  				Optional: true,
   141  				Computed: true,
   142  			},
   143  
   144  			"port": &schema.Schema{
   145  				Type:     schema.TypeInt,
   146  				Optional: true,
   147  				Computed: true,
   148  				ForceNew: true,
   149  			},
   150  
   151  			"publicly_accessible": &schema.Schema{
   152  				Type:     schema.TypeBool,
   153  				Optional: true,
   154  				Computed: true,
   155  			},
   156  
   157  			"vpc_security_group_ids": &schema.Schema{
   158  				Type:     schema.TypeSet,
   159  				Optional: true,
   160  				Computed: true,
   161  				Elem:     &schema.Schema{Type: schema.TypeString},
   162  				Set:      schema.HashString,
   163  			},
   164  
   165  			"security_group_names": &schema.Schema{
   166  				Type:     schema.TypeSet,
   167  				Optional: true,
   168  				Elem:     &schema.Schema{Type: schema.TypeString},
   169  				Set:      schema.HashString,
   170  			},
   171  
   172  			"final_snapshot_identifier": &schema.Schema{
   173  				Type:     schema.TypeString,
   174  				Optional: true,
   175  				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
   176  					value := v.(string)
   177  					if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) {
   178  						es = append(es, fmt.Errorf(
   179  							"only alphanumeric characters and hyphens allowed in %q", k))
   180  					}
   181  					if regexp.MustCompile(`--`).MatchString(value) {
   182  						es = append(es, fmt.Errorf("%q cannot contain two consecutive hyphens", k))
   183  					}
   184  					if regexp.MustCompile(`-$`).MatchString(value) {
   185  						es = append(es, fmt.Errorf("%q cannot end in a hyphen", k))
   186  					}
   187  					return
   188  				},
   189  			},
   190  
   191  			"skip_final_snapshot": &schema.Schema{
   192  				Type:     schema.TypeBool,
   193  				Optional: true,
   194  				Default:  true,
   195  			},
   196  
   197  			"copy_tags_to_snapshot": &schema.Schema{
   198  				Type:     schema.TypeBool,
   199  				Optional: true,
   200  				Default:  false,
   201  			},
   202  
   203  			"db_subnet_group_name": &schema.Schema{
   204  				Type:     schema.TypeString,
   205  				Optional: true,
   206  				ForceNew: true,
   207  				Computed: true,
   208  			},
   209  
   210  			"parameter_group_name": &schema.Schema{
   211  				Type:     schema.TypeString,
   212  				Optional: true,
   213  				Computed: true,
   214  			},
   215  
   216  			"address": &schema.Schema{
   217  				Type:     schema.TypeString,
   218  				Computed: true,
   219  			},
   220  
   221  			"endpoint": &schema.Schema{
   222  				Type:     schema.TypeString,
   223  				Computed: true,
   224  			},
   225  
   226  			"status": &schema.Schema{
   227  				Type:     schema.TypeString,
   228  				Computed: true,
   229  			},
   230  
   231  			// apply_immediately is used to determine when the update modifications
   232  			// take place.
   233  			// See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
   234  			"apply_immediately": &schema.Schema{
   235  				Type:     schema.TypeBool,
   236  				Optional: true,
   237  				Computed: true,
   238  			},
   239  
   240  			"replicate_source_db": &schema.Schema{
   241  				Type:     schema.TypeString,
   242  				Optional: true,
   243  			},
   244  
   245  			"replicas": &schema.Schema{
   246  				Type:     schema.TypeList,
   247  				Computed: true,
   248  				Elem:     &schema.Schema{Type: schema.TypeString},
   249  			},
   250  
   251  			"snapshot_identifier": &schema.Schema{
   252  				Type:     schema.TypeString,
   253  				Computed: false,
   254  				Optional: true,
   255  				Elem:     &schema.Schema{Type: schema.TypeString},
   256  			},
   257  
   258  			"auto_minor_version_upgrade": &schema.Schema{
   259  				Type:     schema.TypeBool,
   260  				Optional: true,
   261  				Default:  true,
   262  			},
   263  
   264  			"allow_major_version_upgrade": &schema.Schema{
   265  				Type:     schema.TypeBool,
   266  				Computed: false,
   267  				Optional: true,
   268  			},
   269  
   270  			"tags": tagsSchema(),
   271  		},
   272  	}
   273  }
   274  
   275  func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error {
   276  	conn := meta.(*AWSClient).rdsconn
   277  	tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
   278  
   279  	if v, ok := d.GetOk("replicate_source_db"); ok {
   280  		opts := rds.CreateDBInstanceReadReplicaInput{
   281  			SourceDBInstanceIdentifier: aws.String(v.(string)),
   282  			CopyTagsToSnapshot:         aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
   283  			DBInstanceClass:            aws.String(d.Get("instance_class").(string)),
   284  			DBInstanceIdentifier:       aws.String(d.Get("identifier").(string)),
   285  			Tags:                       tags,
   286  		}
   287  		if attr, ok := d.GetOk("iops"); ok {
   288  			opts.Iops = aws.Int64(int64(attr.(int)))
   289  		}
   290  
   291  		if attr, ok := d.GetOk("port"); ok {
   292  			opts.Port = aws.Int64(int64(attr.(int)))
   293  		}
   294  
   295  		if attr, ok := d.GetOk("availability_zone"); ok {
   296  			opts.AvailabilityZone = aws.String(attr.(string))
   297  		}
   298  
   299  		if attr, ok := d.GetOk("storage_type"); ok {
   300  			opts.StorageType = aws.String(attr.(string))
   301  		}
   302  
   303  		if attr, ok := d.GetOk("publicly_accessible"); ok {
   304  			opts.PubliclyAccessible = aws.Bool(attr.(bool))
   305  		}
   306  
   307  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   308  			opts.DBSubnetGroupName = aws.String(attr.(string))
   309  		}
   310  
   311  		log.Printf("[DEBUG] DB Instance Replica create configuration: %#v", opts)
   312  		_, err := conn.CreateDBInstanceReadReplica(&opts)
   313  		if err != nil {
   314  			return fmt.Errorf("Error creating DB Instance: %s", err)
   315  		}
   316  	} else if _, ok := d.GetOk("snapshot_identifier"); ok {
   317  		opts := rds.RestoreDBInstanceFromDBSnapshotInput{
   318  			DBInstanceClass:         aws.String(d.Get("instance_class").(string)),
   319  			DBInstanceIdentifier:    aws.String(d.Get("identifier").(string)),
   320  			DBSnapshotIdentifier:    aws.String(d.Get("snapshot_identifier").(string)),
   321  			AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
   322  			Tags: tags,
   323  		}
   324  
   325  		if attr, ok := d.GetOk("availability_zone"); ok {
   326  			opts.AvailabilityZone = aws.String(attr.(string))
   327  		}
   328  
   329  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   330  			opts.DBSubnetGroupName = aws.String(attr.(string))
   331  		}
   332  
   333  		if attr, ok := d.GetOk("engine"); ok {
   334  			opts.Engine = aws.String(attr.(string))
   335  		}
   336  
   337  		if attr, ok := d.GetOk("iops"); ok {
   338  			opts.Iops = aws.Int64(int64(attr.(int)))
   339  		}
   340  
   341  		if attr, ok := d.GetOk("license_model"); ok {
   342  			opts.LicenseModel = aws.String(attr.(string))
   343  		}
   344  
   345  		if attr, ok := d.GetOk("multi_az"); ok {
   346  			opts.MultiAZ = aws.Bool(attr.(bool))
   347  		}
   348  
   349  		if attr, ok := d.GetOk("option_group_name"); ok {
   350  			opts.OptionGroupName = aws.String(attr.(string))
   351  		}
   352  
   353  		if attr, ok := d.GetOk("port"); ok {
   354  			opts.Port = aws.Int64(int64(attr.(int)))
   355  		}
   356  
   357  		if attr, ok := d.GetOk("publicly_accessible"); ok {
   358  			opts.PubliclyAccessible = aws.Bool(attr.(bool))
   359  		}
   360  
   361  		if attr, ok := d.GetOk("tde_credential_arn"); ok {
   362  			opts.TdeCredentialArn = aws.String(attr.(string))
   363  		}
   364  
   365  		if attr, ok := d.GetOk("storage_type"); ok {
   366  			opts.StorageType = aws.String(attr.(string))
   367  		}
   368  
   369  		_, err := conn.RestoreDBInstanceFromDBSnapshot(&opts)
   370  		if err != nil {
   371  			return fmt.Errorf("Error creating DB Instance: %s", err)
   372  		}
   373  
   374  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   375  			log.Printf("[INFO] DB is restoring from snapshot with default security, but custom security should be set, will now update after snapshot is restored!")
   376  
   377  			// wait for instance to get up and then modify security
   378  			d.SetId(d.Get("identifier").(string))
   379  
   380  			log.Printf("[INFO] DB Instance ID: %s", d.Id())
   381  
   382  			log.Println(
   383  				"[INFO] Waiting for DB Instance to be available")
   384  
   385  			stateConf := &resource.StateChangeConf{
   386  				Pending:    []string{"creating", "backing-up", "modifying"},
   387  				Target:     "available",
   388  				Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   389  				Timeout:    40 * time.Minute,
   390  				MinTimeout: 10 * time.Second,
   391  				Delay:      30 * time.Second, // Wait 30 secs before starting
   392  			}
   393  
   394  			// Wait, catching any errors
   395  			_, err := stateConf.WaitForState()
   396  			if err != nil {
   397  				return err
   398  			}
   399  
   400  			err = resourceAwsDbInstanceUpdate(d, meta)
   401  			if err != nil {
   402  				return err
   403  			}
   404  
   405  		}
   406  	} else {
   407  		opts := rds.CreateDBInstanceInput{
   408  			AllocatedStorage:        aws.Int64(int64(d.Get("allocated_storage").(int))),
   409  			DBName:                  aws.String(d.Get("name").(string)),
   410  			DBInstanceClass:         aws.String(d.Get("instance_class").(string)),
   411  			DBInstanceIdentifier:    aws.String(d.Get("identifier").(string)),
   412  			MasterUsername:          aws.String(d.Get("username").(string)),
   413  			MasterUserPassword:      aws.String(d.Get("password").(string)),
   414  			Engine:                  aws.String(d.Get("engine").(string)),
   415  			EngineVersion:           aws.String(d.Get("engine_version").(string)),
   416  			StorageEncrypted:        aws.Bool(d.Get("storage_encrypted").(bool)),
   417  			AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
   418  			Tags: tags,
   419  		}
   420  
   421  		attr := d.Get("backup_retention_period")
   422  		opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int)))
   423  		if attr, ok := d.GetOk("multi_az"); ok {
   424  			opts.MultiAZ = aws.Bool(attr.(bool))
   425  		}
   426  
   427  		if attr, ok := d.GetOk("maintenance_window"); ok {
   428  			opts.PreferredMaintenanceWindow = aws.String(attr.(string))
   429  		}
   430  
   431  		if attr, ok := d.GetOk("backup_window"); ok {
   432  			opts.PreferredBackupWindow = aws.String(attr.(string))
   433  		}
   434  
   435  		if attr, ok := d.GetOk("license_model"); ok {
   436  			opts.LicenseModel = aws.String(attr.(string))
   437  		}
   438  		if attr, ok := d.GetOk("parameter_group_name"); ok {
   439  			opts.DBParameterGroupName = aws.String(attr.(string))
   440  		}
   441  
   442  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   443  			var s []*string
   444  			for _, v := range attr.List() {
   445  				s = append(s, aws.String(v.(string)))
   446  			}
   447  			opts.VpcSecurityGroupIds = s
   448  		}
   449  
   450  		if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 {
   451  			var s []*string
   452  			for _, v := range attr.List() {
   453  				s = append(s, aws.String(v.(string)))
   454  			}
   455  			opts.DBSecurityGroups = s
   456  		}
   457  		if attr, ok := d.GetOk("storage_type"); ok {
   458  			opts.StorageType = aws.String(attr.(string))
   459  		}
   460  
   461  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   462  			opts.DBSubnetGroupName = aws.String(attr.(string))
   463  		}
   464  
   465  		if attr, ok := d.GetOk("iops"); ok {
   466  			opts.Iops = aws.Int64(int64(attr.(int)))
   467  		}
   468  
   469  		if attr, ok := d.GetOk("port"); ok {
   470  			opts.Port = aws.Int64(int64(attr.(int)))
   471  		}
   472  
   473  		if attr, ok := d.GetOk("availability_zone"); ok {
   474  			opts.AvailabilityZone = aws.String(attr.(string))
   475  		}
   476  
   477  		if attr, ok := d.GetOk("publicly_accessible"); ok {
   478  			opts.PubliclyAccessible = aws.Bool(attr.(bool))
   479  		}
   480  
   481  		log.Printf("[DEBUG] DB Instance create configuration: %#v", opts)
   482  		var err error
   483  		_, err = conn.CreateDBInstance(&opts)
   484  		if err != nil {
   485  			return fmt.Errorf("Error creating DB Instance: %s", err)
   486  		}
   487  	}
   488  
   489  	d.SetId(d.Get("identifier").(string))
   490  
   491  	log.Printf("[INFO] DB Instance ID: %s", d.Id())
   492  
   493  	log.Println(
   494  		"[INFO] Waiting for DB Instance to be available")
   495  
   496  	stateConf := &resource.StateChangeConf{
   497  		Pending:    []string{"creating", "backing-up", "modifying"},
   498  		Target:     "available",
   499  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   500  		Timeout:    40 * time.Minute,
   501  		MinTimeout: 10 * time.Second,
   502  		Delay:      30 * time.Second, // Wait 30 secs before starting
   503  	}
   504  
   505  	// Wait, catching any errors
   506  	_, err := stateConf.WaitForState()
   507  	if err != nil {
   508  		return err
   509  	}
   510  
   511  	return resourceAwsDbInstanceRead(d, meta)
   512  }
   513  
   514  func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error {
   515  	v, err := resourceAwsDbInstanceRetrieve(d, meta)
   516  
   517  	if err != nil {
   518  		return err
   519  	}
   520  	if v == nil {
   521  		d.SetId("")
   522  		return nil
   523  	}
   524  
   525  	d.Set("name", v.DBName)
   526  	d.Set("username", v.MasterUsername)
   527  	d.Set("engine", v.Engine)
   528  	d.Set("engine_version", v.EngineVersion)
   529  	d.Set("allocated_storage", v.AllocatedStorage)
   530  	d.Set("copy_tags_to_snapshot", v.CopyTagsToSnapshot)
   531  	d.Set("auto_minor_version_upgrade", v.AutoMinorVersionUpgrade)
   532  	d.Set("storage_type", v.StorageType)
   533  	d.Set("instance_class", v.DBInstanceClass)
   534  	d.Set("availability_zone", v.AvailabilityZone)
   535  	d.Set("backup_retention_period", v.BackupRetentionPeriod)
   536  	d.Set("backup_window", v.PreferredBackupWindow)
   537  	d.Set("license_model", v.LicenseModel)
   538  	d.Set("maintenance_window", v.PreferredMaintenanceWindow)
   539  	d.Set("multi_az", v.MultiAZ)
   540  	if v.DBSubnetGroup != nil {
   541  		d.Set("db_subnet_group_name", v.DBSubnetGroup.DBSubnetGroupName)
   542  	}
   543  
   544  	if len(v.DBParameterGroups) > 0 {
   545  		d.Set("parameter_group_name", v.DBParameterGroups[0].DBParameterGroupName)
   546  	}
   547  
   548  	if v.Endpoint != nil {
   549  		d.Set("port", v.Endpoint.Port)
   550  		d.Set("address", v.Endpoint.Address)
   551  
   552  		if v.Endpoint.Address != nil && v.Endpoint.Port != nil {
   553  			d.Set("endpoint",
   554  				fmt.Sprintf("%s:%d", *v.Endpoint.Address, *v.Endpoint.Port))
   555  		}
   556  	}
   557  
   558  	d.Set("status", v.DBInstanceStatus)
   559  	d.Set("storage_encrypted", v.StorageEncrypted)
   560  
   561  	// list tags for resource
   562  	// set tags
   563  	conn := meta.(*AWSClient).rdsconn
   564  	arn, err := buildRDSARN(d, meta)
   565  	if err != nil {
   566  		name := "<empty>"
   567  		if v.DBName != nil && *v.DBName != "" {
   568  			name = *v.DBName
   569  		}
   570  		log.Printf("[DEBUG] Error building ARN for DB Instance, not setting Tags for DB %s", name)
   571  	} else {
   572  		d.Set("arn", arn)
   573  		resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{
   574  			ResourceName: aws.String(arn),
   575  		})
   576  
   577  		if err != nil {
   578  			log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn)
   579  		}
   580  
   581  		var dt []*rds.Tag
   582  		if len(resp.TagList) > 0 {
   583  			dt = resp.TagList
   584  		}
   585  		d.Set("tags", tagsToMapRDS(dt))
   586  	}
   587  
   588  	// Create an empty schema.Set to hold all vpc security group ids
   589  	ids := &schema.Set{
   590  		F: schema.HashString,
   591  	}
   592  	for _, v := range v.VpcSecurityGroups {
   593  		ids.Add(*v.VpcSecurityGroupId)
   594  	}
   595  	d.Set("vpc_security_group_ids", ids)
   596  
   597  	// Create an empty schema.Set to hold all security group names
   598  	sgn := &schema.Set{
   599  		F: schema.HashString,
   600  	}
   601  	for _, v := range v.DBSecurityGroups {
   602  		sgn.Add(*v.DBSecurityGroupName)
   603  	}
   604  	d.Set("security_group_names", sgn)
   605  
   606  	// replica things
   607  
   608  	var replicas []string
   609  	for _, v := range v.ReadReplicaDBInstanceIdentifiers {
   610  		replicas = append(replicas, *v)
   611  	}
   612  	if err := d.Set("replicas", replicas); err != nil {
   613  		return fmt.Errorf("[DEBUG] Error setting replicas attribute: %#v, error: %#v", replicas, err)
   614  	}
   615  
   616  	d.Set("replicate_source_db", v.ReadReplicaSourceDBInstanceIdentifier)
   617  
   618  	return nil
   619  }
   620  
   621  func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error {
   622  	conn := meta.(*AWSClient).rdsconn
   623  
   624  	log.Printf("[DEBUG] DB Instance destroy: %v", d.Id())
   625  
   626  	opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())}
   627  
   628  	skipFinalSnapshot := d.Get("skip_final_snapshot").(bool)
   629  	opts.SkipFinalSnapshot = aws.Bool(skipFinalSnapshot)
   630  
   631  	if !skipFinalSnapshot {
   632  		if name, present := d.GetOk("final_snapshot_identifier"); present {
   633  			opts.FinalDBSnapshotIdentifier = aws.String(name.(string))
   634  		} else {
   635  			return fmt.Errorf("DB Instance FinalSnapshotIdentifier is required when a final snapshot is required")
   636  		}
   637  	}
   638  
   639  	log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts)
   640  	if _, err := conn.DeleteDBInstance(&opts); err != nil {
   641  		return err
   642  	}
   643  
   644  	log.Println(
   645  		"[INFO] Waiting for DB Instance to be destroyed")
   646  	stateConf := &resource.StateChangeConf{
   647  		Pending: []string{"creating", "backing-up",
   648  			"modifying", "deleting", "available"},
   649  		Target:     "",
   650  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   651  		Timeout:    40 * time.Minute,
   652  		MinTimeout: 10 * time.Second,
   653  		Delay:      30 * time.Second, // Wait 30 secs before starting
   654  	}
   655  	if _, err := stateConf.WaitForState(); err != nil {
   656  		return err
   657  	}
   658  
   659  	return nil
   660  }
   661  
   662  func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
   663  	conn := meta.(*AWSClient).rdsconn
   664  
   665  	d.Partial(true)
   666  
   667  	req := &rds.ModifyDBInstanceInput{
   668  		ApplyImmediately:     aws.Bool(d.Get("apply_immediately").(bool)),
   669  		DBInstanceIdentifier: aws.String(d.Id()),
   670  	}
   671  	d.SetPartial("apply_immediately")
   672  
   673  	requestUpdate := false
   674  	if d.HasChange("allocated_storage") {
   675  		d.SetPartial("allocated_storage")
   676  		req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int)))
   677  		requestUpdate = true
   678  	}
   679  	if d.HasChange("allow_major_version_upgrade") {
   680  		d.SetPartial("allow_major_version_upgrade")
   681  		req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool))
   682  		requestUpdate = true
   683  	}
   684  	if d.HasChange("backup_retention_period") {
   685  		d.SetPartial("backup_retention_period")
   686  		req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int)))
   687  		requestUpdate = true
   688  	}
   689  	if d.HasChange("copy_tags_to_snapshot") {
   690  		d.SetPartial("copy_tags_to_snapshot")
   691  		req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool))
   692  		requestUpdate = true
   693  	}
   694  	if d.HasChange("instance_class") {
   695  		d.SetPartial("instance_class")
   696  		req.DBInstanceClass = aws.String(d.Get("instance_class").(string))
   697  		requestUpdate = true
   698  	}
   699  	if d.HasChange("parameter_group_name") {
   700  		d.SetPartial("parameter_group_name")
   701  		req.DBParameterGroupName = aws.String(d.Get("parameter_group_name").(string))
   702  		requestUpdate = true
   703  	}
   704  	if d.HasChange("engine_version") {
   705  		d.SetPartial("engine_version")
   706  		req.EngineVersion = aws.String(d.Get("engine_version").(string))
   707  		requestUpdate = true
   708  	}
   709  	if d.HasChange("iops") {
   710  		d.SetPartial("iops")
   711  		req.Iops = aws.Int64(int64(d.Get("iops").(int)))
   712  		requestUpdate = true
   713  	}
   714  	if d.HasChange("backup_window") {
   715  		d.SetPartial("backup_window")
   716  		req.PreferredBackupWindow = aws.String(d.Get("backup_window").(string))
   717  		requestUpdate = true
   718  	}
   719  	if d.HasChange("maintenance_window") {
   720  		d.SetPartial("maintenance_window")
   721  		req.PreferredMaintenanceWindow = aws.String(d.Get("maintenance_window").(string))
   722  		requestUpdate = true
   723  	}
   724  	if d.HasChange("password") {
   725  		d.SetPartial("password")
   726  		req.MasterUserPassword = aws.String(d.Get("password").(string))
   727  		requestUpdate = true
   728  	}
   729  	if d.HasChange("multi_az") {
   730  		d.SetPartial("multi_az")
   731  		req.MultiAZ = aws.Bool(d.Get("multi_az").(bool))
   732  		requestUpdate = true
   733  	}
   734  	if d.HasChange("publicly_accessible") {
   735  		d.SetPartial("publicly_accessible")
   736  		req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool))
   737  		requestUpdate = true
   738  	}
   739  	if d.HasChange("storage_type") {
   740  		d.SetPartial("storage_type")
   741  		req.StorageType = aws.String(d.Get("storage_type").(string))
   742  		requestUpdate = true
   743  	}
   744  	if d.HasChange("auto_minor_version_upgrade") {
   745  		d.SetPartial("auto_minor_version_upgrade")
   746  		req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool))
   747  		requestUpdate = true
   748  	}
   749  
   750  	if d.HasChange("vpc_security_group_ids") {
   751  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   752  			var s []*string
   753  			for _, v := range attr.List() {
   754  				s = append(s, aws.String(v.(string)))
   755  			}
   756  			req.VpcSecurityGroupIds = s
   757  		}
   758  		requestUpdate = true
   759  	}
   760  
   761  	if d.HasChange("vpc_security_group_ids") {
   762  		if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 {
   763  			var s []*string
   764  			for _, v := range attr.List() {
   765  				s = append(s, aws.String(v.(string)))
   766  			}
   767  			req.DBSecurityGroups = s
   768  		}
   769  		requestUpdate = true
   770  	}
   771  
   772  	log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate)
   773  	if requestUpdate {
   774  		log.Printf("[DEBUG] DB Instance Modification request: %#v", req)
   775  		_, err := conn.ModifyDBInstance(req)
   776  		if err != nil {
   777  			return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err)
   778  		}
   779  	}
   780  
   781  	// separate request to promote a database
   782  	if d.HasChange("replicate_source_db") {
   783  		if d.Get("replicate_source_db").(string) == "" {
   784  			// promote
   785  			opts := rds.PromoteReadReplicaInput{
   786  				DBInstanceIdentifier: aws.String(d.Id()),
   787  			}
   788  			attr := d.Get("backup_retention_period")
   789  			opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int)))
   790  			if attr, ok := d.GetOk("backup_window"); ok {
   791  				opts.PreferredBackupWindow = aws.String(attr.(string))
   792  			}
   793  			_, err := conn.PromoteReadReplica(&opts)
   794  			if err != nil {
   795  				return fmt.Errorf("Error promoting database: %#v", err)
   796  			}
   797  			d.Set("replicate_source_db", "")
   798  		} else {
   799  			return fmt.Errorf("cannot elect new source database for replication")
   800  		}
   801  	}
   802  
   803  	if arn, err := buildRDSARN(d, meta); err == nil {
   804  		if err := setTagsRDS(conn, d, arn); err != nil {
   805  			return err
   806  		} else {
   807  			d.SetPartial("tags")
   808  		}
   809  	}
   810  	d.Partial(false)
   811  
   812  	return resourceAwsDbInstanceRead(d, meta)
   813  }
   814  
   815  func resourceAwsDbInstanceRetrieve(
   816  	d *schema.ResourceData, meta interface{}) (*rds.DBInstance, error) {
   817  	conn := meta.(*AWSClient).rdsconn
   818  
   819  	opts := rds.DescribeDBInstancesInput{
   820  		DBInstanceIdentifier: aws.String(d.Id()),
   821  	}
   822  
   823  	log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts)
   824  
   825  	resp, err := conn.DescribeDBInstances(&opts)
   826  	if err != nil {
   827  		dbinstanceerr, ok := err.(awserr.Error)
   828  		if ok && dbinstanceerr.Code() == "DBInstanceNotFound" {
   829  			return nil, nil
   830  		}
   831  		return nil, fmt.Errorf("Error retrieving DB Instances: %s", err)
   832  	}
   833  
   834  	if len(resp.DBInstances) != 1 ||
   835  		*resp.DBInstances[0].DBInstanceIdentifier != d.Id() {
   836  		if err != nil {
   837  			return nil, nil
   838  		}
   839  	}
   840  
   841  	return resp.DBInstances[0], nil
   842  }
   843  
   844  func resourceAwsDbInstanceStateRefreshFunc(
   845  	d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
   846  	return func() (interface{}, string, error) {
   847  		v, err := resourceAwsDbInstanceRetrieve(d, meta)
   848  
   849  		if err != nil {
   850  			log.Printf("Error on retrieving DB Instance when waiting: %s", err)
   851  			return nil, "", err
   852  		}
   853  
   854  		if v == nil {
   855  			return nil, "", nil
   856  		}
   857  
   858  		if v.DBInstanceStatus != nil {
   859  			log.Printf("[DEBUG] DB Instance status for instance %s: %s", d.Id(), *v.DBInstanceStatus)
   860  		}
   861  
   862  		return v, *v.DBInstanceStatus, nil
   863  	}
   864  }
   865  
   866  func buildRDSARN(d *schema.ResourceData, meta interface{}) (string, error) {
   867  	iamconn := meta.(*AWSClient).iamconn
   868  	region := meta.(*AWSClient).region
   869  	// An zero value GetUserInput{} defers to the currently logged in user
   870  	resp, err := iamconn.GetUser(&iam.GetUserInput{})
   871  	if err != nil {
   872  		return "", err
   873  	}
   874  	userARN := *resp.User.Arn
   875  	accountID := strings.Split(userARN, ":")[4]
   876  	arn := fmt.Sprintf("arn:aws:rds:%s:%s:db:%s", region, accountID, d.Id())
   877  	return arn, nil
   878  }