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