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