diff --git a/.changelog/18315.txt b/.changelog/18315.txt new file mode 100644 index 00000000000..e9a60628eef --- /dev/null +++ b/.changelog/18315.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_backup_plan: Add `enable_continuous_backup` argument +``` \ No newline at end of file diff --git a/aws/resource_aws_backup_plan.go b/aws/resource_aws_backup_plan.go index 47f4d8af592..70622d88959 100644 --- a/aws/resource_aws_backup_plan.go +++ b/aws/resource_aws_backup_plan.go @@ -57,6 +57,11 @@ func resourceAwsBackupPlan() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "enable_continuous_backup": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, "start_window": { Type: schema.TypeInt, Optional: true, @@ -301,6 +306,9 @@ func expandBackupPlanRules(vRules *schema.Set) []*backup.RuleInput { if vSchedule, ok := mRule["schedule"].(string); ok && vSchedule != "" { rule.ScheduleExpression = aws.String(vSchedule) } + if vEnableContinuousBackup, ok := mRule["enable_continuous_backup"].(bool); ok { + rule.EnableContinuousBackup = aws.Bool(vEnableContinuousBackup) + } if vStartWindow, ok := mRule["start_window"].(int); ok { rule.StartWindowMinutes = aws.Int64(int64(vStartWindow)) } @@ -393,12 +401,13 @@ func flattenBackupPlanRules(rules []*backup.Rule) *schema.Set { for _, rule := range rules { mRule := map[string]interface{}{ - "rule_name": aws.StringValue(rule.RuleName), - "target_vault_name": aws.StringValue(rule.TargetBackupVaultName), - "schedule": aws.StringValue(rule.ScheduleExpression), - "start_window": int(aws.Int64Value(rule.StartWindowMinutes)), - "completion_window": int(aws.Int64Value(rule.CompletionWindowMinutes)), - "recovery_point_tags": keyvaluetags.BackupKeyValueTags(rule.RecoveryPointTags).IgnoreAws().Map(), + "rule_name": aws.StringValue(rule.RuleName), + "target_vault_name": aws.StringValue(rule.TargetBackupVaultName), + "schedule": aws.StringValue(rule.ScheduleExpression), + "enable_continuous_backup": aws.BoolValue(rule.EnableContinuousBackup), + "start_window": int(aws.Int64Value(rule.StartWindowMinutes)), + "completion_window": int(aws.Int64Value(rule.CompletionWindowMinutes)), + "recovery_point_tags": keyvaluetags.BackupKeyValueTags(rule.RecoveryPointTags).IgnoreAws().Map(), } if lifecycle := rule.Lifecycle; lifecycle != nil { @@ -481,6 +490,9 @@ func backupBackupPlanHash(vRule interface{}) int { if v, ok := mRule["schedule"].(string); ok { buf.WriteString(fmt.Sprintf("%s-", v)) } + if v, ok := mRule["enable_continuous_backup"].(bool); ok { + buf.WriteString(fmt.Sprintf("%t-", v)) + } if v, ok := mRule["start_window"].(int); ok { buf.WriteString(fmt.Sprintf("%d-", v)) } diff --git a/aws/resource_aws_backup_plan_test.go b/aws/resource_aws_backup_plan_test.go index 1ae97622b95..c06cc04ceb6 100644 --- a/aws/resource_aws_backup_plan_test.go +++ b/aws/resource_aws_backup_plan_test.go @@ -580,6 +580,45 @@ func TestAccAwsBackupPlan_AdvancedBackupSetting(t *testing.T) { }) } +func TestAccAwsBackupPlan_EnableContinuousBackup(t *testing.T) { + var plan backup.GetBackupPlanOutput + resourceName := "aws_backup_plan.test" + rName := fmt.Sprintf("tf-testacc-backup-%s", acctest.RandString(14)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSBackup(t) }, + ErrorCheck: testAccErrorCheck(t, backup.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsBackupPlanDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsBackupPlanConfigEnableContinuousBackup(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsBackupPlanExists(resourceName, &plan), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "backup", regexp.MustCompile(`backup-plan:.+`)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "rule_name": rName, + "target_vault_name": rName, + "schedule": "cron(0 12 * * ? *)", + "enable_continuous_backup": "true", + "lifecycle.#": "1", + "lifecycle.0.delete_after": "35", + }), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttrSet(resourceName, "version"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAwsBackupPlan_disappears(t *testing.T) { var plan backup.GetBackupPlanOutput resourceName := "aws_backup_plan.test" @@ -1092,3 +1131,26 @@ resource "aws_backup_plan" "test" { } `, rName) } + +func testAccAwsBackupPlanConfigEnableContinuousBackup(rName string) string { + return fmt.Sprintf(` +resource "aws_backup_vault" "test" { + name = %[1]q +} + +resource "aws_backup_plan" "test" { + name = %[1]q + + rule { + rule_name = %[1]q + target_vault_name = aws_backup_vault.test.name + schedule = "cron(0 12 * * ? *)" + enable_continuous_backup = true + + lifecycle { + delete_after = 35 + } + } +} +`, rName) +} diff --git a/website/docs/r/backup_plan.html.markdown b/website/docs/r/backup_plan.html.markdown index 832e9b29866..5bb7c3e652f 100644 --- a/website/docs/r/backup_plan.html.markdown +++ b/website/docs/r/backup_plan.html.markdown @@ -46,6 +46,7 @@ For **rule** the following attributes are supported: * `rule_name` - (Required) An display name for a backup rule. * `target_vault_name` - (Required) The name of a logical container where backups are stored. * `schedule` - (Optional) A CRON expression specifying when AWS Backup initiates a backup job. +* `enable_continuous_backup` - (Optional) Enable continuous backups for supported resources. * `start_window` - (Optional) The amount of time in minutes before beginning a backup. * `completion_window` - (Optional) The amount of time AWS Backup attempts a backup before canceling the job and returning an error. * `lifecycle` - (Optional) The lifecycle defines when a protected resource is transitioned to cold storage and when it expires. Fields documented below.