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

Add efs_file_system_backup_policy resource #18006

Merged
merged 11 commits into from
Jun 23, 2021
24 changes: 24 additions & 0 deletions aws/internal/service/efs/finder/finder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package finder

import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/efs"
)

// FileSystemBackupPolicyById returns the EFS Backup Policy corresponding to the specified Id.
// Returns nil if no policy is found.
func FileSystemBackupPolicyById(conn *efs.EFS, id string) (*efs.BackupPolicy, error) {
output, err := conn.DescribeBackupPolicy(&efs.DescribeBackupPolicyInput{
FileSystemId: aws.String(id),
})

if err != nil {
return nil, err
}

if output == nil {
return nil, nil
}

return output.BackupPolicy, nil
}
18 changes: 18 additions & 0 deletions aws/internal/service/efs/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/efs"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/efs/finder"
)

// AccessPointLifeCycleState fetches the Access Point and its LifecycleState
Expand All @@ -29,6 +30,23 @@ func AccessPointLifeCycleState(conn *efs.EFS, accessPointId string) resource.Sta
}
}

// FileSystemBackupPolicyStatus fetches the EFS Backup Policy status
func FileSystemBackupPolicyStatus(conn *efs.EFS, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
bp, err := finder.FileSystemBackupPolicyById(conn, id)

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

if bp == nil {
return nil, "", nil
}

return bp, aws.StringValue(bp.Status), nil
}
}

// FileSystemLifeCycleState fetches the Access Point and its LifecycleState
func FileSystemLifeCycleState(conn *efs.EFS, fileSystemID string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
Expand Down
42 changes: 41 additions & 1 deletion aws/internal/service/efs/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const (
FileSystemDeletedTimeout = 10 * time.Minute
FileSystemDeletedDelayTimeout = 2 * time.Second
FileSystemDeletedMinTimeout = 3 * time.Second

// Maximum amount of time to wait for an EFS Backup policy operation
FileSystemBackupPolicyCreatedTimeout = 10 * time.Minute
FileSystemBackupPolicyDeletedTimeout = 10 * time.Minute
)

// AccessPointCreated waits for an Operation to return Success
Expand All @@ -37,7 +41,7 @@ func AccessPointCreated(conn *efs.EFS, accessPointId string) (*efs.AccessPointDe
return nil, err
}

// AccessPointDelete waits for an Access Point to return Deleted
// AccessPointDeleted waits for an Access Point to return Deleted
func AccessPointDeleted(conn *efs.EFS, accessPointId string) (*efs.AccessPointDescription, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{efs.LifeCycleStateAvailable, efs.LifeCycleStateDeleting, efs.LifeCycleStateDeleted},
Expand Down Expand Up @@ -94,3 +98,39 @@ func FileSystemDeleted(conn *efs.EFS, fileSystemID string) (*efs.FileSystemDescr

return nil, err
}

// FileSystemBackupPolicyCreated waits for a EFS Backup Policy creation
func FileSystemBackupPolicyCreated(conn *efs.EFS, id string) (*efs.BackupPolicy, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{efs.StatusEnabling},
Target: []string{efs.StatusEnabled},
Refresh: FileSystemBackupPolicyStatus(conn, id),
Timeout: FileSystemBackupPolicyCreatedTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*efs.BackupPolicy); ok {
return output, err
}

return nil, err
}

// FileSystemBackupPolicyDeleted waits for a EFS Backup Policy deletion
func FileSystemBackupPolicyDeleted(conn *efs.EFS, id string) (*efs.BackupPolicy, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{efs.StatusDisabling},
Target: []string{efs.StatusDisabled},
Refresh: FileSystemBackupPolicyStatus(conn, id),
Timeout: FileSystemBackupPolicyDeletedTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*efs.BackupPolicy); ok {
return output, err
}

return nil, err
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@ func Provider() *schema.Provider {
"aws_ecs_task_definition": resourceAwsEcsTaskDefinition(),
"aws_efs_access_point": resourceAwsEfsAccessPoint(),
"aws_efs_file_system": resourceAwsEfsFileSystem(),
"aws_efs_file_system_backup_policy": resourceAwsEfsFileSystemBackupPolicy(),
"aws_efs_file_system_policy": resourceAwsEfsFileSystemPolicy(),
"aws_efs_mount_target": resourceAwsEfsMountTarget(),
"aws_egress_only_internet_gateway": resourceAwsEgressOnlyInternetGateway(),
Expand Down
143 changes: 143 additions & 0 deletions aws/resource_aws_efs_file_system_backup_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/efs"
"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/service/efs/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/efs/waiter"
)

func resourceAwsEfsFileSystemBackupPolicy() *schema.Resource {
return &schema.Resource{
Create: resourceAwsEfsFileSystemBackupPolicyPut,
Read: resourceAwsEfsFileSystemBackupPolicyRead,
Delete: resourceAwsEfsFileSystemBackupPolicyDelete,

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

Schema: map[string]*schema.Schema{
"file_system_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"backup_policy": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"status": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
efs.StatusEnabled,
}, false),
},
},
},
},
},
}
}

