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