Skip to content

Commit

Permalink
Merge pull request #36511 from awsaxeman/f-aws-fsx-ontap_file_system-…
Browse files Browse the repository at this point in the history
…flexgroups

FSx ONTAP FlexGroup and Scale-out update
  • Loading branch information
ewbankkit authored May 2, 2024
2 parents fc1b174 + cddf8d0 commit b6bc9bc
Show file tree
Hide file tree
Showing 37 changed files with 1,339 additions and 1,046 deletions.
23 changes: 23 additions & 0 deletions .changelog/36511.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
```release-note:enhancement
resource/aws_fsx_ontap_file_system: Support up to 12 `ha_pairs`
```

```release-note:enhancement
resource/aws_fsx_ontap_file_system: Increase `storage_capacity` maximum to 1PiB
```

```release-note:enhancement
resource/aws_fsx_ontap_file_system: Update `throughput_capacity_per_ha_pair` to support all values from `throughput_capacity`
```

```release-note:enhancement
resource/aws_fsx_ontap_file_system: Add support for specifying 1 ha_pair with `SINGLE_AZ_1` and `MULTI_AZ_1` deployment types
```

```release-note:enhancement
resource/aws_fsx_ontap_volume: Add `aggregate_configuration` configuration block
```

```release-note:enhancement
resource/aws_fsx_ontap_volume: Add `size_in_bytes` and `volume_style` arguments
```
4 changes: 4 additions & 0 deletions .ci/.golangci2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ issues:
- staticcheck
path: "internal/service/firehose"
text: "SA1019: \\w+.(\\w+) is deprecated: (\\w+) has been deprecated"
- linters:
- staticcheck
path: "internal/service/fsx"
text: "SA1019: \\w+.(\\w+) is deprecated: This property is deprecated"
- linters:
- staticcheck
path: internal/service/globalaccelerator/
Expand Down
8 changes: 4 additions & 4 deletions internal/sdkv2/types/nullable/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func ValidateTypeStringNullableInt(v interface{}, k string) (ws []string, es []e

// ValidateTypeStringNullableIntAtLeast provides custom error messaging for TypeString ints
// Some arguments require an int value or unspecified, empty field.
func ValidateTypeStringNullableIntAtLeast(min int) schema.SchemaValidateFunc {
func ValidateTypeStringNullableIntAtLeast(min int64) schema.SchemaValidateFunc {
return func(i interface{}, k string) (ws []string, es []error) {
value, ok := i.(string)
if !ok {
Expand All @@ -84,7 +84,7 @@ func ValidateTypeStringNullableIntAtLeast(min int) schema.SchemaValidateFunc {
return
}

if v < int64(min) {
if v < min {
es = append(es, fmt.Errorf("expected %s to be at least (%d), got %d", k, min, v))
}

Expand All @@ -94,7 +94,7 @@ func ValidateTypeStringNullableIntAtLeast(min int) schema.SchemaValidateFunc {

// ValidateTypeStringNullableIntBetween provides custom error messaging for TypeString ints
// Some arguments require an int value or unspecified, empty field.
func ValidateTypeStringNullableIntBetween(min int, max int) schema.SchemaValidateFunc {
func ValidateTypeStringNullableIntBetween(min, max int64) schema.SchemaValidateFunc {
return func(i interface{}, k string) (ws []string, es []error) {
value, ok := i.(string)
if !ok {
Expand All @@ -112,7 +112,7 @@ func ValidateTypeStringNullableIntBetween(min int, max int) schema.SchemaValidat
return
}

if v < int64(min) || v > int64(max) {
if v < min || v > max {
es = append(es, fmt.Errorf("expected %s to be at between (%d) and (%d), got %d", k, min, max, v))
}

Expand Down
162 changes: 132 additions & 30 deletions internal/service/fsx/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
Expand All @@ -25,12 +27,13 @@ import (

// @SDKResource("aws_fsx_backup", name="Backup")
// @Tags(identifierAttribute="arn")
func ResourceBackup() *schema.Resource {
func resourceBackup() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceBackupCreate,
ReadWithoutTimeout: resourceBackupRead,
UpdateWithoutTimeout: resourceBackupUpdate,
DeleteWithoutTimeout: resourceBackupDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Expand Down Expand Up @@ -102,34 +105,27 @@ func resourceBackupCreate(ctx context.Context, d *schema.ResourceData, meta inte
return sdkdiag.AppendErrorf(diags, "creating FSx Backup: %s", "can only specify either file_system_id or volume_id")
}

result, err := conn.CreateBackupWithContext(ctx, input)
output, err := conn.CreateBackupWithContext(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating FSx Backup: %s", err)
}

d.SetId(aws.StringValue(result.Backup.BackupId))
d.SetId(aws.StringValue(output.Backup.BackupId))

log.Println("[DEBUG] Waiting for FSx backup to become available")
if _, err := waitBackupAvailable(ctx, conn, d.Id()); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for FSx Backup (%s) to be available: %s", d.Id(), err)
return sdkdiag.AppendErrorf(diags, "waiting for FSx Backup (%s) create: %s", d.Id(), err)
}

return append(diags, resourceBackupRead(ctx, d, meta)...)
}

func resourceBackupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics

// Tags only.

return append(diags, resourceBackupRead(ctx, d, meta)...)
}

func resourceBackupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).FSxConn(ctx)

backup, err := FindBackupByID(ctx, conn, d.Id())
backup, err := findBackupByID(ctx, conn, d.Id())

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] FSx Backup (%s) not found, removing from state", d.Id())
d.SetId("")
Expand All @@ -141,17 +137,12 @@ func resourceBackupRead(ctx context.Context, d *schema.ResourceData, meta interf
}

d.Set("arn", backup.ResourceARN)
d.Set("type", backup.Type)

if backup.FileSystem != nil {
fs := backup.FileSystem
d.Set("file_system_id", fs.FileSystemId)
d.Set("file_system_id", backup.FileSystem.FileSystemId)
}

d.Set("kms_key_id", backup.KmsKeyId)

d.Set("owner_id", backup.OwnerId)

d.Set("type", backup.Type)
if backup.Volume != nil {
d.Set("volume_id", backup.Volume.VolumeId)
}
Expand All @@ -161,28 +152,139 @@ func resourceBackupRead(ctx context.Context, d *schema.ResourceData, meta interf
return diags
}

func resourceBackupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics

// Tags only.

return append(diags, resourceBackupRead(ctx, d, meta)...)
}

func resourceBackupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).FSxConn(ctx)

request := &fsx.DeleteBackupInput{
log.Printf("[INFO] Deleting FSx Backup: %s", d.Id())
_, err := conn.DeleteBackupWithContext(ctx, &fsx.DeleteBackupInput{
BackupId: aws.String(d.Id()),
}
})

log.Printf("[INFO] Deleting FSx Backup: %s", d.Id())
_, err := conn.DeleteBackupWithContext(ctx, request)
if tfawserr.ErrCodeEquals(err, fsx.ErrCodeBackupNotFound) {
return diags
}

if err != nil {
if tfawserr.ErrCodeEquals(err, fsx.ErrCodeBackupNotFound) {
return diags
}
return sdkdiag.AppendErrorf(diags, "deleting FSx Backup (%s): %s", d.Id(), err)
}

log.Println("[DEBUG] Waiting for backup to delete")
if _, err := waitBackupDeleted(ctx, conn, d.Id()); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for FSx Backup (%s) to deleted: %s", d.Id(), err)
return sdkdiag.AppendErrorf(diags, "waiting for FSx Backup (%s) delete: %s", d.Id(), err)
}

return diags
}

func findBackupByID(ctx context.Context, conn *fsx.FSx, id string) (*fsx.Backup, error) {
input := &fsx.DescribeBackupsInput{
BackupIds: aws.StringSlice([]string{id}),
}

return findBackup(ctx, conn, input, tfslices.PredicateTrue[*fsx.Backup]())
}

func findBackup(ctx context.Context, conn *fsx.FSx, input *fsx.DescribeBackupsInput, filter tfslices.Predicate[*fsx.Backup]) (*fsx.Backup, error) {
output, err := findBackups(ctx, conn, input, filter)

if err != nil {
return nil, err
}

return tfresource.AssertSinglePtrResult(output)
}

func findBackups(ctx context.Context, conn *fsx.FSx, input *fsx.DescribeBackupsInput, filter tfslices.Predicate[*fsx.Backup]) ([]*fsx.Backup, error) {
var output []*fsx.Backup

err := conn.DescribeBackupsPagesWithContext(ctx, input, func(page *fsx.DescribeBackupsOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, v := range page.Backups {
if v != nil && filter(v) {
output = append(output, v)
}
}

return !lastPage
})

if tfawserr.ErrCodeEquals(err, fsx.ErrCodeFileSystemNotFound) || tfawserr.ErrCodeEquals(err, fsx.ErrCodeBackupNotFound) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

return output, nil
}

func statusBackup(ctx context.Context, conn *fsx.FSx, id string) retry.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := findBackupByID(ctx, conn, id)

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

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

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

func waitBackupAvailable(ctx context.Context, conn *fsx.FSx, id string) (*fsx.Backup, error) {
const (
timeout = 10 * time.Minute
)
stateConf := &retry.StateChangeConf{
Pending: []string{fsx.BackupLifecycleCreating, fsx.BackupLifecyclePending, fsx.BackupLifecycleTransferring},
Target: []string{fsx.BackupLifecycleAvailable},
Refresh: statusBackup(ctx, conn, id),
Timeout: timeout,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)

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

return nil, err
}

func waitBackupDeleted(ctx context.Context, conn *fsx.FSx, id string) (*fsx.Backup, error) {
const (
timeout = 10 * time.Minute
)
stateConf := &retry.StateChangeConf{
Pending: []string{fsx.FileSystemLifecycleDeleting},
Target: []string{},
Refresh: statusBackup(ctx, conn, id),
Timeout: timeout,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)

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

return nil, err
}
Loading

0 comments on commit b6bc9bc

Please sign in to comment.