Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_db_instance: Add deletion_protection argument #6011

Merged
merged 1 commit into from
Oct 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions aws/resource_aws_db_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func resourceAwsDbInstance() *schema.Resource {
Sensitive: true,
},

"deletion_protection": {
Type: schema.TypeBool,
Optional: true,
},

"engine": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -466,6 +471,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error
opts := rds.CreateDBInstanceReadReplicaInput{
AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)),
DeletionProtection: aws.Bool(d.Get("deletion_protection").(bool)),
DBInstanceClass: aws.String(d.Get("instance_class").(string)),
DBInstanceIdentifier: aws.String(identifier),
PubliclyAccessible: aws.Bool(d.Get("publicly_accessible").(bool)),
Expand Down Expand Up @@ -593,6 +599,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error
DBName: aws.String(d.Get("name").(string)),
DBInstanceClass: aws.String(d.Get("instance_class").(string)),
DBInstanceIdentifier: aws.String(d.Get("identifier").(string)),
DeletionProtection: aws.Bool(d.Get("deletion_protection").(bool)),
Engine: aws.String(d.Get("engine").(string)),
EngineVersion: aws.String(d.Get("engine_version").(string)),
S3BucketName: aws.String(s3_bucket["bucket_name"].(string)),
Expand Down Expand Up @@ -749,6 +756,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error
DBInstanceClass: aws.String(d.Get("instance_class").(string)),
DBInstanceIdentifier: aws.String(d.Get("identifier").(string)),
DBSnapshotIdentifier: aws.String(d.Get("snapshot_identifier").(string)),
DeletionProtection: aws.Bool(d.Get("deletion_protection").(bool)),
PubliclyAccessible: aws.Bool(d.Get("publicly_accessible").(bool)),
Tags: tags,
}
Expand Down Expand Up @@ -921,6 +929,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error
DBName: aws.String(d.Get("name").(string)),
DBInstanceClass: aws.String(d.Get("instance_class").(string)),
DBInstanceIdentifier: aws.String(d.Get("identifier").(string)),
DeletionProtection: aws.Bool(d.Get("deletion_protection").(bool)),
MasterUsername: aws.String(d.Get("username").(string)),
MasterUserPassword: aws.String(d.Get("password").(string)),
Engine: aws.String(d.Get("engine").(string)),
Expand Down Expand Up @@ -1119,6 +1128,7 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error {
d.Set("identifier", v.DBInstanceIdentifier)
d.Set("resource_id", v.DbiResourceId)
d.Set("username", v.MasterUsername)
d.Set("deletion_protection", v.DeletionProtection)
d.Set("engine", v.Engine)
d.Set("engine_version", v.EngineVersion)
d.Set("allocated_storage", v.AllocatedStorage)
Expand Down Expand Up @@ -1335,6 +1345,11 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error
req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool))
requestUpdate = true
}
if d.HasChange("deletion_protection") {
d.SetPartial("deletion_protection")
req.DeletionProtection = aws.Bool(d.Get("deletion_protection").(bool))
requestUpdate = true
}
if d.HasChange("instance_class") {
d.SetPartial("instance_class")
req.DBInstanceClass = aws.String(d.Get("instance_class").(string))
Expand Down
190 changes: 190 additions & 0 deletions aws/resource_aws_db_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func TestAccAWSDBInstance_basic(t *testing.T) {
resource.TestCheckResourceAttr(
"aws_db_instance.bar", "allocated_storage", "10"),
resource.TestMatchResourceAttr("aws_db_instance.bar", "arn", regexp.MustCompile(`^arn:[^:]+:rds:[^:]+:\d{12}:db:.+`)),
resource.TestCheckResourceAttr("aws_db_instance.bar", "deletion_protection", "false"),
resource.TestCheckResourceAttr(
"aws_db_instance.bar", "engine", "mysql"),
resource.TestCheckResourceAttr(
Expand Down Expand Up @@ -285,6 +286,46 @@ func TestAccAWSDBInstance_iamAuth(t *testing.T) {
})
}

func TestAccAWSDBInstance_DeletionProtection(t *testing.T) {
var dbInstance rds.DBInstance

rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_db_instance.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSDBInstanceConfig_DeletionProtection(rName, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBInstanceExists(resourceName, &dbInstance),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "true"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"apply_immediately",
"final_snapshot_identifier",
"password",
"skip_final_snapshot",
},
},
{
Config: testAccAWSDBInstanceConfig_DeletionProtection(rName, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBInstanceExists(resourceName, &dbInstance),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "false"),
),
},
},
})
}

