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