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_rds_cluster: Add deletion_protection argument #6010

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_rds_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ func resourceAwsRDSCluster() *schema.Resource {
Computed: true,
},

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

"endpoint": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -409,6 +414,7 @@ func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error
if _, ok := d.GetOk("snapshot_identifier"); ok {
opts := rds.RestoreDBClusterFromSnapshotInput{
DBClusterIdentifier: aws.String(identifier),
DeletionProtection: aws.Bool(d.Get("deletion_protection").(bool)),
Engine: aws.String(d.Get("engine").(string)),
EngineMode: aws.String(d.Get("engine_mode").(string)),
ScalingConfiguration: expandRdsScalingConfiguration(d.Get("scaling_configuration").([]interface{})),
Expand Down Expand Up @@ -513,6 +519,7 @@ func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error
} else if _, ok := d.GetOk("replication_source_identifier"); ok {
createOpts := &rds.CreateDBClusterInput{
DBClusterIdentifier: aws.String(identifier),
DeletionProtection: aws.Bool(d.Get("deletion_protection").(bool)),
Engine: aws.String(d.Get("engine").(string)),
EngineMode: aws.String(d.Get("engine_mode").(string)),
ReplicationSourceIdentifier: aws.String(d.Get("replication_source_identifier").(string)),
Expand Down Expand Up @@ -607,6 +614,7 @@ func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error
s3_bucket := v.([]interface{})[0].(map[string]interface{})
createOpts := &rds.RestoreDBClusterFromS3Input{
DBClusterIdentifier: aws.String(identifier),
DeletionProtection: aws.Bool(d.Get("deletion_protection").(bool)),
Engine: aws.String(d.Get("engine").(string)),
MasterUsername: aws.String(d.Get("master_username").(string)),
MasterUserPassword: aws.String(d.Get("master_password").(string)),
Expand Down Expand Up @@ -718,6 +726,7 @@ func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error

createOpts := &rds.CreateDBClusterInput{
DBClusterIdentifier: aws.String(identifier),
DeletionProtection: aws.Bool(d.Get("deletion_protection").(bool)),
Engine: aws.String(d.Get("engine").(string)),
EngineMode: aws.String(d.Get("engine_mode").(string)),
MasterUserPassword: aws.String(d.Get("master_password").(string)),
Expand Down Expand Up @@ -913,6 +922,7 @@ func resourceAwsRDSClusterRead(d *schema.ResourceData, meta interface{}) error {

d.Set("db_cluster_parameter_group_name", dbc.DBClusterParameterGroup)
d.Set("db_subnet_group_name", dbc.DBSubnetGroup)
d.Set("deletion_protection", dbc.DeletionProtection)

if err := d.Set("enabled_cloudwatch_logs_exports", aws.StringValueSlice(dbc.EnabledCloudwatchLogsExports)); err != nil {
return fmt.Errorf("error setting enabled_cloudwatch_logs_exports: %s", err)
Expand Down Expand Up @@ -1012,6 +1022,11 @@ func resourceAwsRDSClusterUpdate(d *schema.ResourceData, meta interface{}) error
requestUpdate = true
}

if d.HasChange("deletion_protection") {
req.DeletionProtection = aws.Bool(d.Get("deletion_protection").(bool))
requestUpdate = true
}

if d.HasChange("iam_database_authentication_enabled") {
req.EnableIAMDatabaseAuthentication = aws.Bool(d.Get("iam_database_authentication_enabled").(bool))
requestUpdate = true
Expand Down
124 changes: 124 additions & 0 deletions aws/resource_aws_rds_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,46 @@ func TestAccAWSRDSCluster_iamAuth(t *testing.T) {
})
}

func TestAccAWSRDSCluster_DeletionProtection(t *testing.T) {
var dbCluster1 rds.DBCluster
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_rds_cluster.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSRDSClusterConfig_DeletionProtection(rName, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSClusterExists(resourceName, &dbCluster1),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "true"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"apply_immediately",
"cluster_identifier_prefix",
"master_password",
"skip_final_snapshot",
"snapshot_identifier",
},
},
{
Config: testAccAWSRDSClusterConfig_DeletionProtection(rName, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSClusterExists(resourceName, &dbCluster1),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "false"),
),
},
},
})
}