func resourceAwsEfsFileSystemBackupPolicyPut(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn

fsId := d.Get("file_system_id").(string)
input := &efs.PutBackupPolicyInput{
FileSystemId: aws.String(fsId),
}

if v, ok := d.GetOk("backup_policy"); ok {
input.BackupPolicy = expandEfsFileSystemBackupPolicy(v.([]interface{}))
}

log.Printf("[DEBUG] Adding EFS File System Backup Policy: %#v", input)
_, err := conn.PutBackupPolicy(input)
if err != nil {
return fmt.Errorf("error creating EFS File System Backup Policy %q: %s", fsId, err.Error())
}

d.SetId(fsId)

if _, err := waiter.FileSystemBackupPolicyCreated(conn, d.Id()); err != nil {
return fmt.Errorf("error waiting for EFS File System Backup Policy (%q) creation : %s", d.Id(), err)
}

return resourceAwsEfsFileSystemBackupPolicyRead(d, meta)
}

func resourceAwsEfsFileSystemBackupPolicyRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn

bp, err := finder.FileSystemBackupPolicyById(conn, d.Id())
if err != nil {
if isAWSErr(err, efs.ErrCodeFileSystemNotFound, "") {
log.Printf("[WARN] EFS File System (%q) not found, removing from state", d.Id())
d.SetId("")
return nil
}
if isAWSErr(err, efs.ErrCodePolicyNotFound, "") {
log.Printf("[WARN] EFS File System Backup Policy (%q) not found, removing from state", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("error describing policy for EFS File System Backup Policy (%q): %s", d.Id(), err)
}

if bp == nil || aws.StringValue(bp.Status) == efs.StatusDisabled {
log.Printf("[WARN] EFS File System Backup Policy (%q) is disabled, removing from state", d.Id())
d.SetId("")
return nil
}

d.Set("file_system_id", d.Id())
if err := d.Set("backup_policy", flattenEfsFileSystemBackupPolicy(bp)); err != nil {
return fmt.Errorf("error setting backup_policy: %s", err)
}

return nil
}

func resourceAwsEfsFileSystemBackupPolicyDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn

log.Printf("[DEBUG] Deleting EFS File System Backup Policy: %s", d.Id())
_, err := conn.PutBackupPolicy(&efs.PutBackupPolicyInput{
FileSystemId: aws.String(d.Id()),
BackupPolicy: &efs.BackupPolicy{
Status: aws.String(efs.StatusDisabled),
},
})

if err != nil {
return fmt.Errorf("error deleting EFS File System Backup Policy: %s with err %s", d.Id(), err.Error())
}

if _, err := waiter.FileSystemBackupPolicyDeleted(conn, d.Id()); err != nil {
return fmt.Errorf("error waiting for EFS File System Backup Policy (%q) deletion : %s", d.Id(), err)
}

log.Printf("[DEBUG] EFS File System Backup Policy %q deleted.", d.Id())

return nil
}

func expandEfsFileSystemBackupPolicy(tfList []interface{}) *efs.BackupPolicy {
return &efs.BackupPolicy{
Status: aws.String(tfList[0].(map[string]interface{})["status"].(string)),
}
}

func flattenEfsFileSystemBackupPolicy(apiObjects *efs.BackupPolicy) []interface{} {
return []interface{}{map[string]interface{}{"status": apiObjects.Status}}
}
Loading