func TestAccAWSDBInstance_FinalSnapshotIdentifier(t *testing.T) {
var snap rds.DBInstance
rInt := acctest.RandInt()
Expand Down Expand Up @@ -509,6 +550,53 @@ func TestAccAWSDBInstance_ReplicateSourceDb_BackupWindow(t *testing.T) {
})
}

func TestAccAWSDBInstance_ReplicateSourceDb_DeletionProtection(t *testing.T) {
t.Skip("CreateDBInstanceReadReplica API currently ignores DeletionProtection=true with SourceDBInstanceIdentifier set")
// --- FAIL: TestAccAWSDBInstance_ReplicateSourceDb_DeletionProtection (1624.88s)
// testing.go:527: Step 0 error: Check failed: Check 4/4 error: aws_db_instance.test: Attribute 'deletion_protection' expected "true", got "false"
//
// Action=CreateDBInstanceReadReplica&AutoMinorVersionUpgrade=true&CopyTagsToSnapshot=false&DBInstanceClass=db.t2.micro&DBInstanceIdentifier=tf-acc-test-6591588621809891413&DeletionProtection=true&PubliclyAccessible=false&SourceDBInstanceIdentifier=tf-acc-test-6591588621809891413-source&Tags=&Version=2014-10-31
// <RestoreDBInstanceFromDBSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
// <RestoreDBInstanceFromDBSnapshotResult>
// <DBInstance>
// <DeletionProtection>false</DeletionProtection>
//
// AWS Support has confirmed this issue and noted that it will be fixed in the future.

var dbInstance, sourceDbInstance rds.DBInstance

rName := acctest.RandomWithPrefix("tf-acc-test")
sourceResourceName := "aws_db_instance.source"
resourceName := "aws_db_instance.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSDBInstanceConfig_ReplicateSourceDb_DeletionProtection(rName, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBInstanceExists(sourceResourceName, &sourceDbInstance),
testAccCheckAWSDBInstanceExists(resourceName, &dbInstance),
testAccCheckAWSDBInstanceReplicaAttributes(&sourceDbInstance, &dbInstance),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "true"),
),
},
// Ensure we disable deletion protection before attempting to delete :)
{
Config: testAccAWSDBInstanceConfig_ReplicateSourceDb_DeletionProtection(rName, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBInstanceExists(sourceResourceName, &sourceDbInstance),
testAccCheckAWSDBInstanceExists(resourceName, &dbInstance),
testAccCheckAWSDBInstanceReplicaAttributes(&sourceDbInstance, &dbInstance),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "false"),
),
},
},
})
}

func TestAccAWSDBInstance_ReplicateSourceDb_IamDatabaseAuthenticationEnabled(t *testing.T) {
var dbInstance, sourceDbInstance rds.DBInstance

Expand Down Expand Up @@ -893,6 +981,43 @@ func TestAccAWSDBInstance_SnapshotIdentifier_BackupWindow(t *testing.T) {
})
}

func TestAccAWSDBInstance_SnapshotIdentifier_DeletionProtection(t *testing.T) {
var dbInstance, sourceDbInstance rds.DBInstance
var dbSnapshot rds.DBSnapshot

rName := acctest.RandomWithPrefix("tf-acc-test")
sourceDbResourceName := "aws_db_instance.source"
snapshotResourceName := "aws_db_snapshot.test"
resourceName := "aws_db_instance.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSDBInstanceConfig_SnapshotIdentifier_DeletionProtection(rName, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBInstanceExists(sourceDbResourceName, &sourceDbInstance),
testAccCheckDbSnapshotExists(snapshotResourceName, &dbSnapshot),
testAccCheckAWSDBInstanceExists(resourceName, &dbInstance),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "true"),
),
},
// Ensure we disable deletion protection before attempting to delete :)
{
Config: testAccAWSDBInstanceConfig_SnapshotIdentifier_DeletionProtection(rName, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSDBInstanceExists(sourceDbResourceName, &sourceDbInstance),
testAccCheckDbSnapshotExists(snapshotResourceName, &dbSnapshot),
testAccCheckAWSDBInstanceExists(resourceName, &dbInstance),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "false"),
),
},
},
})
}

