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