Skip to content

Commit

Permalink
Merge pull request #9761 from terraform-providers/slapula-resource-fs…
Browse files Browse the repository at this point in the history
…x-file-system

New Resources: aws_fsx_lustre_file_system and aws_fsx_windows_file_system
  • Loading branch information
bflad committed Aug 14, 2019
2 parents 20e523c + f923aa6 commit 2d0dcd7
Show file tree
Hide file tree
Showing 13 changed files with 2,830 additions and 2 deletions.
77 changes: 77 additions & 0 deletions aws/fsx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package aws

import (
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/fsx"
"github.com/hashicorp/terraform/helper/resource"
)

func describeFsxFileSystem(conn *fsx.FSx, id string) (*fsx.FileSystem, error) {
input := &fsx.DescribeFileSystemsInput{
FileSystemIds: []*string{aws.String(id)},
}
var filesystem *fsx.FileSystem

err := conn.DescribeFileSystemsPages(input, func(page *fsx.DescribeFileSystemsOutput, lastPage bool) bool {
for _, fs := range page.FileSystems {
if aws.StringValue(fs.FileSystemId) == id {
filesystem = fs
return false
}
}

return !lastPage
})

return filesystem, err
}

func refreshFsxFileSystemLifecycle(conn *fsx.FSx, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
filesystem, err := describeFsxFileSystem(conn, id)

if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") {
return nil, "", nil
}

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

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

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

func waitForFsxFileSystemCreation(conn *fsx.FSx, id string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{fsx.FileSystemLifecycleCreating},
Target: []string{fsx.FileSystemLifecycleAvailable},
Refresh: refreshFsxFileSystemLifecycle(conn, id),
Timeout: timeout,
Delay: 30 * time.Second,
}

_, err := stateConf.WaitForState()

return err
}

func waitForFsxFileSystemDeletion(conn *fsx.FSx, id string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{fsx.FileSystemLifecycleAvailable, fsx.FileSystemLifecycleDeleting},
Target: []string{},
Refresh: refreshFsxFileSystemLifecycle(conn, id),
Timeout: timeout,
Delay: 30 * time.Second,
}

_, err := stateConf.WaitForState()

return err
}
2 changes: 2 additions & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,8 @@ func Provider() terraform.ResourceProvider {
"aws_emr_instance_group": resourceAwsEMRInstanceGroup(),
"aws_emr_security_configuration": resourceAwsEMRSecurityConfiguration(),
"aws_flow_log": resourceAwsFlowLog(),
"aws_fsx_lustre_file_system": resourceAwsFsxLustreFileSystem(),
"aws_fsx_windows_file_system": resourceAwsFsxWindowsFileSystem(),
"aws_fms_admin_account": resourceAwsFmsAdminAccount(),
"aws_gamelift_alias": resourceAwsGameliftAlias(),
"aws_gamelift_build": resourceAwsGameliftBuild(),
Expand Down
5 changes: 3 additions & 2 deletions aws/resource_aws_directory_service_directory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import (

func init() {
resource.AddTestSweepers("aws_directory_service_directory", &resource.Sweeper{
Name: "aws_directory_service_directory",
F: testSweepDirectoryServiceDirectories,
Name: "aws_directory_service_directory",
F: testSweepDirectoryServiceDirectories,
Dependencies: []string{"aws_fsx_windows_file_system"},
})
}

Expand Down
296 changes: 296 additions & 0 deletions aws/resource_aws_fsx_lustre_file_system.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
package aws

import (
"fmt"
"log"
"regexp"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/fsx"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsFsxLustreFileSystem() *schema.Resource {
return &schema.Resource{
Create: resourceAwsFsxLustreFileSystemCreate,
Read: resourceAwsFsxLustreFileSystemRead,
Update: resourceAwsFsxLustreFileSystemUpdate,
Delete: resourceAwsFsxLustreFileSystemDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

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

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"dns_name": {
Type: schema.TypeString,
Computed: true,
},
"export_path": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: validation.All(
validation.StringLenBetween(3, 900),
validation.StringMatch(regexp.MustCompile(`^s3://`), "must begin with s3://"),
),
},
"import_path": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.All(
validation.StringLenBetween(3, 900),
validation.StringMatch(regexp.MustCompile(`^s3://`), "must begin with s3://"),
),
},
"imported_file_chunk_size": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: validation.IntBetween(1, 512000),
},
"network_interface_ids": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"owner_id": {
Type: schema.TypeString,
Computed: true,
},
"security_group_ids": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
MaxItems: 50,
Elem: &schema.Schema{Type: schema.TypeString},
},
"storage_capacity": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
ValidateFunc: validation.IntAtLeast(3600),
},
"subnet_ids": {
Type: schema.TypeSet,
Required: true,
ForceNew: true,
MinItems: 1,
MaxItems: 1,
Elem: &schema.Schema{Type: schema.TypeString},
},
"tags": tagsSchema(),
"vpc_id": {
Type: schema.TypeString,
Computed: true,
},
"weekly_maintenance_start_time": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.All(
validation.StringLenBetween(7, 7),
validation.StringMatch(regexp.MustCompile(`^[1-7]:([01]\d|2[0-3]):?([0-5]\d)$`), "must be in the format d:HH:MM"),
),
},
},
}
}

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

