From 1d0dbc5d19bfb3451d07070a25d4a9095dd0b124 Mon Sep 17 00:00:00 2001 From: stack72 Date: Wed, 4 Nov 2015 19:40:22 +0000 Subject: [PATCH 1/4] Adding backup_retention_period, preferred_backup_window and preferred_maintenance_window to RDS Cluster --- .../providers/aws/resource_aws_rds_cluster.go | 55 +++++++++++++++++++ .../aws/resource_aws_rds_cluster_test.go | 9 +++ .../providers/aws/r/rds_cluster.html.markdown | 9 ++- 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_rds_cluster.go b/builtin/providers/aws/resource_aws_rds_cluster.go index 57f3a27b333b..f4c54c3d67dd 100644 --- a/builtin/providers/aws/resource_aws_rds_cluster.go +++ b/builtin/providers/aws/resource_aws_rds_cluster.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -122,6 +123,33 @@ func resourceAwsRDSCluster() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, + + "preferred_backup_window": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "preferred_maintenance_window": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + StateFunc: func(val interface{}) string { + return strings.ToLower(val.(string)) + }, + }, + + "backup_retention_period": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: func(v interface{}, k string) (ws []string, es []error) { + value := v.(int) + if value > 35 { + es = append(es, fmt.Errorf( + "backup retention period cannot be more than 35 days")) + } + return + }, + }, }, } } @@ -156,6 +184,18 @@ func resourceAwsRDSClusterCreate(d *schema.ResourceData, meta interface{}) error createOpts.AvailabilityZones = expandStringList(attr.List()) } + if v, ok := d.GetOk("backup_retention_period"); ok { + createOpts.BackupRetentionPeriod = aws.Int64(int64(v.(int))) + } + + if v, ok := d.GetOk("preferred_backup_window"); ok { + createOpts.PreferredBackupWindow = aws.String(v.(string)) + } + + if v, ok := d.GetOk("preferred_maintenance_window"); ok { + createOpts.PreferredMaintenanceWindow = aws.String(v.(string)) + } + log.Printf("[DEBUG] RDS Cluster create options: %s", createOpts) resp, err := conn.CreateDBCluster(createOpts) if err != nil { @@ -223,6 +263,9 @@ func resourceAwsRDSClusterRead(d *schema.ResourceData, meta interface{}) error { d.Set("engine", dbc.Engine) d.Set("master_username", dbc.MasterUsername) d.Set("port", dbc.Port) + d.Set("backup_retention_period", dbc.BackupRetentionPeriod) + d.Set("preferred_backup_window", dbc.PreferredBackupWindow) + d.Set("preferred_maintenance_window", dbc.PreferredMaintenanceWindow) var vpcg []string for _, g := range dbc.VpcSecurityGroups { @@ -263,6 +306,18 @@ func resourceAwsRDSClusterUpdate(d *schema.ResourceData, meta interface{}) error } } + if d.HasChange("preferred_backup_window") { + req.PreferredBackupWindow = aws.String(d.Get("preferred_backup_window").(string)) + } + + if d.HasChange("preferred_maintaince_window") { + req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintaince_window").(string)) + } + + if d.HasChange("backup_retention_limit") { + req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_limit").(int))) + } + _, err := conn.ModifyDBCluster(req) if err != nil { return fmt.Errorf("[WARN] Error modifying RDS Cluster (%s): %s", d.Id(), err) diff --git a/builtin/providers/aws/resource_aws_rds_cluster_test.go b/builtin/providers/aws/resource_aws_rds_cluster_test.go index ffa2fa8e909b..79da2acf4b9d 100644 --- a/builtin/providers/aws/resource_aws_rds_cluster_test.go +++ b/builtin/providers/aws/resource_aws_rds_cluster_test.go @@ -26,6 +26,12 @@ func TestAccAWSRDSCluster_basic(t *testing.T) { Config: testAccAWSClusterConfig, Check: resource.ComposeTestCheckFunc( testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "preferred_backup_window", "07:00-09:00"), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "backup_retention_period", "5"), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "preferred_maintenance_window", "tue:04:00-tue:04:30"), ), }, }, @@ -105,4 +111,7 @@ resource "aws_rds_cluster" "default" { database_name = "mydb" master_username = "foo" master_password = "mustbeeightcharaters" + backup_retention_period = 5 + preferred_backup_window = "07:00-09:00" + preferred_maintenance_window = "tue:04:00-tue:04:30" }`, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) diff --git a/website/source/docs/providers/aws/r/rds_cluster.html.markdown b/website/source/docs/providers/aws/r/rds_cluster.html.markdown index c45814f46621..fb1f0dac852c 100644 --- a/website/source/docs/providers/aws/r/rds_cluster.html.markdown +++ b/website/source/docs/providers/aws/r/rds_cluster.html.markdown @@ -24,6 +24,8 @@ resource "aws_rds_cluster" "default" { database_name = "mydb" master_username = "foo" master_password = "bar" + backup_retention_period = 5 + preferred_backup_window = "07:00-09:00" } ``` @@ -52,6 +54,9 @@ string. instances in the DB cluster can be created in * `backup_retention_period` - (Optional) The days to retain backups for. Default 1 +* `preferred_backup_window` - (Optional) The daily time range during which automated backups are created if automated backups are enabled using the BackupRetentionPeriod parameter. +Default: A 30-minute window selected at random from an 8-hour block of time per region. e.g. 04:00-09:00 +* `preferred_maintenance_window` - (Optional) The weekly time range during which system maintenance can occur, in (UTC) e.g. wed:04:00-wed:04:30 * `port` - (Optional) The port on which the DB accepts connections * `vpc_security_group_ids` - (Optional) List of VPC security groups to associate with the Cluster @@ -70,7 +75,8 @@ The following attributes are exported: * `allocated_storage` - The amount of allocated storage * `availability_zones` - The availability zone of the instance * `backup_retention_period` - The backup retention period -* `backup_window` - The backup window +* `preferred_backup_window` - The backup window +* `preferred_maintenance_window` - The maintenance window * `endpoint` - The primary, writeable connection endpoint * `engine` - The database engine * `engine_version` - The database engine version @@ -80,6 +86,7 @@ The following attributes are exported: * `status` - The RDS instance status * `username` - The master username for the database * `storage_encrypted` - Specifies whether the DB instance is encrypted +* `preferred_backup_window` - The daily time range during which the backups happen [1]: http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Replication.html From 4e485d4254ddb8ed807a701a6bed443bd4108dc3 Mon Sep 17 00:00:00 2001 From: stack72 Date: Wed, 4 Nov 2015 21:06:41 +0000 Subject: [PATCH 2/4] Fixing the spelling mistakes and adding a test to prove that the Updates to the new properties of RDS Cluster work as expected --- .../providers/aws/resource_aws_rds_cluster.go | 8 +-- .../aws/resource_aws_rds_cluster_test.go | 64 ++++++++++++++++++- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/builtin/providers/aws/resource_aws_rds_cluster.go b/builtin/providers/aws/resource_aws_rds_cluster.go index f4c54c3d67dd..ece9b686f13b 100644 --- a/builtin/providers/aws/resource_aws_rds_cluster.go +++ b/builtin/providers/aws/resource_aws_rds_cluster.go @@ -310,12 +310,12 @@ func resourceAwsRDSClusterUpdate(d *schema.ResourceData, meta interface{}) error req.PreferredBackupWindow = aws.String(d.Get("preferred_backup_window").(string)) } - if d.HasChange("preferred_maintaince_window") { - req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintaince_window").(string)) + if d.HasChange("preferred_maintenance_window") { + req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) } - if d.HasChange("backup_retention_limit") { - req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_limit").(int))) + if d.HasChange("backup_retention_period") { + req.BackupRetentionPeriod = aws.Int64(int64(d.Get("backup_retention_period").(int))) } _, err := conn.ModifyDBCluster(req) diff --git a/builtin/providers/aws/resource_aws_rds_cluster_test.go b/builtin/providers/aws/resource_aws_rds_cluster_test.go index 79da2acf4b9d..a9eed687e353 100644 --- a/builtin/providers/aws/resource_aws_rds_cluster_test.go +++ b/builtin/providers/aws/resource_aws_rds_cluster_test.go @@ -17,13 +17,16 @@ import ( func TestAccAWSRDSCluster_basic(t *testing.T) { var v rds.DBCluster + ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int() + config := fmt.Sprintf(testAccAWSClusterConfig, ri) + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSClusterDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccAWSClusterConfig, + Config: config, Check: resource.ComposeTestCheckFunc( testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), resource.TestCheckResourceAttr( @@ -38,6 +41,47 @@ func TestAccAWSRDSCluster_basic(t *testing.T) { }) } +func TestAccAWSRDSCluster_update(t *testing.T) { + var v rds.DBCluster + + ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int() + preConfig := fmt.Sprintf(testAccAWSClusterConfig, ri) + postConfig := fmt.Sprintf(testAccAWSClusterConfig_update, ri) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSClusterDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: preConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "preferred_backup_window", "07:00-09:00"), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "backup_retention_period", "5"), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "preferred_maintenance_window", "tue:04:00-tue:04:30"), + ), + }, + + resource.TestStep{ + Config: postConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "preferred_backup_window", "03:00-09:00"), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "backup_retention_period", "10"), + resource.TestCheckResourceAttr( + "aws_rds_cluster.default", "preferred_maintenance_window", "wed:01:00-wed:01:30"), + ), + }, + }, + }) +} + func testAccCheckAWSClusterDestroy(s *terraform.State) error { for _, rs := range s.RootModule().Resources { if rs.Type != "aws_rds_cluster" { @@ -104,7 +148,7 @@ func testAccCheckAWSClusterExists(n string, v *rds.DBCluster) resource.TestCheck } // Add some random to the name, to avoid collision -var testAccAWSClusterConfig = fmt.Sprintf(` +var testAccAWSClusterConfig = ` resource "aws_rds_cluster" "default" { cluster_identifier = "tf-aurora-cluster-%d" availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] @@ -114,4 +158,18 @@ resource "aws_rds_cluster" "default" { backup_retention_period = 5 preferred_backup_window = "07:00-09:00" preferred_maintenance_window = "tue:04:00-tue:04:30" -}`, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) +}` + +// Add some random to the name, to avoid collision +var testAccAWSClusterConfig_update = ` +resource "aws_rds_cluster" "default" { + cluster_identifier = "tf-aurora-cluster-%d" + availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] + database_name = "mydb" + master_username = "foo" + master_password = "mustbeeightcharaters" + backup_retention_period = 10 + preferred_backup_window = "03:00-09:00" + preferred_maintenance_window = "wed:01:00-wed:01:30" + apply_immediately = true +}` From 409df4866d8a05293ba3d1c87aee18684a8d12a8 Mon Sep 17 00:00:00 2001 From: stack72 Date: Thu, 5 Nov 2015 10:25:01 +0000 Subject: [PATCH 3/4] Changes after the feedback from @catsby - these all made perfect sense --- .../providers/aws/resource_aws_rds_cluster.go | 5 +++ .../aws/resource_aws_rds_cluster_test.go | 40 ++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/builtin/providers/aws/resource_aws_rds_cluster.go b/builtin/providers/aws/resource_aws_rds_cluster.go index ece9b686f13b..6dac39f0eaa7 100644 --- a/builtin/providers/aws/resource_aws_rds_cluster.go +++ b/builtin/providers/aws/resource_aws_rds_cluster.go @@ -127,12 +127,17 @@ func resourceAwsRDSCluster() *schema.Resource { "preferred_backup_window": &schema.Schema{ Type: schema.TypeString, Optional: true, + Computed: true, }, "preferred_maintenance_window": &schema.Schema{ Type: schema.TypeString, Optional: true, + Computed: true, StateFunc: func(val interface{}) string { + if val == nil { + return "" + } return strings.ToLower(val.(string)) }, }, diff --git a/builtin/providers/aws/resource_aws_rds_cluster_test.go b/builtin/providers/aws/resource_aws_rds_cluster_test.go index a9eed687e353..d0d285362793 100644 --- a/builtin/providers/aws/resource_aws_rds_cluster_test.go +++ b/builtin/providers/aws/resource_aws_rds_cluster_test.go @@ -20,6 +20,27 @@ func TestAccAWSRDSCluster_basic(t *testing.T) { ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int() config := fmt.Sprintf(testAccAWSClusterConfig, ri) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSClusterDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: config, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), + ), + }, + }, + }) +} + +func TestAccAWSRDSCluster_backups(t *testing.T) { + var v rds.DBCluster + + ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int() + config := fmt.Sprintf(testAccAWSClusterConfig_backups, ri) + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -41,12 +62,12 @@ func TestAccAWSRDSCluster_basic(t *testing.T) { }) } -func TestAccAWSRDSCluster_update(t *testing.T) { +func TestAccAWSRDSCluster_backupsUpdate(t *testing.T) { var v rds.DBCluster ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int() - preConfig := fmt.Sprintf(testAccAWSClusterConfig, ri) - postConfig := fmt.Sprintf(testAccAWSClusterConfig_update, ri) + preConfig := fmt.Sprintf(testAccAWSClusterConfig_backups, ri) + postConfig := fmt.Sprintf(testAccAWSClusterConfig_backupsUpdate, ri) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -147,8 +168,16 @@ func testAccCheckAWSClusterExists(n string, v *rds.DBCluster) resource.TestCheck } } -// Add some random to the name, to avoid collision var testAccAWSClusterConfig = ` +resource "aws_rds_cluster" "default" { + cluster_identifier = "tf-aurora-cluster-%d" + availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] + database_name = "mydb" + master_username = "foo" + master_password = "mustbeeightcharaters" +}` + +var testAccAWSClusterConfig_backups = ` resource "aws_rds_cluster" "default" { cluster_identifier = "tf-aurora-cluster-%d" availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] @@ -160,8 +189,7 @@ resource "aws_rds_cluster" "default" { preferred_maintenance_window = "tue:04:00-tue:04:30" }` -// Add some random to the name, to avoid collision -var testAccAWSClusterConfig_update = ` +var testAccAWSClusterConfig_backupsUpdate = ` resource "aws_rds_cluster" "default" { cluster_identifier = "tf-aurora-cluster-%d" availability_zones = ["us-west-2a","us-west-2b","us-west-2c"] From 6a5e591143a3789e050780ffd96ba64ff8891230 Mon Sep 17 00:00:00 2001 From: stack72 Date: Thu, 5 Nov 2015 19:01:41 +0000 Subject: [PATCH 4/4] Removing an unnecessary duplicate test for the RDS Cluster Backups --- .../aws/resource_aws_rds_cluster_test.go | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/builtin/providers/aws/resource_aws_rds_cluster_test.go b/builtin/providers/aws/resource_aws_rds_cluster_test.go index d0d285362793..dfb4fcc51abc 100644 --- a/builtin/providers/aws/resource_aws_rds_cluster_test.go +++ b/builtin/providers/aws/resource_aws_rds_cluster_test.go @@ -35,33 +35,6 @@ func TestAccAWSRDSCluster_basic(t *testing.T) { }) } -func TestAccAWSRDSCluster_backups(t *testing.T) { - var v rds.DBCluster - - ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int() - config := fmt.Sprintf(testAccAWSClusterConfig_backups, ri) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSClusterDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: config, - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSClusterExists("aws_rds_cluster.default", &v), - resource.TestCheckResourceAttr( - "aws_rds_cluster.default", "preferred_backup_window", "07:00-09:00"), - resource.TestCheckResourceAttr( - "aws_rds_cluster.default", "backup_retention_period", "5"), - resource.TestCheckResourceAttr( - "aws_rds_cluster.default", "preferred_maintenance_window", "tue:04:00-tue:04:30"), - ), - }, - }, - }) -} - func TestAccAWSRDSCluster_backupsUpdate(t *testing.T) { var v rds.DBCluster