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/iam"
"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 ,
Schema : map [ string ] * schema . Schema {
"name" : & schema . Schema {
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 ,
} ,
"username" : & schema . Schema {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"password" : & schema . Schema {
2014-11-24 14:04:48 +01:00
Type : schema . TypeString ,
2014-11-21 17:58:34 +01:00
Required : true ,
} ,
"engine" : & schema . Schema {
Type : schema . TypeString ,
Required : true ,
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
} ,
"engine_version" : & schema . Schema {
Type : schema . TypeString ,
Required : true ,
} ,
2015-02-24 19:34:08 +01:00
"storage_encrypted" : & schema . Schema {
Type : schema . TypeBool ,
Optional : true ,
ForceNew : true ,
} ,
2014-11-21 17:58:34 +01:00
"allocated_storage" : & schema . Schema {
Type : schema . TypeInt ,
Required : true ,
} ,
2015-01-30 19:01:10 +01:00
"storage_type" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
} ,
2014-11-21 17:58:34 +01:00
"identifier" : & schema . Schema {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
2015-06-25 12:06:16 +02:00
ValidateFunc : func ( v interface { } , k string ) ( ws [ ] string , errors [ ] error ) {
value := v . ( string )
2015-06-26 18:57:13 +02:00
if ! regexp . MustCompile ( ` ^[0-9a-z-]+$ ` ) . MatchString ( value ) {
2015-06-25 12:06:16 +02:00
errors = append ( errors , fmt . Errorf (
"only lowercase alphanumeric characters and hyphens allowed in %q" , k ) )
}
if ! regexp . MustCompile ( ` ^[a-z] ` ) . MatchString ( value ) {
errors = append ( errors , fmt . Errorf (
"first character of %q must be a letter" , k ) )
}
if regexp . MustCompile ( ` -- ` ) . MatchString ( value ) {
errors = append ( errors , fmt . Errorf (
"%q cannot contain two consecutive hyphens" , k ) )
}
if regexp . MustCompile ( ` -$ ` ) . MatchString ( value ) {
errors = append ( errors , fmt . Errorf (
2015-07-09 21:28:50 +02:00
"%q cannot end with a hyphen" , k ) )
2015-06-25 12:06:16 +02:00
}
return
} ,
2014-11-21 17:58:34 +01:00
} ,
"instance_class" : & schema . Schema {
Type : schema . TypeString ,
Required : true ,
} ,
2014-11-24 14:04:48 +01:00
"availability_zone" : & schema . Schema {
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 ,
} ,
2014-11-24 14:04:48 +01:00
"backup_retention_period" : & schema . Schema {
Type : schema . TypeInt ,
Optional : true ,
2015-05-13 23:36:30 +02:00
Computed : true ,
2014-11-21 17:58:34 +01:00
} ,
2014-11-24 14:04:48 +01:00
"backup_window" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
} ,
"iops" : & schema . Schema {
Type : schema . TypeInt ,
Optional : true ,
} ,
2015-05-14 16:44:22 +02:00
"license_model" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
} ,
2014-11-24 14:04:48 +01:00
"maintenance_window" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
} ,
"multi_az" : & schema . Schema {
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
} ,
"port" : & schema . Schema {
Type : schema . TypeInt ,
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
ForceNew : true ,
} ,
"publicly_accessible" : & schema . Schema {
Type : schema . TypeBool ,
Optional : true ,
ForceNew : true ,
} ,
"vpc_security_group_ids" : & schema . Schema {
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
} ,
2014-11-24 14:04:48 +01:00
"security_group_names" : & schema . Schema {
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
"final_snapshot_identifier" : & schema . Schema {
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
} ,
"db_subnet_group_name" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
2015-03-25 16:14:45 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
} ,
"parameter_group_name" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
2015-01-28 17:48:30 +01:00
Computed : true ,
2014-11-24 14:04:48 +01:00
} ,
"address" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"endpoint" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"status" : & schema . Schema {
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
"apply_immediately" : & schema . Schema {
Type : schema . TypeBool ,
Optional : true ,
Computed : true ,
} ,
2015-05-13 23:36:30 +02:00
"replicate_source_db" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
} ,
"replicas" : & schema . Schema {
Type : schema . TypeList ,
Computed : true ,
Elem : & schema . Schema { Type : schema . TypeString } ,
} ,
2015-05-24 23:51:35 +02:00
"snapshot_identifier" : & schema . Schema {
Type : schema . TypeString ,
Computed : false ,
Optional : true ,
Elem : & schema . Schema { Type : schema . TypeString } ,
} ,
2015-05-25 03:18:36 +02:00
"auto_minor_version_upgrade" : & schema . Schema {
Type : schema . TypeBool ,
Computed : false ,
Optional : 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
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 ) ) ,
DBInstanceClass : aws . String ( d . Get ( "instance_class" ) . ( string ) ) ,
DBInstanceIdentifier : aws . String ( d . Get ( "identifier" ) . ( string ) ) ,
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-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "publicly_accessible" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . PubliclyAccessible = aws . Bool ( attr . ( bool ) )
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-05-25 03:18:36 +02:00
DBInstanceClass : aws . String ( d . Get ( "instance_class" ) . ( string ) ) ,
DBInstanceIdentifier : aws . String ( d . Get ( "identifier" ) . ( string ) ) ,
DBSnapshotIdentifier : aws . String ( d . Get ( "snapshot_identifier" ) . ( string ) ) ,
Tags : tags ,
}
if attr , ok := d . GetOk ( "auto_minor_version_upgrade" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . AutoMinorVersionUpgrade = aws . Bool ( attr . ( bool ) )
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 ) )
}
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 ( "publicly_accessible" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . PubliclyAccessible = aws . Bool ( attr . ( bool ) )
2015-05-24 23:51:35 +02:00
}
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 ) )
}
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
if attr := d . Get ( "vpc_security_group_ids" ) . ( * schema . Set ) ; attr . Len ( ) > 0 {
2015-10-29 22:53:40 +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-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 {
Pending : [ ] string { "creating" , "backing-up" , "modifying" } ,
Target : "available" ,
Refresh : resourceAwsDbInstanceStateRefreshFunc ( d , meta ) ,
Timeout : 40 * time . Minute ,
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 {
opts := rds . CreateDBInstanceInput {
2015-07-28 22:29:46 +02:00
AllocatedStorage : aws . Int64 ( int64 ( d . Get ( "allocated_storage" ) . ( int ) ) ) ,
2015-05-13 23:36:30 +02:00
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 ) ) ,
2015-07-28 22:29:46 +02:00
StorageEncrypted : aws . Bool ( d . Get ( "storage_encrypted" ) . ( bool ) ) ,
2015-05-13 23:36:30 +02:00
Tags : tags ,
}
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 ) )
2015-05-13 23:36:30 +02:00
}
2014-11-24 14:04:48 +01:00
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
2015-05-13 23:36:30 +02:00
if attr , ok := d . GetOk ( "publicly_accessible" ) ; ok {
2015-07-28 22:29:46 +02:00
opts . PubliclyAccessible = aws . Bool ( attr . ( bool ) )
2015-05-13 23:36:30 +02:00
}
log . Printf ( "[DEBUG] DB Instance create configuration: %#v" , opts )
var err error
_ , err = conn . CreateDBInstance ( & opts )
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 {
2014-07-30 17:58:00 +02:00
Pending : [ ] string { "creating" , "backing-up" , "modifying" } ,
2014-07-23 00:45:17 +02:00
Target : "available" ,
2014-11-24 14:04:48 +01:00
Refresh : resourceAwsDbInstanceStateRefreshFunc ( d , meta ) ,
2015-02-27 18:38:07 +01:00
Timeout : 40 * time . Minute ,
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 )
d . Set ( "username" , v . MasterUsername )
d . Set ( "engine" , v . Engine )
d . Set ( "engine_version" , v . EngineVersion )
d . Set ( "allocated_storage" , v . AllocatedStorage )
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 )
d . Set ( "multi_az" , v . MultiAZ )
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
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 )
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 )
2014-11-24 14:04:48 +01:00
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
2015-03-24 21:34:13 +01:00
arn , err := buildRDSARN ( d , meta )
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-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-03-25 16:32:54 +01:00
log . Printf ( "[DEBUG] Error retreiving 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
2015-01-28 17:48:30 +01:00
finalSnapshot := d . Get ( "final_snapshot_identifier" ) . ( string )
if finalSnapshot == "" {
2015-07-28 22:29:46 +02:00
opts . SkipFinalSnapshot = aws . Bool ( true )
2014-07-31 21:18:33 +02:00
} else {
2015-02-23 22:22:52 +01:00
opts . FinalDBSnapshotIdentifier = aws . String ( finalSnapshot )
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" } ,
Target : "" ,
2014-11-24 14:04:48 +01:00
Refresh : resourceAwsDbInstanceStateRefreshFunc ( d , meta ) ,
2015-02-27 18:38:07 +01:00
Timeout : 40 * time . Minute ,
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
2015-05-11 16:11:59 +02:00
requestUpdate := false
2015-04-03 19:23:01 +02:00
if d . HasChange ( "allocated_storage" ) {
d . SetPartial ( "allocated_storage" )
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
}
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
}
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 ) )
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 ( "iops" ) {
d . SetPartial ( "iops" )
2015-08-17 20:27:16 +02:00
req . Iops = aws . Int64 ( int64 ( d . Get ( "iops" ) . ( int ) ) )
2015-05-11 16:11:59 +02:00
requestUpdate = true
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-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
2015-04-03 19:23:01 +02:00
}
2015-03-31 16:41:37 +02:00
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
}
2015-04-03 19:23:01 +02:00
if d . HasChange ( "vpc_security_group_ids" ) {
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-05-11 16:11:59 +02:00
log . Printf ( "[DEBUG] Send DB Instance Modification request: %#v" , requestUpdate )
if requestUpdate {
log . Printf ( "[DEBUG] DB Instance Modification request: %#v" , req )
_ , err := conn . ModifyDBInstance ( req )
if err != nil {
return fmt . Errorf ( "Error modifying DB Instance %s: %s" , d . Id ( ) , err )
}
2015-04-03 19:23:01 +02:00
}
2015-05-13 23:36:30 +02:00
// seperate request to promote a database
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" )
}
}
2015-03-25 16:05:15 +01:00
if arn , err := buildRDSARN ( d , meta ) ; 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 )
return resourceAwsDbInstanceRead ( d , meta )
}
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
}
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
func buildRDSARN ( d * schema . ResourceData , meta interface { } ) ( string , error ) {
2015-04-15 21:36:08 +02:00
iamconn := meta . ( * AWSClient ) . iamconn
2015-03-24 21:34:13 +01:00
region := meta . ( * AWSClient ) . region
2015-04-13 22:45:55 +02:00
// An zero value GetUserInput{} defers to the currently logged in user
resp , err := iamconn . GetUser ( & iam . GetUserInput { } )
2015-03-24 21:34:13 +01:00
if err != nil {
return "" , err
}
2015-08-17 20:27:16 +02:00
userARN := * resp . User . Arn
2015-05-11 17:32:06 +02:00
accountID := strings . Split ( userARN , ":" ) [ 4 ]
arn := fmt . Sprintf ( "arn:aws:rds:%s:%s:db:%s" , region , accountID , d . Id ( ) )
2015-03-24 21:34:13 +01:00
return arn , nil
}