github.com/keshavdv/terraform@v0.7.0-rc2.0.20160711232630-d69256dcb425/builtin/providers/aws/resource_aws_db_instance.go (about)

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