diff --git a/aws/fsx.go b/aws/fsx.go index 5468112b962..51dcab9dc17 100644 --- a/aws/fsx.go +++ b/aws/fsx.go @@ -75,3 +75,17 @@ func waitForFsxFileSystemDeletion(conn *fsx.FSx, id string, timeout time.Duratio return err } + +func waitForFsxFileSystemUpdate(conn *fsx.FSx, id string, timeout time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{fsx.FileSystemLifecycleUpdating}, + Target: []string{fsx.FileSystemLifecycleAvailable}, + Refresh: refreshFsxFileSystemLifecycle(conn, id), + Timeout: timeout, + Delay: 30 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +} diff --git a/aws/resource_aws_fsx_lustre_file_system.go b/aws/resource_aws_fsx_lustre_file_system.go index 1813ff078a2..5727ef7711e 100644 --- a/aws/resource_aws_fsx_lustre_file_system.go +++ b/aws/resource_aws_fsx_lustre_file_system.go @@ -131,6 +131,12 @@ func resourceAwsFsxLustreFileSystem() *schema.Resource { 200, }), }, + "automatic_backup_retention_days": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(0, 35), + }, }, } } @@ -143,29 +149,24 @@ func resourceAwsFsxLustreFileSystemCreate(d *schema.ResourceData, meta interface FileSystemType: aws.String(fsx.FileSystemTypeLustre), StorageCapacity: aws.Int64(int64(d.Get("storage_capacity").(int))), SubnetIds: expandStringList(d.Get("subnet_ids").([]interface{})), + LustreConfiguration: &fsx.CreateFileSystemLustreConfiguration{ + DeploymentType: aws.String(d.Get("deployment_type").(string)), + }, } - if v, ok := d.GetOk("export_path"); ok { - if input.LustreConfiguration == nil { - input.LustreConfiguration = &fsx.CreateFileSystemLustreConfiguration{} - } + if v, ok := d.GetOk("automatic_backup_retention_days"); ok { + input.LustreConfiguration.AutomaticBackupRetentionDays = aws.Int64(int64(v.(int))) + } + if v, ok := d.GetOk("export_path"); ok { input.LustreConfiguration.ExportPath = aws.String(v.(string)) } if v, ok := d.GetOk("import_path"); ok { - if input.LustreConfiguration == nil { - input.LustreConfiguration = &fsx.CreateFileSystemLustreConfiguration{} - } - input.LustreConfiguration.ImportPath = aws.String(v.(string)) } if v, ok := d.GetOk("imported_file_chunk_size"); ok { - if input.LustreConfiguration == nil { - input.LustreConfiguration = &fsx.CreateFileSystemLustreConfiguration{} - } - input.LustreConfiguration.ImportedFileChunkSize = aws.Int64(int64(v.(int))) } @@ -178,40 +179,24 @@ func resourceAwsFsxLustreFileSystemCreate(d *schema.ResourceData, meta interface } if v, ok := d.GetOk("weekly_maintenance_start_time"); ok { - if input.LustreConfiguration == nil { - input.LustreConfiguration = &fsx.CreateFileSystemLustreConfiguration{} - } - input.LustreConfiguration.WeeklyMaintenanceStartTime = aws.String(v.(string)) } - if v, ok := d.GetOk("deployment_type"); ok { - if input.LustreConfiguration == nil { - input.LustreConfiguration = &fsx.CreateFileSystemLustreConfiguration{} - } - - input.LustreConfiguration.DeploymentType = aws.String(v.(string)) - } - if v, ok := d.GetOk("per_unit_storage_throughput"); ok { - if input.LustreConfiguration == nil { - input.LustreConfiguration = &fsx.CreateFileSystemLustreConfiguration{} - } - input.LustreConfiguration.PerUnitStorageThroughput = aws.Int64(int64(v.(int))) } result, err := conn.CreateFileSystem(input) if err != nil { - return fmt.Errorf("Error creating FSx filesystem: %s", err) + return fmt.Errorf("Error creating FSx Lustre filesystem: %w", err) } - d.SetId(*result.FileSystem.FileSystemId) + d.SetId(aws.StringValue(result.FileSystem.FileSystemId)) log.Println("[DEBUG] Waiting for filesystem to become available") if err := waitForFsxFileSystemCreation(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { - return fmt.Errorf("Error waiting for filesystem (%s) to become available: %s", d.Id(), err) + return fmt.Errorf("Error waiting for filesystem (%s) to become available: %w", d.Id(), err) } return resourceAwsFsxLustreFileSystemRead(d, meta) @@ -224,7 +209,7 @@ func resourceAwsFsxLustreFileSystemUpdate(d *schema.ResourceData, meta interface o, n := d.GetChange("tags") if err := keyvaluetags.FsxUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating FSx Windows File System (%s) tags: %s", d.Get("arn").(string), err) + return fmt.Errorf("error updating FSx Lustre File System (%s) tags: %w", d.Get("arn").(string), err) } } @@ -240,10 +225,21 @@ func resourceAwsFsxLustreFileSystemUpdate(d *schema.ResourceData, meta interface requestUpdate = true } + if d.HasChange("automatic_backup_retention_days") { + input.LustreConfiguration.AutomaticBackupRetentionDays = aws.Int64(int64(d.Get("automatic_backup_retention_days").(int))) + requestUpdate = true + } + if requestUpdate { _, err := conn.UpdateFileSystem(input) if err != nil { - return fmt.Errorf("error updating FSX File System (%s): %s", d.Id(), err) + return fmt.Errorf("error updating FSX Lustre File System (%s): %w", d.Id(), err) + } + + log.Println("[DEBUG] Waiting for filesystem to become available") + + if err := waitForFsxFileSystemUpdate(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return fmt.Errorf("Error waiting for filesystem (%s) to become available: %w", d.Id(), err) } } @@ -263,7 +259,7 @@ func resourceAwsFsxLustreFileSystemRead(d *schema.ResourceData, meta interface{} } if err != nil { - return fmt.Errorf("Error reading FSx File System (%s): %s", d.Id(), err) + return fmt.Errorf("Error reading FSx Lustre File System (%s): %w", d.Id(), err) } if filesystem == nil { @@ -272,46 +268,49 @@ func resourceAwsFsxLustreFileSystemRead(d *schema.ResourceData, meta interface{} return nil } + lustreConfig := filesystem.LustreConfiguration + if filesystem.WindowsConfiguration != nil { return fmt.Errorf("expected FSx Lustre File System, found FSx Windows File System: %s", d.Id()) } - if filesystem.LustreConfiguration == nil { + if lustreConfig == nil { return fmt.Errorf("error describing FSx Lustre File System (%s): empty Lustre configuration", d.Id()) } - if filesystem.LustreConfiguration.DataRepositoryConfiguration == nil { + if lustreConfig.DataRepositoryConfiguration == nil { // Initialize an empty structure to simplify d.Set() handling - filesystem.LustreConfiguration.DataRepositoryConfiguration = &fsx.DataRepositoryConfiguration{} + lustreConfig.DataRepositoryConfiguration = &fsx.DataRepositoryConfiguration{} } d.Set("arn", filesystem.ResourceARN) d.Set("dns_name", filesystem.DNSName) - d.Set("export_path", filesystem.LustreConfiguration.DataRepositoryConfiguration.ExportPath) - d.Set("import_path", filesystem.LustreConfiguration.DataRepositoryConfiguration.ImportPath) - d.Set("imported_file_chunk_size", filesystem.LustreConfiguration.DataRepositoryConfiguration.ImportedFileChunkSize) - d.Set("deployment_type", filesystem.LustreConfiguration.DeploymentType) - if filesystem.LustreConfiguration.PerUnitStorageThroughput != nil { - d.Set("per_unit_storage_throughput", filesystem.LustreConfiguration.PerUnitStorageThroughput) + d.Set("export_path", lustreConfig.DataRepositoryConfiguration.ExportPath) + d.Set("import_path", lustreConfig.DataRepositoryConfiguration.ImportPath) + d.Set("imported_file_chunk_size", lustreConfig.DataRepositoryConfiguration.ImportedFileChunkSize) + d.Set("deployment_type", lustreConfig.DeploymentType) + if lustreConfig.PerUnitStorageThroughput != nil { + d.Set("per_unit_storage_throughput", lustreConfig.PerUnitStorageThroughput) } if err := d.Set("network_interface_ids", aws.StringValueSlice(filesystem.NetworkInterfaceIds)); err != nil { - return fmt.Errorf("error setting network_interface_ids: %s", err) + return fmt.Errorf("error setting network_interface_ids: %w", err) } d.Set("owner_id", filesystem.OwnerId) d.Set("storage_capacity", filesystem.StorageCapacity) if err := d.Set("subnet_ids", aws.StringValueSlice(filesystem.SubnetIds)); err != nil { - return fmt.Errorf("error setting subnet_ids: %s", err) + return fmt.Errorf("error setting subnet_ids: %w", err) } if err := d.Set("tags", keyvaluetags.FsxKeyValueTags(filesystem.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("error setting tags: %w", err) } d.Set("vpc_id", filesystem.VpcId) - d.Set("weekly_maintenance_start_time", filesystem.LustreConfiguration.WeeklyMaintenanceStartTime) + d.Set("weekly_maintenance_start_time", lustreConfig.WeeklyMaintenanceStartTime) + d.Set("automatic_backup_retention_days", lustreConfig.AutomaticBackupRetentionDays) return nil } @@ -330,13 +329,13 @@ func resourceAwsFsxLustreFileSystemDelete(d *schema.ResourceData, meta interface } if err != nil { - return fmt.Errorf("Error deleting FSx filesystem: %s", err) + return fmt.Errorf("Error deleting FSx Lustre filesystem: %w", err) } log.Println("[DEBUG] Waiting for filesystem to delete") if err := waitForFsxFileSystemDeletion(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("Error waiting for filesystem (%s) to delete: %s", d.Id(), err) + return fmt.Errorf("Error waiting for filesystem (%s) to delete: %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_fsx_lustre_file_system_test.go b/aws/resource_aws_fsx_lustre_file_system_test.go index ce91ea68dba..ce4c9b9cb35 100644 --- a/aws/resource_aws_fsx_lustre_file_system_test.go +++ b/aws/resource_aws_fsx_lustre_file_system_test.go @@ -95,6 +95,7 @@ func TestAccAWSFsxLustreFileSystem_basic(t *testing.T) { resource.TestMatchResourceAttr(resourceName, "vpc_id", regexp.MustCompile(`^vpc-.+`)), resource.TestMatchResourceAttr(resourceName, "weekly_maintenance_start_time", regexp.MustCompile(`^\d:\d\d:\d\d$`)), resource.TestCheckResourceAttr(resourceName, "deployment_type", fsx.LustreDeploymentTypeScratch1), + resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "0"), ), }, { @@ -124,7 +125,7 @@ func TestAccAWSFsxLustreFileSystem_disappears(t *testing.T) { Config: testAccAwsFsxLustreFileSystemConfigSubnetIds1(), Check: resource.ComposeTestCheckFunc( testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem), - testAccCheckFsxLustreFileSystemDisappears(&filesystem), + testAccCheckResourceDisappears(testAccProvider, resourceAwsFsxLustreFileSystem(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -387,6 +388,47 @@ func TestAccAWSFsxLustreFileSystem_WeeklyMaintenanceStartTime(t *testing.T) { }) } +func TestAccAWSFsxLustreFileSystem_automaticBackupRetentionDays(t *testing.T) { + var filesystem1, filesystem2 fsx.FileSystem + resourceName := "aws_fsx_lustre_file_system.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckFsxLustreFileSystemDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsFsxLustreFileSystemConfigAutomaticBackupRetentionDays(1), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem1), + resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"security_group_ids"}, + }, + { + Config: testAccAwsFsxLustreFileSystemConfigAutomaticBackupRetentionDays(0), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem2), + testAccCheckFsxLustreFileSystemNotRecreated(&filesystem1, &filesystem2), + resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "0"), + ), + }, + { + Config: testAccAwsFsxLustreFileSystemConfigAutomaticBackupRetentionDays(1), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem1), + resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "1"), + ), + }, + }, + }) +} + func TestAccAWSFsxLustreFileSystem_DeploymentTypePersistent1(t *testing.T) { var filesystem fsx.FileSystem resourceName := "aws_fsx_lustre_file_system.test" @@ -403,6 +445,7 @@ func TestAccAWSFsxLustreFileSystem_DeploymentTypePersistent1(t *testing.T) { // per_unit_storage_throughput is only available with deployment_type=PERSISTENT_1, so we test both here. resource.TestCheckResourceAttr(resourceName, "per_unit_storage_throughput", "50"), resource.TestCheckResourceAttr(resourceName, "deployment_type", fsx.LustreDeploymentTypePersistent1), + resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "0"), ), }, { @@ -491,24 +534,6 @@ func testAccCheckFsxLustreFileSystemDestroy(s *terraform.State) error { return nil } -func testAccCheckFsxLustreFileSystemDisappears(filesystem *fsx.FileSystem) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).fsxconn - - input := &fsx.DeleteFileSystemInput{ - FileSystemId: filesystem.FileSystemId, - } - - _, err := conn.DeleteFileSystem(input) - - if err != nil { - return err - } - - return waitForFsxFileSystemDeletion(conn, aws.StringValue(filesystem.FileSystemId), 30*time.Minute) - } -} - func testAccCheckFsxLustreFileSystemNotRecreated(i, j *fsx.FileSystem) resource.TestCheckFunc { return func(s *terraform.State) error { if aws.StringValue(i.FileSystemId) != aws.StringValue(j.FileSystemId) { @@ -731,6 +756,18 @@ resource "aws_fsx_lustre_file_system" "test" { `, weeklyMaintenanceStartTime) } +func testAccAwsFsxLustreFileSystemConfigAutomaticBackupRetentionDays(retention int) string { + return testAccAwsFsxLustreFileSystemConfigBase() + fmt.Sprintf(` +resource "aws_fsx_lustre_file_system" "test" { + storage_capacity = 1200 + subnet_ids = ["${aws_subnet.test1.id}"] + deployment_type = "PERSISTENT_1" + per_unit_storage_throughput = 50 + automatic_backup_retention_days = %[1]d +} +`, retention) +} + func testAccAwsFsxLustreFileSystemDeploymentType(deploymentType string) string { return testAccAwsFsxLustreFileSystemConfigBase() + fmt.Sprintf(` resource "aws_fsx_lustre_file_system" "test" { diff --git a/website/docs/r/fsx_lustre_file_system.html.markdown b/website/docs/r/fsx_lustre_file_system.html.markdown index efe96d56381..79fb92fac1d 100644 --- a/website/docs/r/fsx_lustre_file_system.html.markdown +++ b/website/docs/r/fsx_lustre_file_system.html.markdown @@ -32,8 +32,9 @@ The following arguments are supported: * `security_group_ids` - (Optional) A list of IDs for the security groups that apply to the specified network interfaces created for file system access. These security groups will apply to all network interfaces. * `tags` - (Optional) A map of tags to assign to the file system. * `weekly_maintenance_start_time` - (Optional) The preferred start time (in `d:HH:MM` format) to perform weekly maintenance, in the UTC time zone. -* `deployment_type` - (Optional) - The filesystem deployment type. One of: `SCRATCH_1`, `SCRATCH_2`, `PERSISTENT_1`. -* `per_unit_storage_throughput` - (Optional) - Describes the amount of read and write throughput for each 1 tebibyte of storage, in MB/s/TiB, required for the `PERSISTENT_1` deployment_type. For valid values, see the [AWS documentation](https://docs.aws.amazon.com/fsx/latest/APIReference/API_CreateFileSystemLustreConfiguration.html). +* `deployment_type` - (Optional) The filesystem deployment type. One of: `SCRATCH_1`, `SCRATCH_2`, `PERSISTENT_1`. +* `per_unit_storage_throughput` - (Optional) Describes the amount of read and write throughput for each 1 tebibyte of storage, in MB/s/TiB, required for the `PERSISTENT_1` deployment_type. For valid values, see the [AWS documentation](https://docs.aws.amazon.com/fsx/latest/APIReference/API_CreateFileSystemLustreConfiguration.html). +* `automatic_backup_retention_days` - (Optional) The number of days to retain automatic backups. Setting this to 0 disables automatic backups. You can retain automatic backups for a maximum of 35 days. only valid for `PERSISTENT_1` deployment_type. ## Attributes Reference