diff --git a/aws/resource_aws_storagegateway_smb_file_share.go b/aws/resource_aws_storagegateway_smb_file_share.go index 64cbe15219f2..f0edaa55127e 100644 --- a/aws/resource_aws_storagegateway_smb_file_share.go +++ b/aws/resource_aws_storagegateway_smb_file_share.go @@ -56,6 +56,7 @@ func resourceAwsStorageGatewaySmbFileShare() *schema.Resource { "S3_ONEZONE_IA", "S3_STANDARD_IA", "S3_STANDARD", + "S3_INTELLIGENT_TIERING", }, false), }, "fileshare_id": { @@ -87,6 +88,7 @@ func resourceAwsStorageGatewaySmbFileShare() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validateArn, + RequiredWith: []string{"kms_encrypted"}, }, "location_arn": { Type: schema.TypeString, @@ -95,18 +97,24 @@ func resourceAwsStorageGatewaySmbFileShare() *schema.Resource { ValidateFunc: validateArn, }, "object_acl": { - Type: schema.TypeString, + Type: schema.TypeString, + Optional: true, + Default: storagegateway.ObjectACLPrivate, + ValidateFunc: validation.StringInSlice(storagegateway.ObjectACL_Values(), false), + }, + "cache_attributes": { + Type: schema.TypeList, Optional: true, - Default: storagegateway.ObjectACLPrivate, - ValidateFunc: validation.StringInSlice([]string{ - storagegateway.ObjectACLAuthenticatedRead, - storagegateway.ObjectACLAwsExecRead, - storagegateway.ObjectACLBucketOwnerFullControl, - storagegateway.ObjectACLBucketOwnerRead, - storagegateway.ObjectACLPrivate, - storagegateway.ObjectACLPublicRead, - storagegateway.ObjectACLPublicReadWrite, - }, false), + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cache_stale_timeout_in_seconds": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(300, 2592000), + }, + }, + }, }, "path": { Type: schema.TypeString, @@ -137,6 +145,12 @@ func resourceAwsStorageGatewaySmbFileShare() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "case_sensitivity": { + Type: schema.TypeString, + Optional: true, + Default: storagegateway.CaseSensitivityClientSpecified, + ValidateFunc: validation.StringInSlice(storagegateway.CaseSensitivity_Values(), false), + }, "tags": tagsSchema(), }, } @@ -158,6 +172,7 @@ func resourceAwsStorageGatewaySmbFileShareCreate(d *schema.ResourceData, meta in ReadOnly: aws.Bool(d.Get("read_only").(bool)), RequesterPays: aws.Bool(d.Get("requester_pays").(bool)), Role: aws.String(d.Get("role_arn").(string)), + CaseSensitivity: aws.String(d.Get("case_sensitivity").(string)), ValidUserList: expandStringSet(d.Get("valid_user_list").(*schema.Set)), Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().StoragegatewayTags(), } @@ -174,10 +189,14 @@ func resourceAwsStorageGatewaySmbFileShareCreate(d *schema.ResourceData, meta in input.SMBACLEnabled = aws.Bool(v.(bool)) } - log.Printf("[DEBUG] Creating Storage Gateway SMB File Share: %s", input) + if v, ok := d.GetOk("cache_attributes"); ok { + input.CacheAttributes = expandStorageGatewayNfsFileShareCacheAttributes(v.([]interface{})) + } + + log.Printf("[DEBUG] Creating Storage Gateway SMB File Share: %#v", input) output, err := conn.CreateSMBFileShare(input) if err != nil { - return fmt.Errorf("error creating Storage Gateway SMB File Share: %s", err) + return fmt.Errorf("error creating Storage Gateway SMB File Share: %w", err) } d.SetId(aws.StringValue(output.FileShareARN)) @@ -192,7 +211,7 @@ func resourceAwsStorageGatewaySmbFileShareCreate(d *schema.ResourceData, meta in } _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("error waiting for Storage Gateway SMB File Share creation: %s", err) + return fmt.Errorf("error waiting for Storage Gateway SMB File Share creation: %w", err) } return resourceAwsStorageGatewaySmbFileShareRead(d, meta) @@ -206,7 +225,7 @@ func resourceAwsStorageGatewaySmbFileShareRead(d *schema.ResourceData, meta inte FileShareARNList: []*string{aws.String(d.Id())}, } - log.Printf("[DEBUG] Reading Storage Gateway SMB File Share: %s", input) + 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.") { @@ -214,7 +233,7 @@ func resourceAwsStorageGatewaySmbFileShareRead(d *schema.ResourceData, meta inte d.SetId("") return nil } - return fmt.Errorf("error reading Storage Gateway SMB File Share: %s", err) + return fmt.Errorf("error reading Storage Gateway SMB File Share: %w", err) } if output == nil || len(output.SMBFileShareInfoList) == 0 || output.SMBFileShareInfoList[0] == nil { @@ -232,9 +251,14 @@ func resourceAwsStorageGatewaySmbFileShareRead(d *schema.ResourceData, meta inte d.Set("fileshare_id", fileshare.FileShareId) d.Set("gateway_arn", fileshare.GatewayARN) d.Set("guess_mime_type_enabled", fileshare.GuessMIMETypeEnabled) + d.Set("case_sensitivity", fileshare.CaseSensitivity) if err := d.Set("invalid_user_list", flattenStringSet(fileshare.InvalidUserList)); err != nil { - return fmt.Errorf("error setting invalid_user_list: %s", err) + return fmt.Errorf("error setting invalid_user_list: %w", err) + } + + if err := d.Set("cache_attributes", flattenStorageGatewayNfsFileShareCacheAttributes(fileshare.CacheAttributes)); err != nil { + return fmt.Errorf("error setting cache_attributes: %w", err) } d.Set("kms_encrypted", fileshare.KMSEncrypted) @@ -249,11 +273,11 @@ func resourceAwsStorageGatewaySmbFileShareRead(d *schema.ResourceData, meta inte d.Set("smb_acl_enabled", fileshare.SMBACLEnabled) if err := d.Set("valid_user_list", flattenStringSet(fileshare.ValidUserList)); err != nil { - return fmt.Errorf("error setting valid_user_list: %s", err) + return fmt.Errorf("error setting valid_user_list: %w", err) } if err := d.Set("tags", keyvaluetags.StoragegatewayKeyValueTags(fileshare.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("error setting tags: %w", err) } return nil @@ -265,13 +289,14 @@ func resourceAwsStorageGatewaySmbFileShareUpdate(d *schema.ResourceData, meta in if d.HasChange("tags") { o, n := d.GetChange("tags") if err := keyvaluetags.StoragegatewayUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("error updating tags: %w", err) } } if d.HasChanges("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") { + "valid_user_list", "kms_key_arn", "audit_destination_arn", "smb_acl_enabled", "cache_attributes", + "case_sensitivity") { input := &storagegateway.UpdateSMBFileShareInput{ DefaultStorageClass: aws.String(d.Get("default_storage_class").(string)), FileShareARN: aws.String(d.Id()), @@ -283,6 +308,7 @@ func resourceAwsStorageGatewaySmbFileShareUpdate(d *schema.ResourceData, meta in RequesterPays: aws.Bool(d.Get("requester_pays").(bool)), ValidUserList: expandStringSet(d.Get("valid_user_list").(*schema.Set)), SMBACLEnabled: aws.Bool(d.Get("smb_acl_enabled").(bool)), + CaseSensitivity: aws.String(d.Get("case_sensitivity").(string)), } if v, ok := d.GetOk("kms_key_arn"); ok && v.(string) != "" { @@ -293,10 +319,14 @@ func resourceAwsStorageGatewaySmbFileShareUpdate(d *schema.ResourceData, meta in input.AuditDestinationARN = aws.String(v.(string)) } - log.Printf("[DEBUG] Updating Storage Gateway SMB File Share: %s", input) + if v, ok := d.GetOk("cache_attributes"); ok { + input.CacheAttributes = expandStorageGatewayNfsFileShareCacheAttributes(v.([]interface{})) + } + + log.Printf("[DEBUG] Updating Storage Gateway SMB File Share: %#v", input) _, err := conn.UpdateSMBFileShare(input) if err != nil { - return fmt.Errorf("error updating Storage Gateway SMB File Share: %s", err) + return fmt.Errorf("error updating Storage Gateway SMB File Share: %w", err) } stateConf := &resource.StateChangeConf{ @@ -309,7 +339,7 @@ func resourceAwsStorageGatewaySmbFileShareUpdate(d *schema.ResourceData, meta in } _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("error waiting for Storage Gateway SMB File Share update: %s", err) + return fmt.Errorf("error waiting for Storage Gateway SMB File Share update: %w", err) } } @@ -323,13 +353,13 @@ func resourceAwsStorageGatewaySmbFileShareDelete(d *schema.ResourceData, meta in FileShareARN: aws.String(d.Id()), } - log.Printf("[DEBUG] Deleting Storage Gateway SMB File Share: %s", input) + log.Printf("[DEBUG] Deleting Storage Gateway SMB File Share: %#v", input) _, err := conn.DeleteFileShare(input) if err != nil { if isAWSErr(err, storagegateway.ErrCodeInvalidGatewayRequestException, "The specified file share was not found.") { return nil } - return fmt.Errorf("error deleting Storage Gateway SMB File Share: %s", err) + return fmt.Errorf("error deleting Storage Gateway SMB File Share: %w", err) } stateConf := &resource.StateChangeConf{ @@ -346,7 +376,7 @@ func resourceAwsStorageGatewaySmbFileShareDelete(d *schema.ResourceData, meta in if isResourceNotFoundError(err) { return nil } - return fmt.Errorf("error waiting for Storage Gateway SMB File Share deletion: %s", err) + return fmt.Errorf("error waiting for Storage Gateway SMB File Share deletion: %w", err) } return nil @@ -358,13 +388,13 @@ func storageGatewaySmbFileShareRefreshFunc(fileShareArn string, conn *storagegat FileShareARNList: []*string{aws.String(fileShareArn)}, } - log.Printf("[DEBUG] Reading Storage Gateway SMB File Share: %s", input) + 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: %s", err) + 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 { diff --git a/aws/resource_aws_storagegateway_smb_file_share_test.go b/aws/resource_aws_storagegateway_smb_file_share_test.go index 21f7529a6e14..da04190d1844 100644 --- a/aws/resource_aws_storagegateway_smb_file_share_test.go +++ b/aws/resource_aws_storagegateway_smb_file_share_test.go @@ -88,6 +88,8 @@ func TestAccAWSStorageGatewaySmbFileShare_Authentication_GuestAccess(t *testing. resource.TestCheckResourceAttr(resourceName, "requester_pays", "false"), resource.TestCheckResourceAttrPair(resourceName, "role_arn", iamResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "valid_user_list.#", "0"), + resource.TestCheckResourceAttr(resourceName, "cache_attributes.#", "0"), + resource.TestCheckResourceAttr(resourceName, "case_sensitivity", "ClientSpecified"), ), }, { @@ -537,6 +539,111 @@ func TestAccAWSStorageGatewaySmbFileShare_audit(t *testing.T) { }) } +func TestAccAWSStorageGatewaySmbFileShare_cacheAttributes(t *testing.T) { + var smbFileShare storagegateway.SMBFileShareInfo + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_storagegateway_smb_file_share.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSStorageGatewaySmbFileShareDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSStorageGatewaySmbFileShareCacheAttributesConfig(rName, 300), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewaySmbFileShareExists(resourceName, &smbFileShare), + resource.TestCheckResourceAttr(resourceName, "cache_attributes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cache_attributes.0.cache_stale_timeout_in_seconds", "300"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSStorageGatewaySmbFileShareCacheAttributesConfig(rName, 500), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewaySmbFileShareExists(resourceName, &smbFileShare), + resource.TestCheckResourceAttr(resourceName, "cache_attributes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cache_attributes.0.cache_stale_timeout_in_seconds", "500"), + ), + }, + { + Config: testAccAWSStorageGatewaySmbFileShareCacheAttributesConfig(rName, 300), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewaySmbFileShareExists(resourceName, &smbFileShare), + resource.TestCheckResourceAttr(resourceName, "cache_attributes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cache_attributes.0.cache_stale_timeout_in_seconds", "300"), + ), + }, + }, + }) +} + +func TestAccAWSStorageGatewaySmbFileShare_caseSensitivity(t *testing.T) { + var smbFileShare storagegateway.SMBFileShareInfo + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_storagegateway_smb_file_share.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSStorageGatewaySmbFileShareDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSStorageGatewaySmbFileShareCaseSensitivityConfig(rName, "CaseSensitive"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewaySmbFileShareExists(resourceName, &smbFileShare), + resource.TestCheckResourceAttr(resourceName, "case_sensitivity", "CaseSensitive"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSStorageGatewaySmbFileShareCaseSensitivityConfig(rName, "ClientSpecified"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewaySmbFileShareExists(resourceName, &smbFileShare), + resource.TestCheckResourceAttr(resourceName, "case_sensitivity", "ClientSpecified"), + ), + }, + { + Config: testAccAWSStorageGatewaySmbFileShareCaseSensitivityConfig(rName, "CaseSensitive"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewaySmbFileShareExists(resourceName, &smbFileShare), + resource.TestCheckResourceAttr(resourceName, "case_sensitivity", "CaseSensitive"), + ), + }, + }, + }) +} + +func TestAccAWSStorageGatewaySmbFileShare_disappears(t *testing.T) { + var smbFileShare storagegateway.SMBFileShareInfo + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_storagegateway_smb_file_share.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSStorageGatewaySmbFileShareDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSStorageGatewaySmbFileShareConfig_Authentication_GuestAccess(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewaySmbFileShareExists(resourceName, &smbFileShare), + testAccCheckResourceDisappears(testAccProvider, resourceAwsStorageGatewaySmbFileShare(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSStorageGatewaySmbFileShareDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).storagegatewayconn @@ -932,9 +1039,9 @@ func testAccAWSStorageGatewaySmbFileShareSMBACLConfig(rName string, enabled bool return testAccAWSStorageGateway_SmbFileShare_ActiveDirectoryBase(rName) + fmt.Sprintf(` resource "aws_storagegateway_smb_file_share" "test" { authentication = "ActiveDirectory" - gateway_arn = "${aws_storagegateway_gateway.test.arn}" - location_arn = "${aws_s3_bucket.test.arn}" - role_arn = "${aws_iam_role.test.arn}" + gateway_arn = aws_storagegateway_gateway.test.arn + location_arn = aws_s3_bucket.test.arn + role_arn = aws_iam_role.test.arn smb_acl_enabled = %[1]t } `, enabled) @@ -949,10 +1056,10 @@ resource "aws_cloudwatch_log_group" "test" { resource "aws_storagegateway_smb_file_share" "test" { # Use GuestAccess to simplify testing authentication = "GuestAccess" - gateway_arn = "${aws_storagegateway_gateway.test.arn}" - location_arn = "${aws_s3_bucket.test.arn}" - role_arn = "${aws_iam_role.test.arn}" - audit_destination_arn = "${aws_cloudwatch_log_group.test.arn}" + gateway_arn = aws_storagegateway_gateway.test.arn + location_arn = aws_s3_bucket.test.arn + role_arn = aws_iam_role.test.arn + audit_destination_arn = aws_cloudwatch_log_group.test.arn } `, rName) } @@ -977,3 +1084,32 @@ resource "aws_storagegateway_smb_file_share" "test" { } `, rName) } + +func testAccAWSStorageGatewaySmbFileShareCacheAttributesConfig(rName string, timeout int) string { + return testAccAWSStorageGateway_SmbFileShare_GuestAccessBase(rName) + fmt.Sprintf(` +resource "aws_storagegateway_smb_file_share" "test" { + # Use GuestAccess to simplify testing + authentication = "GuestAccess" + gateway_arn = aws_storagegateway_gateway.test.arn + location_arn = aws_s3_bucket.test.arn + role_arn = aws_iam_role.test.arn + + cache_attributes { + cache_stale_timeout_in_seconds = %[1]d + } +} +`, timeout) +} + +func testAccAWSStorageGatewaySmbFileShareCaseSensitivityConfig(rName, option string) string { + return testAccAWSStorageGateway_SmbFileShare_GuestAccessBase(rName) + fmt.Sprintf(` +resource "aws_storagegateway_smb_file_share" "test" { + # Use GuestAccess to simplify testing + authentication = "GuestAccess" + gateway_arn = aws_storagegateway_gateway.test.arn + location_arn = aws_s3_bucket.test.arn + role_arn = aws_iam_role.test.arn + case_sensitivity = %[1]q +} +`, option) +} diff --git a/website/docs/r/storagegateway_smb_file_share.html.markdown b/website/docs/r/storagegateway_smb_file_share.html.markdown index 7e63be659978..6a203fb48845 100644 --- a/website/docs/r/storagegateway_smb_file_share.html.markdown +++ b/website/docs/r/storagegateway_smb_file_share.html.markdown @@ -52,22 +52,21 @@ The following arguments are supported: * `invalid_user_list` - (Optional) A list of users in the Active Directory that are not allowed to access the file share. Only valid if `authentication` is set to `ActiveDirectory`. * `kms_encrypted` - (Optional) Boolean value if `true` to use Amazon S3 server side encryption with your own AWS KMS key, or `false` to use a key managed by Amazon S3. Defaults to `false`. * `kms_key_arn` - (Optional) Amazon Resource Name (ARN) for KMS key used for Amazon S3 server side encryption. This value can only be set when `kms_encrypted` is true. -* `smb_file_share_defaults` - (Optional) Nested argument with file share default values. More information below. * `object_acl` - (Optional) Access Control List permission for S3 bucket objects. Defaults to `private`. +* `cache_attributes` - (Optional) Refresh cache information. see [Cache Attributes](#cache_attributes) for more details. * `read_only` - (Optional) Boolean to indicate write status of file share. File share does not accept writes if `true`. Defaults to `false`. * `requester_pays` - (Optional) Boolean who pays the cost of the request and the data download from the Amazon S3 bucket. Set this value to `true` if you want the requester to pay instead of the bucket owner. Defaults to `false`. * `smb_acl_enabled` - (Optional) Set this value to `true` to enable ACL (access control list) on the SMB fileshare. Set it to `false` to map file and directory permissions to the POSIX permissions. This setting applies only to `ActiveDirectory` authentication type. +* `case_sensitivity` - (Optional) The case of an object name in an Amazon S3 bucket. For `ClientSpecified`, the client determines the case sensitivity. For `CaseSensitive`, the gateway determines the case sensitivity. The default value is `ClientSpecified`. * `valid_user_list` - (Optional) A list of users in the Active Directory that are allowed to access the file share. Only valid if `authentication` is set to `ActiveDirectory`. * `tags` - (Optional) Key-value map of resource tags -### smb_file_share_defaults +### cache_attributes -Files and folders stored as Amazon S3 objects in S3 buckets don't, by default, have Unix file permissions assigned to them. Upon discovery in an S3 bucket by Storage Gateway, the S3 objects that represent files and folders are assigned these default Unix permissions. +* `cache_stale_timeout_in_seconds` - (Optional) Refreshes a file share's cache by using Time To Live (TTL). + TTL is the length of time since the last refresh after which access to the directory would cause the file gateway + to first refresh that directory's contents from the Amazon S3 bucket. Valid Values: 300 to 2,592,000 seconds (5 minutes to 30 days) -* `directory_mode` - (Optional) The Unix directory mode in the string form "nnnn". Defaults to `"0777"`. -* `file_mode` - (Optional) The Unix file mode in the string form "nnnn". Defaults to `"0666"`. -* `group_id` - (Optional) The default group ID for the file share (unless the files have another group ID specified). Defaults to `0`. Valid values: `0` through `4294967294`. -* `owner_id` - (Optional) The default owner ID for the file share (unless the files have another owner ID specified). Defaults to `0`. Valid values: `0` through `4294967294`. ## Attribute Reference