Skip to content

Commit

Permalink
resource/aws_backup_plan: Retry on eventual consistency error on dele…
Browse files Browse the repository at this point in the history
…tion + validations (#16476)

* retry on delete + validations

* Apply suggestions from code review

Co-authored-by: Brian Flad <bflad417@gmail.com>

Co-authored-by: Brian Flad <bflad417@gmail.com>
  • Loading branch information
DrFaust92 and bflad authored Dec 2, 2020
1 parent e64740f commit 9c386bf
Showing 1 changed file with 52 additions and 17 deletions.
69 changes: 52 additions & 17 deletions aws/resource_aws_backup_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import (
"bytes"
"fmt"
"log"
"regexp"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/backup"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)
Expand Down Expand Up @@ -36,10 +40,18 @@ func resourceAwsBackupPlan() *schema.Resource {
"rule_name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.All(
validation.StringLenBetween(1, 50),
validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9\-\_\.]+$`), "must contain only alphanumeric characters, hyphens, underscores, and periods"),
),
},
"target_vault_name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.All(
validation.StringLenBetween(2, 50),
validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9\-\_]+$`), "must contain only alphanumeric characters, hyphens, and underscores"),
),
},
"schedule": {
Type: schema.TypeString,
Expand All @@ -66,8 +78,9 @@ func resourceAwsBackupPlan() *schema.Resource {
Optional: true,
},
"delete_after": {
Type: schema.TypeInt,
Optional: true,
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntAtLeast(90),
},
},
},
Expand All @@ -88,8 +101,9 @@ func resourceAwsBackupPlan() *schema.Resource {
Optional: true,
},
"delete_after": {
Type: schema.TypeInt,
Optional: true,
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntAtLeast(90),
},
},
},
Expand Down Expand Up @@ -120,6 +134,9 @@ func resourceAwsBackupPlan() *schema.Resource {
"resource_type": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"EC2",
}, false),
},
},
},
Expand Down Expand Up @@ -152,7 +169,7 @@ func resourceAwsBackupPlanCreate(d *schema.ResourceData, meta interface{}) error
log.Printf("[DEBUG] Creating Backup Plan: %#v", input)
resp, err := conn.CreateBackupPlan(input)
if err != nil {
return fmt.Errorf("error creating Backup Plan: %s", err)
return fmt.Errorf("error creating Backup Plan: %w", err)
}

d.SetId(aws.StringValue(resp.BackupPlanId))
Expand All @@ -173,29 +190,29 @@ func resourceAwsBackupPlanRead(d *schema.ResourceData, meta interface{}) error {
return nil
}
if err != nil {
return fmt.Errorf("error reading Backup Plan (%s): %s", d.Id(), err)
return fmt.Errorf("error reading Backup Plan (%s): %w", d.Id(), err)
}

d.Set("arn", resp.BackupPlanArn)
d.Set("name", resp.BackupPlan.BackupPlanName)
d.Set("version", resp.VersionId)

if err := d.Set("rule", flattenBackupPlanRules(resp.BackupPlan.Rules)); err != nil {
return fmt.Errorf("error setting rule: %s", err)
return fmt.Errorf("error setting rule: %w", err)
}

// AdvancedBackupSettings being read direct from resp and not from under
// resp.BackupPlan is deliberate - the latter always contains null
if err := d.Set("advanced_backup_setting", flattenBackupPlanAdvancedBackupSettings(resp.AdvancedBackupSettings)); err != nil {
return fmt.Errorf("error setting advanced_backup_setting: %s", err)
return fmt.Errorf("error setting advanced_backup_setting: %w", err)
}

tags, err := keyvaluetags.BackupListTags(conn, d.Get("arn").(string))
if err != nil {
return fmt.Errorf("error listing tags for Backup Plan (%s): %s", d.Id(), err)
return fmt.Errorf("error listing tags for Backup Plan (%s): %w", d.Id(), err)
}
if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %s", err)
return fmt.Errorf("error setting tags: %w", err)
}

return nil
Expand All @@ -217,14 +234,14 @@ func resourceAwsBackupPlanUpdate(d *schema.ResourceData, meta interface{}) error
log.Printf("[DEBUG] Updating Backup Plan: %#v", input)
_, err := conn.UpdateBackupPlan(input)
if err != nil {
return fmt.Errorf("error updating Backup Plan (%s): %s", d.Id(), err)
return fmt.Errorf("error updating Backup Plan (%s): %w", d.Id(), err)
}
}

if d.HasChange("tags") {
o, n := d.GetChange("tags")
if err := keyvaluetags.BackupUpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
return fmt.Errorf("error updating tags for Backup Plan (%s): %s", d.Id(), err)
return fmt.Errorf("error updating tags for Backup Plan (%s): %w", d.Id(), err)
}
}

Expand All @@ -234,16 +251,34 @@ func resourceAwsBackupPlanUpdate(d *schema.ResourceData, meta interface{}) error
func resourceAwsBackupPlanDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).backupconn

log.Printf("[DEBUG] Deleting Backup Plan: %s", d.Id())
_, err := conn.DeleteBackupPlan(&backup.DeleteBackupPlanInput{
input := &backup.DeleteBackupPlanInput{
BackupPlanId: aws.String(d.Id()),
})
if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") {
}

log.Printf("[DEBUG] Deleting Backup Plan: %s", d.Id())
err := resource.Retry(2*time.Minute, func() *resource.RetryError {
_, err := conn.DeleteBackupPlan(input)

if isAWSErr(err, backup.ErrCodeInvalidRequestException, "Related backup plan selections must be deleted prior to backup") {
return resource.RetryableError(err)
}

if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") {
return nil
}

if err != nil {
return resource.NonRetryableError(err)
}
return nil
})

if isResourceTimeoutError(err) {
_, err = conn.DeleteBackupPlan(input)
}

if err != nil {
return fmt.Errorf("error deleting Backup Plan (%s): %s", d.Id(), err)
return fmt.Errorf("error deleting Backup Plan (%s): %w", d.Id(), err)
}

return nil
Expand Down

0 comments on commit 9c386bf

Please sign in to comment.