github.com/IBM-Cloud/terraform@v0.6.4-0.20170726051544-8872b87621df/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  			"tags": tagsSchema(),
   344  		},
   345  	}
   346  }
   347  
   348  func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error {
   349  	conn := meta.(*AWSClient).rdsconn
   350  	tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
   351  
   352  	var identifier string
   353  	if v, ok := d.GetOk("identifier"); ok {
   354  		identifier = v.(string)
   355  	} else {
   356  		if v, ok := d.GetOk("identifier_prefix"); ok {
   357  			identifier = resource.PrefixedUniqueId(v.(string))
   358  		} else {
   359  			identifier = resource.UniqueId()
   360  		}
   361  
   362  		// SQL Server identifier size is max 15 chars, so truncate
   363  		if engine := d.Get("engine").(string); engine != "" {
   364  			if strings.Contains(strings.ToLower(engine), "sqlserver") {
   365  				identifier = identifier[:15]
   366  			}
   367  		}
   368  		d.Set("identifier", identifier)
   369  	}
   370  
   371  	if v, ok := d.GetOk("replicate_source_db"); ok {
   372  		opts := rds.CreateDBInstanceReadReplicaInput{
   373  			SourceDBInstanceIdentifier: aws.String(v.(string)),
   374  			CopyTagsToSnapshot:         aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
   375  			DBInstanceClass:            aws.String(d.Get("instance_class").(string)),
   376  			DBInstanceIdentifier:       aws.String(identifier),
   377  			PubliclyAccessible:         aws.Bool(d.Get("publicly_accessible").(bool)),
   378  			Tags:                       tags,
   379  		}
   380  		if attr, ok := d.GetOk("iops"); ok {
   381  			opts.Iops = aws.Int64(int64(attr.(int)))
   382  		}
   383  
   384  		if attr, ok := d.GetOk("port"); ok {
   385  			opts.Port = aws.Int64(int64(attr.(int)))
   386  		}
   387  
   388  		if attr, ok := d.GetOk("availability_zone"); ok {
   389  			opts.AvailabilityZone = aws.String(attr.(string))
   390  		}
   391  
   392  		if attr, ok := d.GetOk("storage_type"); ok {
   393  			opts.StorageType = aws.String(attr.(string))
   394  		}
   395  
   396  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   397  			opts.DBSubnetGroupName = aws.String(attr.(string))
   398  		}
   399  
   400  		if attr, ok := d.GetOk("monitoring_role_arn"); ok {
   401  			opts.MonitoringRoleArn = aws.String(attr.(string))
   402  		}
   403  
   404  		if attr, ok := d.GetOk("monitoring_interval"); ok {
   405  			opts.MonitoringInterval = aws.Int64(int64(attr.(int)))
   406  		}
   407  
   408  		if attr, ok := d.GetOk("option_group_name"); ok {
   409  			opts.OptionGroupName = aws.String(attr.(string))
   410  		}
   411  
   412  		log.Printf("[DEBUG] DB Instance Replica create configuration: %#v", opts)
   413  		_, err := conn.CreateDBInstanceReadReplica(&opts)
   414  		if err != nil {
   415  			return fmt.Errorf("Error creating DB Instance: %s", err)
   416  		}
   417  	} else if _, ok := d.GetOk("snapshot_identifier"); ok {
   418  		opts := rds.RestoreDBInstanceFromDBSnapshotInput{
   419  			DBInstanceClass:         aws.String(d.Get("instance_class").(string)),
   420  			DBInstanceIdentifier:    aws.String(d.Get("identifier").(string)),
   421  			DBSnapshotIdentifier:    aws.String(d.Get("snapshot_identifier").(string)),
   422  			AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
   423  			PubliclyAccessible:      aws.Bool(d.Get("publicly_accessible").(bool)),
   424  			Tags:                    tags,
   425  			CopyTagsToSnapshot:      aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
   426  		}
   427  
   428  		if attr, ok := d.GetOk("name"); ok {
   429  			// "Note: This parameter [DBName] doesn't apply to the MySQL, PostgreSQL, or MariaDB engines."
   430  			// https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromDBSnapshot.html
   431  			switch strings.ToLower(d.Get("engine").(string)) {
   432  			case "mysql", "postgres", "mariadb":
   433  				// skip
   434  			default:
   435  				opts.DBName = aws.String(attr.(string))
   436  			}
   437  		}
   438  
   439  		if attr, ok := d.GetOk("availability_zone"); ok {
   440  			opts.AvailabilityZone = aws.String(attr.(string))
   441  		}
   442  
   443  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   444  			opts.DBSubnetGroupName = aws.String(attr.(string))
   445  		}
   446  
   447  		if attr, ok := d.GetOk("engine"); ok {
   448  			opts.Engine = aws.String(attr.(string))
   449  		}
   450  
   451  		if attr, ok := d.GetOk("iops"); ok {
   452  			opts.Iops = aws.Int64(int64(attr.(int)))
   453  		}
   454  
   455  		if attr, ok := d.GetOk("license_model"); ok {
   456  			opts.LicenseModel = aws.String(attr.(string))
   457  		}
   458  
   459  		if attr, ok := d.GetOk("multi_az"); ok {
   460  			opts.MultiAZ = aws.Bool(attr.(bool))
   461  		}
   462  
   463  		if attr, ok := d.GetOk("option_group_name"); ok {
   464  			opts.OptionGroupName = aws.String(attr.(string))
   465  
   466  		}
   467  
   468  		if attr, ok := d.GetOk("port"); ok {
   469  			opts.Port = aws.Int64(int64(attr.(int)))
   470  		}
   471  
   472  		if attr, ok := d.GetOk("tde_credential_arn"); ok {
   473  			opts.TdeCredentialArn = aws.String(attr.(string))
   474  		}
   475  
   476  		if attr, ok := d.GetOk("storage_type"); ok {
   477  			opts.StorageType = aws.String(attr.(string))
   478  		}
   479  
   480  		log.Printf("[DEBUG] DB Instance restore from snapshot configuration: %s", opts)
   481  		_, err := conn.RestoreDBInstanceFromDBSnapshot(&opts)
   482  		if err != nil {
   483  			return fmt.Errorf("Error creating DB Instance: %s", err)
   484  		}
   485  
   486  		var sgUpdate bool
   487  		var passwordUpdate bool
   488  
   489  		if _, ok := d.GetOk("password"); ok {
   490  			passwordUpdate = true
   491  		}
   492  
   493  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   494  			sgUpdate = true
   495  		}
   496  		if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 {
   497  			sgUpdate = true
   498  		}
   499  		if sgUpdate || passwordUpdate {
   500  			log.Printf("[INFO] DB is restoring from snapshot with default security, but custom security should be set, will now update after snapshot is restored!")
   501  
   502  			// wait for instance to get up and then modify security
   503  			d.SetId(d.Get("identifier").(string))
   504  
   505  			log.Printf("[INFO] DB Instance ID: %s", d.Id())
   506  
   507  			log.Println(
   508  				"[INFO] Waiting for DB Instance to be available")
   509  
   510  			stateConf := &resource.StateChangeConf{
   511  				Pending: []string{"creating", "backing-up", "modifying", "resetting-master-credentials",
   512  					"maintenance", "renaming", "rebooting", "upgrading"},
   513  				Target:     []string{"available"},
   514  				Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   515  				Timeout:    d.Timeout(schema.TimeoutCreate),
   516  				MinTimeout: 10 * time.Second,
   517  				Delay:      30 * time.Second, // Wait 30 secs before starting
   518  			}
   519  
   520  			// Wait, catching any errors
   521  			_, err := stateConf.WaitForState()
   522  			if err != nil {
   523  				return err
   524  			}
   525  
   526  			err = resourceAwsDbInstanceUpdate(d, meta)
   527  			if err != nil {
   528  				return err
   529  			}
   530  
   531  		}
   532  	} else {
   533  		if _, ok := d.GetOk("allocated_storage"); !ok {
   534  			return fmt.Errorf(`provider.aws: aws_db_instance: %s: "allocated_storage": required field is not set`, d.Get("name").(string))
   535  		}
   536  		if _, ok := d.GetOk("engine"); !ok {
   537  			return fmt.Errorf(`provider.aws: aws_db_instance: %s: "engine": required field is not set`, d.Get("name").(string))
   538  		}
   539  		if _, ok := d.GetOk("password"); !ok {
   540  			return fmt.Errorf(`provider.aws: aws_db_instance: %s: "password": required field is not set`, d.Get("name").(string))
   541  		}
   542  		if _, ok := d.GetOk("username"); !ok {
   543  			return fmt.Errorf(`provider.aws: aws_db_instance: %s: "username": required field is not set`, d.Get("name").(string))
   544  		}
   545  		opts := rds.CreateDBInstanceInput{
   546  			AllocatedStorage:        aws.Int64(int64(d.Get("allocated_storage").(int))),
   547  			DBName:                  aws.String(d.Get("name").(string)),
   548  			DBInstanceClass:         aws.String(d.Get("instance_class").(string)),
   549  			DBInstanceIdentifier:    aws.String(d.Get("identifier").(string)),
   550  			MasterUsername:          aws.String(d.Get("username").(string)),
   551  			MasterUserPassword:      aws.String(d.Get("password").(string)),
   552  			Engine:                  aws.String(d.Get("engine").(string)),
   553  			EngineVersion:           aws.String(d.Get("engine_version").(string)),
   554  			StorageEncrypted:        aws.Bool(d.Get("storage_encrypted").(bool)),
   555  			AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
   556  			PubliclyAccessible:      aws.Bool(d.Get("publicly_accessible").(bool)),
   557  			Tags:                    tags,
   558  			CopyTagsToSnapshot:      aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
   559  		}
   560  
   561  		attr := d.Get("backup_retention_period")
   562  		opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int)))
   563  		if attr, ok := d.GetOk("multi_az"); ok {
   564  			opts.MultiAZ = aws.Bool(attr.(bool))
   565  
   566  		}
   567  
   568  		if attr, ok := d.GetOk("character_set_name"); ok {
   569  			opts.CharacterSetName = aws.String(attr.(string))
   570  		}
   571  
   572  		if attr, ok := d.GetOk("timezone"); ok {
   573  			opts.Timezone = aws.String(attr.(string))
   574  		}
   575  
   576  		if attr, ok := d.GetOk("maintenance_window"); ok {
   577  			opts.PreferredMaintenanceWindow = aws.String(attr.(string))
   578  		}
   579  
   580  		if attr, ok := d.GetOk("backup_window"); ok {
   581  			opts.PreferredBackupWindow = aws.String(attr.(string))
   582  		}
   583  
   584  		if attr, ok := d.GetOk("license_model"); ok {
   585  			opts.LicenseModel = aws.String(attr.(string))
   586  		}
   587  		if attr, ok := d.GetOk("parameter_group_name"); ok {
   588  			opts.DBParameterGroupName = aws.String(attr.(string))
   589  		}
   590  
   591  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   592  			var s []*string
   593  			for _, v := range attr.List() {
   594  				s = append(s, aws.String(v.(string)))
   595  			}
   596  			opts.VpcSecurityGroupIds = s
   597  		}
   598  
   599  		if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 {
   600  			var s []*string
   601  			for _, v := range attr.List() {
   602  				s = append(s, aws.String(v.(string)))
   603  			}
   604  			opts.DBSecurityGroups = s
   605  		}
   606  		if attr, ok := d.GetOk("storage_type"); ok {
   607  			opts.StorageType = aws.String(attr.(string))
   608  		}
   609  
   610  		if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   611  			opts.DBSubnetGroupName = aws.String(attr.(string))
   612  		}
   613  
   614  		if attr, ok := d.GetOk("iops"); ok {
   615  			opts.Iops = aws.Int64(int64(attr.(int)))
   616  		}
   617  
   618  		if attr, ok := d.GetOk("port"); ok {
   619  			opts.Port = aws.Int64(int64(attr.(int)))
   620  		}
   621  
   622  		if attr, ok := d.GetOk("availability_zone"); ok {
   623  			opts.AvailabilityZone = aws.String(attr.(string))
   624  		}
   625  
   626  		if attr, ok := d.GetOk("monitoring_role_arn"); ok {
   627  			opts.MonitoringRoleArn = aws.String(attr.(string))
   628  		}
   629  
   630  		if attr, ok := d.GetOk("monitoring_interval"); ok {
   631  			opts.MonitoringInterval = aws.Int64(int64(attr.(int)))
   632  		}
   633  
   634  		if attr, ok := d.GetOk("option_group_name"); ok {
   635  			opts.OptionGroupName = aws.String(attr.(string))
   636  		}
   637  
   638  		if attr, ok := d.GetOk("kms_key_id"); ok {
   639  			opts.KmsKeyId = aws.String(attr.(string))
   640  		}
   641  
   642  		if attr, ok := d.GetOk("iam_database_authentication_enabled"); ok {
   643  			opts.EnableIAMDatabaseAuthentication = aws.Bool(attr.(bool))
   644  		}
   645  
   646  		log.Printf("[DEBUG] DB Instance create configuration: %#v", opts)
   647  		var err error
   648  		err = resource.Retry(5*time.Minute, func() *resource.RetryError {
   649  			_, err = conn.CreateDBInstance(&opts)
   650  			if err != nil {
   651  				if awsErr, ok := err.(awserr.Error); ok {
   652  					if awsErr.Code() == "InvalidParameterValue" && strings.Contains(awsErr.Message(), "ENHANCED_MONITORING") {
   653  						return resource.RetryableError(awsErr)
   654  					}
   655  				}
   656  				return resource.NonRetryableError(err)
   657  			}
   658  			return nil
   659  		})
   660  		if err != nil {
   661  			return fmt.Errorf("Error creating DB Instance: %s", err)
   662  		}
   663  	}
   664  
   665  	d.SetId(d.Get("identifier").(string))
   666  
   667  	log.Printf("[INFO] DB Instance ID: %s", d.Id())
   668  
   669  	log.Println(
   670  		"[INFO] Waiting for DB Instance to be available")
   671  
   672  	stateConf := &resource.StateChangeConf{
   673  		Pending: []string{"creating", "backing-up", "modifying", "resetting-master-credentials",
   674  			"maintenance", "renaming", "rebooting", "upgrading", "configuring-enhanced-monitoring"},
   675  		Target:     []string{"available"},
   676  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   677  		Timeout:    d.Timeout(schema.TimeoutCreate),
   678  		MinTimeout: 10 * time.Second,
   679  		Delay:      30 * time.Second, // Wait 30 secs before starting
   680  	}
   681  
   682  	// Wait, catching any errors
   683  	_, err := stateConf.WaitForState()
   684  	if err != nil {
   685  		return err
   686  	}
   687  
   688  	return resourceAwsDbInstanceRead(d, meta)
   689  }
   690  
   691  func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error {
   692  	v, err := resourceAwsDbInstanceRetrieve(d, meta)
   693  
   694  	if err != nil {
   695  		return err
   696  	}
   697  	if v == nil {
   698  		d.SetId("")
   699  		return nil
   700  	}
   701  
   702  	d.Set("name", v.DBName)
   703  	d.Set("identifier", v.DBInstanceIdentifier)
   704  	d.Set("username", v.MasterUsername)
   705  	d.Set("engine", v.Engine)
   706  	d.Set("engine_version", v.EngineVersion)
   707  	d.Set("allocated_storage", v.AllocatedStorage)
   708  	d.Set("iops", v.Iops)
   709  	d.Set("copy_tags_to_snapshot", v.CopyTagsToSnapshot)
   710  	d.Set("auto_minor_version_upgrade", v.AutoMinorVersionUpgrade)
   711  	d.Set("storage_type", v.StorageType)
   712  	d.Set("instance_class", v.DBInstanceClass)
   713  	d.Set("availability_zone", v.AvailabilityZone)
   714  	d.Set("backup_retention_period", v.BackupRetentionPeriod)
   715  	d.Set("backup_window", v.PreferredBackupWindow)
   716  	d.Set("license_model", v.LicenseModel)
   717  	d.Set("maintenance_window", v.PreferredMaintenanceWindow)
   718  	d.Set("publicly_accessible", v.PubliclyAccessible)
   719  	d.Set("multi_az", v.MultiAZ)
   720  	d.Set("kms_key_id", v.KmsKeyId)
   721  	d.Set("port", v.DbInstancePort)
   722  	d.Set("iam_database_authentication_enabled", v.IAMDatabaseAuthenticationEnabled)
   723  	if v.DBSubnetGroup != nil {
   724  		d.Set("db_subnet_group_name", v.DBSubnetGroup.DBSubnetGroupName)
   725  	}
   726  
   727  	if v.CharacterSetName != nil {
   728  		d.Set("character_set_name", v.CharacterSetName)
   729  	}
   730  
   731  	d.Set("timezone", v.Timezone)
   732  
   733  	if len(v.DBParameterGroups) > 0 {
   734  		d.Set("parameter_group_name", v.DBParameterGroups[0].DBParameterGroupName)
   735  	}
   736  
   737  	if v.Endpoint != nil {
   738  		d.Set("port", v.Endpoint.Port)
   739  		d.Set("address", v.Endpoint.Address)
   740  		d.Set("hosted_zone_id", v.Endpoint.HostedZoneId)
   741  		if v.Endpoint.Address != nil && v.Endpoint.Port != nil {
   742  			d.Set("endpoint",
   743  				fmt.Sprintf("%s:%d", *v.Endpoint.Address, *v.Endpoint.Port))
   744  		}
   745  	}
   746  
   747  	d.Set("status", v.DBInstanceStatus)
   748  	d.Set("storage_encrypted", v.StorageEncrypted)
   749  	if v.OptionGroupMemberships != nil {
   750  		d.Set("option_group_name", v.OptionGroupMemberships[0].OptionGroupName)
   751  	}
   752  
   753  	if v.MonitoringInterval != nil {
   754  		d.Set("monitoring_interval", v.MonitoringInterval)
   755  	}
   756  
   757  	if v.MonitoringRoleArn != nil {
   758  		d.Set("monitoring_role_arn", v.MonitoringRoleArn)
   759  	}
   760  
   761  	// list tags for resource
   762  	// set tags
   763  	conn := meta.(*AWSClient).rdsconn
   764  	arn, err := buildRDSARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region)
   765  	if err != nil {
   766  		name := "<empty>"
   767  		if v.DBName != nil && *v.DBName != "" {
   768  			name = *v.DBName
   769  		}
   770  		log.Printf("[DEBUG] Error building ARN for DB Instance, not setting Tags for DB %s", name)
   771  	} else {
   772  		d.Set("arn", arn)
   773  		resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{
   774  			ResourceName: aws.String(arn),
   775  		})
   776  
   777  		if err != nil {
   778  			log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn)
   779  		}
   780  
   781  		var dt []*rds.Tag
   782  		if len(resp.TagList) > 0 {
   783  			dt = resp.TagList
   784  		}
   785  		d.Set("tags", tagsToMapRDS(dt))
   786  	}
   787  
   788  	// Create an empty schema.Set to hold all vpc security group ids
   789  	ids := &schema.Set{
   790  		F: schema.HashString,
   791  	}
   792  	for _, v := range v.VpcSecurityGroups {
   793  		ids.Add(*v.VpcSecurityGroupId)
   794  	}
   795  	d.Set("vpc_security_group_ids", ids)
   796  
   797  	// Create an empty schema.Set to hold all security group names
   798  	sgn := &schema.Set{
   799  		F: schema.HashString,
   800  	}
   801  	for _, v := range v.DBSecurityGroups {
   802  		sgn.Add(*v.DBSecurityGroupName)
   803  	}
   804  	d.Set("security_group_names", sgn)
   805  
   806  	// replica things
   807  
   808  	var replicas []string
   809  	for _, v := range v.ReadReplicaDBInstanceIdentifiers {
   810  		replicas = append(replicas, *v)
   811  	}
   812  	if err := d.Set("replicas", replicas); err != nil {
   813  		return fmt.Errorf("[DEBUG] Error setting replicas attribute: %#v, error: %#v", replicas, err)
   814  	}
   815  
   816  	d.Set("replicate_source_db", v.ReadReplicaSourceDBInstanceIdentifier)
   817  
   818  	return nil
   819  }
   820  
   821  func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error {
   822  	conn := meta.(*AWSClient).rdsconn
   823  
   824  	log.Printf("[DEBUG] DB Instance destroy: %v", d.Id())
   825  
   826  	opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())}
   827  
   828  	skipFinalSnapshot := d.Get("skip_final_snapshot").(bool)
   829  	opts.SkipFinalSnapshot = aws.Bool(skipFinalSnapshot)
   830  
   831  	if skipFinalSnapshot == false {
   832  		if name, present := d.GetOk("final_snapshot_identifier"); present {
   833  			opts.FinalDBSnapshotIdentifier = aws.String(name.(string))
   834  		} else {
   835  			return fmt.Errorf("DB Instance FinalSnapshotIdentifier is required when a final snapshot is required")
   836  		}
   837  	}
   838  
   839  	log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts)
   840  	if _, err := conn.DeleteDBInstance(&opts); err != nil {
   841  		return err
   842  	}
   843  
   844  	log.Println(
   845  		"[INFO] Waiting for DB Instance to be destroyed")
   846  	stateConf := &resource.StateChangeConf{
   847  		Pending: []string{"creating", "backing-up",
   848  			"modifying", "deleting", "available"},
   849  		Target:     []string{},
   850  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   851  		Timeout:    d.Timeout(schema.TimeoutDelete),
   852  		MinTimeout: 10 * time.Second,
   853  		Delay:      30 * time.Second, // Wait 30 secs before starting
   854  	}
   855  	if _, err := stateConf.WaitForState(); err != nil {
   856  		return err
   857  	}
   858  
   859  	return nil
   860  }
   861  
   862  func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
   863  	conn := meta.(*AWSClient).rdsconn
   864  
   865  	d.Partial(true)
   866  
   867  	req := &rds.ModifyDBInstanceInput{
   868  		ApplyImmediately:     aws.Bool(d.Get("apply_immediately").(bool)),
   869  		DBInstanceIdentifier: aws.String(d.Id()),
   870  	}
   871  	d.SetPartial("apply_immediately")
   872  
   873  	if !d.Get("apply_immediately").(bool) {
   874  		log.Println("[INFO] Only settings updating, instance changes will be applied in next maintenance window")
   875  	}
   876  
   877  	requestUpdate := false
   878  	if d.HasChange("allocated_storage") || d.HasChange("iops") {
   879  		d.SetPartial("allocated_storage")
   880  		d.SetPartial("iops")
   881  		req.Iops = aws.Int64(int64(d.Get("iops").(int)))
   882  		req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int)))
   883  		requestUpdate = true
   884  	}
   885  	if d.HasChange("allow_major_version_upgrade") {
   886  		d.SetPartial("allow_major_version_upgrade")
   887  		req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool))
   888  		requestUpdate = true
   889  	}
   890  	if d.HasChange("backup_retention_period") {
   891  		d.SetPartial("backup_retention_period")
   892  		req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int)))
   893  		requestUpdate = true
   894  	}
   895  	if d.HasChange("copy_tags_to_snapshot") {
   896  		d.SetPartial("copy_tags_to_snapshot")
   897  		req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool))
   898  		requestUpdate = true
   899  	}
   900  	if d.HasChange("instance_class") {
   901  		d.SetPartial("instance_class")
   902  		req.DBInstanceClass = aws.String(d.Get("instance_class").(string))
   903  		requestUpdate = true
   904  	}
   905  	if d.HasChange("parameter_group_name") {
   906  		d.SetPartial("parameter_group_name")
   907  		req.DBParameterGroupName = aws.String(d.Get("parameter_group_name").(string))
   908  		requestUpdate = true
   909  	}
   910  	if d.HasChange("engine_version") {
   911  		d.SetPartial("engine_version")
   912  		req.EngineVersion = aws.String(d.Get("engine_version").(string))
   913  		req.AllowMajorVersionUpgrade = aws.Bool(d.Get("allow_major_version_upgrade").(bool))
   914  		requestUpdate = true
   915  	}
   916  	if d.HasChange("backup_window") {
   917  		d.SetPartial("backup_window")
   918  		req.PreferredBackupWindow = aws.String(d.Get("backup_window").(string))
   919  		requestUpdate = true
   920  	}
   921  	if d.HasChange("maintenance_window") {
   922  		d.SetPartial("maintenance_window")
   923  		req.PreferredMaintenanceWindow = aws.String(d.Get("maintenance_window").(string))
   924  		requestUpdate = true
   925  	}
   926  	if d.HasChange("password") {
   927  		d.SetPartial("password")
   928  		req.MasterUserPassword = aws.String(d.Get("password").(string))
   929  		requestUpdate = true
   930  	}
   931  	if d.HasChange("multi_az") {
   932  		d.SetPartial("multi_az")
   933  		req.MultiAZ = aws.Bool(d.Get("multi_az").(bool))
   934  		requestUpdate = true
   935  	}
   936  	if d.HasChange("publicly_accessible") {
   937  		d.SetPartial("publicly_accessible")
   938  		req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool))
   939  		requestUpdate = true
   940  	}
   941  	if d.HasChange("storage_type") {
   942  		d.SetPartial("storage_type")
   943  		req.StorageType = aws.String(d.Get("storage_type").(string))
   944  		requestUpdate = true
   945  
   946  		if *req.StorageType == "io1" {
   947  			req.Iops = aws.Int64(int64(d.Get("iops").(int)))
   948  		}
   949  	}
   950  	if d.HasChange("auto_minor_version_upgrade") {
   951  		d.SetPartial("auto_minor_version_upgrade")
   952  		req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool))
   953  		requestUpdate = true
   954  	}
   955  
   956  	if d.HasChange("monitoring_role_arn") {
   957  		d.SetPartial("monitoring_role_arn")
   958  		req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string))
   959  		requestUpdate = true
   960  	}
   961  
   962  	if d.HasChange("monitoring_interval") {
   963  		d.SetPartial("monitoring_interval")
   964  		req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int)))
   965  		requestUpdate = true
   966  	}
   967  
   968  	if d.HasChange("vpc_security_group_ids") {
   969  		if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 {
   970  			var s []*string
   971  			for _, v := range attr.List() {
   972  				s = append(s, aws.String(v.(string)))
   973  			}
   974  			req.VpcSecurityGroupIds = s
   975  		}
   976  		requestUpdate = true
   977  	}
   978  
   979  	if d.HasChange("security_group_names") {
   980  		if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 {
   981  			var s []*string
   982  			for _, v := range attr.List() {
   983  				s = append(s, aws.String(v.(string)))
   984  			}
   985  			req.DBSecurityGroups = s
   986  		}
   987  		requestUpdate = true
   988  	}
   989  
   990  	if d.HasChange("option_group_name") {
   991  		d.SetPartial("option_group_name")
   992  		req.OptionGroupName = aws.String(d.Get("option_group_name").(string))
   993  		requestUpdate = true
   994  	}
   995  
   996  	if d.HasChange("port") {
   997  		d.SetPartial("port")
   998  		req.DBPortNumber = aws.Int64(int64(d.Get("port").(int)))
   999  		requestUpdate = true
  1000  	}
  1001  	if d.HasChange("db_subnet_group_name") && !d.IsNewResource() {
  1002  		d.SetPartial("db_subnet_group_name")
  1003  		req.DBSubnetGroupName = aws.String(d.Get("db_subnet_group_name").(string))
  1004  		requestUpdate = true
  1005  	}
  1006  
  1007  	if d.HasChange("iam_database_authentication_enabled") {
  1008  		req.EnableIAMDatabaseAuthentication = aws.Bool(d.Get("iam_database_authentication_enabled").(bool))
  1009  		requestUpdate = true
  1010  	}
  1011  
  1012  	log.Printf("[DEBUG] Send DB Instance Modification request: %t", requestUpdate)
  1013  	if requestUpdate {
  1014  		log.Printf("[DEBUG] DB Instance Modification request: %s", req)
  1015  		_, err := conn.ModifyDBInstance(req)
  1016  		if err != nil {
  1017  			return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err)
  1018  		}
  1019  
  1020  		log.Println("[INFO] Waiting for DB Instance to be available")
  1021  
  1022  		stateConf := &resource.StateChangeConf{
  1023  			Pending: []string{"creating", "backing-up", "modifying", "resetting-master-credentials",
  1024  				"maintenance", "renaming", "rebooting", "upgrading", "configuring-enhanced-monitoring", "moving-to-vpc"},
  1025  			Target:     []string{"available"},
  1026  			Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
  1027  			Timeout:    d.Timeout(schema.TimeoutUpdate),
  1028  			MinTimeout: 10 * time.Second,
  1029  			Delay:      30 * time.Second, // Wait 30 secs before starting
  1030  		}
  1031  
  1032  		// Wait, catching any errors
  1033  		_, dbStateErr := stateConf.WaitForState()
  1034  		if dbStateErr != nil {
  1035  			return dbStateErr
  1036  		}
  1037  	}
  1038  
  1039  	// separate request to promote a database
  1040  	if d.HasChange("replicate_source_db") {
  1041  		if d.Get("replicate_source_db").(string) == "" {
  1042  			// promote
  1043  			opts := rds.PromoteReadReplicaInput{
  1044  				DBInstanceIdentifier: aws.String(d.Id()),
  1045  			}
  1046  			attr := d.Get("backup_retention_period")
  1047  			opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int)))
  1048  			if attr, ok := d.GetOk("backup_window"); ok {
  1049  				opts.PreferredBackupWindow = aws.String(attr.(string))
  1050  			}
  1051  			_, err := conn.PromoteReadReplica(&opts)
  1052  			if err != nil {
  1053  				return fmt.Errorf("Error promoting database: %#v", err)
  1054  			}
  1055  			d.Set("replicate_source_db", "")
  1056  		} else {
  1057  			return fmt.Errorf("cannot elect new source database for replication")
  1058  		}
  1059  	}
  1060  
  1061  	if arn, err := buildRDSARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region); err == nil {
  1062  		if err := setTagsRDS(conn, d, arn); err != nil {
  1063  			return err
  1064  		} else {
  1065  			d.SetPartial("tags")
  1066  		}
  1067  	}
  1068  	d.Partial(false)
  1069  
  1070  	return resourceAwsDbInstanceRead(d, meta)
  1071  }
  1072  
  1073  // resourceAwsDbInstanceRetrieve fetches DBInstance information from the AWS
  1074  // API. It returns an error if there is a communication problem or unexpected
  1075  // error with AWS. When the DBInstance is not found, it returns no error and a
  1076  // nil pointer.
  1077  func resourceAwsDbInstanceRetrieve(
  1078  	d *schema.ResourceData, meta interface{}) (*rds.DBInstance, error) {
  1079  	conn := meta.(*AWSClient).rdsconn
  1080  
  1081  	opts := rds.DescribeDBInstancesInput{
  1082  		DBInstanceIdentifier: aws.String(d.Id()),
  1083  	}
  1084  
  1085  	log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts)
  1086  
  1087  	resp, err := conn.DescribeDBInstances(&opts)
  1088  	if err != nil {
  1089  		dbinstanceerr, ok := err.(awserr.Error)
  1090  		if ok && dbinstanceerr.Code() == "DBInstanceNotFound" {
  1091  			return nil, nil
  1092  		}
  1093  		return nil, fmt.Errorf("Error retrieving DB Instances: %s", err)
  1094  	}
  1095  
  1096  	if len(resp.DBInstances) != 1 ||
  1097  		*resp.DBInstances[0].DBInstanceIdentifier != d.Id() {
  1098  		if err != nil {
  1099  			return nil, nil
  1100  		}
  1101  	}
  1102  
  1103  	return resp.DBInstances[0], nil
  1104  }
  1105  
  1106  func resourceAwsDbInstanceImport(
  1107  	d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
  1108  	// Neither skip_final_snapshot nor final_snapshot_identifier can be fetched
  1109  	// from any API call, so we need to default skip_final_snapshot to true so
  1110  	// that final_snapshot_identifier is not required
  1111  	d.Set("skip_final_snapshot", true)
  1112  	return []*schema.ResourceData{d}, nil
  1113  }
  1114  
  1115  func resourceAwsDbInstanceStateRefreshFunc(
  1116  	d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
  1117  	return func() (interface{}, string, error) {
  1118  		v, err := resourceAwsDbInstanceRetrieve(d, meta)
  1119  
  1120  		if err != nil {
  1121  			log.Printf("Error on retrieving DB Instance when waiting: %s", err)
  1122  			return nil, "", err
  1123  		}
  1124  
  1125  		if v == nil {
  1126  			return nil, "", nil
  1127  		}
  1128  
  1129  		if v.DBInstanceStatus != nil {
  1130  			log.Printf("[DEBUG] DB Instance status for instance %s: %s", d.Id(), *v.DBInstanceStatus)
  1131  		}
  1132  
  1133  		return v, *v.DBInstanceStatus, nil
  1134  	}
  1135  }
  1136  
  1137  func buildRDSARN(identifier, partition, accountid, region string) (string, error) {
  1138  	if partition == "" {
  1139  		return "", fmt.Errorf("Unable to construct RDS ARN because of missing AWS partition")
  1140  	}
  1141  	if accountid == "" {
  1142  		return "", fmt.Errorf("Unable to construct RDS ARN because of missing AWS Account ID")
  1143  	}
  1144  	arn := fmt.Sprintf("arn:%s:rds:%s:%s:db:%s", partition, region, accountid, identifier)
  1145  	return arn, nil
  1146  }