func TestAccAWSDBInstance_SnapshotIdentifier_IamDatabaseAuthenticationEnabled(t *testing.T) {
var dbInstance, sourceDbInstance rds.DBInstance
var dbSnapshot rds.DBSnapshot
Expand Down Expand Up @@ -3247,6 +3372,21 @@ resource "aws_db_instance" "test" {
`, rName)
}

func testAccAWSDBInstanceConfig_DeletionProtection(rName string, deletionProtection bool) string {
return fmt.Sprintf(`
resource "aws_db_instance" "test" {
allocated_storage = 5
deletion_protection = %t
engine = "mysql"
identifier = %q
instance_class = "db.t2.micro"
password = "avoid-plaintext-passwords"
username = "tfacctest"
skip_final_snapshot = true
}
`, deletionProtection, rName)
}

func testAccAWSDBInstanceConfig_EnabledCloudwatchLogsExports_Oracle(rName string) string {
return fmt.Sprintf(`
resource "aws_db_instance" "test" {
Expand Down Expand Up @@ -3401,6 +3541,29 @@ resource "aws_db_instance" "test" {
`, rName, backupWindow, rName)
}

func testAccAWSDBInstanceConfig_ReplicateSourceDb_DeletionProtection(rName string, deletionProtection bool) string {
return fmt.Sprintf(`
resource "aws_db_instance" "source" {
allocated_storage = 5
backup_retention_period = 1
engine = "mysql"
identifier = "%s-source"
instance_class = "db.t2.micro"
password = "avoid-plaintext-passwords"
username = "tfacctest"
skip_final_snapshot = true
}

resource "aws_db_instance" "test" {
deletion_protection = %t
identifier = %q
instance_class = "${aws_db_instance.source.instance_class}"
replicate_source_db = "${aws_db_instance.source.id}"
skip_final_snapshot = true
}
`, rName, deletionProtection, rName)
}

func testAccAWSDBInstanceConfig_ReplicateSourceDb_IamDatabaseAuthenticationEnabled(rName string, iamDatabaseAuthenticationEnabled bool) string {
return fmt.Sprintf(`
resource "aws_db_instance" "source" {
Expand Down Expand Up @@ -3800,6 +3963,33 @@ resource "aws_db_instance" "test" {
`, rName, rName, backupWindow, rName)
}

func testAccAWSDBInstanceConfig_SnapshotIdentifier_DeletionProtection(rName string, deletionProtection bool) string {
return fmt.Sprintf(`
resource "aws_db_instance" "source" {
allocated_storage = 5
engine = "mysql"
identifier = "%s-source"
instance_class = "db.t2.micro"
password = "avoid-plaintext-passwords"
username = "tfacctest"
skip_final_snapshot = true
}

resource "aws_db_snapshot" "test" {
db_instance_identifier = "${aws_db_instance.source.id}"
db_snapshot_identifier = %q
}

resource "aws_db_instance" "test" {
deletion_protection = %t
identifier = %q
instance_class = "${aws_db_instance.source.instance_class}"
snapshot_identifier = "${aws_db_snapshot.test.id}"
skip_final_snapshot = true
}
`, rName, rName, deletionProtection, rName)
}

func testAccAWSDBInstanceConfig_SnapshotIdentifier_IamDatabaseAuthenticationEnabled(rName string, iamDatabaseAuthenticationEnabled bool) string {
return fmt.Sprintf(`
resource "aws_db_instance" "source" {
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/db_instance.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ with read replicas, it needs to be specified only if the source database
specifies an instance in another AWS Region. See [DBSubnetGroupName in API
action CreateDBInstanceReadReplica](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstanceReadReplica.html)
for additional read replica contraints.
* `deletion_protection` - (Optional) If the DB instance should have deletion protection enabled. The database can't be deleted when this value is set to `true`. The default is `false`.
* `domain` - (Optional) The ID of the Directory Service Active Directory domain to create the instance in.
* `domain_iam_role_name` - (Optional, but required if domain is provided) The name of the IAM role to be used when making API calls to the Directory Service.
* `enabled_cloudwatch_logs_exports` - (Optional) List of log types to enable for exporting to CloudWatch logs. If omitted, no logs will be exported. Valid values (depending on `engine`): `alert`, `audit`, `error`, `general`, `listener`, `slowquery`, `trace`.
Expand Down