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