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