Skip to content

Commit

Permalink
Merge pull request #26199 from hashicorp/f-aws_backup_vault.force_delete
Browse files Browse the repository at this point in the history
r/aws_backup_vault: Add `force_destroy` argument
  • Loading branch information
ewbankkit authored Aug 10, 2022
2 parents dadf492 + 5653a39 commit fc43804
Show file tree
Hide file tree
Showing 7 changed files with 412 additions and 93 deletions.
3 changes: 3 additions & 0 deletions .changelog/26199.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_backup_vault: Add `force_destroy` argument
```
55 changes: 53 additions & 2 deletions internal/service/backup/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,65 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func FindJobByID(conn *backup.Backup, id string) (*backup.DescribeBackupJobOutput, error) {
input := &backup.DescribeBackupJobInput{
BackupJobId: aws.String(id),
}

output, err := conn.DescribeBackupJob(input)

if tfawserr.ErrCodeEquals(err, backup.ErrCodeResourceNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output, nil
}

func FindRecoveryPointByTwoPartKey(conn *backup.Backup, backupVaultName, recoveryPointARN string) (*backup.DescribeRecoveryPointOutput, error) {
input := &backup.DescribeRecoveryPointInput{
BackupVaultName: aws.String(backupVaultName),
RecoveryPointArn: aws.String(recoveryPointARN),
}

output, err := conn.DescribeRecoveryPoint(input)

if tfawserr.ErrCodeEquals(err, backup.ErrCodeResourceNotFoundException, errCodeAccessDeniedException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output, nil
}

func FindVaultAccessPolicyByName(conn *backup.Backup, name string) (*backup.GetBackupVaultAccessPolicyOutput, error) {
input := &backup.GetBackupVaultAccessPolicyInput{
BackupVaultName: aws.String(name),
}

output, err := conn.GetBackupVaultAccessPolicy(input)

if tfawserr.ErrCodeEquals(err, backup.ErrCodeResourceNotFoundException) || tfawserr.ErrCodeEquals(err, errCodeAccessDeniedException) {
if tfawserr.ErrCodeEquals(err, backup.ErrCodeResourceNotFoundException, errCodeAccessDeniedException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
Expand All @@ -40,7 +91,7 @@ func FindVaultByName(conn *backup.Backup, name string) (*backup.DescribeBackupVa

output, err := conn.DescribeBackupVault(input)

if tfawserr.ErrCodeEquals(err, backup.ErrCodeResourceNotFoundException) || tfawserr.ErrCodeEquals(err, errCodeAccessDeniedException) {
if tfawserr.ErrCodeEquals(err, backup.ErrCodeResourceNotFoundException, errCodeAccessDeniedException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
Expand Down
33 changes: 33 additions & 0 deletions internal/service/backup/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,25 @@ import (
"github.com/aws/aws-sdk-go/service/backup"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func statusJobState(conn *backup.Backup, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := FindJobByID(conn, id)

if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return output, aws.StringValue(output.State), nil
}
}

func statusFramework(conn *backup.Backup, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &backup.DescribeFrameworkInput{
Expand All @@ -26,3 +43,19 @@ func statusFramework(conn *backup.Backup, id string) resource.StateRefreshFunc {
return output, aws.StringValue(output.DeploymentStatus), nil
}
}

func statusRecoveryPoint(conn *backup.Backup, backupVaultName, recoveryPointARN string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := FindRecoveryPointByTwoPartKey(conn, backupVaultName, recoveryPointARN)

if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return output, aws.StringValue(output.Status), nil
}
}
79 changes: 68 additions & 11 deletions internal/service/backup/vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"fmt"
"log"
"regexp"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/backup"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
Expand All @@ -22,15 +24,25 @@ func ResourceVault() *schema.Resource {
Read: resourceVaultRead,
Update: resourceVaultUpdate,
Delete: resourceVaultDelete,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Timeouts: &schema.ResourceTimeout{
Delete: schema.DefaultTimeout(10 * time.Minute),
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"force_destroy": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"kms_key_arn": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -39,10 +51,13 @@ func ResourceVault() *schema.Resource {
ValidateFunc: verify.ValidARN,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9\-\_\.]{1,50}$`), "must consist of lowercase letters, numbers, and hyphens."),
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.All(
validation.StringLenBetween(2, 50),
validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9\-\_]*$`), "must consist of letters, numbers, and hyphens."),
),
},
"recovery_points": {
Type: schema.TypeInt,
Expand Down Expand Up @@ -74,7 +89,7 @@ func resourceVaultCreate(d *schema.ResourceData, meta interface{}) error {
_, err := conn.CreateBackupVault(input)

if err != nil {
return fmt.Errorf("error creating Backup Vault (%s): %w", name, err)
return fmt.Errorf("creating Backup Vault (%s): %w", name, err)
}

d.SetId(name)
Expand All @@ -96,7 +111,7 @@ func resourceVaultRead(d *schema.ResourceData, meta interface{}) error {
}

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

d.Set("arn", output.BackupVaultArn)
Expand All @@ -107,18 +122,18 @@ func resourceVaultRead(d *schema.ResourceData, meta interface{}) error {
tags, err := ListTags(conn, d.Get("arn").(string))

if err != nil {
return fmt.Errorf("error listing tags for Backup Vault (%s): %w", d.Id(), err)
return fmt.Errorf("listing tags for Backup Vault (%s): %w", d.Id(), err)
}

tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig)

//lintignore:AWSR002
if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
return fmt.Errorf("setting tags: %w", err)
}

if err := d.Set("tags_all", tags.Map()); err != nil {
return fmt.Errorf("error setting tags_all: %w", err)
return fmt.Errorf("setting tags_all: %w", err)
}

return nil
Expand All @@ -130,7 +145,7 @@ func resourceVaultUpdate(d *schema.ResourceData, meta interface{}) error {
if d.HasChange("tags_all") {
o, n := d.GetChange("tags_all")
if err := UpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
return fmt.Errorf("error updating tags for Backup Vault (%s): %w", d.Id(), err)
return fmt.Errorf("updating tags for Backup Vault (%s): %w", d.Id(), err)
}
}

Expand All @@ -140,6 +155,48 @@ func resourceVaultUpdate(d *schema.ResourceData, meta interface{}) error {
func resourceVaultDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).BackupConn

if d.Get("force_destroy").(bool) {
input := &backup.ListRecoveryPointsByBackupVaultInput{
BackupVaultName: aws.String(d.Id()),
}
var recoveryPointErrs *multierror.Error

err := conn.ListRecoveryPointsByBackupVaultPages(input, func(page *backup.ListRecoveryPointsByBackupVaultOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, v := range page.RecoveryPoints {
recoveryPointARN := aws.StringValue(v.RecoveryPointArn)

log.Printf("[DEBUG] Deleting Backup Vault recovery point: %s", recoveryPointARN)
_, err := conn.DeleteRecoveryPoint(&backup.DeleteRecoveryPointInput{
BackupVaultName: aws.String(d.Id()),
RecoveryPointArn: aws.String(recoveryPointARN),
})

if err != nil {
recoveryPointErrs = multierror.Append(recoveryPointErrs, fmt.Errorf("deleting Backup Vault (%s) recovery point (%s): %w", d.Id(), recoveryPointARN, err))
continue
}

if _, err := waitRecoveryPointDeleted(conn, d.Id(), recoveryPointARN, d.Timeout(schema.TimeoutDelete)); err != nil {
recoveryPointErrs = multierror.Append(recoveryPointErrs, fmt.Errorf("waiting for Backup Vault (%s) recovery point (%s) delete: %w", d.Id(), recoveryPointARN, err))
}
}

return !lastPage
})

if err != nil {
return fmt.Errorf("listing Backup Vault (%s) recovery points: %w", d.Id(), err)
}

if err := recoveryPointErrs.ErrorOrNil(); err != nil {
return err
}
}

log.Printf("[DEBUG] Deleting Backup Vault: %s", d.Id())
_, err := conn.DeleteBackupVault(&backup.DeleteBackupVaultInput{
BackupVaultName: aws.String(d.Id()),
Expand All @@ -150,7 +207,7 @@ func resourceVaultDelete(d *schema.ResourceData, meta interface{}) error {
}

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

return nil
Expand Down
Loading

0 comments on commit fc43804

Please sign in to comment.