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