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