input := &fsx.CreateFileSystemInput{
ClientRequestToken: aws.String(resource.UniqueId()),
FileSystemType: aws.String(fsx.FileSystemTypeLustre),
StorageCapacity: aws.Int64(int64(d.Get("storage_capacity").(int))),
SubnetIds: expandStringSet(d.Get("subnet_ids").(*schema.Set)),
}

if v, ok := d.GetOk("export_path"); ok {
if input.LustreConfiguration == nil {
input.LustreConfiguration = &fsx.CreateFileSystemLustreConfiguration{}
}

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)))
}

if v, ok := d.GetOk("security_group_ids"); ok {
input.SecurityGroupIds = expandStringSet(v.(*schema.Set))
}

if v, ok := d.GetOk("tags"); ok {
input.Tags = tagsFromMapFSX(v.(map[string]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))
}

result, err := conn.CreateFileSystem(input)
if err != nil {
return fmt.Errorf("Error creating FSx filesystem: %s", err)
}

d.SetId(*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 resourceAwsFsxLustreFileSystemRead(d, meta)
}

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

if d.HasChange("tags") {
if err := setTagsFSX(conn, d); err != nil {
return fmt.Errorf("Error updating tags for FSx filesystem: %s", err)
}
}

requestUpdate := false
input := &fsx.UpdateFileSystemInput{
ClientRequestToken: aws.String(resource.UniqueId()),
FileSystemId: aws.String(d.Id()),
LustreConfiguration: &fsx.UpdateFileSystemLustreConfiguration{},
}

if d.HasChange("weekly_maintenance_start_time") {
input.LustreConfiguration.WeeklyMaintenanceStartTime = aws.String(d.Get("weekly_maintenance_start_time").(string))
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 resourceAwsFsxLustreFileSystemRead(d, meta)
}

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

filesystem, err := describeFsxFileSystem(conn, d.Id())

if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") {
log.Printf("[WARN] FSx File System (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("Error reading FSx File System (%s): %s", d.Id(), err)
}

if filesystem == nil {
log.Printf("[WARN] FSx File System (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if filesystem.WindowsConfiguration != nil {
return fmt.Errorf("expected FSx Lustre File System, found FSx Windows File System: %s", d.Id())
}

if filesystem.LustreConfiguration == nil {
return fmt.Errorf("error describing FSx Lustre File System (%s): empty Lustre configuration", d.Id())
}

if filesystem.LustreConfiguration.DataRepositoryConfiguration == nil {
// Initialize an empty structure to simplify d.Set() handling
filesystem.LustreConfiguration.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)

if err := d.Set("network_interface_ids", aws.StringValueSlice(filesystem.NetworkInterfaceIds)); err != nil {
return fmt.Errorf("error setting network_interface_ids: %s", 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)
}

if err := d.Set("tags", tagsToMapFSX(filesystem.Tags)); err != nil {
return fmt.Errorf("error setting tags: %s", err)
}

d.Set("vpc_id", filesystem.VpcId)
d.Set("weekly_maintenance_start_time", filesystem.LustreConfiguration.WeeklyMaintenanceStartTime)

return nil
}

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

request := &fsx.DeleteFileSystemInput{
FileSystemId: aws.String(d.Id()),
}

_, err := conn.DeleteFileSystem(request)

if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") {
return nil
}

if err != nil {
return fmt.Errorf("Error deleting FSx filesystem: %s", 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 nil
}
Loading

0 comments on commit 2d0dcd7

Please sign in to comment.