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