2014-07-22 22:26:48 +02:00
package aws
import (
"fmt"
"log"
2015-06-08 03:49:48 +02:00
"regexp"
2015-05-11 17:32:06 +02:00
"strings"
2014-07-22 22:26:48 +02:00
"time"
2015-06-03 20:36:57 +02:00
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/rds"
2015-02-23 22:22:52 +01:00
2014-07-22 22:26:48 +02:00
"github.com/hashicorp/terraform/helper/resource"
2014-11-21 17:58:34 +01:00
"github.com/hashicorp/terraform/helper/schema"
2014-07-22 22:26:48 +02:00
)
2014-11-21 17:58:34 +01:00
func resourceAwsDbInstance ( ) * schema . Resource {
return & schema . Resource {
Create : resourceAwsDbInstanceCreate ,
Read : resourceAwsDbInstanceRead ,
2015-03-24 21:34:13 +01:00
Update : resourceAwsDbInstanceUpdate ,
2014-11-21 17:58:34 +01:00
Delete : resourceAwsDbInstanceDelete ,
2016-07-07 17:26:35 +02:00
Importer : & schema . ResourceImporter {
2016-07-15 19:24:58 +02:00
State : resourceAwsDbInstanceImport ,
2016-07-07 17:26:35 +02:00
} ,
2014-11-21 17:58:34 +01:00
2017-03-02 18:07:49 +01:00
Timeouts : & schema . ResourceTimeout {
Create : schema . DefaultTimeout ( 40 * time . Minute ) ,
Update : schema . DefaultTimeout ( 80 * time . Minute ) ,
Delete : schema . DefaultTimeout ( 40 * time . Minute ) ,
} ,
2014-11-21 17:58:34 +01:00
Schema : map [ string ] * schema . Schema {
2016-11-30 12:50:26 +01:00
"name" : {
2014-11-21 17:58:34 +01:00
Type : schema . TypeString ,
2015-01-28 17:48:30 +01:00
Optional : true ,
2015-05-13 23:36:30 +02:00
Computed : true ,
2014-11-21 17:58:34 +01:00
ForceNew : true ,
} ,
2016-11-30 12:50:26 +01:00
"arn" : {
2015-12-08 17:52:17 +01:00
Type : schema . TypeString ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"username" : {
2014-11-21 17:58:34 +01:00
Type : schema . TypeString ,
2015-09-09 14:06:53 +02:00
Optional : true ,
Computed : true ,
2014-11-21 17:58:34 +01:00
ForceNew : true ,
} ,
2016-11-30 12:50:26 +01:00
"password" : {
2016-05-28 02:00:59 +02:00
Type : schema . TypeString ,
Optional : true ,
Sensitive : true ,
2014-11-21 17:58:34 +01:00
} ,
2016-11-30 12:50:26 +01:00
"engine" : {
2014-11-21 17:58:34 +01:00
Type : schema . TypeString ,
2015-09-09 14:06:53 +02:00
Optional : true ,
Computed : true ,
2014-11-21 17:58:34 +01:00
ForceNew : true ,
2015-07-16 07:37:21 +02:00
StateFunc : func ( v interface { } ) string {
value := v . ( string )
return strings . ToLower ( value )
} ,
2014-11-21 17:58:34 +01:00
} ,
2016-11-30 12:50:26 +01:00
"engine_version" : {
2017-01-24 00:12:34 +01:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
DiffSuppressFunc : suppressAwsDbEngineVersionDiffs ,
2014-11-21 17:58:34 +01:00
} ,
2016-11-30 12:50:26 +01:00
"character_set_name" : {
2016-01-27 18:39:00 +01:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2016-11-30 12:50:26 +01:00
"storage_encrypted" : {
2015-02-24 19:34:08 +01:00
Type : schema . TypeBool ,
Optional : true ,
ForceNew : true ,
} ,
2016-11-30 12:50:26 +01:00
"allocated_storage" : {
2014-11-21 17:58:34 +01:00
Type : schema . TypeInt ,
2015-09-09 14:06:53 +02:00
Optional : true ,
Computed : true ,
2014-11-21 17:58:34 +01:00
} ,
2016-11-30 12:50:26 +01:00
"storage_type" : {
2015-01-30 19:01:10 +01:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"identifier" : {
2017-03-31 19:22:57 +02:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
ConflictsWith : [ ] string { "identifier_prefix" } ,
ValidateFunc : validateRdsIdentifier ,
} ,
"identifier_prefix" : {
2015-10-07 22:35:06 +02:00
Type : schema . TypeString ,
2016-03-18 21:15:30 +01:00
Optional : true ,
Computed : true ,
2015-10-07 22:35:06 +02:00
ForceNew : true ,
2017-03-31 19:22:57 +02:00
ValidateFunc : validateRdsIdentifierPrefix ,
2014-11-21 17:58:34 +01:00
} ,
2016-11-30 12:50:26 +01:00
"instance_class" : {
2014-11-21 17:58:34 +01:00
Type : schema . TypeString ,
Required : true ,
} ,
2014-11-24 14:04:48 +01:00
2016-11-30 12:50:26 +01:00
"availability_zone" : {
2014-11-21 17:58:34 +01:00
Type : schema . TypeString ,
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2014-11-21 17:58:34 +01:00
ForceNew : true ,
} ,
2016-11-30 12:50:26 +01:00
"backup_retention_period" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeInt ,
Optional : true ,
2015-05-13 23:36:30 +02:00
Computed : true ,
2014-11-21 17:58:34 +01:00
} ,
2016-11-30 12:50:26 +01:00
"backup_window" : {
2017-01-09 14:12:07 +01:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ValidateFunc : validateOnceADayWindowFormat ,
2014-11-24 14:04:48 +01:00
} ,
2016-11-30 12:50:26 +01:00
"iops" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeInt ,
Optional : true ,
} ,
2016-11-30 12:50:26 +01:00
"license_model" : {
2015-05-14 16:44:22 +02:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"maintenance_window" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeString ,
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2015-08-24 18:08:19 +02:00
StateFunc : func ( v interface { } ) string {
2015-08-24 18:25:43 +02:00
if v != nil {
value := v . ( string )
return strings . ToLower ( value )
}
return ""
2015-08-24 18:08:19 +02:00
} ,
2017-01-09 14:12:07 +01:00
ValidateFunc : validateOnceAWeekWindowFormat ,
2014-11-24 14:04:48 +01:00
} ,
2016-11-30 12:50:26 +01:00
"multi_az" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeBool ,
2014-11-21 17:58:34 +01:00
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
} ,
2016-11-30 12:50:26 +01:00
"port" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeInt ,
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
} ,
2016-11-30 12:50:26 +01:00
"publicly_accessible" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeBool ,
Optional : true ,
2016-06-11 00:13:53 +02:00
Default : false ,
2014-11-24 14:04:48 +01:00
} ,
2016-11-30 12:50:26 +01:00
"vpc_security_group_ids" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeSet ,
Optional : true ,
2015-03-25 16:14:45 +01:00
Computed : true ,
2014-11-21 17:58:34 +01:00
Elem : & schema . Schema { Type : schema . TypeString } ,
2015-04-09 15:38:16 +02:00
Set : schema . HashString ,
2014-11-21 17:58:34 +01:00
} ,
2016-11-30 12:50:26 +01:00
"security_group_names" : {
2014-11-21 17:58:34 +01:00
Type : schema . TypeSet ,
Optional : true ,
Elem : & schema . Schema { Type : schema . TypeString } ,
2015-04-09 15:38:16 +02:00
Set : schema . HashString ,
2014-11-21 17:58:34 +01:00
} ,
2014-11-24 14:04:48 +01:00
2016-11-30 12:50:26 +01:00
"final_snapshot_identifier" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeString ,
Optional : true ,
2015-06-24 18:29:24 +02:00
ValidateFunc : func ( v interface { } , k string ) ( ws [ ] string , es [ ] error ) {
2015-06-25 12:06:00 +02:00
value := v . ( string )
if ! regexp . MustCompile ( ` ^[0-9A-Za-z-]+$ ` ) . MatchString ( value ) {
2015-06-08 03:49:48 +02:00
es = append ( es , fmt . Errorf (
2015-06-25 12:06:00 +02:00
"only alphanumeric characters and hyphens allowed in %q" , k ) )
2015-06-08 03:49:48 +02:00
}
2015-06-25 12:06:00 +02:00
if regexp . MustCompile ( ` -- ` ) . MatchString ( value ) {
es = append ( es , fmt . Errorf ( "%q cannot contain two consecutive hyphens" , k ) )
2015-06-08 03:49:48 +02:00
}
2015-06-25 12:06:00 +02:00
if regexp . MustCompile ( ` -$ ` ) . MatchString ( value ) {
es = append ( es , fmt . Errorf ( "%q cannot end in a hyphen" , k ) )
2015-06-08 03:49:48 +02:00
}
return
} ,
2014-11-24 14:04:48 +01:00
} ,
2016-11-30 12:50:26 +01:00
"skip_final_snapshot" : {
2015-11-11 00:05:07 +01:00
Type : schema . TypeBool ,
Optional : true ,
2017-02-03 18:21:25 +01:00
Default : false ,
2015-11-11 00:05:07 +01:00
} ,
2016-11-30 12:50:26 +01:00
"copy_tags_to_snapshot" : {
2015-10-16 18:14:11 +02:00
Type : schema . TypeBool ,
Optional : true ,
Default : false ,
} ,
2016-11-30 12:50:26 +01:00
"db_subnet_group_name" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeString ,
Optional : true ,
2015-03-25 16:14:45 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
} ,
2016-11-30 12:50:26 +01:00
"parameter_group_name" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeString ,
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
} ,
2016-11-30 12:50:26 +01:00
"address" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeString ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"endpoint" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeString ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"hosted_zone_id" : {
2016-11-09 19:40:35 +01:00
Type : schema . TypeString ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"status" : {
2014-11-24 14:04:48 +01:00
Type : schema . TypeString ,
Computed : true ,
} ,
2015-03-31 16:41:37 +02:00
// apply_immediately is used to determine when the update modifications
// take place.
// See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
2016-11-30 12:50:26 +01:00
"apply_immediately" : {
2015-03-31 16:41:37 +02:00
Type : schema . TypeBool ,
Optional : true ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"replicate_source_db" : {
2015-05-13 23:36:30 +02:00
Type : schema . TypeString ,
Optional : true ,
} ,
2016-11-30 12:50:26 +01:00
"replicas" : {
2015-05-13 23:36:30 +02:00
Type : schema . TypeList ,
Computed : true ,
Elem : & schema . Schema { Type : schema . TypeString } ,
} ,
2016-11-30 12:50:26 +01:00
"snapshot_identifier" : {
2015-05-24 23:51:35 +02:00
Type : schema . TypeString ,
Computed : false ,
Optional : true ,
2016-09-13 04:09:15 +02:00
ForceNew : true ,
2015-05-24 23:51:35 +02:00
Elem : & schema . Schema { Type : schema . TypeString } ,
} ,
2016-11-30 12:50:26 +01:00
"auto_minor_version_upgrade" : {
2015-05-25 03:18:36 +02:00
Type : schema . TypeBool ,
Optional : true ,
2015-10-28 21:07:11 +01:00
Default : true ,
2015-05-25 03:18:36 +02:00
} ,
2016-11-30 12:50:26 +01:00
"allow_major_version_upgrade" : {
2015-08-21 23:56:04 +02:00
Type : schema . TypeBool ,
Computed : false ,
Optional : true ,
} ,
2016-11-30 12:50:26 +01:00
"monitoring_role_arn" : {
2016-02-01 23:32:38 +01:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"monitoring_interval" : {
2016-02-01 23:32:38 +01:00
Type : schema . TypeInt ,
Optional : true ,
Default : 0 ,
} ,
2016-11-30 12:50:26 +01:00
"option_group_name" : {
2015-12-21 10:15:52 +01:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
} ,
2016-11-30 12:50:26 +01:00
"kms_key_id" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
ValidateFunc : validateArn ,
2016-05-13 18:20:29 +02:00
} ,
2017-01-17 23:43:53 +01:00
"timezone" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2017-04-29 21:32:21 +02:00
"iam_database_authentication_enabled" : {
Type : schema . TypeBool ,
Optional : true ,
} ,
2017-05-28 07:47:55 +02:00
"resource_id" : {
Type : schema . TypeString ,
Computed : true ,
} ,
2015-03-24 21:34:13 +01:00
"tags" : tagsSchema ( ) ,
2014-11-21 17:58:34 +01:00
} ,
}
}
2014-07-22 22:26:48 +02:00
2014-11-21 17:58:34 +01:00
func resourceAwsDbInstanceCreate ( d * schema . ResourceData , meta interface { } ) error {
2015-04-13 22:45:55 +02:00
conn := meta . ( * AWSClient ) . rdsconn
2015-03-24 21:34:13 +01:00
tags := tagsFromMapRDS ( d . Get ( "tags" ) . ( map [ string ] interface { } ) )
2014-07-22 22:26:48 +02:00
2017-03-31 19:22:57 +02:00
var identifier string
if v , ok := d . GetOk ( "identifier" ) ; ok {
identifier = v . ( string )
} else {
if v , ok := d . GetOk ( "identifier_prefix" ) ; ok {
identifier = resource . PrefixedUniqueId ( v . ( string ) )
} else {
identifier = resource . UniqueId ( )
}
2016-03-18 21:15:30 +01:00
// SQL Server identifier size is max 15 chars, so truncate
if engine := d . Get ( "engine" ) . ( string ) ; engine != "" {
if strings . Contains ( strings . ToLower ( engine ) , "sqlserver" ) {
identifier = identifier [ : 15 ]
}
}
d . Set ( "identifier" , identifier )
}
2015-05-13 23:36:30 +02:00
if v , ok := d . GetOk ( "replicate_source_db" ) ; ok {
opts := rds . CreateDBInstanceReadReplicaInput {
SourceDBInstanceIdentifier : aws . String ( v . ( string ) ) ,
2015-10-16 18:14:11 +02:00
CopyTagsToSnapshot : aws . Bool ( d . Get ( "copy_tags_to_snapshot" ) . ( bool ) ) ,
2015-05-13 23:36:30 +02:00
DBInstanceClass : aws . String ( d . Get ( "instance_class" ) . ( string ) ) ,
2016-03-18 21:15:30 +01:00
DBInstanceIdentifier : aws . String ( identifier ) ,
2016-06-10 23:55:36 +02:00
PubliclyAccessible : aws . Bool ( d . Get ( "publicly_accessible" ) . ( bool ) ) ,
2015-05-13 23:36:30 +02:00
Tags : tags ,
}
if attr , ok := d . GetOk ( "iops" ) ; ok {
2015-08-17 20:27:16 +02:00
opts . Iops = aws . Int64 ( int64 ( attr . ( int ) ) )
2015-05-13 23:36:30 +02:00
}
2015-01-30 19:01:10 +01:00
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "port" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . Port = aws . Int64 ( int64 ( attr . ( int ) ) )
2015-05-13 23:36:30 +02:00
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "availability_zone" ) ; ok {
opts . AvailabilityZone = aws . String ( attr . ( string ) )
}
2014-07-22 22:26:48 +02:00
2015-12-03 17:48:34 +01:00
if attr , ok := d . GetOk ( "storage_type" ) ; ok {
opts . StorageType = aws . String ( attr . ( string ) )
}
2015-12-08 14:55:17 +01:00
if attr , ok := d . GetOk ( "db_subnet_group_name" ) ; ok {
opts . DBSubnetGroupName = aws . String ( attr . ( string ) )
}
2015-12-03 17:48:34 +01:00
2016-02-01 23:32:38 +01:00
if attr , ok := d . GetOk ( "monitoring_role_arn" ) ; ok {
opts . MonitoringRoleArn = aws . String ( attr . ( string ) )
}
if attr , ok := d . GetOk ( "monitoring_interval" ) ; ok {
opts . MonitoringInterval = aws . Int64 ( int64 ( attr . ( int ) ) )
}
2015-12-21 10:15:52 +01:00
if attr , ok := d . GetOk ( "option_group_name" ) ; ok {
opts . OptionGroupName = aws . String ( attr . ( string ) )
}
2015-12-03 17:48:34 +01:00
log . Printf ( "[DEBUG] DB Instance Replica create configuration: %#v" , opts )
2015-05-13 23:36:30 +02:00
_ , err := conn . CreateDBInstanceReadReplica ( & opts )
if err != nil {
return fmt . Errorf ( "Error creating DB Instance: %s" , err )
}
2015-05-24 23:51:35 +02:00
} else if _ , ok := d . GetOk ( "snapshot_identifier" ) ; ok {
opts := rds . RestoreDBInstanceFromDBSnapshotInput {
2015-10-28 21:07:11 +01:00
DBInstanceClass : aws . String ( d . Get ( "instance_class" ) . ( string ) ) ,
DBInstanceIdentifier : aws . String ( d . Get ( "identifier" ) . ( string ) ) ,
DBSnapshotIdentifier : aws . String ( d . Get ( "snapshot_identifier" ) . ( string ) ) ,
AutoMinorVersionUpgrade : aws . Bool ( d . Get ( "auto_minor_version_upgrade" ) . ( bool ) ) ,
2016-06-10 23:55:36 +02:00
PubliclyAccessible : aws . Bool ( d . Get ( "publicly_accessible" ) . ( bool ) ) ,
Tags : tags ,
CopyTagsToSnapshot : aws . Bool ( d . Get ( "copy_tags_to_snapshot" ) . ( bool ) ) ,
2015-05-25 03:18:36 +02:00
}
2016-12-12 13:56:56 +01:00
if attr , ok := d . GetOk ( "name" ) ; ok {
2017-03-29 00:10:34 +02:00
// "Note: This parameter [DBName] doesn't apply to the MySQL, PostgreSQL, or MariaDB engines."
// https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromDBSnapshot.html
switch strings . ToLower ( d . Get ( "engine" ) . ( string ) ) {
case "mysql" , "postgres" , "mariadb" :
// skip
default :
opts . DBName = aws . String ( attr . ( string ) )
}
2016-12-12 13:56:56 +01:00
}
2015-05-25 03:18:36 +02:00
if attr , ok := d . GetOk ( "availability_zone" ) ; ok {
opts . AvailabilityZone = aws . String ( attr . ( string ) )
}
if attr , ok := d . GetOk ( "db_subnet_group_name" ) ; ok {
opts . DBSubnetGroupName = aws . String ( attr . ( string ) )
}
if attr , ok := d . GetOk ( "engine" ) ; ok {
opts . Engine = aws . String ( attr . ( string ) )
}
if attr , ok := d . GetOk ( "iops" ) ; ok {
2015-08-17 20:27:16 +02:00
opts . Iops = aws . Int64 ( int64 ( attr . ( int ) ) )
2015-05-25 03:18:36 +02:00
}
if attr , ok := d . GetOk ( "license_model" ) ; ok {
opts . LicenseModel = aws . String ( attr . ( string ) )
}
if attr , ok := d . GetOk ( "multi_az" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . MultiAZ = aws . Bool ( attr . ( bool ) )
2015-05-25 03:18:36 +02:00
}
if attr , ok := d . GetOk ( "option_group_name" ) ; ok {
opts . OptionGroupName = aws . String ( attr . ( string ) )
2016-05-13 18:20:29 +02:00
2015-05-25 03:18:36 +02:00
}
if attr , ok := d . GetOk ( "port" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . Port = aws . Int64 ( int64 ( attr . ( int ) ) )
2015-05-25 03:18:36 +02:00
}
if attr , ok := d . GetOk ( "tde_credential_arn" ) ; ok {
2015-08-17 20:27:16 +02:00
opts . TdeCredentialArn = aws . String ( attr . ( string ) )
2015-05-25 03:18:36 +02:00
}
if attr , ok := d . GetOk ( "storage_type" ) ; ok {
opts . StorageType = aws . String ( attr . ( string ) )
}
2016-02-11 23:39:53 +01:00
log . Printf ( "[DEBUG] DB Instance restore from snapshot configuration: %s" , opts )
2015-05-24 23:51:35 +02:00
_ , err := conn . RestoreDBInstanceFromDBSnapshot ( & opts )
if err != nil {
return fmt . Errorf ( "Error creating DB Instance: %s" , err )
}
2015-10-14 19:23:11 +02:00
2016-02-11 23:39:53 +01:00
var sgUpdate bool
2016-09-02 06:21:37 +02:00
var passwordUpdate bool
if _ , ok := d . GetOk ( "password" ) ; ok {
passwordUpdate = true
}
2015-10-14 19:23:11 +02:00
if attr := d . Get ( "vpc_security_group_ids" ) . ( * schema . Set ) ; attr . Len ( ) > 0 {
2016-02-11 23:39:53 +01:00
sgUpdate = true
}
if attr := d . Get ( "security_group_names" ) . ( * schema . Set ) ; attr . Len ( ) > 0 {
sgUpdate = true
}
2016-09-02 06:21:37 +02:00
if sgUpdate || passwordUpdate {
2015-10-29 22:55:23 +01:00
log . Printf ( "[INFO] DB is restoring from snapshot with default security, but custom security should be set, will now update after snapshot is restored!" )
2015-10-29 22:53:40 +01:00
2015-10-14 19:23:11 +02:00
// wait for instance to get up and then modify security
d . SetId ( d . Get ( "identifier" ) . ( string ) )
log . Printf ( "[INFO] DB Instance ID: %s" , d . Id ( ) )
log . Println (
"[INFO] Waiting for DB Instance to be available" )
stateConf := & resource . StateChangeConf {
2016-01-04 16:44:53 +01:00
Pending : [ ] string { "creating" , "backing-up" , "modifying" , "resetting-master-credentials" ,
"maintenance" , "renaming" , "rebooting" , "upgrading" } ,
2016-01-21 02:20:41 +01:00
Target : [ ] string { "available" } ,
2015-10-14 19:23:11 +02:00
Refresh : resourceAwsDbInstanceStateRefreshFunc ( d , meta ) ,
2017-03-02 18:07:49 +01:00
Timeout : d . Timeout ( schema . TimeoutCreate ) ,
2015-10-14 19:23:11 +02:00
MinTimeout : 10 * time . Second ,
Delay : 30 * time . Second , // Wait 30 secs before starting
}
// Wait, catching any errors
_ , err := stateConf . WaitForState ( )
if err != nil {
return err
}
err = resourceAwsDbInstanceUpdate ( d , meta )
if err != nil {
return err
}
}
2015-05-13 23:36:30 +02:00
} else {
2015-09-09 14:06:53 +02:00
if _ , ok := d . GetOk ( "allocated_storage" ) ; ! ok {
return fmt . Errorf ( ` provider.aws: aws_db_instance: %s: "allocated_storage": required field is not set ` , d . Get ( "name" ) . ( string ) )
}
if _ , ok := d . GetOk ( "engine" ) ; ! ok {
return fmt . Errorf ( ` provider.aws: aws_db_instance: %s: "engine": required field is not set ` , d . Get ( "name" ) . ( string ) )
}
if _ , ok := d . GetOk ( "password" ) ; ! ok {
return fmt . Errorf ( ` provider.aws: aws_db_instance: %s: "password": required field is not set ` , d . Get ( "name" ) . ( string ) )
}
if _ , ok := d . GetOk ( "username" ) ; ! ok {
return fmt . Errorf ( ` provider.aws: aws_db_instance: %s: "username": required field is not set ` , d . Get ( "name" ) . ( string ) )
}
2015-05-13 23:36:30 +02:00
opts := rds . CreateDBInstanceInput {
2015-07-07 09:58:37 +02:00
AllocatedStorage : aws . Int64 ( int64 ( d . Get ( "allocated_storage" ) . ( int ) ) ) ,
DBName : aws . String ( d . Get ( "name" ) . ( string ) ) ,
DBInstanceClass : aws . String ( d . Get ( "instance_class" ) . ( string ) ) ,
DBInstanceIdentifier : aws . String ( d . Get ( "identifier" ) . ( string ) ) ,
MasterUsername : aws . String ( d . Get ( "username" ) . ( string ) ) ,
MasterUserPassword : aws . String ( d . Get ( "password" ) . ( string ) ) ,
Engine : aws . String ( d . Get ( "engine" ) . ( string ) ) ,
EngineVersion : aws . String ( d . Get ( "engine_version" ) . ( string ) ) ,
StorageEncrypted : aws . Bool ( d . Get ( "storage_encrypted" ) . ( bool ) ) ,
AutoMinorVersionUpgrade : aws . Bool ( d . Get ( "auto_minor_version_upgrade" ) . ( bool ) ) ,
2016-06-10 23:55:36 +02:00
PubliclyAccessible : aws . Bool ( d . Get ( "publicly_accessible" ) . ( bool ) ) ,
Tags : tags ,
CopyTagsToSnapshot : aws . Bool ( d . Get ( "copy_tags_to_snapshot" ) . ( bool ) ) ,
2015-05-13 23:36:30 +02:00
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
attr := d . Get ( "backup_retention_period" )
2015-07-28 22:29:46 +02:00
opts . BackupRetentionPeriod = aws . Int64 ( int64 ( attr . ( int ) ) )
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "multi_az" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . MultiAZ = aws . Bool ( attr . ( bool ) )
2016-05-13 18:20:29 +02:00
2015-05-13 23:36:30 +02:00
}
2014-11-24 14:04:48 +01:00
2016-01-27 18:39:00 +01:00
if attr , ok := d . GetOk ( "character_set_name" ) ; ok {
opts . CharacterSetName = aws . String ( attr . ( string ) )
}
2017-01-17 23:43:53 +01:00
if attr , ok := d . GetOk ( "timezone" ) ; ok {
opts . Timezone = aws . String ( attr . ( string ) )
}
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "maintenance_window" ) ; ok {
opts . PreferredMaintenanceWindow = aws . String ( attr . ( string ) )
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "backup_window" ) ; ok {
opts . PreferredBackupWindow = aws . String ( attr . ( string ) )
}
2015-05-14 16:44:22 +02:00
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "license_model" ) ; ok {
opts . LicenseModel = aws . String ( attr . ( string ) )
}
if attr , ok := d . GetOk ( "parameter_group_name" ) ; ok {
opts . DBParameterGroupName = aws . String ( attr . ( string ) )
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
if attr := d . Get ( "vpc_security_group_ids" ) . ( * schema . Set ) ; attr . Len ( ) > 0 {
var s [ ] * string
for _ , v := range attr . List ( ) {
s = append ( s , aws . String ( v . ( string ) ) )
}
2015-08-17 20:27:16 +02:00
opts . VpcSecurityGroupIds = s
2015-05-13 23:36:30 +02:00
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
if attr := d . Get ( "security_group_names" ) . ( * schema . Set ) ; attr . Len ( ) > 0 {
var s [ ] * string
for _ , v := range attr . List ( ) {
s = append ( s , aws . String ( v . ( string ) ) )
}
opts . DBSecurityGroups = s
}
if attr , ok := d . GetOk ( "storage_type" ) ; ok {
opts . StorageType = aws . String ( attr . ( string ) )
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "db_subnet_group_name" ) ; ok {
opts . DBSubnetGroupName = aws . String ( attr . ( string ) )
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "iops" ) ; ok {
2015-08-17 20:27:16 +02:00
opts . Iops = aws . Int64 ( int64 ( attr . ( int ) ) )
2015-05-13 23:36:30 +02:00
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "port" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . Port = aws . Int64 ( int64 ( attr . ( int ) ) )
2014-11-24 14:04:48 +01:00
}
2014-07-22 22:26:48 +02:00
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "availability_zone" ) ; ok {
opts . AvailabilityZone = aws . String ( attr . ( string ) )
2014-11-24 14:04:48 +01:00
}
2014-07-23 04:22:52 +02:00
2016-02-01 23:32:38 +01:00
if attr , ok := d . GetOk ( "monitoring_role_arn" ) ; ok {
opts . MonitoringRoleArn = aws . String ( attr . ( string ) )
}
if attr , ok := d . GetOk ( "monitoring_interval" ) ; ok {
opts . MonitoringInterval = aws . Int64 ( int64 ( attr . ( int ) ) )
}
2015-12-21 10:15:52 +01:00
if attr , ok := d . GetOk ( "option_group_name" ) ; ok {
opts . OptionGroupName = aws . String ( attr . ( string ) )
}
2016-05-13 18:20:29 +02:00
if attr , ok := d . GetOk ( "kms_key_id" ) ; ok {
opts . KmsKeyId = aws . String ( attr . ( string ) )
}
2017-04-29 21:32:21 +02:00
if attr , ok := d . GetOk ( "iam_database_authentication_enabled" ) ; ok {
opts . EnableIAMDatabaseAuthentication = aws . Bool ( attr . ( bool ) )
}
2015-05-13 23:36:30 +02:00
log . Printf ( "[DEBUG] DB Instance create configuration: %#v" , opts )
var err error
2016-03-09 23:53:32 +01:00
err = resource . Retry ( 5 * time . Minute , func ( ) * resource . RetryError {
2016-03-08 21:08:20 +01:00
_ , err = conn . CreateDBInstance ( & opts )
if err != nil {
if awsErr , ok := err . ( awserr . Error ) ; ok {
if awsErr . Code ( ) == "InvalidParameterValue" && strings . Contains ( awsErr . Message ( ) , "ENHANCED_MONITORING" ) {
2016-03-09 23:53:32 +01:00
return resource . RetryableError ( awsErr )
2016-03-08 21:08:20 +01:00
}
}
2016-03-09 23:53:32 +01:00
return resource . NonRetryableError ( err )
2016-03-08 21:08:20 +01:00
}
return nil
} )
2015-05-13 23:36:30 +02:00
if err != nil {
return fmt . Errorf ( "Error creating DB Instance: %s" , err )
}
2014-07-22 22:26:48 +02:00
}
2014-11-21 17:58:34 +01:00
d . SetId ( d . Get ( "identifier" ) . ( string ) )
2014-07-22 22:26:48 +02:00
2014-11-21 17:58:34 +01:00
log . Printf ( "[INFO] DB Instance ID: %s" , d . Id ( ) )
2014-07-22 22:26:48 +02:00
log . Println (
"[INFO] Waiting for DB Instance to be available" )
stateConf := & resource . StateChangeConf {
2016-01-04 16:44:53 +01:00
Pending : [ ] string { "creating" , "backing-up" , "modifying" , "resetting-master-credentials" ,
2016-09-11 20:29:23 +02:00
"maintenance" , "renaming" , "rebooting" , "upgrading" , "configuring-enhanced-monitoring" } ,
2016-01-21 02:20:41 +01:00
Target : [ ] string { "available" } ,
2014-11-24 14:04:48 +01:00
Refresh : resourceAwsDbInstanceStateRefreshFunc ( d , meta ) ,
2017-03-02 18:07:49 +01:00
Timeout : d . Timeout ( schema . TimeoutCreate ) ,
2014-07-23 00:45:17 +02:00
MinTimeout : 10 * time . Second ,
Delay : 30 * time . Second , // Wait 30 secs before starting
2014-07-22 22:26:48 +02:00
}
// Wait, catching any errors
2015-05-13 23:36:30 +02:00
_ , err := stateConf . WaitForState ( )
2014-07-22 22:26:48 +02:00
if err != nil {
2014-11-21 17:58:34 +01:00
return err
2014-07-22 22:26:48 +02:00
}
2014-11-21 17:58:34 +01:00
return resourceAwsDbInstanceRead ( d , meta )
}
func resourceAwsDbInstanceRead ( d * schema . ResourceData , meta interface { } ) error {
2015-05-07 23:21:37 +02:00
v , err := resourceAwsDbInstanceRetrieve ( d , meta )
2014-11-21 17:58:34 +01:00
2014-11-24 14:04:48 +01:00
if err != nil {
return err
2014-11-21 17:58:34 +01:00
}
2014-11-24 14:04:48 +01:00
if v == nil {
d . SetId ( "" )
return nil
2014-11-21 17:58:34 +01:00
}
2014-11-24 14:04:48 +01:00
2015-04-01 16:13:41 +02:00
d . Set ( "name" , v . DBName )
2016-07-07 17:26:35 +02:00
d . Set ( "identifier" , v . DBInstanceIdentifier )
2017-05-28 07:47:55 +02:00
d . Set ( "resource_id" , v . DbiResourceId )
2015-04-01 16:13:41 +02:00
d . Set ( "username" , v . MasterUsername )
d . Set ( "engine" , v . Engine )
d . Set ( "engine_version" , v . EngineVersion )
d . Set ( "allocated_storage" , v . AllocatedStorage )
2016-06-21 21:53:13 +02:00
d . Set ( "iops" , v . Iops )
2015-10-16 18:14:11 +02:00
d . Set ( "copy_tags_to_snapshot" , v . CopyTagsToSnapshot )
2015-10-28 21:07:11 +01:00
d . Set ( "auto_minor_version_upgrade" , v . AutoMinorVersionUpgrade )
2015-04-01 16:13:41 +02:00
d . Set ( "storage_type" , v . StorageType )
d . Set ( "instance_class" , v . DBInstanceClass )
d . Set ( "availability_zone" , v . AvailabilityZone )
d . Set ( "backup_retention_period" , v . BackupRetentionPeriod )
d . Set ( "backup_window" , v . PreferredBackupWindow )
2015-05-14 16:44:22 +02:00
d . Set ( "license_model" , v . LicenseModel )
2015-04-01 16:13:41 +02:00
d . Set ( "maintenance_window" , v . PreferredMaintenanceWindow )
2016-03-09 19:33:00 +01:00
d . Set ( "publicly_accessible" , v . PubliclyAccessible )
2015-04-01 16:13:41 +02:00
d . Set ( "multi_az" , v . MultiAZ )
2016-05-13 18:20:29 +02:00
d . Set ( "kms_key_id" , v . KmsKeyId )
2016-07-12 10:07:25 +02:00
d . Set ( "port" , v . DbInstancePort )
2017-04-29 21:32:21 +02:00
d . Set ( "iam_database_authentication_enabled" , v . IAMDatabaseAuthenticationEnabled )
2015-04-01 16:13:41 +02:00
if v . DBSubnetGroup != nil {
d . Set ( "db_subnet_group_name" , v . DBSubnetGroup . DBSubnetGroupName )
2015-04-01 14:33:08 +02:00
}
2015-02-23 22:22:52 +01:00
2016-01-27 18:39:00 +01:00
if v . CharacterSetName != nil {
d . Set ( "character_set_name" , v . CharacterSetName )
}
2017-01-17 23:43:53 +01:00
d . Set ( "timezone" , v . Timezone )
2015-02-23 22:22:52 +01:00
if len ( v . DBParameterGroups ) > 0 {
2015-04-01 16:13:41 +02:00
d . Set ( "parameter_group_name" , v . DBParameterGroups [ 0 ] . DBParameterGroupName )
2015-02-23 22:22:52 +01:00
}
2015-04-01 16:13:41 +02:00
if v . Endpoint != nil {
d . Set ( "port" , v . Endpoint . Port )
d . Set ( "address" , v . Endpoint . Address )
2016-11-10 07:41:43 +01:00
d . Set ( "hosted_zone_id" , v . Endpoint . HostedZoneId )
2015-04-01 16:13:41 +02:00
if v . Endpoint . Address != nil && v . Endpoint . Port != nil {
d . Set ( "endpoint" ,
fmt . Sprintf ( "%s:%d" , * v . Endpoint . Address , * v . Endpoint . Port ) )
}
}
d . Set ( "status" , v . DBInstanceStatus )
d . Set ( "storage_encrypted" , v . StorageEncrypted )
2015-12-21 10:15:52 +01:00
if v . OptionGroupMemberships != nil {
d . Set ( "option_group_name" , v . OptionGroupMemberships [ 0 ] . OptionGroupName )
}
2014-11-24 14:04:48 +01:00
2016-02-01 23:32:38 +01:00
if v . MonitoringInterval != nil {
d . Set ( "monitoring_interval" , v . MonitoringInterval )
}
if v . MonitoringRoleArn != nil {
d . Set ( "monitoring_role_arn" , v . MonitoringRoleArn )
}
2015-03-24 21:34:13 +01:00
// list tags for resource
// set tags
2015-04-13 22:45:55 +02:00
conn := meta . ( * AWSClient ) . rdsconn
2016-10-07 05:36:44 +02:00
arn , err := buildRDSARN ( d . Id ( ) , meta . ( * AWSClient ) . partition , meta . ( * AWSClient ) . accountid , meta . ( * AWSClient ) . region )
2015-03-24 21:34:13 +01:00
if err != nil {
2015-04-09 20:19:33 +02:00
name := "<empty>"
2015-04-09 21:27:52 +02:00
if v . DBName != nil && * v . DBName != "" {
2015-04-09 20:19:33 +02:00
name = * v . DBName
}
log . Printf ( "[DEBUG] Error building ARN for DB Instance, not setting Tags for DB %s" , name )
2015-03-24 21:34:13 +01:00
} else {
2015-12-08 17:52:17 +01:00
d . Set ( "arn" , arn )
2015-04-13 22:45:55 +02:00
resp , err := conn . ListTagsForResource ( & rds . ListTagsForResourceInput {
2015-03-24 21:34:13 +01:00
ResourceName : aws . String ( arn ) ,
} )
if err != nil {
2015-09-11 20:56:20 +02:00
log . Printf ( "[DEBUG] Error retrieving tags for ARN: %s" , arn )
2015-03-24 21:34:13 +01:00
}
2015-04-13 22:45:55 +02:00
var dt [ ] * rds . Tag
2015-03-24 21:34:13 +01:00
if len ( resp . TagList ) > 0 {
dt = resp . TagList
}
d . Set ( "tags" , tagsToMapRDS ( dt ) )
}
2014-11-24 14:04:48 +01:00
// Create an empty schema.Set to hold all vpc security group ids
ids := & schema . Set {
2015-04-09 15:38:16 +02:00
F : schema . HashString ,
2014-11-24 14:04:48 +01:00
}
2015-08-17 20:27:16 +02:00
for _ , v := range v . VpcSecurityGroups {
ids . Add ( * v . VpcSecurityGroupId )
2014-07-22 22:26:48 +02:00
}
2014-11-24 14:04:48 +01:00
d . Set ( "vpc_security_group_ids" , ids )
2014-07-22 22:26:48 +02:00
2014-11-24 14:04:48 +01:00
// Create an empty schema.Set to hold all security group names
sgn := & schema . Set {
2015-04-09 15:38:16 +02:00
F : schema . HashString ,
2014-11-24 14:04:48 +01:00
}
2015-02-23 22:22:52 +01:00
for _ , v := range v . DBSecurityGroups {
sgn . Add ( * v . DBSecurityGroupName )
2014-11-24 14:04:48 +01:00
}
d . Set ( "security_group_names" , sgn )
2015-05-13 23:36:30 +02:00
// replica things
var replicas [ ] string
for _ , v := range v . ReadReplicaDBInstanceIdentifiers {
replicas = append ( replicas , * v )
}
if err := d . Set ( "replicas" , replicas ) ; err != nil {
return fmt . Errorf ( "[DEBUG] Error setting replicas attribute: %#v, error: %#v" , replicas , err )
}
d . Set ( "replicate_source_db" , v . ReadReplicaSourceDBInstanceIdentifier )
2014-11-24 14:04:48 +01:00
return nil
2014-07-22 22:26:48 +02:00
}
2014-11-21 17:58:34 +01:00
func resourceAwsDbInstanceDelete ( d * schema . ResourceData , meta interface { } ) error {
2015-04-13 22:45:55 +02:00
conn := meta . ( * AWSClient ) . rdsconn
2014-07-22 22:26:48 +02:00
2014-11-21 17:58:34 +01:00
log . Printf ( "[DEBUG] DB Instance destroy: %v" , d . Id ( ) )
2014-07-22 22:26:48 +02:00
2015-04-13 22:45:55 +02:00
opts := rds . DeleteDBInstanceInput { DBInstanceIdentifier : aws . String ( d . Id ( ) ) }
2014-07-22 22:26:48 +02:00
2016-07-15 19:24:58 +02:00
skipFinalSnapshot := d . Get ( "skip_final_snapshot" ) . ( bool )
opts . SkipFinalSnapshot = aws . Bool ( skipFinalSnapshot )
2015-11-11 00:05:07 +01:00
2016-07-07 17:26:35 +02:00
if skipFinalSnapshot == false {
2015-11-11 17:39:24 +01:00
if name , present := d . GetOk ( "final_snapshot_identifier" ) ; present {
opts . FinalDBSnapshotIdentifier = aws . String ( name . ( string ) )
} else {
return fmt . Errorf ( "DB Instance FinalSnapshotIdentifier is required when a final snapshot is required" )
}
2014-07-22 22:26:48 +02:00
}
log . Printf ( "[DEBUG] DB Instance destroy configuration: %v" , opts )
2014-10-11 20:02:11 +02:00
if _ , err := conn . DeleteDBInstance ( & opts ) ; err != nil {
return err
}
2014-07-22 22:26:48 +02:00
2014-07-31 21:18:33 +02:00
log . Println (
"[INFO] Waiting for DB Instance to be destroyed" )
stateConf := & resource . StateChangeConf {
Pending : [ ] string { "creating" , "backing-up" ,
"modifying" , "deleting" , "available" } ,
2016-01-21 02:20:41 +01:00
Target : [ ] string { } ,
2014-11-24 14:04:48 +01:00
Refresh : resourceAwsDbInstanceStateRefreshFunc ( d , meta ) ,
2017-03-02 18:07:49 +01:00
Timeout : d . Timeout ( schema . TimeoutDelete ) ,
2014-07-31 21:18:33 +02:00
MinTimeout : 10 * time . Second ,
Delay : 30 * time . Second , // Wait 30 secs before starting
}
2014-10-11 20:02:11 +02:00
if _ , err := stateConf . WaitForState ( ) ; err != nil {
2014-07-22 22:26:48 +02:00
return err
}
return nil
}
2015-03-24 21:34:13 +01:00
func resourceAwsDbInstanceUpdate ( d * schema . ResourceData , meta interface { } ) error {
2015-04-13 22:45:55 +02:00
conn := meta . ( * AWSClient ) . rdsconn
2015-03-24 21:34:13 +01:00
d . Partial ( true )
2015-03-31 16:41:37 +02:00
2015-04-13 22:45:55 +02:00
req := & rds . ModifyDBInstanceInput {
2015-07-28 22:29:46 +02:00
ApplyImmediately : aws . Bool ( d . Get ( "apply_immediately" ) . ( bool ) ) ,
2015-03-31 16:41:37 +02:00
DBInstanceIdentifier : aws . String ( d . Id ( ) ) ,
}
2015-04-03 19:23:01 +02:00
d . SetPartial ( "apply_immediately" )
2015-03-31 16:41:37 +02:00
2017-03-15 17:02:00 +01:00
if ! d . Get ( "apply_immediately" ) . ( bool ) {
log . Println ( "[INFO] Only settings updating, instance changes will be applied in next maintenance window" )
}
2015-05-11 16:11:59 +02:00
requestUpdate := false
2016-06-21 21:53:13 +02:00
if d . HasChange ( "allocated_storage" ) || d . HasChange ( "iops" ) {
2015-04-03 19:23:01 +02:00
d . SetPartial ( "allocated_storage" )
2016-06-21 21:53:13 +02:00
d . SetPartial ( "iops" )
req . Iops = aws . Int64 ( int64 ( d . Get ( "iops" ) . ( int ) ) )
2015-07-28 22:29:46 +02:00
req . AllocatedStorage = aws . Int64 ( int64 ( d . Get ( "allocated_storage" ) . ( int ) ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-04-03 19:23:01 +02:00
}
2015-08-21 23:56:04 +02:00
if d . HasChange ( "allow_major_version_upgrade" ) {
d . SetPartial ( "allow_major_version_upgrade" )
req . AllowMajorVersionUpgrade = aws . Bool ( d . Get ( "allow_major_version_upgrade" ) . ( bool ) )
requestUpdate = true
}
2015-04-03 19:23:01 +02:00
if d . HasChange ( "backup_retention_period" ) {
d . SetPartial ( "backup_retention_period" )
2015-07-28 22:29:46 +02:00
req . BackupRetentionPeriod = aws . Int64 ( int64 ( d . Get ( "backup_retention_period" ) . ( int ) ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-04-03 19:23:01 +02:00
}
2015-10-16 18:14:11 +02:00
if d . HasChange ( "copy_tags_to_snapshot" ) {
d . SetPartial ( "copy_tags_to_snapshot" )
req . CopyTagsToSnapshot = aws . Bool ( d . Get ( "copy_tags_to_snapshot" ) . ( bool ) )
requestUpdate = true
}
2015-04-03 19:23:01 +02:00
if d . HasChange ( "instance_class" ) {
d . SetPartial ( "instance_class" )
req . DBInstanceClass = aws . String ( d . Get ( "instance_class" ) . ( string ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-04-03 19:23:01 +02:00
}
if d . HasChange ( "parameter_group_name" ) {
d . SetPartial ( "parameter_group_name" )
req . DBParameterGroupName = aws . String ( d . Get ( "parameter_group_name" ) . ( string ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-04-03 19:23:01 +02:00
}
2015-03-31 16:41:37 +02:00
if d . HasChange ( "engine_version" ) {
d . SetPartial ( "engine_version" )
req . EngineVersion = aws . String ( d . Get ( "engine_version" ) . ( string ) )
2016-08-25 14:54:40 +02:00
req . AllowMajorVersionUpgrade = aws . Bool ( d . Get ( "allow_major_version_upgrade" ) . ( bool ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-03-31 16:41:37 +02:00
}
2015-04-03 19:23:01 +02:00
if d . HasChange ( "backup_window" ) {
d . SetPartial ( "backup_window" )
req . PreferredBackupWindow = aws . String ( d . Get ( "backup_window" ) . ( string ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-04-03 19:23:01 +02:00
}
if d . HasChange ( "maintenance_window" ) {
d . SetPartial ( "maintenance_window" )
req . PreferredMaintenanceWindow = aws . String ( d . Get ( "maintenance_window" ) . ( string ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-04-03 19:23:01 +02:00
}
if d . HasChange ( "password" ) {
d . SetPartial ( "password" )
req . MasterUserPassword = aws . String ( d . Get ( "password" ) . ( string ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-04-03 19:23:01 +02:00
}
2015-03-31 16:41:37 +02:00
if d . HasChange ( "multi_az" ) {
d . SetPartial ( "multi_az" )
2015-07-28 22:29:46 +02:00
req . MultiAZ = aws . Bool ( d . Get ( "multi_az" ) . ( bool ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-03-31 16:41:37 +02:00
}
2015-11-17 02:47:35 +01:00
if d . HasChange ( "publicly_accessible" ) {
d . SetPartial ( "publicly_accessible" )
req . PubliclyAccessible = aws . Bool ( d . Get ( "publicly_accessible" ) . ( bool ) )
requestUpdate = true
}
2015-04-03 19:23:01 +02:00
if d . HasChange ( "storage_type" ) {
d . SetPartial ( "storage_type" )
req . StorageType = aws . String ( d . Get ( "storage_type" ) . ( string ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
2016-03-16 23:32:11 +01:00
if * req . StorageType == "io1" {
req . Iops = aws . Int64 ( int64 ( d . Get ( "iops" ) . ( int ) ) )
}
2015-04-03 19:23:01 +02:00
}
2015-07-07 09:58:37 +02:00
if d . HasChange ( "auto_minor_version_upgrade" ) {
d . SetPartial ( "auto_minor_version_upgrade" )
req . AutoMinorVersionUpgrade = aws . Bool ( d . Get ( "auto_minor_version_upgrade" ) . ( bool ) )
requestUpdate = true
}
2015-03-31 16:41:37 +02:00
2016-02-01 23:32:38 +01:00
if d . HasChange ( "monitoring_role_arn" ) {
d . SetPartial ( "monitoring_role_arn" )
req . MonitoringRoleArn = aws . String ( d . Get ( "monitoring_role_arn" ) . ( string ) )
requestUpdate = true
}
if d . HasChange ( "monitoring_interval" ) {
d . SetPartial ( "monitoring_interval" )
req . MonitoringInterval = aws . Int64 ( int64 ( d . Get ( "monitoring_interval" ) . ( int ) ) )
requestUpdate = true
}
2015-04-03 19:23:01 +02:00
if d . HasChange ( "vpc_security_group_ids" ) {
if attr := d . Get ( "vpc_security_group_ids" ) . ( * schema . Set ) ; attr . Len ( ) > 0 {
2015-04-13 22:45:55 +02:00
var s [ ] * string
2015-04-03 19:23:01 +02:00
for _ , v := range attr . List ( ) {
2015-04-13 22:45:55 +02:00
s = append ( s , aws . String ( v . ( string ) ) )
2015-04-03 19:23:01 +02:00
}
2015-08-17 20:27:16 +02:00
req . VpcSecurityGroupIds = s
2015-04-03 19:23:01 +02:00
}
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-04-01 23:05:19 +02:00
}
2016-02-03 09:33:42 +01:00
if d . HasChange ( "security_group_names" ) {
2015-04-03 19:23:01 +02:00
if attr := d . Get ( "security_group_names" ) . ( * schema . Set ) ; attr . Len ( ) > 0 {
2015-04-13 22:45:55 +02:00
var s [ ] * string
2015-04-03 19:23:01 +02:00
for _ , v := range attr . List ( ) {
2015-04-13 22:45:55 +02:00
s = append ( s , aws . String ( v . ( string ) ) )
2015-04-03 19:23:01 +02:00
}
req . DBSecurityGroups = s
2015-03-31 16:41:37 +02:00
}
2015-05-11 16:11:59 +02:00
requestUpdate = true
2015-03-31 16:41:37 +02:00
}
2015-12-21 10:15:52 +01:00
if d . HasChange ( "option_group_name" ) {
d . SetPartial ( "option_group_name" )
req . OptionGroupName = aws . String ( d . Get ( "option_group_name" ) . ( string ) )
requestUpdate = true
}
2016-07-12 10:07:25 +02:00
if d . HasChange ( "port" ) {
d . SetPartial ( "port" )
req . DBPortNumber = aws . Int64 ( int64 ( d . Get ( "port" ) . ( int ) ) )
requestUpdate = true
}
2017-01-09 20:10:13 +01:00
if d . HasChange ( "db_subnet_group_name" ) && ! d . IsNewResource ( ) {
2016-12-18 15:35:24 +01:00
d . SetPartial ( "db_subnet_group_name" )
req . DBSubnetGroupName = aws . String ( d . Get ( "db_subnet_group_name" ) . ( string ) )
requestUpdate = true
}
2016-07-12 10:07:25 +02:00
2017-04-29 21:32:21 +02:00
if d . HasChange ( "iam_database_authentication_enabled" ) {
req . EnableIAMDatabaseAuthentication = aws . Bool ( d . Get ( "iam_database_authentication_enabled" ) . ( bool ) )
requestUpdate = true
}
2016-06-21 21:53:13 +02:00
log . Printf ( "[DEBUG] Send DB Instance Modification request: %t" , requestUpdate )
2015-05-11 16:11:59 +02:00
if requestUpdate {
2016-06-21 21:53:13 +02:00
log . Printf ( "[DEBUG] DB Instance Modification request: %s" , req )
2015-05-11 16:11:59 +02:00
_ , err := conn . ModifyDBInstance ( req )
if err != nil {
return fmt . Errorf ( "Error modifying DB Instance %s: %s" , d . Id ( ) , err )
}
2016-07-12 10:07:25 +02:00
log . Println ( "[INFO] Waiting for DB Instance to be available" )
stateConf := & resource . StateChangeConf {
Pending : [ ] string { "creating" , "backing-up" , "modifying" , "resetting-master-credentials" ,
2016-12-18 15:35:24 +01:00
"maintenance" , "renaming" , "rebooting" , "upgrading" , "configuring-enhanced-monitoring" , "moving-to-vpc" } ,
2016-07-12 10:07:25 +02:00
Target : [ ] string { "available" } ,
Refresh : resourceAwsDbInstanceStateRefreshFunc ( d , meta ) ,
2017-03-02 18:07:49 +01:00
Timeout : d . Timeout ( schema . TimeoutUpdate ) ,
2016-07-12 10:07:25 +02:00
MinTimeout : 10 * time . Second ,
Delay : 30 * time . Second , // Wait 30 secs before starting
}
// Wait, catching any errors
_ , dbStateErr := stateConf . WaitForState ( )
if dbStateErr != nil {
return dbStateErr
}
2015-04-03 19:23:01 +02:00
}
2015-09-11 20:56:20 +02:00
// separate request to promote a database
2015-05-13 23:36:30 +02:00
if d . HasChange ( "replicate_source_db" ) {
if d . Get ( "replicate_source_db" ) . ( string ) == "" {
// promote
opts := rds . PromoteReadReplicaInput {
DBInstanceIdentifier : aws . String ( d . Id ( ) ) ,
}
attr := d . Get ( "backup_retention_period" )
2015-07-28 22:29:46 +02:00
opts . BackupRetentionPeriod = aws . Int64 ( int64 ( attr . ( int ) ) )
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "backup_window" ) ; ok {
opts . PreferredBackupWindow = aws . String ( attr . ( string ) )
}
_ , err := conn . PromoteReadReplica ( & opts )
if err != nil {
return fmt . Errorf ( "Error promoting database: %#v" , err )
}
d . Set ( "replicate_source_db" , "" )
} else {
return fmt . Errorf ( "cannot elect new source database for replication" )
}
}
2016-10-07 05:36:44 +02:00
if arn , err := buildRDSARN ( d . Id ( ) , meta . ( * AWSClient ) . partition , meta . ( * AWSClient ) . accountid , meta . ( * AWSClient ) . region ) ; err == nil {
2015-03-24 21:34:13 +01:00
if err := setTagsRDS ( conn , d , arn ) ; err != nil {
return err
} else {
d . SetPartial ( "tags" )
}
}
d . Partial ( false )
2015-08-21 23:56:04 +02:00
2015-03-24 21:34:13 +01:00
return resourceAwsDbInstanceRead ( d , meta )
}
2016-03-18 17:12:31 +01:00
// resourceAwsDbInstanceRetrieve fetches DBInstance information from the AWS
// API. It returns an error if there is a communication problem or unexpected
// error with AWS. When the DBInstance is not found, it returns no error and a
// nil pointer.
2015-05-07 23:21:37 +02:00
func resourceAwsDbInstanceRetrieve (
2014-11-24 14:04:48 +01:00
d * schema . ResourceData , meta interface { } ) ( * rds . DBInstance , error ) {
2015-04-13 22:45:55 +02:00
conn := meta . ( * AWSClient ) . rdsconn
2014-07-22 22:26:48 +02:00
2015-04-13 22:45:55 +02:00
opts := rds . DescribeDBInstancesInput {
2015-02-23 22:22:52 +01:00
DBInstanceIdentifier : aws . String ( d . Id ( ) ) ,
2014-07-22 22:26:48 +02:00
}
log . Printf ( "[DEBUG] DB Instance describe configuration: %#v" , opts )
resp , err := conn . DescribeDBInstances ( & opts )
if err != nil {
2015-05-20 13:21:23 +02:00
dbinstanceerr , ok := err . ( awserr . Error )
if ok && dbinstanceerr . Code ( ) == "DBInstanceNotFound" {
2014-09-18 22:25:30 +02:00
return nil , nil
}
2014-07-22 22:26:48 +02:00
return nil , fmt . Errorf ( "Error retrieving DB Instances: %s" , err )
}
if len ( resp . DBInstances ) != 1 ||
2015-02-23 22:22:52 +01:00
* resp . DBInstances [ 0 ] . DBInstanceIdentifier != d . Id ( ) {
2014-07-22 22:26:48 +02:00
if err != nil {
2014-09-18 22:25:30 +02:00
return nil , nil
2014-07-22 22:26:48 +02:00
}
}
2015-04-13 22:45:55 +02:00
return resp . DBInstances [ 0 ] , nil
2014-07-22 22:26:48 +02:00
}
2016-07-15 19:24:58 +02:00
func resourceAwsDbInstanceImport (
d * schema . ResourceData , meta interface { } ) ( [ ] * schema . ResourceData , error ) {
// Neither skip_final_snapshot nor final_snapshot_identifier can be fetched
// from any API call, so we need to default skip_final_snapshot to true so
// that final_snapshot_identifier is not required
d . Set ( "skip_final_snapshot" , true )
return [ ] * schema . ResourceData { d } , nil
}
2014-11-24 14:04:48 +01:00
func resourceAwsDbInstanceStateRefreshFunc (
d * schema . ResourceData , meta interface { } ) resource . StateRefreshFunc {
2014-07-22 22:26:48 +02:00
return func ( ) ( interface { } , string , error ) {
2015-05-07 23:21:37 +02:00
v , err := resourceAwsDbInstanceRetrieve ( d , meta )
2014-07-22 22:26:48 +02:00
if err != nil {
log . Printf ( "Error on retrieving DB Instance when waiting: %s" , err )
return nil , "" , err
}
2014-09-18 22:25:30 +02:00
if v == nil {
return nil , "" , nil
}
2015-05-20 16:28:33 +02:00
if v . DBInstanceStatus != nil {
log . Printf ( "[DEBUG] DB Instance status for instance %s: %s" , d . Id ( ) , * v . DBInstanceStatus )
}
2015-02-23 22:22:52 +01:00
return v , * v . DBInstanceStatus , nil
2014-07-22 22:26:48 +02:00
}
}
2015-03-24 21:34:13 +01:00
2016-10-07 05:36:44 +02:00
func buildRDSARN ( identifier , partition , accountid , region string ) ( string , error ) {
2016-10-08 06:52:50 +02:00
if partition == "" {
return "" , fmt . Errorf ( "Unable to construct RDS ARN because of missing AWS partition" )
}
2016-08-07 09:36:00 +02:00
if accountid == "" {
return "" , fmt . Errorf ( "Unable to construct RDS ARN because of missing AWS Account ID" )
2015-03-24 21:34:13 +01:00
}
2016-10-07 05:36:44 +02:00
arn := fmt . Sprintf ( "arn:%s:rds:%s:%s:db:%s" , partition , region , accountid , identifier )
2015-03-24 21:34:13 +01:00
return arn , nil
}