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