github.com/wangzhucn/terraform@v0.6.7-0.20151109233120-4eea011b56b3/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  			"copy_tags_to_snapshot": &schema.Schema{
   186  				Type:     schema.TypeBool,
   187  				Optional: true,
   188  				Default:  false,
   189  			},
   190  
   191  			"db_subnet_group_name": &schema.Schema{
   192  				Type:     schema.TypeString,
   193  				Optional: true,
   194  				ForceNew: true,
   195  				Computed: true,
   196  			},
   197  
   198  			"parameter_group_name": &schema.Schema{
   199  				Type:     schema.TypeString,
   200  				Optional: true,
   201  				Computed: true,
   202  			},
   203  
   204  			"address": &schema.Schema{
   205  				Type:     schema.TypeString,
   206  				Computed: true,
   207  			},
   208  
   209  			"endpoint": &schema.Schema{
   210  				Type:     schema.TypeString,
   211  				Computed: true,
   212  			},
   213  
   214  			"status": &schema.Schema{
   215  				Type:     schema.TypeString,
   216  				Computed: true,
   217  			},
   218  
   219  			// apply_immediately is used to determine when the update modifications
   220  			// take place.
   221  			// See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
   222  			"apply_immediately": &schema.Schema{
   223  				Type:     schema.TypeBool,
   224  				Optional: true,
   225  				Computed: true,
   226  			},
   227  
   228  			"replicate_source_db": &schema.Schema{
   229  				Type:     schema.TypeString,
   230  				Optional: true,
   231  			},
   232  
   233  			"replicas": &schema.Schema{
   234  				Type:     schema.TypeList,
   235  				Computed: true,
   236  				Elem:     &schema.Schema{Type: schema.TypeString},
   237  			},
   238  
   239  			"snapshot_identifier": &schema.Schema{
   240  				Type:     schema.TypeString,
   241  				Computed: false,
   242  				Optional: true,
   243  				Elem:     &schema.Schema{Type: schema.TypeString},
   244  			},
   245  
   246  			"auto_minor_version_upgrade": &schema.Schema{
   247  				Type:     schema.TypeBool,
   248  				Computed: false,
   249  				Optional: true,
   250  			},
   251  
   252  			"allow_major_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  			CopyTagsToSnapshot:         aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
   271  			DBInstanceClass:            aws.String(d.Get("instance_class").(string)),
   272  			DBInstanceIdentifier:       aws.String(d.Get("identifier").(string)),
   273  			Tags:                       tags,
   274  		}
   275  		if attr, ok := d.GetOk("iops"); ok {
   276  			opts.Iops = aws.Int64(int64(attr.(int)))
   277  		}
   278  
   279  		if attr, ok := d.GetOk("port"); ok {
   280  			opts.Port = aws.Int64(int64(attr.(int)))
   281  		}
   282  
   283  		if attr, ok := d.GetOk("availability_zone"); ok {
   284  			opts.AvailabilityZone = aws.String(attr.(string))
   285  		}
   286  
   287  		if attr, ok := d.GetOk("publicly_accessible"); ok {
   288  			opts.PubliclyAccessible = aws.Bool(attr.(bool))
   289  		}
   290  		_, err := conn.CreateDBInstanceReadReplica(&opts)
   291  		if err != nil {
   292  			return fmt.Errorf("Error creating DB Instance: %s", err)
   293  		}
   294  	} else if _, ok := d.GetOk("snapshot_identifier"); ok {
   295  		opts := rds.RestoreDBInstanceFromDBSnapshotInput{
   296  			DBInstanceClass:      aws.String(d.Get("instance_class").(string)),
   297  			DBInstanceIdentifier: aws.String(d.Get("identifier").(string)),
   298  			DBSnapshotIdentifier: aws.String(d.Get("snapshot_identifier").(string)),
   299  			Tags:                 tags,
   300  		}
   301  
   302  		if attr, ok := d.GetOk("auto_minor_version_upgrade"); ok {
   303  			opts.AutoMinorVersionUpgrade = aws.Bool(attr.(bool))
   304  		}
   305  
   306  		if attr, ok := d.GetOk("availability_zone"); ok {
   307  			opts.AvailabilityZone = aws.String(attr.(string))
   308  		}
   309  
   310  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   311  			opts.DBSubnetGroupName = aws.String(attr.(string))
   312  		}
   313  
   314  		if attr, ok := d.GetOk("engine"); ok {
   315  			opts.Engine = aws.String(attr.(string))
   316  		}
   317  
   318  		if attr, ok := d.GetOk("iops"); ok {
   319  			opts.Iops = aws.Int64(int64(attr.(int)))
   320  		}
   321  
   322  		if attr, ok := d.GetOk("license_model"); ok {
   323  			opts.LicenseModel = aws.String(attr.(string))
   324  		}
   325  
   326  		if attr, ok := d.GetOk("multi_az"); ok {
   327  			opts.MultiAZ = aws.Bool(attr.(bool))
   328  		}
   329  
   330  		if attr, ok := d.GetOk("option_group_name"); ok {
   331  			opts.OptionGroupName = aws.String(attr.(string))
   332  		}
   333  
   334  		if attr, ok := d.GetOk("port"); ok {
   335  			opts.Port = aws.Int64(int64(attr.(int)))
   336  		}
   337  
   338  		if attr, ok := d.GetOk("publicly_accessible"); ok {
   339  			opts.PubliclyAccessible = aws.Bool(attr.(bool))
   340  		}
   341  
   342  		if attr, ok := d.GetOk("tde_credential_arn"); ok {
   343  			opts.TdeCredentialArn = aws.String(attr.(string))
   344  		}
   345  
   346  		if attr, ok := d.GetOk("storage_type"); ok {
   347  			opts.StorageType = aws.String(attr.(string))
   348  		}
   349  
   350  		_, err := conn.RestoreDBInstanceFromDBSnapshot(&opts)
   351  		if err != nil {
   352  			return fmt.Errorf("Error creating DB Instance: %s", err)
   353  		}
   354  
   355  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   356  			log.Printf("[INFO] DB is restoring from snapshot with default security, but custom security should be set, will now update after snapshot is restored!")
   357  
   358  			// wait for instance to get up and then modify security
   359  			d.SetId(d.Get("identifier").(string))
   360  
   361  			log.Printf("[INFO] DB Instance ID: %s", d.Id())
   362  
   363  			log.Println(
   364  				"[INFO] Waiting for DB Instance to be available")
   365  
   366  			stateConf := &resource.StateChangeConf{
   367  				Pending:    []string{"creating", "backing-up", "modifying"},
   368  				Target:     "available",
   369  				Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   370  				Timeout:    40 * time.Minute,
   371  				MinTimeout: 10 * time.Second,
   372  				Delay:      30 * time.Second, // Wait 30 secs before starting
   373  			}
   374  
   375  			// Wait, catching any errors
   376  			_, err := stateConf.WaitForState()
   377  			if err != nil {
   378  				return err
   379  			}
   380  
   381  			err = resourceAwsDbInstanceUpdate(d, meta)
   382  			if err != nil {
   383  				return err
   384  			}
   385  
   386  		}
   387  	} else {
   388  		opts := rds.CreateDBInstanceInput{
   389  			AllocatedStorage:     aws.Int64(int64(d.Get("allocated_storage").(int))),
   390  			CopyTagsToSnapshot:   aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
   391  			DBName:               aws.String(d.Get("name").(string)),
   392  			DBInstanceClass:      aws.String(d.Get("instance_class").(string)),
   393  			DBInstanceIdentifier: aws.String(d.Get("identifier").(string)),
   394  			MasterUsername:       aws.String(d.Get("username").(string)),
   395  			MasterUserPassword:   aws.String(d.Get("password").(string)),
   396  			Engine:               aws.String(d.Get("engine").(string)),
   397  			EngineVersion:        aws.String(d.Get("engine_version").(string)),
   398  			StorageEncrypted:     aws.Bool(d.Get("storage_encrypted").(bool)),
   399  			Tags:                 tags,
   400  		}
   401  
   402  		attr := d.Get("backup_retention_period")
   403  		opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int)))
   404  		if attr, ok := d.GetOk("multi_az"); ok {
   405  			opts.MultiAZ = aws.Bool(attr.(bool))
   406  		}
   407  
   408  		if attr, ok := d.GetOk("maintenance_window"); ok {
   409  			opts.PreferredMaintenanceWindow = aws.String(attr.(string))
   410  		}
   411  
   412  		if attr, ok := d.GetOk("backup_window"); ok {
   413  			opts.PreferredBackupWindow = aws.String(attr.(string))
   414  		}
   415  
   416  		if attr, ok := d.GetOk("license_model"); ok {
   417  			opts.LicenseModel = aws.String(attr.(string))
   418  		}
   419  		if attr, ok := d.GetOk("parameter_group_name"); ok {
   420  			opts.DBParameterGroupName = aws.String(attr.(string))
   421  		}
   422  
   423  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   424  			var s []*string
   425  			for _, v := range attr.List() {
   426  				s = append(s, aws.String(v.(string)))
   427  			}
   428  			opts.VpcSecurityGroupIds = s
   429  		}
   430  
   431  		if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 {
   432  			var s []*string
   433  			for _, v := range attr.List() {
   434  				s = append(s, aws.String(v.(string)))
   435  			}
   436  			opts.DBSecurityGroups = s
   437  		}
   438  		if attr, ok := d.GetOk("storage_type"); ok {
   439  			opts.StorageType = aws.String(attr.(string))
   440  		}
   441  
   442  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   443  			opts.DBSubnetGroupName = aws.String(attr.(string))
   444  		}
   445  
   446  		if attr, ok := d.GetOk("iops"); ok {
   447  			opts.Iops = aws.Int64(int64(attr.(int)))
   448  		}
   449  
   450  		if attr, ok := d.GetOk("port"); ok {
   451  			opts.Port = aws.Int64(int64(attr.(int)))
   452  		}
   453  
   454  		if attr, ok := d.GetOk("availability_zone"); ok {
   455  			opts.AvailabilityZone = aws.String(attr.(string))
   456  		}
   457  
   458  		if attr, ok := d.GetOk("publicly_accessible"); ok {
   459  			opts.PubliclyAccessible = aws.Bool(attr.(bool))
   460  		}
   461  
   462  		log.Printf("[DEBUG] DB Instance create configuration: %#v", opts)
   463  		var err error
   464  		_, err = conn.CreateDBInstance(&opts)
   465  		if err != nil {
   466  			return fmt.Errorf("Error creating DB Instance: %s", err)
   467  		}
   468  	}
   469  
   470  	d.SetId(d.Get("identifier").(string))
   471  
   472  	log.Printf("[INFO] DB Instance ID: %s", d.Id())
   473  
   474  	log.Println(
   475  		"[INFO] Waiting for DB Instance to be available")
   476  
   477  	stateConf := &resource.StateChangeConf{
   478  		Pending:    []string{"creating", "backing-up", "modifying"},
   479  		Target:     "available",
   480  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   481  		Timeout:    40 * time.Minute,
   482  		MinTimeout: 10 * time.Second,
   483  		Delay:      30 * time.Second, // Wait 30 secs before starting
   484  	}
   485  
   486  	// Wait, catching any errors
   487  	_, err := stateConf.WaitForState()
   488  	if err != nil {
   489  		return err
   490  	}
   491  
   492  	return resourceAwsDbInstanceRead(d, meta)
   493  }
   494  
   495  func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error {
   496  	v, err := resourceAwsDbInstanceRetrieve(d, meta)
   497  
   498  	if err != nil {
   499  		return err
   500  	}
   501  	if v == nil {
   502  		d.SetId("")
   503  		return nil
   504  	}
   505  
   506  	d.Set("name", v.DBName)
   507  	d.Set("username", v.MasterUsername)
   508  	d.Set("engine", v.Engine)
   509  	d.Set("engine_version", v.EngineVersion)
   510  	d.Set("allocated_storage", v.AllocatedStorage)
   511  	d.Set("copy_tags_to_snapshot", v.CopyTagsToSnapshot)
   512  	d.Set("storage_type", v.StorageType)
   513  	d.Set("instance_class", v.DBInstanceClass)
   514  	d.Set("availability_zone", v.AvailabilityZone)
   515  	d.Set("backup_retention_period", v.BackupRetentionPeriod)
   516  	d.Set("backup_window", v.PreferredBackupWindow)
   517  	d.Set("license_model", v.LicenseModel)
   518  	d.Set("maintenance_window", v.PreferredMaintenanceWindow)
   519  	d.Set("multi_az", v.MultiAZ)
   520  	if v.DBSubnetGroup != nil {
   521  		d.Set("db_subnet_group_name", v.DBSubnetGroup.DBSubnetGroupName)
   522  	}
   523  
   524  	if len(v.DBParameterGroups) > 0 {
   525  		d.Set("parameter_group_name", v.DBParameterGroups[0].DBParameterGroupName)
   526  	}
   527  
   528  	if v.Endpoint != nil {
   529  		d.Set("port", v.Endpoint.Port)
   530  		d.Set("address", v.Endpoint.Address)
   531  
   532  		if v.Endpoint.Address != nil && v.Endpoint.Port != nil {
   533  			d.Set("endpoint",
   534  				fmt.Sprintf("%s:%d", *v.Endpoint.Address, *v.Endpoint.Port))
   535  		}
   536  	}
   537  
   538  	d.Set("status", v.DBInstanceStatus)
   539  	d.Set("storage_encrypted", v.StorageEncrypted)
   540  
   541  	// list tags for resource
   542  	// set tags
   543  	conn := meta.(*AWSClient).rdsconn
   544  	arn, err := buildRDSARN(d, meta)
   545  	if err != nil {
   546  		name := "<empty>"
   547  		if v.DBName != nil && *v.DBName != "" {
   548  			name = *v.DBName
   549  		}
   550  		log.Printf("[DEBUG] Error building ARN for DB Instance, not setting Tags for DB %s", name)
   551  	} else {
   552  		resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{
   553  			ResourceName: aws.String(arn),
   554  		})
   555  
   556  		if err != nil {
   557  			log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn)
   558  		}
   559  
   560  		var dt []*rds.Tag
   561  		if len(resp.TagList) > 0 {
   562  			dt = resp.TagList
   563  		}
   564  		d.Set("tags", tagsToMapRDS(dt))
   565  	}
   566  
   567  	// Create an empty schema.Set to hold all vpc security group ids
   568  	ids := &schema.Set{
   569  		F: schema.HashString,
   570  	}
   571  	for _, v := range v.VpcSecurityGroups {
   572  		ids.Add(*v.VpcSecurityGroupId)
   573  	}
   574  	d.Set("vpc_security_group_ids", ids)
   575  
   576  	// Create an empty schema.Set to hold all security group names
   577  	sgn := &schema.Set{
   578  		F: schema.HashString,
   579  	}
   580  	for _, v := range v.DBSecurityGroups {
   581  		sgn.Add(*v.DBSecurityGroupName)
   582  	}
   583  	d.Set("security_group_names", sgn)
   584  
   585  	// replica things
   586  
   587  	var replicas []string
   588  	for _, v := range v.ReadReplicaDBInstanceIdentifiers {
   589  		replicas = append(replicas, *v)
   590  	}
   591  	if err := d.Set("replicas", replicas); err != nil {
   592  		return fmt.Errorf("[DEBUG] Error setting replicas attribute: %#v, error: %#v", replicas, err)
   593  	}
   594  
   595  	d.Set("replicate_source_db", v.ReadReplicaSourceDBInstanceIdentifier)
   596  
   597  	return nil
   598  }
   599  
   600  func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error {
   601  	conn := meta.(*AWSClient).rdsconn
   602  
   603  	log.Printf("[DEBUG] DB Instance destroy: %v", d.Id())
   604  
   605  	opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())}
   606  
   607  	finalSnapshot := d.Get("final_snapshot_identifier").(string)
   608  	if finalSnapshot == "" {
   609  		opts.SkipFinalSnapshot = aws.Bool(true)
   610  	} else {
   611  		opts.FinalDBSnapshotIdentifier = aws.String(finalSnapshot)
   612  	}
   613  
   614  	log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts)
   615  	if _, err := conn.DeleteDBInstance(&opts); err != nil {
   616  		return err
   617  	}
   618  
   619  	log.Println(
   620  		"[INFO] Waiting for DB Instance to be destroyed")
   621  	stateConf := &resource.StateChangeConf{
   622  		Pending: []string{"creating", "backing-up",
   623  			"modifying", "deleting", "available"},
   624  		Target:     "",
   625  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   626  		Timeout:    40 * time.Minute,
   627  		MinTimeout: 10 * time.Second,
   628  		Delay:      30 * time.Second, // Wait 30 secs before starting
   629  	}
   630  	if _, err := stateConf.WaitForState(); err != nil {
   631  		return err
   632  	}
   633  
   634  	return nil
   635  }
   636  
   637  func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
   638  	conn := meta.(*AWSClient).rdsconn
   639  
   640  	d.Partial(true)
   641  
   642  	req := &rds.ModifyDBInstanceInput{
   643  		ApplyImmediately:     aws.Bool(d.Get("apply_immediately").(bool)),
   644  		DBInstanceIdentifier: aws.String(d.Id()),
   645  	}
   646  	d.SetPartial("apply_immediately")
   647  
   648  	requestUpdate := false
   649  	if d.HasChange("allocated_storage") {
   650  		d.SetPartial("allocated_storage")
   651  		req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int)))
   652  		requestUpdate = true
   653  	}
   654  	if d.HasChange("allow_major_version_upgrade") {
   655  		d.SetPartial("allow_major_version_upgrade")
   656  		req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool))
   657  		requestUpdate = true
   658  	}
   659  	if d.HasChange("backup_retention_period") {
   660  		d.SetPartial("backup_retention_period")
   661  		req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int)))
   662  		requestUpdate = true
   663  	}
   664  	if d.HasChange("copy_tags_to_snapshot") {
   665  		d.SetPartial("copy_tags_to_snapshot")
   666  		req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool))
   667  		requestUpdate = true
   668  	}
   669  	if d.HasChange("instance_class") {
   670  		d.SetPartial("instance_class")
   671  		req.DBInstanceClass = aws.String(d.Get("instance_class").(string))
   672  		requestUpdate = true
   673  	}
   674  	if d.HasChange("parameter_group_name") {
   675  		d.SetPartial("parameter_group_name")
   676  		req.DBParameterGroupName = aws.String(d.Get("parameter_group_name").(string))
   677  		requestUpdate = true
   678  	}
   679  	if d.HasChange("engine_version") {
   680  		d.SetPartial("engine_version")
   681  		req.EngineVersion = aws.String(d.Get("engine_version").(string))
   682  		requestUpdate = true
   683  	}
   684  	if d.HasChange("iops") {
   685  		d.SetPartial("iops")
   686  		req.Iops = aws.Int64(int64(d.Get("iops").(int)))
   687  		requestUpdate = true
   688  	}
   689  	if d.HasChange("backup_window") {
   690  		d.SetPartial("backup_window")
   691  		req.PreferredBackupWindow = aws.String(d.Get("backup_window").(string))
   692  		requestUpdate = true
   693  	}
   694  	if d.HasChange("maintenance_window") {
   695  		d.SetPartial("maintenance_window")
   696  		req.PreferredMaintenanceWindow = aws.String(d.Get("maintenance_window").(string))
   697  		requestUpdate = true
   698  	}
   699  	if d.HasChange("password") {
   700  		d.SetPartial("password")
   701  		req.MasterUserPassword = aws.String(d.Get("password").(string))
   702  		requestUpdate = true
   703  	}
   704  	if d.HasChange("multi_az") {
   705  		d.SetPartial("multi_az")
   706  		req.MultiAZ = aws.Bool(d.Get("multi_az").(bool))
   707  		requestUpdate = true
   708  	}
   709  	if d.HasChange("storage_type") {
   710  		d.SetPartial("storage_type")
   711  		req.StorageType = aws.String(d.Get("storage_type").(string))
   712  		requestUpdate = true
   713  	}
   714  
   715  	if d.HasChange("vpc_security_group_ids") {
   716  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   717  			var s []*string
   718  			for _, v := range attr.List() {
   719  				s = append(s, aws.String(v.(string)))
   720  			}
   721  			req.VpcSecurityGroupIds = s
   722  		}
   723  		requestUpdate = true
   724  	}
   725  
   726  	if d.HasChange("vpc_security_group_ids") {
   727  		if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 {
   728  			var s []*string
   729  			for _, v := range attr.List() {
   730  				s = append(s, aws.String(v.(string)))
   731  			}
   732  			req.DBSecurityGroups = s
   733  		}
   734  		requestUpdate = true
   735  	}
   736  
   737  	log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate)
   738  	if requestUpdate {
   739  		log.Printf("[DEBUG] DB Instance Modification request: %#v", req)
   740  		_, err := conn.ModifyDBInstance(req)
   741  		if err != nil {
   742  			return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err)
   743  		}
   744  	}
   745  
   746  	// separate request to promote a database
   747  	if d.HasChange("replicate_source_db") {
   748  		if d.Get("replicate_source_db").(string) == "" {
   749  			// promote
   750  			opts := rds.PromoteReadReplicaInput{
   751  				DBInstanceIdentifier: aws.String(d.Id()),
   752  			}
   753  			attr := d.Get("backup_retention_period")
   754  			opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int)))
   755  			if attr, ok := d.GetOk("backup_window"); ok {
   756  				opts.PreferredBackupWindow = aws.String(attr.(string))
   757  			}
   758  			_, err := conn.PromoteReadReplica(&opts)
   759  			if err != nil {
   760  				return fmt.Errorf("Error promoting database: %#v", err)
   761  			}
   762  			d.Set("replicate_source_db", "")
   763  		} else {
   764  			return fmt.Errorf("cannot elect new source database for replication")
   765  		}
   766  	}
   767  
   768  	if arn, err := buildRDSARN(d, meta); err == nil {
   769  		if err := setTagsRDS(conn, d, arn); err != nil {
   770  			return err
   771  		} else {
   772  			d.SetPartial("tags")
   773  		}
   774  	}
   775  	d.Partial(false)
   776  
   777  	return resourceAwsDbInstanceRead(d, meta)
   778  }
   779  
   780  func resourceAwsDbInstanceRetrieve(
   781  	d *schema.ResourceData, meta interface{}) (*rds.DBInstance, error) {
   782  	conn := meta.(*AWSClient).rdsconn
   783  
   784  	opts := rds.DescribeDBInstancesInput{
   785  		DBInstanceIdentifier: aws.String(d.Id()),
   786  	}
   787  
   788  	log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts)
   789  
   790  	resp, err := conn.DescribeDBInstances(&opts)
   791  	if err != nil {
   792  		dbinstanceerr, ok := err.(awserr.Error)
   793  		if ok && dbinstanceerr.Code() == "DBInstanceNotFound" {
   794  			return nil, nil
   795  		}
   796  		return nil, fmt.Errorf("Error retrieving DB Instances: %s", err)
   797  	}
   798  
   799  	if len(resp.DBInstances) != 1 ||
   800  		*resp.DBInstances[0].DBInstanceIdentifier != d.Id() {
   801  		if err != nil {
   802  			return nil, nil
   803  		}
   804  	}
   805  
   806  	return resp.DBInstances[0], nil
   807  }
   808  
   809  func resourceAwsDbInstanceStateRefreshFunc(
   810  	d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
   811  	return func() (interface{}, string, error) {
   812  		v, err := resourceAwsDbInstanceRetrieve(d, meta)
   813  
   814  		if err != nil {
   815  			log.Printf("Error on retrieving DB Instance when waiting: %s", err)
   816  			return nil, "", err
   817  		}
   818  
   819  		if v == nil {
   820  			return nil, "", nil
   821  		}
   822  
   823  		if v.DBInstanceStatus != nil {
   824  			log.Printf("[DEBUG] DB Instance status for instance %s: %s", d.Id(), *v.DBInstanceStatus)
   825  		}
   826  
   827  		return v, *v.DBInstanceStatus, nil
   828  	}
   829  }
   830  
   831  func buildRDSARN(d *schema.ResourceData, meta interface{}) (string, error) {
   832  	iamconn := meta.(*AWSClient).iamconn
   833  	region := meta.(*AWSClient).region
   834  	// An zero value GetUserInput{} defers to the currently logged in user
   835  	resp, err := iamconn.GetUser(&iam.GetUserInput{})
   836  	if err != nil {
   837  		return "", err
   838  	}
   839  	userARN := *resp.User.Arn
   840  	accountID := strings.Split(userARN, ":")[4]
   841  	arn := fmt.Sprintf("arn:aws:rds:%s:%s:db:%s", region, accountID, d.Id())
   842  	return arn, nil
   843  }