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

r/storagegateway_smb_file_share - add support for notification_policy and access_based_enumeration + validations. #16414

Merged
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
27 changes: 27 additions & 0 deletions aws/internal/service/storagegateway/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const (
StoredIscsiVolumeStatusUnknown = "Unknown"
NfsFileShareStatusNotFound = "NotFound"
NfsFileShareStatusUnknown = "Unknown"
SmbFileShareStatusNotFound = "NotFound"
SmbFileShareStatusUnknown = "Unknown"
)

// StoredIscsiVolumeStatus fetches the Volume and its Status
Expand Down Expand Up @@ -67,3 +69,28 @@ func NfsFileShareStatus(conn *storagegateway.StorageGateway, fileShareArn string
return fileshare, aws.StringValue(fileshare.FileShareStatus), nil
}
}

func SmbFileShareStatus(conn *storagegateway.StorageGateway, fileShareArn string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &storagegateway.DescribeSMBFileSharesInput{
FileShareARNList: []*string{aws.String(fileShareArn)},
}

log.Printf("[DEBUG] Reading Storage Gateway SMB File Share: %s", input)
output, err := conn.DescribeSMBFileShares(input)
if err != nil {
if tfawserr.ErrMessageContains(err, storagegateway.ErrCodeInvalidGatewayRequestException, "The specified file share was not found.") {
return nil, SmbFileShareStatusNotFound, nil
}
return nil, SmbFileShareStatusUnknown, fmt.Errorf("error reading Storage Gateway SMB File Share: %w", err)
}

if output == nil || len(output.SMBFileShareInfoList) == 0 || output.SMBFileShareInfoList[0] == nil {
return nil, SmbFileShareStatusNotFound, nil
}

fileshare := output.SMBFileShareInfoList[0]

return fileshare, aws.StringValue(fileshare.FileShareStatus), nil
}
}
40 changes: 40 additions & 0 deletions aws/internal/service/storagegateway/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const (
StoredIscsiVolumeAvailableTimeout = 5 * time.Minute
NfsFileShareAvailableDelay = 5 * time.Second
NfsFileShareDeletedDelay = 5 * time.Second
SmbFileShareAvailableDelay = 5 * time.Second
SmbFileShareDeletedDelay = 5 * time.Second
)

// StoredIscsiVolumeAvailable waits for a StoredIscsiVolume to return Available
Expand Down Expand Up @@ -68,3 +70,41 @@ func NfsFileShareDeleted(conn *storagegateway.StorageGateway, fileShareArn strin

return nil, err
}

// SmbFileShareAvailable waits for a SMB File Share to return Available
func SmbFileShareAvailable(conn *storagegateway.StorageGateway, fileShareArn string, timeout time.Duration) (*storagegateway.SMBFileShareInfo, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{"CREATING", "UPDATING"},
Target: []string{"AVAILABLE"},
Refresh: SmbFileShareStatus(conn, fileShareArn),
Timeout: timeout,
Delay: SmbFileShareAvailableDelay,
}

outputRaw, err := stateConf.WaitForState()

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

return nil, err
}

func SmbFileShareDeleted(conn *storagegateway.StorageGateway, fileShareArn string, timeout time.Duration) (*storagegateway.SMBFileShareInfo, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{"AVAILABLE", "DELETING", "FORCE_DELETING"},
Target: []string{},
Refresh: SmbFileShareStatus(conn, fileShareArn),
Timeout: timeout,
Delay: SmbFileShareDeletedDelay,
NotFoundChecks: 1,
}

outputRaw, err := stateConf.WaitForState()

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