func TestAccAWSRDSCluster_EngineMode(t *testing.T) {
var dbCluster1, dbCluster2 rds.DBCluster

Expand Down Expand Up @@ -649,6 +689,55 @@ func TestAccAWSRDSCluster_SnapshotIdentifier(t *testing.T) {
})
}

func TestAccAWSRDSCluster_SnapshotIdentifier_DeletionProtection(t *testing.T) {
var dbCluster, sourceDbCluster rds.DBCluster
var dbClusterSnapshot rds.DBClusterSnapshot

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

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSRDSClusterConfig_SnapshotIdentifier_DeletionProtection(rName, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSClusterExists(sourceDbResourceName, &sourceDbCluster),
testAccCheckDbClusterSnapshotExists(snapshotResourceName, &dbClusterSnapshot),
testAccCheckAWSClusterExists(resourceName, &dbCluster),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "true"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"apply_immediately",
"cluster_identifier_prefix",
"master_password",
"skip_final_snapshot",
"snapshot_identifier",
},
},
// Ensure we disable deletion protection before attempting to delete :)
{
Config: testAccAWSRDSClusterConfig_SnapshotIdentifier_DeletionProtection(rName, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSClusterExists(sourceDbResourceName, &sourceDbCluster),
testAccCheckDbClusterSnapshotExists(snapshotResourceName, &dbClusterSnapshot),
testAccCheckAWSClusterExists(resourceName, &dbCluster),
resource.TestCheckResourceAttr(resourceName, "deletion_protection", "false"),
),
},
},
})
}

func TestAccAWSRDSCluster_SnapshotIdentifier_EngineMode_ParallelQuery(t *testing.T) {
var dbCluster, sourceDbCluster rds.DBCluster
var dbClusterSnapshot rds.DBClusterSnapshot
Expand Down Expand Up @@ -1754,6 +1843,18 @@ resource "aws_rds_cluster" "test_replica" {
`, n)
}

func testAccAWSRDSClusterConfig_DeletionProtection(rName string, deletionProtection bool) string {
return fmt.Sprintf(`
resource "aws_rds_cluster" "test" {
cluster_identifier = %q
deletion_protection = %t
master_password = "barbarbarbar"
master_username = "foo"
skip_final_snapshot = true
}
`, rName, deletionProtection)
}

func testAccAWSRDSClusterConfig_EngineMode(rName, engineMode string) string {
return fmt.Sprintf(`
resource "aws_rds_cluster" "test" {
Expand Down Expand Up @@ -1807,6 +1908,29 @@ resource "aws_rds_cluster" "test" {
`, rName, rName, rName)
}

func testAccAWSRDSClusterConfig_SnapshotIdentifier_DeletionProtection(rName string, deletionProtection bool) string {
return fmt.Sprintf(`
resource "aws_rds_cluster" "source" {
cluster_identifier = "%s-source"
master_password = "barbarbarbar"
master_username = "foo"
skip_final_snapshot = true
}

resource "aws_db_cluster_snapshot" "test" {
db_cluster_identifier = "${aws_rds_cluster.source.id}"
db_cluster_snapshot_identifier = %q
}

resource "aws_rds_cluster" "test" {
cluster_identifier = %q
deletion_protection = %t
skip_final_snapshot = true
snapshot_identifier = "${aws_db_cluster_snapshot.test.id}"
}
`, rName, rName, rName, deletionProtection)
}

func testAccAWSRDSClusterConfig_SnapshotIdentifier_EngineMode(rName, engineMode string) string {
return fmt.Sprintf(`
resource "aws_rds_cluster" "source" {
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/rds_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ The following arguments are supported:
* `cluster_identifier` - (Optional, Forces new resources) The cluster identifier. If omitted, Terraform will assign a random, unique identifier.
* `cluster_identifier_prefix` - (Optional, Forces new resource) Creates a unique cluster identifier beginning with the specified prefix. Conflicts with `cluster_identifer`.
* `database_name` - (Optional) Name for an automatically created database on cluster creation. There are different naming restrictions per database engine: [RDS Naming Constraints][5]
* `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`.
* `master_password` - (Required unless a `snapshot_identifier` is provided) Password for the master DB user. Note that this may
show up in logs, and it will be stored in the state file. Please refer to the [RDS Naming Constraints][5]
* `master_username` - (Required unless a `snapshot_identifier` is provided) Username for the master DB user. Please refer to the [RDS Naming Constraints][5]
Expand Down