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

New Resources: aws_fsx_lustre_file_system and aws_fsx_windows_file_system #9761

Merged
merged 13 commits into from
Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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