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