return nil, err
}
121 changes: 52 additions & 69 deletions aws/resource_aws_storagegateway_smb_file_share.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package aws
import (
"fmt"
"log"
"regexp"
"time"

"github.com/aws/aws-sdk-go/aws"
Expand All @@ -11,6 +12,7 @@ import (
"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/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/storagegateway/waiter"
)

func resourceAwsStorageGatewaySmbFileShare() *schema.Resource {
Expand Down Expand Up @@ -82,6 +84,7 @@ func resourceAwsStorageGatewaySmbFileShare() *schema.Resource {
"invalid_user_list": {
Type: schema.TypeSet,
Optional: true,
MaxItems: 100,
Elem: &schema.Schema{Type: schema.TypeString},
},
"kms_encrypted": {
Expand Down Expand Up @@ -145,9 +148,15 @@ func resourceAwsStorageGatewaySmbFileShare() *schema.Resource {
Type: schema.TypeBool,
Optional: true,
},
"access_based_enumeration": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"valid_user_list": {
Type: schema.TypeSet,
Optional: true,
MaxItems: 100,
Elem: &schema.Schema{Type: schema.TypeString},
},
"admin_user_list": {
Expand All @@ -161,6 +170,15 @@ func resourceAwsStorageGatewaySmbFileShare() *schema.Resource {
Default: storagegateway.CaseSensitivityClientSpecified,
ValidateFunc: validation.StringInSlice(storagegateway.CaseSensitivity_Values(), false),
},
"notification_policy": {
Type: schema.TypeString,
Optional: true,
Default: "{}",
ValidateFunc: validation.All(
validation.StringMatch(regexp.MustCompile(`^\{[\w\s:\{\}\[\]"]*}$`), ""),
validation.StringLenBetween(2, 100),
),
},
"tags": tagsSchema(),
},
}
Expand Down Expand Up @@ -204,10 +222,18 @@ func resourceAwsStorageGatewaySmbFileShareCreate(d *schema.ResourceData, meta in
input.SMBACLEnabled = aws.Bool(v.(bool))
}

if v, ok := d.GetOk("access_based_enumeration"); ok {
input.AccessBasedEnumeration = aws.Bool(v.(bool))
}

if v, ok := d.GetOk("cache_attributes"); ok {
input.CacheAttributes = expandStorageGatewayNfsFileShareCacheAttributes(v.([]interface{}))
}

if v, ok := d.GetOk("notification_policy"); ok {
input.NotificationPolicy = aws.String(v.(string))
}

log.Printf("[DEBUG] Creating Storage Gateway SMB File Share: %#v", input)
output, err := conn.CreateSMBFileShare(input)
if err != nil {
Expand All @@ -216,17 +242,8 @@ func resourceAwsStorageGatewaySmbFileShareCreate(d *schema.ResourceData, meta in

d.SetId(aws.StringValue(output.FileShareARN))

stateConf := &resource.StateChangeConf{
Pending: []string{"CREATING", "MISSING"},
Target: []string{"AVAILABLE"},
Refresh: storageGatewaySmbFileShareRefreshFunc(d.Id(), conn),
Timeout: d.Timeout(schema.TimeoutCreate),
Delay: 5 * time.Second,
MinTimeout: 5 * time.Second,
}
_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("error waiting for Storage Gateway SMB File Share creation: %w", err)
if _, err = waiter.SmbFileShareAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil {
return fmt.Errorf("error waiting for Storage Gateway SMB File Share (%q) to be Available: %w", d.Id(), err)
}

return resourceAwsStorageGatewaySmbFileShareRead(d, meta)
Expand Down Expand Up @@ -287,6 +304,8 @@ func resourceAwsStorageGatewaySmbFileShareRead(d *schema.ResourceData, meta inte
d.Set("role_arn", fileshare.Role)
d.Set("audit_destination_arn", fileshare.AuditDestinationARN)
d.Set("smb_acl_enabled", fileshare.SMBACLEnabled)
d.Set("access_based_enumeration", fileshare.AccessBasedEnumeration)
d.Set("notification_policy", fileshare.NotificationPolicy)

if err := d.Set("valid_user_list", flattenStringSet(fileshare.ValidUserList)); err != nil {
return fmt.Errorf("error setting valid_user_list: %w", err)
Expand Down Expand Up @@ -316,26 +335,31 @@ func resourceAwsStorageGatewaySmbFileShareUpdate(d *schema.ResourceData, meta in
if d.HasChanges("admin_user_list", "default_storage_class", "guess_mime_type_enabled", "invalid_user_list",
"kms_encrypted", "object_acl", "read_only", "requester_pays", "requester_pays",
"valid_user_list", "kms_key_arn", "audit_destination_arn", "smb_acl_enabled", "cache_attributes",
"case_sensitivity", "file_share_name") {
"case_sensitivity", "file_share_name", "notification_policy", "access_based_enumeration") {
input := &storagegateway.UpdateSMBFileShareInput{
DefaultStorageClass: aws.String(d.Get("default_storage_class").(string)),
FileShareARN: aws.String(d.Id()),
GuessMIMETypeEnabled: aws.Bool(d.Get("guess_mime_type_enabled").(bool)),
InvalidUserList: expandStringSet(d.Get("invalid_user_list").(*schema.Set)),
KMSEncrypted: aws.Bool(d.Get("kms_encrypted").(bool)),
ObjectACL: aws.String(d.Get("object_acl").(string)),
ReadOnly: aws.Bool(d.Get("read_only").(bool)),
RequesterPays: aws.Bool(d.Get("requester_pays").(bool)),
ValidUserList: expandStringSet(d.Get("valid_user_list").(*schema.Set)),
AdminUserList: expandStringSet(d.Get("admin_user_list").(*schema.Set)),
SMBACLEnabled: aws.Bool(d.Get("smb_acl_enabled").(bool)),
CaseSensitivity: aws.String(d.Get("case_sensitivity").(string)),
DefaultStorageClass: aws.String(d.Get("default_storage_class").(string)),
FileShareARN: aws.String(d.Id()),
GuessMIMETypeEnabled: aws.Bool(d.Get("guess_mime_type_enabled").(bool)),
InvalidUserList: expandStringSet(d.Get("invalid_user_list").(*schema.Set)),
KMSEncrypted: aws.Bool(d.Get("kms_encrypted").(bool)),
ObjectACL: aws.String(d.Get("object_acl").(string)),
ReadOnly: aws.Bool(d.Get("read_only").(bool)),
RequesterPays: aws.Bool(d.Get("requester_pays").(bool)),
ValidUserList: expandStringSet(d.Get("valid_user_list").(*schema.Set)),
AdminUserList: expandStringSet(d.Get("admin_user_list").(*schema.Set)),
SMBACLEnabled: aws.Bool(d.Get("smb_acl_enabled").(bool)),
CaseSensitivity: aws.String(d.Get("case_sensitivity").(string)),
AccessBasedEnumeration: aws.Bool(d.Get("access_based_enumeration").(bool)),
}

if v, ok := d.GetOk("kms_key_arn"); ok {
input.KMSKey = aws.String(v.(string))
}

if v, ok := d.GetOk("notification_policy"); ok {
input.NotificationPolicy = aws.String(v.(string))
}

if v, ok := d.GetOk("audit_destination_arn"); ok {
input.AuditDestinationARN = aws.String(v.(string))
}
Expand All @@ -354,17 +378,8 @@ func resourceAwsStorageGatewaySmbFileShareUpdate(d *schema.ResourceData, meta in
return fmt.Errorf("error updating Storage Gateway SMB File Share: %w", err)
}

stateConf := &resource.StateChangeConf{
Pending: []string{"UPDATING"},
Target: []string{"AVAILABLE"},
Refresh: storageGatewaySmbFileShareRefreshFunc(d.Id(), conn),
Timeout: d.Timeout(schema.TimeoutUpdate),
Delay: 5 * time.Second,
MinTimeout: 5 * time.Second,
}
_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("error waiting for Storage Gateway SMB File Share update: %w", err)
if _, err = waiter.SmbFileShareAvailable(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil {
return fmt.Errorf("error waiting for Storage Gateway SMB File Share (%q) to be Available: %w", d.Id(), err)
}
}

Expand All @@ -387,16 +402,9 @@ func resourceAwsStorageGatewaySmbFileShareDelete(d *schema.ResourceData, meta in
return fmt.Errorf("error deleting Storage Gateway SMB File Share: %w", err)
}

stateConf := &resource.StateChangeConf{
Pending: []string{"AVAILABLE", "DELETING", "FORCE_DELETING"},
Target: []string{"MISSING"},
Refresh: storageGatewaySmbFileShareRefreshFunc(d.Id(), conn),
Timeout: d.Timeout(schema.TimeoutDelete),
Delay: 5 * time.Second,
MinTimeout: 5 * time.Second,
NotFoundChecks: 1,
if _, err = waiter.SmbFileShareDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
return fmt.Errorf("error waiting for Storage Gateway SMB File Share (%q) to be Deleted: %w", d.Id(), err)
}
_, err = stateConf.WaitForState()
if err != nil {
if isResourceNotFoundError(err) {
return nil
Expand All @@ -406,28 +414,3 @@ func resourceAwsStorageGatewaySmbFileShareDelete(d *schema.ResourceData, meta in

return nil
}

func storageGatewaySmbFileShareRefreshFunc(fileShareArn string, conn *storagegateway.StorageGateway) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &storagegateway.DescribeSMBFileSharesInput{
FileShareARNList: []*string{aws.String(fileShareArn)},
}

log.Printf("[DEBUG] Reading Storage Gateway SMB File Share: %#v", input)
output, err := conn.DescribeSMBFileShares(input)
if err != nil {
if isAWSErr(err, storagegateway.ErrCodeInvalidGatewayRequestException, "The specified file share was not found.") {
return nil, "MISSING", nil
}
return nil, "ERROR", fmt.Errorf("error reading Storage Gateway SMB File Share: %w", err)
}

if output == nil || len(output.SMBFileShareInfoList) == 0 || output.SMBFileShareInfoList[0] == nil {
return nil, "MISSING", nil
}

fileshare := output.SMBFileShareInfoList[0]

return fileshare, aws.StringValue(fileshare.FileShareStatus), nil
}
}
Loading