From 6164986e06da8198170adf03731b48fa2e107e58 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 11:46:53 -0400 Subject: [PATCH 01/61] s3: 'ObjectUpdateTags' -> 'ObjectUpdateTagsV1'. --- internal/service/s3/bucket_object.go | 2 +- internal/service/s3/bucket_object_test.go | 6 +++--- internal/service/s3/object_test.go | 6 +++--- internal/service/s3/tags.go | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/service/s3/bucket_object.go b/internal/service/s3/bucket_object.go index 4c5f6cc7407..17bf8f3c729 100644 --- a/internal/service/s3/bucket_object.go +++ b/internal/service/s3/bucket_object.go @@ -349,7 +349,7 @@ func resourceBucketObjectUpdate(ctx context.Context, d *schema.ResourceData, met if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") - if err := ObjectUpdateTags(ctx, conn, bucket, key, o, n); err != nil { + if err := ObjectUpdateTagsV1(ctx, conn, bucket, key, o, n); err != nil { return sdkdiag.AppendErrorf(diags, "updating S3 Bucket (%s) Object (%s) tags: %s", bucket, key, err) } } diff --git a/internal/service/s3/bucket_object_test.go b/internal/service/s3/bucket_object_test.go index de8fe87b00f..81ac525f25c 100644 --- a/internal/service/s3/bucket_object_test.go +++ b/internal/service/s3/bucket_object_test.go @@ -1314,7 +1314,7 @@ func TestAccS3BucketObject_ignoreTags(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckBucketObjectExists(ctx, resourceName, &obj), testAccCheckBucketObjectBody(&obj, "stuff"), - testAccCheckBucketObjectUpdateTags(ctx, resourceName, nil, map[string]string{"ignorekey1": "ignorevalue1"}), + testAccCheckBucketObjectUpdateTagsV1(ctx, resourceName, nil, map[string]string{"ignorekey1": "ignorevalue1"}), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), testAccCheckBucketObjectCheckTags(ctx, resourceName, map[string]string{ "ignorekey1": "ignorevalue1", @@ -1568,12 +1568,12 @@ func testAccBucketObjectCreateTempFile(t *testing.T, data string) string { return filename } -func testAccCheckBucketObjectUpdateTags(ctx context.Context, n string, oldTags, newTags map[string]string) resource.TestCheckFunc { +func testAccCheckBucketObjectUpdateTagsV1(ctx context.Context, n string, oldTags, newTags map[string]string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) - return tfs3.ObjectUpdateTags(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], oldTags, newTags) + return tfs3.ObjectUpdateTagsV1(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], oldTags, newTags) } } diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index 1cd52f5c8d5..5938148210f 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -1342,7 +1342,7 @@ func TestAccS3Object_ignoreTags(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectBody(&obj, "stuff"), - testAccCheckObjectUpdateTags(ctx, resourceName, nil, map[string]string{"ignorekey1": "ignorevalue1"}), + testAccCheckObjectUpdateTagsV1(ctx, resourceName, nil, map[string]string{"ignorekey1": "ignorevalue1"}), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), testAccCheckObjectCheckTags(ctx, resourceName, map[string]string{ "ignorekey1": "ignorevalue1", @@ -1596,12 +1596,12 @@ func testAccObjectCreateTempFile(t *testing.T, data string) string { return filename } -func testAccCheckObjectUpdateTags(ctx context.Context, n string, oldTags, newTags map[string]string) resource.TestCheckFunc { +func testAccCheckObjectUpdateTagsV1(ctx context.Context, n string, oldTags, newTags map[string]string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) - return tfs3.ObjectUpdateTags(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], oldTags, newTags) + return tfs3.ObjectUpdateTagsV1(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], oldTags, newTags) } } diff --git a/internal/service/s3/tags.go b/internal/service/s3/tags.go index c7aa0a09ccc..956361e9b2b 100644 --- a/internal/service/s3/tags.go +++ b/internal/service/s3/tags.go @@ -135,8 +135,8 @@ func ObjectListTagsV1(ctx context.Context, conn s3iface_sdkv1.S3API, bucket, key return KeyValueTags(ctx, outputRaw.(*s3_sdkv1.GetObjectTaggingOutput).TagSet), nil } -// ObjectUpdateTags updates S3 object tags. -func ObjectUpdateTags(ctx context.Context, conn s3iface_sdkv1.S3API, bucket, key string, oldTagsMap, newTagsMap any) error { +// ObjectUpdateTagsV1 updates S3 object tags. +func ObjectUpdateTagsV1(ctx context.Context, conn s3iface_sdkv1.S3API, bucket, key string, oldTagsMap, newTagsMap any) error { oldTags := tftags.New(ctx, oldTagsMap) newTags := tftags.New(ctx, newTagsMap) From 64a82e6f63d1009568e56bb75738e6dadfee7299 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 12:22:12 -0400 Subject: [PATCH 02/61] s3: Add 'ObjectUpdateTags'. --- internal/service/s3/tags.go | 48 ++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/internal/service/s3/tags.go b/internal/service/s3/tags.go index 956361e9b2b..15cf6ff925c 100644 --- a/internal/service/s3/tags.go +++ b/internal/service/s3/tags.go @@ -98,6 +98,8 @@ func ObjectListTags(ctx context.Context, conn *s3_sdkv2.Client, bucket, key stri Key: aws_sdkv2.String(key), } + // TODO Is this retry still necessary with strong read consistency for read operations on Amazon S3 Object Tags? + // https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html#ConsistencyModel. outputRaw, err := tfresource.RetryWhenIsA[*s3types_sdkv2.NoSuchKey](ctx, 1*time.Minute, func() (interface{}, error) { return conn.GetObjectTagging(ctx, input) }) @@ -113,6 +115,50 @@ func ObjectListTags(ctx context.Context, conn *s3_sdkv2.Client, bucket, key stri return keyValueTagsV2(ctx, outputRaw.(*s3_sdkv2.GetObjectTaggingOutput).TagSet), nil } +// ObjectUpdateTags updates S3 object tags. +func ObjectUpdateTags(ctx context.Context, conn *s3_sdkv2.Client, bucket, key string, oldTagsMap, newTagsMap any) error { + oldTags := tftags.New(ctx, oldTagsMap) + newTags := tftags.New(ctx, newTagsMap) + + // We need to also consider any existing ignored tags. + allTags, err := ObjectListTags(ctx, conn, bucket, key) + + if err != nil { + return fmt.Errorf("listing resource tags (%s/%s): %w", bucket, key, err) + } + + ignoredTags := allTags.Ignore(oldTags).Ignore(newTags) + + if len(newTags)+len(ignoredTags) > 0 { + input := &s3_sdkv2.PutObjectTaggingInput{ + Bucket: aws_sdkv2.String(bucket), + Key: aws_sdkv2.String(key), + Tagging: &s3types_sdkv2.Tagging{ + TagSet: Tags(newTags.Merge(ignoredTags)), + }, + } + + _, err := conn.PutObjectTagging(ctx, input) + + if err != nil { + return fmt.Errorf("setting resource tags (%s/%s): %w", bucket, key, err) + } + } else if len(oldTags) > 0 && len(ignoredTags) == 0 { + input := &s3_sdkv2.DeleteObjectTaggingInput{ + Bucket: aws_sdkv2.String(bucket), + Key: aws_sdkv2.String(key), + } + + _, err := conn.DeleteObjectTagging(ctx, input) + + if err != nil { + return fmt.Errorf("deleting resource tags (%s/%s): %w", bucket, key, err) + } + } + + return nil +} + // ObjectListTagsV1 lists S3 object tags (AWS SDK for Go v1). func ObjectListTagsV1(ctx context.Context, conn s3iface_sdkv1.S3API, bucket, key string) (tftags.KeyValueTags, error) { input := &s3_sdkv1.GetObjectTaggingInput{ @@ -135,7 +181,7 @@ func ObjectListTagsV1(ctx context.Context, conn s3iface_sdkv1.S3API, bucket, key return KeyValueTags(ctx, outputRaw.(*s3_sdkv1.GetObjectTaggingOutput).TagSet), nil } -// ObjectUpdateTagsV1 updates S3 object tags. +// ObjectUpdateTagsV1 updates S3 object tags (AWS SDK for Go v1). func ObjectUpdateTagsV1(ctx context.Context, conn s3iface_sdkv1.S3API, bucket, key string, oldTagsMap, newTagsMap any) error { oldTags := tftags.New(ctx, oldTagsMap) newTags := tftags.New(ctx, newTagsMap) From df861857a9f4b47744221d617cef929b7108e419 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 12:23:35 -0400 Subject: [PATCH 03/61] Run 'go get github.com/aws/aws-sdk-go-v2/feature/s3/manager@v1.11.83 && go mod tidy'. --- go.mod | 11 ++++++----- go.sum | 31 ++++++++++++------------------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index a5c81bf4f5d..87c8f8cd314 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/aws/aws-sdk-go v1.45.4 github.com/aws/aws-sdk-go-v2 v1.21.0 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.83 github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.20.5 github.com/aws/aws-sdk-go-v2/service/account v1.11.5 github.com/aws/aws-sdk-go-v2/service/acm v1.18.5 @@ -113,11 +114,11 @@ require ( github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 // indirect - github.com/aws/aws-sdk-go-v2/config v1.18.33 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.32 // indirect + github.com/aws/aws-sdk-go-v2/config v1.18.39 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.37 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 // indirect github.com/aws/aws-sdk-go-v2/service/iam v1.22.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 // indirect @@ -125,8 +126,8 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.35 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.13.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 // indirect github.com/aws/smithy-go v1.14.2 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect diff --git a/go.sum b/go.sum index ea9cee8b4f8..73514d26ce2 100644 --- a/go.sum +++ b/go.sum @@ -24,26 +24,24 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.45.4 h1:6B8oTYNEncxga8EV1C6Q4iJNnpDIqLEigy0v0oh2qYw= github.com/aws/aws-sdk-go v1.45.4/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac= github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc= github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 h1:OPLEkmhXf6xFPiz0bLeDArZIDx1NNS4oJyG4nv3Gct0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13/go.mod h1:gpAbvyDGQFozTEmlTFO8XcQKHzubdq0LzRyJpG6MiXM= -github.com/aws/aws-sdk-go-v2/config v1.18.33 h1:JKcw5SFxFW/rpM4mOPjv0VQ11E2kxW13F3exWOy7VZU= -github.com/aws/aws-sdk-go-v2/config v1.18.33/go.mod h1:hXO/l9pgY3K5oZJldamP0pbZHdPqqk+4/maa7DSD3cA= -github.com/aws/aws-sdk-go-v2/credentials v1.13.32 h1:lIH1eKPcCY1ylR4B6PkBGRWMHO3aVenOKJHWiS4/G2w= -github.com/aws/aws-sdk-go-v2/credentials v1.13.32/go.mod h1:lL8U3v/Y79YRG69WlAho0OHIKUXCyFvSXaIvfo81sls= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8/go.mod h1:ce7BgLQfYr5hQFdy67oX2svto3ufGtm6oBvmsHScI1Q= +github.com/aws/aws-sdk-go-v2/config v1.18.39 h1:oPVyh6fuu/u4OiW4qcuQyEtk7U7uuNBmHmJSLg1AJsQ= +github.com/aws/aws-sdk-go-v2/config v1.18.39/go.mod h1:+NH/ZigdPckFpgB1TRcRuWCB/Kbbvkxc/iNAKTq5RhE= +github.com/aws/aws-sdk-go-v2/credentials v1.13.37 h1:BvEdm09+ZEh2XtN+PVHPcYwKY3wIeB6pw7vPRM4M9/U= +github.com/aws/aws-sdk-go-v2/credentials v1.13.37/go.mod h1:ACLrdkd4CLZyXOghZ8IYumQbcooAcp2jo/s2xsFH8IM= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38/go.mod h1:qggunOChCMu9ZF/UkAfhTz25+U2rLVb3ya0Ua6TTfCA= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.83 h1:wcluDLIQ0uYaxv0fCWQRimbXkPdTgWHUD21j1CzXEwc= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.83/go.mod h1:nGCBuon134gW67yAtxHKV73x+tAcY/xG4ZPNPDB1h/I= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32/go.mod h1:0ZXSqrty4FtQ7p8TEuRde/SZm9X05KT18LAUlR40Ln0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 h1:fc0ukRAiP1syoSGZYu+DaE+FulSYhTiJ8WpVu5jElU4= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39/go.mod h1:WLAW8PT7+JhjZfLSWe7WEJaJu0GNo0cKc2Zyo003RBs= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 h1:GPUcE/Yq7Ur8YSUk6lVkoIMWnJNO0HT18GUzCWCgCI0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo= github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 h1:6lJvvkQ9HmbHZ4h/IEwclwv2mrTW8Uq1SOB/kXy0mfw= github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4/go.mod h1:1PrKYwxTM+zjpw9Y41KFtoJCQrJ34Z47Y4VgVbfndjo= github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.20.5 h1:1w0ELQMC3AptxEFS4A+vJuhyIuC9IoNN2YxNKK5pSYQ= @@ -100,7 +98,6 @@ github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 h1:eev2yZX7esGRjq github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36/go.mod h1:lGnOkH9NJATw0XEPcAknFBj3zzNTEGRHtSw+CwC1YTg= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.35 h1:UKjpIDLVF90RfV88XurdduMoTxPqtGHZMIDYZQM7RO4= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.35/go.mod h1:B3dUg0V6eJesUTi+m27NUkj7n8hdDKYUpxj8f4+TqaQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32/go.mod h1:4jwAWKEkCR0anWk5+1RbfSg1R5Gzld7NLiuaq5bTR/Y= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 h1:v0jkRigbSD6uOdwcaUQmgEwG1BkPfAPDqaeNt/29ghg= @@ -165,13 +162,10 @@ github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.16.5 h1:kt2JpBjKnG2GfiHJU0es github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.16.5/go.mod h1:g6xJdpynIx7D1UW9te8ul36qWGyuzIL6ATrJF6E6ygI= github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.22.5 h1:1PesErC0GN25MaKtBju52HlJOXtLeFoAsOxAgHhEoCk= github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.22.5/go.mod h1:11Z2L2mDhJbRZo5rwRs1NPz1Vi37U5N1EiaazEoBGag= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.2/go.mod h1:ju+nNXUunfIFamXUIZQiICjnO/TPlOmWcYhZcSy7xaE= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.5 h1:oCvTFSDi67AX0pOX3PuPdGFewvLRU2zzFSrTsgURNo0= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.5/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2/go.mod h1:ubDBBaDFs1GHijSOTi8ljppML15GLG0HxhILtbjNNYQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 h1:dnInJb4S0oy8aQuri1mV6ipLlnZPfnsDNB9BGO9PDNY= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.2/go.mod h1:FQ/DQcOfESELfJi5ED+IPPAjI5xC6nxtSolVVB773jM= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 h1:2PylFCfKCEDv6PeSN09pC/VUiRd10wi1VfHG5FrW0/g= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.6/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 h1:pSB560BbVj9ZlJZF4WYj5zsytWHWKxg+NgyGV4B2L58= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvTZW2S44Lt9Mk2aYQ= github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= github.com/aws/aws-sdk-go-v2/service/swf v1.17.3 h1:E2i7UVmrS7D+RqvOHdv/6pag549LNrR+W8x8z+fwFWo= @@ -188,7 +182,6 @@ github.com/aws/aws-sdk-go-v2/service/workspaces v1.29.5 h1:WE+Y5exd/Jowh2eVl2vmd github.com/aws/aws-sdk-go-v2/service/workspaces v1.29.5/go.mod h1:AVjfc8q87mKUZgiW4NjqJgG1OzcFIO6OHyfkOQSrPSY= github.com/aws/aws-sdk-go-v2/service/xray v1.17.5 h1:fJ7KMcuZXBfmK0A8ZfMZIKle0/WuiZwOl+JDpR+LV4I= github.com/aws/aws-sdk-go-v2/service/xray v1.17.5/go.mod h1:aE2t25bCn8YrfL6faz73m5Q/7gKa25HjCoa+z6OQMG4= -github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ= github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beevik/etree v1.2.0 h1:l7WETslUG/T+xOPs47dtd6jov2Ii/8/OjCldk5fYfQw= From 8b0885764401541fe507e8bc94c7b09ded326d3a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 12:58:41 -0400 Subject: [PATCH 04/61] r/aws_s3_object_copy: Tweak error message. --- internal/service/s3/object_copy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index 9628dd10186..ace3ccea6c1 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -610,7 +610,7 @@ func resourceObjectCopyDoCopy(ctx context.Context, d *schema.ResourceData, meta output, err := conn.CopyObject(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "copying S3 object (bucket: %s; key: %s; source: %s): %s", aws.ToString(input.Bucket), aws.ToString(input.Key), aws.ToString(input.CopySource), err) + return sdkdiag.AppendErrorf(diags, "copying %s to S3 Bucket (%s) Object (%s): %s", aws.ToString(input.CopySource), aws.ToString(input.Bucket), aws.ToString(input.Key), err) } if d.IsNewResource() { From 591a9d9818d63e784769c46f696f150535641c11 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 14:13:37 -0400 Subject: [PATCH 05/61] Fixup 'ObjectUpdateTags'. --- internal/service/s3/tags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/s3/tags.go b/internal/service/s3/tags.go index 15cf6ff925c..eabcd1119b3 100644 --- a/internal/service/s3/tags.go +++ b/internal/service/s3/tags.go @@ -134,7 +134,7 @@ func ObjectUpdateTags(ctx context.Context, conn *s3_sdkv2.Client, bucket, key st Bucket: aws_sdkv2.String(bucket), Key: aws_sdkv2.String(key), Tagging: &s3types_sdkv2.Tagging{ - TagSet: Tags(newTags.Merge(ignoredTags)), + TagSet: tagsV2(newTags.Merge(ignoredTags)), }, } From 438ce49fd946f9bb5ee8d2f41a3ae37d9bf427b2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 14:18:38 -0400 Subject: [PATCH 06/61] r/aws_s3_object: Migrate to AWS SDK for Go v2. --- internal/service/s3/bucket_object.go | 2 +- internal/service/s3/object.go | 333 +++++++++++++-------------- internal/service/s3/object_copy.go | 2 +- 3 files changed, 163 insertions(+), 174 deletions(-) diff --git a/internal/service/s3/bucket_object.go b/internal/service/s3/bucket_object.go index 17bf8f3c729..09b4dd4d36e 100644 --- a/internal/service/s3/bucket_object.go +++ b/internal/service/s3/bucket_object.go @@ -359,7 +359,7 @@ func resourceBucketObjectUpdate(ctx context.Context, d *schema.ResourceData, met func resourceBucketObjectDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).S3Conn(ctx) + conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) key := d.Get("key").(string) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 48b911eb835..6a8176a3c7e 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -15,15 +15,18 @@ import ( "time" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3manager" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/feature/s3/manager" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/service/kms" @@ -56,10 +59,10 @@ func ResourceObject() *schema.Resource { Schema: map[string]*schema.Schema{ "acl": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice(s3.ObjectCannedACL_Values(), false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateDiagFunc: enum.Validate[types.ObjectCannedACL](), }, "bucket": { Type: schema.TypeString, @@ -130,7 +133,7 @@ func ResourceObject() *schema.Resource { ValidateFunc: verify.ValidARN, DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { // ignore diffs where the user hasn't specified a kms_key_id but the bucket has a default KMS key configured - if new == "" && d.Get("server_side_encryption") == s3.ServerSideEncryptionAwsKms { + if new == "" && d.Get("server_side_encryption") == types.ServerSideEncryptionAwsKms { return true } return false @@ -143,14 +146,14 @@ func ResourceObject() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, "object_lock_legal_hold_status": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(s3.ObjectLockLegalHoldStatus_Values(), false), + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.ObjectLockLegalHoldStatus](), }, "object_lock_mode": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(s3.ObjectLockMode_Values(), false), + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.ObjectLockMode](), }, "object_lock_retain_until_date": { Type: schema.TypeString, @@ -158,10 +161,10 @@ func ResourceObject() *schema.Resource { ValidateFunc: validation.IsRFC3339Time, }, "server_side_encryption": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(s3.ServerSideEncryption_Values(), false), - Computed: true, + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.ServerSideEncryption](), + Computed: true, }, "source": { Type: schema.TypeString, @@ -173,10 +176,10 @@ func ResourceObject() *schema.Resource { Optional: true, }, "storage_class": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice(s3.ObjectStorageClass_Values(), false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateDiagFunc: enum.Validate[types.ObjectStorageClass](), }, names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), @@ -199,12 +202,14 @@ func resourceObjectCreate(ctx context.Context, d *schema.ResourceData, meta inte func resourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).S3Conn(ctx) + conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) key := d.Get("key").(string) + // TODO Is this retry still necessary with strong read-after-write consistency for PUT and DELETE requests of objects? + // https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html#ConsistencyModel. outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, objectCreationTimeout, func() (interface{}, error) { - return FindObjectByThreePartKeyV1(ctx, conn, bucket, key, "") + return FindObjectByThreePartKey(ctx, conn, bucket, key, "") }, d.IsNewResource()) if !d.IsNewResource() && tfresource.NotFound(err) { @@ -225,52 +230,30 @@ func resourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interf d.Set("content_encoding", output.ContentEncoding) d.Set("content_language", output.ContentLanguage) d.Set("content_type", output.ContentType) - metadata := flex.PointersMapToStringList(output.Metadata) - - // AWS Go SDK capitalizes metadata, this is a workaround. https://github.com/aws/aws-sdk-go/issues/445 - for k, v := range metadata { - delete(metadata, k) - metadata[strings.ToLower(k)] = v - } - - if err := d.Set("metadata", metadata); err != nil { - return sdkdiag.AppendErrorf(diags, "setting metadata: %s", err) - } - d.Set("version_id", output.VersionId) - d.Set("server_side_encryption", output.ServerSideEncryption) - d.Set("website_redirect", output.WebsiteRedirectLocation) + // See https://forums.aws.amazon.com/thread.jspa?threadID=44003 + d.Set("etag", strings.Trim(aws.ToString(output.ETag), `"`)) + d.Set("metadata", output.Metadata) d.Set("object_lock_legal_hold_status", output.ObjectLockLegalHoldStatus) d.Set("object_lock_mode", output.ObjectLockMode) d.Set("object_lock_retain_until_date", flattenObjectDate(output.ObjectLockRetainUntilDate)) - - if err := resourceObjectSetKMS(ctx, d, meta, output.SSEKMSKeyId); err != nil { - return sdkdiag.AppendErrorf(diags, "object KMS: %s", err) - } - - // See https://forums.aws.amazon.com/thread.jspa?threadID=44003 - d.Set("etag", strings.Trim(aws.StringValue(output.ETag), `"`)) - + d.Set("server_side_encryption", output.ServerSideEncryption) // The "STANDARD" (which is also the default) storage // class when set would not be included in the results. - if output.StorageClass == nil { - d.Set("storage_class", s3.StorageClassStandard) - } else { + d.Set("storage_class", types.ObjectStorageClassStandard) + if output.StorageClass != "" { d.Set("storage_class", output.StorageClass) } + d.Set("version_id", output.VersionId) + d.Set("website_redirect", output.WebsiteRedirectLocation) - // Retry due to S3 eventual consistency - tagsRaw, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, 2*time.Minute, func() (interface{}, error) { - return ObjectListTagsV1(ctx, conn, bucket, key) - }, s3.ErrCodeNoSuchBucket) - - if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for S3 Bucket (%s) Object (%s): %s", bucket, key, err) + if err := resourceObjectSetKMS(ctx, d, meta, output.SSEKMSKeyId); err != nil { + return sdkdiag.AppendFromErr(diags, err) } - tags, ok := tagsRaw.(tftags.KeyValueTags) + tags, err := ObjectListTags(ctx, conn, bucket, key) - if !ok { - return sdkdiag.AppendErrorf(diags, "listing tags for S3 Bucket (%s) Object (%s): unable to convert tags", bucket, key) + if err != nil { + return sdkdiag.AppendErrorf(diags, "listing tags for S3 Bucket (%s) Object (%s): %s", bucket, key, err) } setTagsOut(ctx, Tags(tags)) @@ -284,41 +267,47 @@ func resourceObjectUpdate(ctx context.Context, d *schema.ResourceData, meta inte return append(diags, resourceObjectUpload(ctx, d, meta)...) } - conn := meta.(*conns.AWSClient).S3Conn(ctx) + conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) key := d.Get("key").(string) if d.HasChange("acl") { - _, err := conn.PutObjectAclWithContext(ctx, &s3.PutObjectAclInput{ + input := &s3.PutObjectAclInput{ + ACL: types.ObjectCannedACL(d.Get("acl").(string)), Bucket: aws.String(bucket), Key: aws.String(key), - ACL: aws.String(d.Get("acl").(string)), - }) + } + + _, err := conn.PutObjectAcl(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "putting S3 object ACL: %s", err) + return sdkdiag.AppendErrorf(diags, "putting S3 Object (%s) ACL: %s", d.Id(), err) } } if d.HasChange("object_lock_legal_hold_status") { - _, err := conn.PutObjectLegalHoldWithContext(ctx, &s3.PutObjectLegalHoldInput{ + input := &s3.PutObjectLegalHoldInput{ Bucket: aws.String(bucket), Key: aws.String(key), - LegalHold: &s3.ObjectLockLegalHold{ - Status: aws.String(d.Get("object_lock_legal_hold_status").(string)), + LegalHold: &types.ObjectLockLegalHold{ + Status: types.ObjectLockLegalHoldStatus(d.Get("object_lock_legal_hold_status").(string)), }, - }) + } + + _, err := conn.PutObjectLegalHold(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "putting S3 object lock legal hold: %s", err) + return sdkdiag.AppendErrorf(diags, "putting S3 Object (%s) legal hold: %s", d.Id(), err) } } if d.HasChanges("object_lock_mode", "object_lock_retain_until_date") { - req := &s3.PutObjectRetentionInput{ + input := &s3.PutObjectRetentionInput{ Bucket: aws.String(bucket), Key: aws.String(key), - Retention: &s3.ObjectLockRetention{ - Mode: aws.String(d.Get("object_lock_mode").(string)), + Retention: &types.ObjectLockRetention{ + Mode: types.ObjectLockRetentionMode(d.Get("object_lock_mode").(string)), RetainUntilDate: expandObjectDate(d.Get("object_lock_retain_until_date").(string)), }, } @@ -326,16 +315,17 @@ func resourceObjectUpdate(ctx context.Context, d *schema.ResourceData, meta inte // Bypass required to lower or clear retain-until date. if d.HasChange("object_lock_retain_until_date") { oraw, nraw := d.GetChange("object_lock_retain_until_date") - o := expandObjectDate(oraw.(string)) - n := expandObjectDate(nraw.(string)) + o, n := expandObjectDate(oraw.(string)), expandObjectDate(nraw.(string)) + if n == nil || (o != nil && n.Before(*o)) { - req.BypassGovernanceRetention = aws.Bool(true) + input.BypassGovernanceRetention = true } } - _, err := conn.PutObjectRetentionWithContext(ctx, req) + _, err := conn.PutObjectRetention(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "putting S3 object lock retention: %s", err) + return sdkdiag.AppendErrorf(diags, "putting S3 Object (%s) retention: %s", d.Id(), err) } } @@ -352,7 +342,7 @@ func resourceObjectUpdate(ctx context.Context, d *schema.ResourceData, meta inte func resourceObjectDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).S3Conn(ctx) + conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) key := d.Get("key").(string) @@ -396,8 +386,8 @@ func resourceObjectImport(ctx context.Context, d *schema.ResourceData, meta inte func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).S3Conn(ctx) - uploader := s3manager.NewUploaderWithClient(conn) + conn := meta.(*conns.AWSClient).S3Client(ctx) + uploader := manager.NewUploader(conn) defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) @@ -439,31 +429,26 @@ func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta inte bucket := d.Get("bucket").(string) key := d.Get("key").(string) - - input := &s3manager.UploadInput{ + input := &s3.PutObjectInput{ Body: body, Bucket: aws.String(bucket), Key: aws.String(key), } if v, ok := d.GetOk("acl"); ok { - input.ACL = aws.String(v.(string)) + input.ACL = types.ObjectCannedACL(v.(string)) } - if v, ok := d.GetOk("storage_class"); ok { - input.StorageClass = aws.String(v.(string)) + if v, ok := d.GetOk("bucket_key_enabled"); ok { + input.BucketKeyEnabled = v.(bool) } if v, ok := d.GetOk("cache_control"); ok { input.CacheControl = aws.String(v.(string)) } - if v, ok := d.GetOk("content_type"); ok { - input.ContentType = aws.String(v.(string)) - } - - if v, ok := d.GetOk("metadata"); ok { - input.Metadata = flex.ExpandStringMap(v.(map[string]interface{})) + if v, ok := d.GetOk("content_disposition"); ok { + input.ContentDisposition = aws.String(v.(string)) } if v, ok := d.GetOk("content_encoding"); ok { @@ -474,21 +459,37 @@ func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta inte input.ContentLanguage = aws.String(v.(string)) } - if v, ok := d.GetOk("content_disposition"); ok { - input.ContentDisposition = aws.String(v.(string)) + if v, ok := d.GetOk("content_type"); ok { + input.ContentType = aws.String(v.(string)) } - if v, ok := d.GetOk("bucket_key_enabled"); ok { - input.BucketKeyEnabled = aws.Bool(v.(bool)) + if v, ok := d.GetOk("kms_key_id"); ok { + input.SSEKMSKeyId = aws.String(v.(string)) + input.ServerSideEncryption = types.ServerSideEncryptionAwsKms + } + + if v, ok := d.GetOk("metadata"); ok { + input.Metadata = flex.ExpandStringValueMap(v.(map[string]interface{})) + } + + if v, ok := d.GetOk("object_lock_legal_hold_status"); ok { + input.ObjectLockLegalHoldStatus = types.ObjectLockLegalHoldStatus(v.(string)) + } + + if v, ok := d.GetOk("object_lock_mode"); ok { + input.ObjectLockMode = types.ObjectLockMode(v.(string)) + } + + if v, ok := d.GetOk("object_lock_retain_until_date"); ok { + input.ObjectLockRetainUntilDate = expandObjectDate(v.(string)) } if v, ok := d.GetOk("server_side_encryption"); ok { - input.ServerSideEncryption = aws.String(v.(string)) + input.ServerSideEncryption = types.ServerSideEncryption(v.(string)) } - if v, ok := d.GetOk("kms_key_id"); ok { - input.SSEKMSKeyId = aws.String(v.(string)) - input.ServerSideEncryption = aws.String(s3.ServerSideEncryptionAwsKms) + if v, ok := d.GetOk("storage_class"); ok { + input.StorageClass = types.StorageClass(v.(string)) } if len(tags) > 0 { @@ -500,24 +501,14 @@ func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta inte input.WebsiteRedirectLocation = aws.String(v.(string)) } - if v, ok := d.GetOk("object_lock_legal_hold_status"); ok { - input.ObjectLockLegalHoldStatus = aws.String(v.(string)) - } - - if v, ok := d.GetOk("object_lock_mode"); ok { - input.ObjectLockMode = aws.String(v.(string)) - } - - if v, ok := d.GetOk("object_lock_retain_until_date"); ok { - input.ObjectLockRetainUntilDate = expandObjectDate(v.(string)) + if _, err := uploader.Upload(ctx, input); err != nil { + return sdkdiag.AppendErrorf(diags, "uploading S3 Object (%s) to Bucket (%s): %s", key, bucket, err) } - if _, err := uploader.Upload(input); err != nil { - return sdkdiag.AppendErrorf(diags, "uploading object to S3 bucket (%s): %s", bucket, err) + if d.IsNewResource() { + d.SetId(key) } - d.SetId(key) - return append(diags, resourceObjectRead(ctx, d, meta)...) } @@ -531,8 +522,8 @@ func resourceObjectSetKMS(ctx context.Context, d *schema.ResourceData, meta inte return fmt.Errorf("Failed to describe default S3 KMS key (%s): %s", DefaultKMSKeyAlias, err) } - if aws.StringValue(sseKMSKeyId) != aws.StringValue(keyMetadata.Arn) { - log.Printf("[DEBUG] S3 object is encrypted using a non-default KMS Key ID: %s", aws.StringValue(sseKMSKeyId)) + if kmsKeyID := aws.ToString(sseKMSKeyId); kmsKeyID != aws.ToString(keyMetadata.Arn) { + log.Printf("[DEBUG] S3 object is encrypted using a non-default KMS Key ID: %s", kmsKeyID) d.Set("kms_key_id", sseKMSKeyId) } } @@ -595,7 +586,7 @@ func hasObjectContentChanges(d verify.ResourceDiffer) bool { // If key is empty then all versions of all objects are deleted. // Set force to true to override any S3 object lock protections on object lock enabled buckets. // Returns the number of objects deleted. -func DeleteAllObjectVersions(ctx context.Context, conn *s3.S3, bucketName, key string, force, ignoreObjectErrors bool) (int64, error) { +func DeleteAllObjectVersions(ctx context.Context, conn *s3.Client, bucketName, key string, force, ignoreObjectErrors bool) (int64, error) { var nObjects int64 input := &s3.ListObjectVersionsInput{ @@ -606,14 +597,22 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.S3, bucketName, key s } var lastErr error - err := conn.ListObjectVersionsPagesWithContext(ctx, input, func(page *s3.ListObjectVersionsOutput, lastPage bool) bool { - if page == nil { - return !lastPage + + pages := s3.NewListObjectVersionsPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if errs.IsA[*types.NoSuchBucket](err) { + break + } + + if err != nil { + return nObjects, err } for _, objectVersion := range page.Versions { - objectKey := aws.StringValue(objectVersion.Key) - objectVersionID := aws.StringValue(objectVersion.VersionId) + objectKey := aws.ToString(objectVersion.Key) + objectVersionID := aws.ToString(objectVersion.VersionId) if key != "" && key != objectKey { continue @@ -625,32 +624,36 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.S3, bucketName, key s nObjects++ } - if tfawserr.ErrCodeEquals(err, "AccessDenied") && force { + if tfawserr.ErrCodeEquals(err, errCodeAccessDenied) && force { // Remove any legal hold. - resp, err := conn.HeadObjectWithContext(ctx, &s3.HeadObjectInput{ + input := &s3.HeadObjectInput{ Bucket: aws.String(bucketName), - Key: objectVersion.Key, - VersionId: objectVersion.VersionId, - }) + Key: aws.String(objectKey), + VersionId: aws.String(objectVersionID), + } + + output, err := conn.HeadObject(ctx, input) if err != nil { - log.Printf("[ERROR] Error getting S3 Bucket (%s) Object (%s) Version (%s) metadata: %s", bucketName, objectKey, objectVersionID, err) + log.Printf("[ERROR] Getting S3 Bucket (%s) Object (%s) Version (%s) metadata: %s", bucketName, objectKey, objectVersionID, err) lastErr = err continue } - if aws.StringValue(resp.ObjectLockLegalHoldStatus) == s3.ObjectLockLegalHoldStatusOn { - _, err := conn.PutObjectLegalHoldWithContext(ctx, &s3.PutObjectLegalHoldInput{ - Bucket: aws.String(bucketName), - Key: objectVersion.Key, - VersionId: objectVersion.VersionId, - LegalHold: &s3.ObjectLockLegalHold{ - Status: aws.String(s3.ObjectLockLegalHoldStatusOff), + if output.ObjectLockLegalHoldStatus == types.ObjectLockLegalHoldStatusOn { + input := &s3.PutObjectLegalHoldInput{ + Bucket: aws.String(bucketName), + Key: aws.String(objectKey), + LegalHold: &types.ObjectLockLegalHold{ + Status: types.ObjectLockLegalHoldStatusOff, }, - }) + VersionId: aws.String(objectVersionID), + } + + _, err := conn.PutObjectLegalHold(ctx, input) if err != nil { - log.Printf("[ERROR] Error putting S3 Bucket (%s) Object (%s) Version(%s) legal hold: %s", bucketName, objectKey, objectVersionID, err) + log.Printf("[ERROR] Putting S3 Bucket (%s) Object (%s) Version(%s) legal hold: %s", bucketName, objectKey, objectVersionID, err) lastErr = err continue } @@ -668,7 +671,7 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.S3, bucketName, key s } // AccessDenied for another reason. - lastErr = fmt.Errorf("AccessDenied deleting S3 Bucket (%s) Object (%s) Version: %s", bucketName, objectKey, objectVersionID) + lastErr = fmt.Errorf("deleting S3 Bucket (%s) Object (%s) Version (%s): %w", bucketName, objectKey, objectVersionID, err) continue } @@ -676,34 +679,31 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.S3, bucketName, key s lastErr = err } } - - return !lastPage - }) - - if tfawserr.ErrCodeEquals(err, s3.ErrCodeNoSuchBucket) { - err = nil - } - - if err != nil { - return nObjects, err } if lastErr != nil { if !ignoreObjectErrors { - return nObjects, fmt.Errorf("deleting at least one object version, last error: %s", lastErr) + return nObjects, fmt.Errorf("deleting at least one S3 Object version, last error: %w", lastErr) } lastErr = nil } - err = conn.ListObjectVersionsPagesWithContext(ctx, input, func(page *s3.ListObjectVersionsOutput, lastPage bool) bool { - if page == nil { - return !lastPage + pages = s3.NewListObjectVersionsPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if errs.IsA[*types.NoSuchBucket](err) { + break + } + + if err != nil { + return nObjects, err } for _, deleteMarker := range page.DeleteMarkers { - deleteMarkerKey := aws.StringValue(deleteMarker.Key) - deleteMarkerVersionID := aws.StringValue(deleteMarker.VersionId) + deleteMarkerKey := aws.ToString(deleteMarker.Key) + deleteMarkerVersionID := aws.ToString(deleteMarker.VersionId) if key != "" && key != deleteMarkerKey { continue @@ -718,21 +718,11 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.S3, bucketName, key s nObjects++ } } - - return !lastPage - }) - - if tfawserr.ErrCodeEquals(err, s3.ErrCodeNoSuchBucket) { - err = nil - } - - if err != nil { - return nObjects, err } if lastErr != nil { if !ignoreObjectErrors { - return nObjects, fmt.Errorf("deleting at least one object delete marker, last error: %s", lastErr) + return nObjects, fmt.Errorf("deleting at least one S3 Object delete marker, last error: %w", lastErr) } lastErr = nil @@ -743,7 +733,7 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.S3, bucketName, key s // deleteObjectVersion deletes a specific object version. // Set force to true to override any S3 object lock protections. -func deleteObjectVersion(ctx context.Context, conn *s3.S3, b, k, v string, force bool) error { +func deleteObjectVersion(ctx context.Context, conn *s3.Client, b, k, v string, force bool) error { input := &s3.DeleteObjectInput{ Bucket: aws.String(b), Key: aws.String(k), @@ -752,19 +742,18 @@ func deleteObjectVersion(ctx context.Context, conn *s3.S3, b, k, v string, force if v != "" { input.VersionId = aws.String(v) } - if force { - input.BypassGovernanceRetention = aws.Bool(true) + input.BypassGovernanceRetention = true } - log.Printf("[INFO] Deleting S3 Bucket (%s) Object (%s) Version: %s", b, k, v) - _, err := conn.DeleteObjectWithContext(ctx, input) + log.Printf("[INFO] Deleting S3 Bucket (%s) Object (%s) Version (%s)", b, k, v) + _, err := conn.DeleteObject(ctx, input) if err != nil { - log.Printf("[WARN] Error deleting S3 Bucket (%s) Object (%s) Version (%s): %s", b, k, v, err) + log.Printf("[WARN] Deleting S3 Bucket (%s) Object (%s) Version (%s): %s", b, k, v, err) } - if tfawserr.ErrCodeEquals(err, s3.ErrCodeNoSuchBucket) || tfawserr.ErrCodeEquals(err, s3.ErrCodeNoSuchKey) { + if errs.IsA[*types.NoSuchBucket](err) || errs.IsA[*types.NoSuchKey](err) { return nil } diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index ace3ccea6c1..62606ae9ae3 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -430,7 +430,7 @@ func resourceObjectCopyUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceObjectCopyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).S3Conn(ctx) + conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) key := d.Get("key").(string) From 8ecd1b95bee2b6a0810394190025b3a97a3b4e7b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 14:25:40 -0400 Subject: [PATCH 07/61] TestDeleteAllObjectVersions: Migrate to AWS SDK for Go v2. --- internal/service/s3/delete_test.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/internal/service/s3/delete_test.go b/internal/service/s3/delete_test.go index 0bbce64ca1b..e8c61d75e56 100644 --- a/internal/service/s3/delete_test.go +++ b/internal/service/s3/delete_test.go @@ -7,8 +7,10 @@ import ( "flag" "testing" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" + config_sdkv2 "github.com/aws/aws-sdk-go-v2/config" + s3_sdkv2 "github.com/aws/aws-sdk-go-v2/service/s3" + session_sdkv1 "github.com/aws/aws-sdk-go/aws/session" + s3_sdkv1 "github.com/aws/aws-sdk-go/service/s3" "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfs3 "github.com/hashicorp/terraform-provider-aws/internal/service/s3" ) @@ -27,8 +29,8 @@ func TestEmptyBucket(t *testing.T) { t.Skip("bucket not specified") } - sess := session.Must(session.NewSession()) - svc := s3.New(sess) + sess := session_sdkv1.Must(session_sdkv1.NewSession()) + svc := s3_sdkv1.New(sess) n, err := tfs3.EmptyBucket(ctx, svc, *bucket, *force) @@ -48,10 +50,13 @@ func TestDeleteAllObjectVersions(t *testing.T) { t.Skip("bucket not specified") } - sess := session.Must(session.NewSession()) - svc := s3.New(sess) + cfg, err := config_sdkv2.LoadDefaultConfig(ctx) + if err != nil { + t.Fatalf("error loading default SDK config: %s", err) + } - n, err := tfs3.DeleteAllObjectVersions(ctx, svc, *bucket, "", *force, false) + client := s3_sdkv2.NewFromConfig(cfg) + n, err := tfs3.DeleteAllObjectVersions(ctx, client, *bucket, "", *force, false) if err != nil { t.Fatalf("error emptying S3 bucket (%s): %s", *bucket, err) From 845af9a2ac23fba8ccd495c257ba389c68e92b4a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 14:59:36 -0400 Subject: [PATCH 08/61] ObjectListTags: Remove retry as there is now string consistency for read operations on Amazon S3 Object Tags. --- internal/service/s3/tags.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/internal/service/s3/tags.go b/internal/service/s3/tags.go index eabcd1119b3..e6e544cb210 100644 --- a/internal/service/s3/tags.go +++ b/internal/service/s3/tags.go @@ -98,11 +98,7 @@ func ObjectListTags(ctx context.Context, conn *s3_sdkv2.Client, bucket, key stri Key: aws_sdkv2.String(key), } - // TODO Is this retry still necessary with strong read consistency for read operations on Amazon S3 Object Tags? - // https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html#ConsistencyModel. - outputRaw, err := tfresource.RetryWhenIsA[*s3types_sdkv2.NoSuchKey](ctx, 1*time.Minute, func() (interface{}, error) { - return conn.GetObjectTagging(ctx, input) - }) + output, err := conn.GetObjectTagging(ctx, input) if tfawserr_sdkv2.ErrCodeEquals(err, errCodeNoSuchTagSet, errCodeNoSuchTagSetError) { return tftags.New(ctx, nil), nil @@ -112,7 +108,7 @@ func ObjectListTags(ctx context.Context, conn *s3_sdkv2.Client, bucket, key stri return tftags.New(ctx, nil), err } - return keyValueTagsV2(ctx, outputRaw.(*s3_sdkv2.GetObjectTaggingOutput).TagSet), nil + return keyValueTagsV2(ctx, output.TagSet), nil } // ObjectUpdateTags updates S3 object tags. From e57f69736d24fe32d4053b5dbaf5cd1049f7d211 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 15:00:34 -0400 Subject: [PATCH 09/61] s3: 'errs.IsA' doesn't work as expected because the errors in 'types' aren't exposed as nested. --- internal/service/s3/errors.go | 2 ++ internal/service/s3/object.go | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/service/s3/errors.go b/internal/service/s3/errors.go index 0be44a488b0..e01d3ce5e1b 100644 --- a/internal/service/s3/errors.go +++ b/internal/service/s3/errors.go @@ -13,10 +13,12 @@ const ( errCodeInvalidRequest = "InvalidRequest" errCodeMalformedPolicy = "MalformedPolicy" errCodeMethodNotAllowed = "MethodNotAllowed" + errCodeNoSuchBucket = "NoSuchBucket" ErrCodeNoSuchBucketPolicy = "NoSuchBucketPolicy" errCodeNoSuchConfiguration = "NoSuchConfiguration" ErrCodeNoSuchCORSConfiguration = "NoSuchCORSConfiguration" ErrCodeNoSuchLifecycleConfiguration = "NoSuchLifecycleConfiguration" + errCodeNoSuchKey = "NoSuchKey" ErrCodeNoSuchPublicAccessBlockConfiguration = "NoSuchPublicAccessBlockConfiguration" errCodeNoSuchTagSet = "NoSuchTagSet" errCodeNoSuchTagSetError = "NoSuchTagSetError" diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 6a8176a3c7e..6edbf4be948 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -26,7 +26,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/enum" - "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/service/kms" @@ -602,7 +601,7 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.Client, bucketName, k for pages.HasMorePages() { page, err := pages.NextPage(ctx) - if errs.IsA[*types.NoSuchBucket](err) { + if tfawserr.ErrCodeEquals(err, errCodeNoSuchBucket) { break } @@ -693,7 +692,7 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.Client, bucketName, k for pages.HasMorePages() { page, err := pages.NextPage(ctx) - if errs.IsA[*types.NoSuchBucket](err) { + if tfawserr.ErrCodeEquals(err, errCodeNoSuchBucket) { break } @@ -753,7 +752,7 @@ func deleteObjectVersion(ctx context.Context, conn *s3.Client, b, k, v string, f log.Printf("[WARN] Deleting S3 Bucket (%s) Object (%s) Version (%s): %s", b, k, v, err) } - if errs.IsA[*types.NoSuchBucket](err) || errs.IsA[*types.NoSuchKey](err) { + if tfawserr.ErrCodeEquals(err, errCodeNoSuchBucket, errCodeNoSuchKey) { return nil } From 457bda21743be46e092f70309cde5dfa866c6896 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 15:03:13 -0400 Subject: [PATCH 10/61] resourceObjectRead: Remove retry as there is now strong read-after-write consistency for PUT and DELETE requests of objects. --- internal/service/s3/bucket_object.go | 3 +++ internal/service/s3/object.go | 10 +--------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/internal/service/s3/bucket_object.go b/internal/service/s3/bucket_object.go index 09b4dd4d36e..e7c707ba33f 100644 --- a/internal/service/s3/bucket_object.go +++ b/internal/service/s3/bucket_object.go @@ -206,6 +206,9 @@ func resourceBucketObjectCreate(ctx context.Context, d *schema.ResourceData, met } func resourceBucketObjectRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + const ( + objectCreationTimeout = 2 * time.Minute + ) var diags diag.Diagnostics conn := meta.(*conns.AWSClient).S3Conn(ctx) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 6edbf4be948..458c9f9c330 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -36,8 +36,6 @@ import ( "github.com/mitchellh/go-homedir" ) -const objectCreationTimeout = 2 * time.Minute - // @SDKResource("aws_s3_object", name="Object") // @Tags func ResourceObject() *schema.Resource { @@ -205,11 +203,7 @@ func resourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interf bucket := d.Get("bucket").(string) key := d.Get("key").(string) - // TODO Is this retry still necessary with strong read-after-write consistency for PUT and DELETE requests of objects? - // https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html#ConsistencyModel. - outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, objectCreationTimeout, func() (interface{}, error) { - return FindObjectByThreePartKey(ctx, conn, bucket, key, "") - }, d.IsNewResource()) + output, err := FindObjectByThreePartKey(ctx, conn, bucket, key, "") if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] S3 Object (%s) not found, removing from state", d.Id()) @@ -221,8 +215,6 @@ func resourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interf return sdkdiag.AppendErrorf(diags, "reading S3 Object (%s): %s", d.Id(), err) } - output := outputRaw.(*s3.HeadObjectOutput) - d.Set("bucket_key_enabled", output.BucketKeyEnabled) d.Set("cache_control", output.CacheControl) d.Set("content_disposition", output.ContentDisposition) From a2c8dbbf8831903f65e93a97a89e1621178fe3c8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 15:34:02 -0400 Subject: [PATCH 11/61] r/aws_s3_object: Migrate acceptance tests to AWS SDK for Go v2. --- .../s3/bucket_object_data_source_test.go | 24 +-- .../service/s3/object_data_source_test.go | 28 +-- internal/service/s3/object_test.go | 170 ++++++++---------- 3 files changed, 85 insertions(+), 137 deletions(-) diff --git a/internal/service/s3/bucket_object_data_source_test.go b/internal/service/s3/bucket_object_data_source_test.go index b12e172c472..ac54e24671b 100644 --- a/internal/service/s3/bucket_object_data_source_test.go +++ b/internal/service/s3/bucket_object_data_source_test.go @@ -38,7 +38,7 @@ func TestAccS3BucketObjectDataSource_basic(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_basic(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -71,9 +71,9 @@ func TestAccS3BucketObjectDataSource_basicViaAccessPoint(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_basicViaAccessPoint(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), resource.TestCheckResourceAttrPair(dataSourceName, "bucket", accessPointResourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "key", resourceName, "key"), ), @@ -101,7 +101,7 @@ func TestAccS3BucketObjectDataSource_readableBody(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_readableBody(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -136,7 +136,7 @@ func TestAccS3BucketObjectDataSource_kmsEncrypted(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_kmsEncrypted(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -173,7 +173,7 @@ func TestAccS3BucketObjectDataSource_bucketKeyEnabled(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_keyEnabled(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -211,7 +211,7 @@ func TestAccS3BucketObjectDataSource_allParams(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_allParams(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "25"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -263,7 +263,7 @@ func TestAccS3BucketObjectDataSource_objectLockLegalHoldOff(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_lockLegalHoldOff(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -299,7 +299,7 @@ func TestAccS3BucketObjectDataSource_objectLockLegalHoldOn(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_lockLegalHoldOn(rInt, retainUntilDate), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -337,7 +337,7 @@ func TestAccS3BucketObjectDataSource_leadingSlash(t *testing.T) { { // nosemgrep:ci.test-config-funcs-correct-form Config: resourceOnlyConf, Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), + testAccCheckBucketObjectExists(ctx, resourceName, &rObj), ), }, { // nosemgrep:ci.test-config-funcs-correct-form @@ -392,8 +392,8 @@ func TestAccS3BucketObjectDataSource_multipleSlashes(t *testing.T) { { // nosemgrep:ci.test-config-funcs-correct-form Config: resourceOnlyConf, Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName1, &rObj1), - testAccCheckObjectExists(ctx, resourceName2, &rObj2), + testAccCheckBucketObjectExists(ctx, resourceName1, &rObj1), + testAccCheckBucketObjectExists(ctx, resourceName2, &rObj2), ), }, { // nosemgrep:ci.test-config-funcs-correct-form diff --git a/internal/service/s3/object_data_source_test.go b/internal/service/s3/object_data_source_test.go index 68b5a4f957e..c465212f624 100644 --- a/internal/service/s3/object_data_source_test.go +++ b/internal/service/s3/object_data_source_test.go @@ -25,7 +25,6 @@ func TestAccS3ObjectDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput var dsObj s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -40,7 +39,6 @@ func TestAccS3ObjectDataSource_basic(t *testing.T) { { Config: testAccObjectDataSourceConfig_basic(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -58,9 +56,10 @@ func TestAccS3ObjectDataSource_basic(t *testing.T) { func TestAccS3ObjectDataSource_basicViaAccessPoint(t *testing.T) { ctx := acctest.Context(t) - var dsObj, rObj s3.GetObjectOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var dsObj s3.GetObjectOutput + dataSourceName := "data.aws_s3_object.test" resourceName := "aws_s3_object.test" accessPointResourceName := "aws_s3_access_point.test" @@ -73,9 +72,7 @@ func TestAccS3ObjectDataSource_basicViaAccessPoint(t *testing.T) { { Config: testAccObjectDataSourceConfig_basicViaAccessPoint(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), - testAccCheckObjectExists(ctx, resourceName, &rObj), resource.TestCheckResourceAttrPair(dataSourceName, "bucket", accessPointResourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "key", resourceName, "key"), ), @@ -88,7 +85,6 @@ func TestAccS3ObjectDataSource_readableBody(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput var dsObj s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -103,7 +99,6 @@ func TestAccS3ObjectDataSource_readableBody(t *testing.T) { { Config: testAccObjectDataSourceConfig_readableBody(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -123,7 +118,6 @@ func TestAccS3ObjectDataSource_kmsEncrypted(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput var dsObj s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -138,7 +132,6 @@ func TestAccS3ObjectDataSource_kmsEncrypted(t *testing.T) { { Config: testAccObjectDataSourceConfig_kmsEncrypted(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -160,7 +153,6 @@ func TestAccS3ObjectDataSource_bucketKeyEnabled(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput var dsObj s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -175,7 +167,6 @@ func TestAccS3ObjectDataSource_bucketKeyEnabled(t *testing.T) { { Config: testAccObjectDataSourceConfig_bucketKeyEnabled(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -198,7 +189,6 @@ func TestAccS3ObjectDataSource_allParams(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput var dsObj s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -213,7 +203,6 @@ func TestAccS3ObjectDataSource_allParams(t *testing.T) { { Config: testAccObjectDataSourceConfig_allParams(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "25"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -250,7 +239,6 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOff(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput var dsObj s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -265,7 +253,6 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOff(t *testing.T) { { Config: testAccObjectDataSourceConfig_lockLegalHoldOff(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -286,7 +273,6 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { rInt := sdkacctest.RandInt() retainUntilDate := time.Now().UTC().AddDate(0, 0, 10).Format(time.RFC3339) - var rObj s3.GetObjectOutput var dsObj s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -301,7 +287,6 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { { Config: testAccObjectDataSourceConfig_lockLegalHoldOn(rInt, retainUntilDate), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), @@ -319,7 +304,6 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { ctx := acctest.Context(t) - var rObj s3.GetObjectOutput var dsObj1, dsObj2, dsObj3 s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -338,9 +322,6 @@ func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { Steps: []resource.TestStep{ { // nosemgrep:ci.test-config-funcs-correct-form Config: resourceOnlyConf, - Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName, &rObj), - ), }, { // nosemgrep:ci.test-config-funcs-correct-form Config: conf, @@ -373,7 +354,6 @@ func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { ctx := acctest.Context(t) - var rObj1, rObj2 s3.GetObjectOutput var dsObj1, dsObj2, dsObj3 s3.GetObjectOutput resourceName1 := "aws_s3_object.object1" @@ -393,10 +373,6 @@ func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { Steps: []resource.TestStep{ { // nosemgrep:ci.test-config-funcs-correct-form Config: resourceOnlyConf, - Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExists(ctx, resourceName1, &rObj1), - testAccCheckObjectExists(ctx, resourceName2, &rObj2), - ), }, { // nosemgrep:ci.test-config-funcs-correct-form Config: conf, diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index 5938148210f..69770ae2418 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -15,10 +15,9 @@ import ( "time" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -27,6 +26,7 @@ import ( tfs3 "github.com/hashicorp/terraform-provider-aws/internal/service/s3" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" ) func TestAccS3Object_noNameNoKey(t *testing.T) { @@ -36,7 +36,7 @@ func TestAccS3Object_noNameNoKey(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -62,7 +62,7 @@ func TestAccS3Object_empty(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -93,7 +93,7 @@ func TestAccS3Object_upgradeFromV4(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { @@ -128,7 +128,7 @@ func TestAccS3Object_source(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -158,7 +158,7 @@ func TestAccS3Object_content(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -191,7 +191,7 @@ func TestAccS3Object_etagEncryption(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -223,7 +223,7 @@ func TestAccS3Object_contentBase64(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -261,7 +261,7 @@ func TestAccS3Object_sourceHashTrigger(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -307,7 +307,7 @@ func TestAccS3Object_withContentCharacteristics(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -334,7 +334,7 @@ func TestAccS3Object_nonVersioned(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckAssumeRoleARN(t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -370,7 +370,7 @@ func TestAccS3Object_updates(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -429,7 +429,7 @@ func TestAccS3Object_updateSameFile(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -468,7 +468,7 @@ func TestAccS3Object_updatesWithVersioning(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -514,7 +514,7 @@ func TestAccS3Object_updatesWithVersioningViaAccessPoint(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -551,7 +551,7 @@ func TestAccS3Object_kms(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -586,7 +586,7 @@ func TestAccS3Object_sse(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -618,36 +618,36 @@ func TestAccS3Object_acl(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccObjectConfig_acl(rName, "some_bucket_content", s3.BucketCannedACLPrivate, true), + Config: testAccObjectConfig_acl(rName, "some_bucket_content", string(types.BucketCannedACLPrivate), true), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj1), testAccCheckObjectBody(&obj1, "some_bucket_content"), - resource.TestCheckResourceAttr(resourceName, "acl", s3.BucketCannedACLPrivate), + resource.TestCheckResourceAttr(resourceName, "acl", string(types.BucketCannedACLPrivate)), testAccCheckObjectACL(ctx, resourceName, []string{"FULL_CONTROL"}), ), }, { - Config: testAccObjectConfig_acl(rName, "some_bucket_content", s3.BucketCannedACLPublicRead, false), + Config: testAccObjectConfig_acl(rName, "some_bucket_content", string(types.BucketCannedACLPublicRead), false), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), testAccCheckObjectVersionIdEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "some_bucket_content"), - resource.TestCheckResourceAttr(resourceName, "acl", s3.BucketCannedACLPublicRead), + resource.TestCheckResourceAttr(resourceName, "acl", string(types.BucketCannedACLPublicRead)), testAccCheckObjectACL(ctx, resourceName, []string{"FULL_CONTROL", "READ"}), ), }, { - Config: testAccObjectConfig_acl(rName, "changed_some_bucket_content", s3.BucketCannedACLPrivate, true), + Config: testAccObjectConfig_acl(rName, "changed_some_bucket_content", string(types.BucketCannedACLPrivate), true), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), testAccCheckObjectVersionIdDiffers(&obj3, &obj2), testAccCheckObjectBody(&obj3, "changed_some_bucket_content"), - resource.TestCheckResourceAttr(resourceName, "acl", s3.BucketCannedACLPrivate), + resource.TestCheckResourceAttr(resourceName, "acl", string(types.BucketCannedACLPrivate)), testAccCheckObjectACL(ctx, resourceName, []string{"FULL_CONTROL"}), ), }, @@ -670,7 +670,7 @@ func TestAccS3Object_metadata(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -718,7 +718,7 @@ func TestAccS3Object_storageClass(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -783,7 +783,7 @@ func TestAccS3Object_tags(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -856,7 +856,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -929,7 +929,7 @@ func TestAccS3Object_tagsLeadingMultipleSlashes(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -995,7 +995,7 @@ func TestAccS3Object_tagsMultipleSlashes(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1060,7 +1060,7 @@ func TestAccS3Object_objectLockLegalHoldStartWithNone(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1109,7 +1109,7 @@ func TestAccS3Object_objectLockLegalHoldStartWithOn(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1147,7 +1147,7 @@ func TestAccS3Object_objectLockRetentionStartWithNone(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1199,7 +1199,7 @@ func TestAccS3Object_objectLockRetentionStartWithSet(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1258,7 +1258,7 @@ func TestAccS3Object_objectBucketKeyEnabled(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1282,7 +1282,7 @@ func TestAccS3Object_bucketBucketKeyEnabled(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1306,7 +1306,7 @@ func TestAccS3Object_defaultBucketSSE(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1330,7 +1330,7 @@ func TestAccS3Object_ignoreTags(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ @@ -1376,10 +1376,10 @@ func TestAccS3Object_ignoreTags(t *testing.T) { func testAccCheckObjectVersionIdDiffers(first, second *s3.GetObjectOutput) resource.TestCheckFunc { return func(s *terraform.State) error { if first.VersionId == nil { - return fmt.Errorf("Expected first object to have VersionId: %s", first) + return fmt.Errorf("Expected first object to have VersionId: %v", first) } if second.VersionId == nil { - return fmt.Errorf("Expected second object to have VersionId: %s", second) + return fmt.Errorf("Expected second object to have VersionId: %v", second) } if *first.VersionId == *second.VersionId { @@ -1393,10 +1393,10 @@ func testAccCheckObjectVersionIdDiffers(first, second *s3.GetObjectOutput) resou func testAccCheckObjectVersionIdEquals(first, second *s3.GetObjectOutput) resource.TestCheckFunc { return func(s *terraform.State) error { if first.VersionId == nil { - return fmt.Errorf("Expected first object to have VersionId: %s", first) + return fmt.Errorf("Expected first object to have VersionId: %v", first) } if second.VersionId == nil { - return fmt.Errorf("Expected second object to have VersionId: %s", second) + return fmt.Errorf("Expected second object to have VersionId: %v", second) } if *first.VersionId != *second.VersionId { @@ -1409,14 +1409,14 @@ func testAccCheckObjectVersionIdEquals(first, second *s3.GetObjectOutput) resour func testAccCheckObjectDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_s3_object" { continue } - _, err := tfs3.FindObjectByThreePartKeyV1(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"]) + _, err := tfs3.FindObjectByThreePartKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"]) if tfresource.NotFound(err) { continue @@ -1433,18 +1433,14 @@ func testAccCheckObjectDestroy(ctx context.Context) resource.TestCheckFunc { } } -func testAccCheckObjectExists(ctx context.Context, n string, obj *s3.GetObjectOutput) resource.TestCheckFunc { +func testAccCheckObjectExists(ctx context.Context, n string, v *s3.GetObjectOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not Found: %s", n) } - if rs.Primary.ID == "" { - return fmt.Errorf("No S3 Object ID is set") - } - - conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) input := &s3.GetObjectInput{ Bucket: aws.String(rs.Primary.Attributes["bucket"]), @@ -1452,33 +1448,13 @@ func testAccCheckObjectExists(ctx context.Context, n string, obj *s3.GetObjectOu IfMatch: aws.String(rs.Primary.Attributes["etag"]), } - var out *s3.GetObjectOutput - - err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError { - var err error - out, err = conn.GetObjectWithContext(ctx, input) - - if tfawserr.ErrCodeEquals(err, s3.ErrCodeNoSuchKey) { - return retry.RetryableError( - fmt.Errorf("getting object %s, retrying: %w", rs.Primary.Attributes["bucket"], err), - ) - } - - if err != nil { - return retry.NonRetryableError(err) - } - - return nil - }) - if tfresource.TimedOut(err) { - out, err = conn.GetObjectWithContext(ctx, input) - } + output, err := conn.GetObject(ctx, input) if err != nil { - return fmt.Errorf("S3 Object error: %s", err) + return err } - *obj = *out + *v = *output return nil } @@ -1503,20 +1479,20 @@ func testAccCheckObjectBody(obj *s3.GetObjectOutput, want string) resource.TestC func testAccCheckObjectACL(ctx context.Context, n string, expectedPerms []string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] - conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - out, err := conn.GetObjectAclWithContext(ctx, &s3.GetObjectAclInput{ + output, err := conn.GetObjectAcl(ctx, &s3.GetObjectAclInput{ Bucket: aws.String(rs.Primary.Attributes["bucket"]), Key: aws.String(rs.Primary.Attributes["key"]), }) if err != nil { - return fmt.Errorf("GetObjectAcl error: %v", err) + return err } var perms []string - for _, v := range out.Grants { - perms = append(perms, *v.Permission) + for _, v := range output.Grants { + perms = append(perms, string(v.Permission)) } sort.Strings(perms) @@ -1531,9 +1507,9 @@ func testAccCheckObjectACL(ctx context.Context, n string, expectedPerms []string func testAccCheckObjectStorageClass(ctx context.Context, n, expectedClass string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] - conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - out, err := tfs3.FindObjectByThreePartKeyV1(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "") + output, err := tfs3.FindObjectByThreePartKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "") if err != nil { return err @@ -1541,12 +1517,12 @@ func testAccCheckObjectStorageClass(ctx context.Context, n, expectedClass string // The "STANDARD" (which is also the default) storage // class when set would not be included in the results. - storageClass := s3.StorageClassStandard - if out.StorageClass != nil { - storageClass = *out.StorageClass + storageClass := types.StorageClassStandard + if output.StorageClass != "" { + storageClass = output.StorageClass } - if storageClass != expectedClass { + if string(storageClass) != expectedClass { return fmt.Errorf("Expected Storage Class to be %v, got %v", expectedClass, storageClass) } @@ -1558,20 +1534,16 @@ func testAccCheckObjectStorageClass(ctx context.Context, n, expectedClass string func testAccCheckObjectSSE(ctx context.Context, n, expectedSSE string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] - conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - out, err := tfs3.FindObjectByThreePartKeyV1(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "") + output, err := tfs3.FindObjectByThreePartKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "") if err != nil { return err } - if out.ServerSideEncryption == nil { - return fmt.Errorf("Expected a non %v Server Side Encryption.", out.ServerSideEncryption) - } - - sse := *out.ServerSideEncryption - if sse != expectedSSE { + sse := output.ServerSideEncryption + if string(sse) != expectedSSE { return fmt.Errorf("Expected Server Side Encryption %v, got %v.", expectedSSE, sse) } @@ -1599,18 +1571,18 @@ func testAccObjectCreateTempFile(t *testing.T, data string) string { func testAccCheckObjectUpdateTagsV1(ctx context.Context, n string, oldTags, newTags map[string]string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] - conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - return tfs3.ObjectUpdateTagsV1(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], oldTags, newTags) + return tfs3.ObjectUpdateTags(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], oldTags, newTags) } } func testAccCheckObjectCheckTags(ctx context.Context, n string, expectedTags map[string]string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] - conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - got, err := tfs3.ObjectListTagsV1(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"]) + got, err := tfs3.ObjectListTags(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"]) if err != nil { return err } From 702161d8245af4cf20c547e6fb8d701065ea9e37 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 15:41:11 -0400 Subject: [PATCH 12/61] Use 'cmp.Diff', not 'reflect.DeppEqual'. --- internal/service/s3/object_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index 69770ae2418..09b379d8d90 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "os" - "reflect" "sort" "testing" "time" @@ -18,6 +17,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/google/go-cmp/cmp" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -1496,8 +1496,8 @@ func testAccCheckObjectACL(ctx context.Context, n string, expectedPerms []string } sort.Strings(perms) - if !reflect.DeepEqual(perms, expectedPerms) { - return fmt.Errorf("Expected ACL permissions to be %v, got %v", expectedPerms, perms) + if diff := cmp.Diff(perms, expectedPerms); diff != "" { + return fmt.Errorf("unexpected diff (+wanted, -got): %s", diff) } return nil @@ -1588,8 +1588,8 @@ func testAccCheckObjectCheckTags(ctx context.Context, n string, expectedTags map } want := tftags.New(ctx, expectedTags) - if !reflect.DeepEqual(want, got) { - return fmt.Errorf("Incorrect tags, want: %v got: %v", want, got) + if diff := cmp.Diff(got, want); diff != "" { + return fmt.Errorf("unexpected diff (+wanted, -got): %s", diff) } return nil From 74955e1c7ed07adf89f10d8725955e7f24412fd4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 16:33:47 -0400 Subject: [PATCH 13/61] s3: Fix sweepers. --- internal/service/s3/sweep.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/service/s3/sweep.go b/internal/service/s3/sweep.go index b5c1fc95e4d..18ad73bf62f 100644 --- a/internal/service/s3/sweep.go +++ b/internal/service/s3/sweep.go @@ -14,6 +14,7 @@ import ( "time" "github.com/YakDriver/regexache" + s3_sdkv2 "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/service/s3" @@ -50,6 +51,7 @@ func sweepObjects(region string) error { } conn := client.S3ConnURICleaningDisabled(ctx) + connV2 := client.S3Client(ctx) input := &s3.ListBucketsInput{} output, err := conn.ListBucketsWithContext(ctx, input) @@ -89,7 +91,7 @@ func sweepObjects(region string) error { } sweepables = append(sweepables, objectSweeper{ - conn: conn, + conn: connV2, name: bucketName, locked: objectLockEnabled, }) @@ -103,7 +105,7 @@ func sweepObjects(region string) error { } type objectSweeper struct { - conn *s3.S3 + conn *s3_sdkv2.Client name string locked bool } From 8fd99e98d79ef10936f92959ffbaba8845128188 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 7 Sep 2023 16:35:05 -0400 Subject: [PATCH 14/61] Fix golangci-lint 'ineffassign'. --- internal/service/s3/object.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 458c9f9c330..9da4b304319 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -715,8 +715,6 @@ func DeleteAllObjectVersions(ctx context.Context, conn *s3.Client, bucketName, k if !ignoreObjectErrors { return nObjects, fmt.Errorf("deleting at least one S3 Object delete marker, last error: %w", lastErr) } - - lastErr = nil } return nObjects, nil From c70217102f7932849a58f1518d818b7382e51a85 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 09:37:31 -0400 Subject: [PATCH 15/61] s3: 'DeleteAllObjectVersions' -> 'deleteAllObjectVersions'. --- internal/service/s3/bucket_object.go | 2 +- internal/service/s3/exports_test.go | 9 +++++++++ internal/service/s3/object.go | 6 +++--- internal/service/s3/object_copy.go | 2 +- internal/service/s3/sweep.go | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 internal/service/s3/exports_test.go diff --git a/internal/service/s3/bucket_object.go b/internal/service/s3/bucket_object.go index e7c707ba33f..bc696e299e6 100644 --- a/internal/service/s3/bucket_object.go +++ b/internal/service/s3/bucket_object.go @@ -373,7 +373,7 @@ func resourceBucketObjectDelete(ctx context.Context, d *schema.ResourceData, met var err error if _, ok := d.GetOk("version_id"); ok { - _, err = DeleteAllObjectVersions(ctx, conn, bucket, key, d.Get("force_destroy").(bool), false) + _, err = deleteAllObjectVersions(ctx, conn, bucket, key, d.Get("force_destroy").(bool), false) } else { err = deleteObjectVersion(ctx, conn, bucket, key, "", false) } diff --git a/internal/service/s3/exports_test.go b/internal/service/s3/exports_test.go new file mode 100644 index 00000000000..42f33b00ce5 --- /dev/null +++ b/internal/service/s3/exports_test.go @@ -0,0 +1,9 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package s3 + +// Exports for use in tests only. +var ( + DeleteAllObjectVersions = deleteAllObjectVersions +) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 9da4b304319..e1cddcde9c2 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -344,7 +344,7 @@ func resourceObjectDelete(ctx context.Context, d *schema.ResourceData, meta inte var err error if _, ok := d.GetOk("version_id"); ok { - _, err = DeleteAllObjectVersions(ctx, conn, bucket, key, d.Get("force_destroy").(bool), false) + _, err = deleteAllObjectVersions(ctx, conn, bucket, key, d.Get("force_destroy").(bool), false) } else { err = deleteObjectVersion(ctx, conn, bucket, key, "", false) } @@ -573,11 +573,11 @@ func hasObjectContentChanges(d verify.ResourceDiffer) bool { return false } -// DeleteAllObjectVersions deletes all versions of a specified key from an S3 bucket. +// deleteAllObjectVersions deletes all versions of a specified key from an S3 bucket. // If key is empty then all versions of all objects are deleted. // Set force to true to override any S3 object lock protections on object lock enabled buckets. // Returns the number of objects deleted. -func DeleteAllObjectVersions(ctx context.Context, conn *s3.Client, bucketName, key string, force, ignoreObjectErrors bool) (int64, error) { +func deleteAllObjectVersions(ctx context.Context, conn *s3.Client, bucketName, key string, force, ignoreObjectErrors bool) (int64, error) { var nObjects int64 input := &s3.ListObjectVersionsInput{ diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index 62606ae9ae3..ce53c8f74a6 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -441,7 +441,7 @@ func resourceObjectCopyDelete(ctx context.Context, d *schema.ResourceData, meta var err error if _, ok := d.GetOk("version_id"); ok { - _, err = DeleteAllObjectVersions(ctx, conn, bucket, key, d.Get("force_destroy").(bool), false) + _, err = deleteAllObjectVersions(ctx, conn, bucket, key, d.Get("force_destroy").(bool), false) } else { err = deleteObjectVersion(ctx, conn, bucket, key, "", false) } diff --git a/internal/service/s3/sweep.go b/internal/service/s3/sweep.go index 18ad73bf62f..5fbb9465c0e 100644 --- a/internal/service/s3/sweep.go +++ b/internal/service/s3/sweep.go @@ -112,7 +112,7 @@ type objectSweeper struct { func (os objectSweeper) Delete(ctx context.Context, timeout time.Duration, optFns ...tfresource.OptionsFunc) error { // Delete everything including locked objects - _, err := DeleteAllObjectVersions(ctx, os.conn, os.name, "", os.locked, true) + _, err := deleteAllObjectVersions(ctx, os.conn, os.name, "", os.locked, true) if err != nil { return fmt.Errorf("deleting S3 Bucket (%s) contents: %w", os.name, err) } From 5428ce0faeee7018b04cbdf19bb6242b2656cb59 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 10:02:35 -0400 Subject: [PATCH 16/61] s3: 'FindObjectByThreePartKey' -> 'findObjectByThreePartKey'. --- internal/service/s3/exports_test.go | 3 ++- internal/service/s3/object.go | 2 +- internal/service/s3/object_copy.go | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/service/s3/exports_test.go b/internal/service/s3/exports_test.go index 42f33b00ce5..ed7faa779d8 100644 --- a/internal/service/s3/exports_test.go +++ b/internal/service/s3/exports_test.go @@ -5,5 +5,6 @@ package s3 // Exports for use in tests only. var ( - DeleteAllObjectVersions = deleteAllObjectVersions + DeleteAllObjectVersions = deleteAllObjectVersions + FindObjectByThreePartKey = findObjectByThreePartKey ) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index e1cddcde9c2..2c43ff00f65 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -203,7 +203,7 @@ func resourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interf bucket := d.Get("bucket").(string) key := d.Get("key").(string) - output, err := FindObjectByThreePartKey(ctx, conn, bucket, key, "") + output, err := findObjectByThreePartKey(ctx, conn, bucket, key, "") if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] S3 Object (%s) not found, removing from state", d.Id()) diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index ce53c8f74a6..a674f2d69ce 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -316,7 +316,7 @@ func resourceObjectCopyRead(ctx context.Context, d *schema.ResourceData, meta in bucket := d.Get("bucket").(string) key := d.Get("key").(string) - output, err := FindObjectByThreePartKey(ctx, conn, bucket, key, "") + output, err := findObjectByThreePartKey(ctx, conn, bucket, key, "") if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] S3 Object (%s) not found, removing from state", d.Id()) @@ -625,7 +625,7 @@ func resourceObjectCopyDoCopy(ctx context.Context, d *schema.ResourceData, meta return append(diags, resourceObjectCopyRead(ctx, d, meta)...) } -func FindObjectByThreePartKey(ctx context.Context, conn *s3.Client, bucket, key, etag string) (*s3.HeadObjectOutput, error) { +func findObjectByThreePartKey(ctx context.Context, conn *s3.Client, bucket, key, etag string) (*s3.HeadObjectOutput, error) { input := &s3.HeadObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), From 1e9cd4a25a82cace948e23a1ce4cf7a76167b6c3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 11:00:52 -0400 Subject: [PATCH 17/61] Add 'findObject'. --- internal/service/s3/object_copy.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index a674f2d69ce..aabc83c36b6 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -634,6 +634,10 @@ func findObjectByThreePartKey(ctx context.Context, conn *s3.Client, bucket, key, input.IfMatch = aws.String(etag) } + return findObject(ctx, conn, input) +} + +func findObject(ctx context.Context, conn *s3.Client, input *s3.HeadObjectInput) (*s3.HeadObjectOutput, error) { output, err := conn.HeadObject(ctx, input) if tfawserr.ErrHTTPStatusCodeEquals(err, http.StatusNotFound) { From 452c073a2f1e48c0cca75afe65b67cf5d8e34bb0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 11:14:22 -0400 Subject: [PATCH 18/61] r/aws_s3_object: Add `checksum_algorithm` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes. --- .changelog/33358.txt | 3 +++ internal/service/s3/exports_test.go | 2 +- internal/service/s3/object.go | 32 ++++++++++++++++++++++++- internal/service/s3/object_copy.go | 7 ++++-- internal/service/s3/object_copy_test.go | 4 ++-- internal/service/s3/object_test.go | 6 ++--- website/docs/r/s3_object.html.markdown | 5 ++++ 7 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 .changelog/33358.txt diff --git a/.changelog/33358.txt b/.changelog/33358.txt new file mode 100644 index 00000000000..51aea8f4f5f --- /dev/null +++ b/.changelog/33358.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_s3_object: Add `checksum_algorithm` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes +``` \ No newline at end of file diff --git a/internal/service/s3/exports_test.go b/internal/service/s3/exports_test.go index ed7faa779d8..15c502515b9 100644 --- a/internal/service/s3/exports_test.go +++ b/internal/service/s3/exports_test.go @@ -6,5 +6,5 @@ package s3 // Exports for use in tests only. var ( DeleteAllObjectVersions = deleteAllObjectVersions - FindObjectByThreePartKey = findObjectByThreePartKey + FindObjectByBucketAndKey = findObjectByBucketAndKey ) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 2c43ff00f65..1b16027e620 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -76,6 +76,27 @@ func ResourceObject() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "checksum_algorithm": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.ChecksumAlgorithm](), + }, + "checksum_crc32": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_crc32c": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_sha1": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_sha256": { + Type: schema.TypeString, + Computed: true, + }, "content": { Type: schema.TypeString, Optional: true, @@ -203,7 +224,7 @@ func resourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interf bucket := d.Get("bucket").(string) key := d.Get("key").(string) - output, err := findObjectByThreePartKey(ctx, conn, bucket, key, "") + output, err := findObjectByBucketAndKey(ctx, conn, bucket, key, "", d.Get("checksum_algorithm").(string)) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] S3 Object (%s) not found, removing from state", d.Id()) @@ -217,6 +238,10 @@ func resourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interf d.Set("bucket_key_enabled", output.BucketKeyEnabled) d.Set("cache_control", output.CacheControl) + d.Set("checksum_crc32", output.ChecksumCRC32) + d.Set("checksum_crc32c", output.ChecksumCRC32C) + d.Set("checksum_sha1", output.ChecksumSHA1) + d.Set("checksum_sha256", output.ChecksumSHA256) d.Set("content_disposition", output.ContentDisposition) d.Set("content_encoding", output.ContentEncoding) d.Set("content_language", output.ContentLanguage) @@ -438,6 +463,10 @@ func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta inte input.CacheControl = aws.String(v.(string)) } + if v, ok := d.GetOk("checksum_algorithm"); ok { + input.ChecksumAlgorithm = types.ChecksumAlgorithm(v.(string)) + } + if v, ok := d.GetOk("content_disposition"); ok { input.ContentDisposition = aws.String(v.(string)) } @@ -551,6 +580,7 @@ func hasObjectContentChanges(d verify.ResourceDiffer) bool { for _, key := range []string{ "bucket_key_enabled", "cache_control", + "checksum_algorithm", "content_base64", "content_disposition", "content_encoding", diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index aabc83c36b6..fcce5725031 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -316,7 +316,7 @@ func resourceObjectCopyRead(ctx context.Context, d *schema.ResourceData, meta in bucket := d.Get("bucket").(string) key := d.Get("key").(string) - output, err := findObjectByThreePartKey(ctx, conn, bucket, key, "") + output, err := findObjectByBucketAndKey(ctx, conn, bucket, key, "", "") if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] S3 Object (%s) not found, removing from state", d.Id()) @@ -625,11 +625,14 @@ func resourceObjectCopyDoCopy(ctx context.Context, d *schema.ResourceData, meta return append(diags, resourceObjectCopyRead(ctx, d, meta)...) } -func findObjectByThreePartKey(ctx context.Context, conn *s3.Client, bucket, key, etag string) (*s3.HeadObjectOutput, error) { +func findObjectByBucketAndKey(ctx context.Context, conn *s3.Client, bucket, key, etag, checksumAlgorithm string) (*s3.HeadObjectOutput, error) { input := &s3.HeadObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), } + if checksumAlgorithm != "" { + input.ChecksumMode = types.ChecksumModeEnabled + } if etag != "" { input.IfMatch = aws.String(etag) } diff --git a/internal/service/s3/object_copy_test.go b/internal/service/s3/object_copy_test.go index 1506fc95338..25e5050cf00 100644 --- a/internal/service/s3/object_copy_test.go +++ b/internal/service/s3/object_copy_test.go @@ -306,7 +306,7 @@ func testAccCheckObjectCopyDestroy(ctx context.Context) resource.TestCheckFunc { continue } - _, err := tfs3.FindObjectByThreePartKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"]) + _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"], "") if tfresource.NotFound(err) { continue @@ -332,7 +332,7 @@ func testAccCheckObjectCopyExists(ctx context.Context, n string) resource.TestCh conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - _, err := tfs3.FindObjectByThreePartKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"]) + _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"], "") return err } diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index 09b379d8d90..2d794ef0338 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -1416,7 +1416,7 @@ func testAccCheckObjectDestroy(ctx context.Context) resource.TestCheckFunc { continue } - _, err := tfs3.FindObjectByThreePartKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"]) + _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"], rs.Primary.Attributes["checksum_algorithm"]) if tfresource.NotFound(err) { continue @@ -1509,7 +1509,7 @@ func testAccCheckObjectStorageClass(ctx context.Context, n, expectedClass string rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - output, err := tfs3.FindObjectByThreePartKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "") + output, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "", "") if err != nil { return err @@ -1536,7 +1536,7 @@ func testAccCheckObjectSSE(ctx context.Context, n, expectedSSE string) resource. rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - output, err := tfs3.FindObjectByThreePartKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "") + output, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "", "") if err != nil { return err diff --git a/website/docs/r/s3_object.html.markdown b/website/docs/r/s3_object.html.markdown index fe982bc9e11..9bb45d8f794 100644 --- a/website/docs/r/s3_object.html.markdown +++ b/website/docs/r/s3_object.html.markdown @@ -143,6 +143,7 @@ The following arguments are optional: * `acl` - (Optional) [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) to apply. Valid values are `private`, `public-read`, `public-read-write`, `aws-exec-read`, `authenticated-read`, `bucket-owner-read`, and `bucket-owner-full-control`. * `bucket_key_enabled` - (Optional) Whether or not to use [Amazon S3 Bucket Keys](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html) for SSE-KMS. * `cache_control` - (Optional) Caching behavior along the request/reply chain Read [w3c cache_control](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) for further details. +* `checksum_algorithm` - (Optional) Indicates the algorithm used to create the checksum for the object. If a value is specified and the object is encrypted with KMS, you must have permission to use the `kms:Decrypt` action. Valid values: `CRC32`, `CRC32C`, `SHA1`, `SHA256`. * `content_base64` - (Optional, conflicts with `source` and `content`) Base64-encoded data that will be decoded and uploaded as raw bytes for the object content. This allows safely uploading non-UTF8 binary data, but is recommended only for small content such as the result of the `gzipbase64` function with small text strings. For larger objects, use `source` to stream the content from a disk file. * `content_disposition` - (Optional) Presentational information for the object. Read [w3c content_disposition](http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1) for further information. * `content_encoding` - (Optional) Content encodings that have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. Read [w3c content encoding](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11) for further information. @@ -171,6 +172,10 @@ If no content is provided through `source`, `content` or `content_base64`, then This resource exports the following attributes in addition to the arguments above: +* `checksum_crc32` - The base64-encoded, 32-bit CRC32 checksum of the object. +* `checksum_crc32c` - The base64-encoded, 32-bit CRC32C checksum of the object. +* `checksum_sha1` - The base64-encoded, 160-bit SHA-1 digest of the object. +* `checksum_sha256` - The base64-encoded, 256-bit SHA-256 digest of the object. * `etag` - ETag generated for the object (an MD5 sum of the object content). For plaintext objects or objects encrypted with an AWS-managed key, the hash is an MD5 digest of the object data. For objects encrypted with a KMS key or objects created by either the Multipart Upload or Part Copy operation, the hash is not an MD5 digest, regardless of the method of encryption. More information on possible values can be found on [Common Response Headers](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html). * `id` - `key` of the resource supplied above * `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). From d6a1f93e83ab69dc08b2da70bad2969064821a61 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 13:21:39 -0400 Subject: [PATCH 19/61] Enhance 'TestAccS3Object_basic'. --- internal/service/s3/object.go | 4 +- internal/service/s3/object_test.go | 154 ++++++++++++----------------- 2 files changed, 63 insertions(+), 95 deletions(-) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 1b16027e620..2d6e34fb9d5 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -159,9 +159,9 @@ func ResourceObject() *schema.Resource { }, "metadata": { Type: schema.TypeMap, - ValidateFunc: validateMetadataIsLowerCase, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, + ValidateFunc: validateMetadataIsLowerCase, }, "object_lock_legal_hold_status": { Type: schema.TypeString, @@ -181,8 +181,8 @@ func ResourceObject() *schema.Resource { "server_side_encryption": { Type: schema.TypeString, Optional: true, - ValidateDiagFunc: enum.Validate[types.ServerSideEncryption](), Computed: true, + ValidateDiagFunc: enum.Validate[types.ServerSideEncryption](), }, "source": { Type: schema.TypeString, diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index 2d794ef0338..ed00d0f8647 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -13,7 +13,6 @@ import ( "testing" "time" - "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" @@ -29,32 +28,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccS3Object_noNameNoKey(t *testing.T) { - ctx := acctest.Context(t) - bucketError := regexache.MustCompile(`bucket must not be empty`) - keyError := regexache.MustCompile(`key must not be empty`) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckObjectDestroy(ctx), - Steps: []resource.TestStep{ - { - PreConfig: func() {}, - Config: testAccObjectConfig_basic("", "a key"), - ExpectError: bucketError, - }, - { - PreConfig: func() {}, - Config: testAccObjectConfig_basic("a name", ""), - ExpectError: keyError, - }, - }, - }) -} - -func TestAccS3Object_empty(t *testing.T) { +func TestAccS3Object_basic(t *testing.T) { ctx := acctest.Context(t) var obj s3.GetObjectOutput resourceName := "aws_s3_object.object" @@ -67,11 +41,40 @@ func TestAccS3Object_empty(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_empty(rName), - Check: resource.ComposeTestCheckFunc( + Config: testAccObjectConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectBody(&obj, ""), + resource.TestCheckNoResourceAttr(resourceName, "acl"), + resource.TestCheckResourceAttr(resourceName, "bucket", rName), + resource.TestCheckResourceAttr(resourceName, "bucket_key_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "cache_control", ""), + resource.TestCheckNoResourceAttr(resourceName, "checksum_algorithm"), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32c", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha1", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha256", ""), + resource.TestCheckNoResourceAttr(resourceName, "content"), + resource.TestCheckNoResourceAttr(resourceName, "content_base64"), + resource.TestCheckResourceAttr(resourceName, "content_disposition", ""), + resource.TestCheckResourceAttr(resourceName, "content_encoding", ""), + resource.TestCheckResourceAttr(resourceName, "content_language", ""), + resource.TestCheckResourceAttr(resourceName, "content_type", "application/octet-stream"), + resource.TestCheckResourceAttrSet(resourceName, "etag"), + resource.TestCheckResourceAttr(resourceName, "force_destroy", "false"), + resource.TestCheckResourceAttr(resourceName, "key", "test-key"), + resource.TestCheckNoResourceAttr(resourceName, "kms_key_id"), + resource.TestCheckResourceAttr(resourceName, "metadata.%", "0"), + resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", ""), + resource.TestCheckResourceAttr(resourceName, "object_lock_mode", ""), + resource.TestCheckResourceAttr(resourceName, "object_lock_retain_until_date", ""), + resource.TestCheckResourceAttr(resourceName, "server_side_encryption", "AES256"), + resource.TestCheckNoResourceAttr(resourceName, "source"), + resource.TestCheckNoResourceAttr(resourceName, "source_hash"), + resource.TestCheckResourceAttr(resourceName, "storage_class", "STANDARD"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "version_id", ""), + resource.TestCheckResourceAttr(resourceName, "website_redirect", ""), ), }, { @@ -103,14 +106,14 @@ func TestAccS3Object_upgradeFromV4(t *testing.T) { VersionConstraint: "4.67.0", }, }, - Config: testAccObjectConfig_empty(rName), + Config: testAccObjectConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), ), }, { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - Config: testAccObjectConfig_empty(rName), + Config: testAccObjectConfig_basic(rName), PlanOnly: true, }, }, @@ -163,8 +166,7 @@ func TestAccS3Object_content(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_content(rName, "some_bucket_content"), + Config: testAccObjectConfig_content(rName, "some_bucket_content"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectBody(&obj, "some_bucket_content"), @@ -196,8 +198,7 @@ func TestAccS3Object_etagEncryption(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_etagEncryption(rName, source), + Config: testAccObjectConfig_etagEncryption(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectBody(&obj, "{anything will do }"), @@ -228,8 +229,7 @@ func TestAccS3Object_contentBase64(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_contentBase64(rName, base64.StdEncoding.EncodeToString([]byte("some_bucket_content"))), + Config: testAccObjectConfig_contentBase64(rName, base64.StdEncoding.EncodeToString([]byte("some_bucket_content"))), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectBody(&obj, "some_bucket_content"), @@ -266,8 +266,7 @@ func TestAccS3Object_sourceHashTrigger(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_sourceHashTrigger(rName, filename), + Config: testAccObjectConfig_sourceHashTrigger(rName, filename), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectBody(&obj, "Ebben!"), @@ -277,8 +276,7 @@ func TestAccS3Object_sourceHashTrigger(t *testing.T) { ExpectNonEmptyPlan: true, }, { - PreConfig: func() {}, - Config: testAccObjectConfig_sourceHashTrigger(rName, filename), + Config: testAccObjectConfig_sourceHashTrigger(rName, filename), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &updated_obj), testAccCheckObjectBody(&updated_obj, "Ne andrò lontana"), @@ -556,8 +554,7 @@ func TestAccS3Object_kms(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_kmsID(rName, source), + Config: testAccObjectConfig_kmsID(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectSSE(ctx, resourceName, "aws:kms"), @@ -591,8 +588,7 @@ func TestAccS3Object_sse(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_sse(rName, source), + Config: testAccObjectConfig_sse(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectSSE(ctx, resourceName, "AES256"), @@ -693,7 +689,7 @@ func TestAccS3Object_metadata(t *testing.T) { ), }, { - Config: testAccObjectConfig_empty(rName), + Config: testAccObjectConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "metadata.%", "0"), @@ -723,8 +719,7 @@ func TestAccS3Object_storageClass(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_content(rName, "some_bucket_content"), + Config: testAccObjectConfig_content(rName, "some_bucket_content"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "storage_class", "STANDARD"), @@ -788,8 +783,7 @@ func TestAccS3Object_tags(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_tags(rName, key, "stuff"), + Config: testAccObjectConfig_tags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj1), testAccCheckObjectBody(&obj1, "stuff"), @@ -800,8 +794,7 @@ func TestAccS3Object_tags(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), + Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), testAccCheckObjectVersionIdEquals(&obj2, &obj1), @@ -814,8 +807,7 @@ func TestAccS3Object_tags(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_noTags(rName, key, "stuff"), + Config: testAccObjectConfig_noTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), testAccCheckObjectVersionIdEquals(&obj3, &obj2), @@ -824,8 +816,7 @@ func TestAccS3Object_tags(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_tags(rName, key, "changed stuff"), + Config: testAccObjectConfig_tags(rName, key, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), testAccCheckObjectVersionIdDiffers(&obj4, &obj3), @@ -861,8 +852,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_tags(rName, key, "stuff"), + Config: testAccObjectConfig_tags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj1), testAccCheckObjectBody(&obj1, "stuff"), @@ -873,8 +863,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), + Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), testAccCheckObjectVersionIdEquals(&obj2, &obj1), @@ -887,8 +876,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_noTags(rName, key, "stuff"), + Config: testAccObjectConfig_noTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), testAccCheckObjectVersionIdEquals(&obj3, &obj2), @@ -897,8 +885,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_tags(rName, key, "changed stuff"), + Config: testAccObjectConfig_tags(rName, key, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), testAccCheckObjectVersionIdDiffers(&obj4, &obj3), @@ -934,8 +921,7 @@ func TestAccS3Object_tagsLeadingMultipleSlashes(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_tags(rName, key, "stuff"), + Config: testAccObjectConfig_tags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj1), testAccCheckObjectBody(&obj1, "stuff"), @@ -946,8 +932,7 @@ func TestAccS3Object_tagsLeadingMultipleSlashes(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), + Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), testAccCheckObjectVersionIdEquals(&obj2, &obj1), @@ -960,8 +945,7 @@ func TestAccS3Object_tagsLeadingMultipleSlashes(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_noTags(rName, key, "stuff"), + Config: testAccObjectConfig_noTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), testAccCheckObjectVersionIdEquals(&obj3, &obj2), @@ -970,8 +954,7 @@ func TestAccS3Object_tagsLeadingMultipleSlashes(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_tags(rName, key, "changed stuff"), + Config: testAccObjectConfig_tags(rName, key, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), testAccCheckObjectVersionIdDiffers(&obj4, &obj3), @@ -1000,8 +983,7 @@ func TestAccS3Object_tagsMultipleSlashes(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, - Config: testAccObjectConfig_tags(rName, key, "stuff"), + Config: testAccObjectConfig_tags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj1), testAccCheckObjectBody(&obj1, "stuff"), @@ -1012,8 +994,7 @@ func TestAccS3Object_tagsMultipleSlashes(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), + Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), testAccCheckObjectVersionIdEquals(&obj2, &obj1), @@ -1026,8 +1007,7 @@ func TestAccS3Object_tagsMultipleSlashes(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_noTags(rName, key, "stuff"), + Config: testAccObjectConfig_noTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), testAccCheckObjectVersionIdEquals(&obj3, &obj2), @@ -1036,8 +1016,7 @@ func TestAccS3Object_tagsMultipleSlashes(t *testing.T) { ), }, { - PreConfig: func() {}, - Config: testAccObjectConfig_tags(rName, key, "changed stuff"), + Config: testAccObjectConfig_tags(rName, key, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), testAccCheckObjectVersionIdDiffers(&obj4, &obj3), @@ -1335,7 +1314,6 @@ func TestAccS3Object_ignoreTags(t *testing.T) { CheckDestroy: testAccCheckObjectDestroy(ctx), Steps: []resource.TestStep{ { - PreConfig: func() {}, Config: acctest.ConfigCompose( acctest.ConfigIgnoreTagsKeyPrefixes1("ignorekey"), testAccObjectConfig_noTags(rName, key, "stuff")), @@ -1350,7 +1328,6 @@ func TestAccS3Object_ignoreTags(t *testing.T) { ), }, { - PreConfig: func() {}, Config: acctest.ConfigCompose( acctest.ConfigIgnoreTagsKeyPrefixes1("ignorekey"), testAccObjectConfig_tags(rName, key, "stuff")), @@ -1596,16 +1573,7 @@ func testAccCheckObjectCheckTags(ctx context.Context, n string, expectedTags map } } -func testAccObjectConfig_basic(bucket, key string) string { - return fmt.Sprintf(` -resource "aws_s3_object" "object" { - bucket = %[1]q - key = %[2]q -} -`, bucket, key) -} - -func testAccObjectConfig_empty(rName string) string { +func testAccObjectConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q From e30e3fb62ccdfe7942fcc08ff09bad3b25c2ed00 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 13:21:56 -0400 Subject: [PATCH 20/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3Object_basic' PKG=s3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 20 -run=TestAccS3Object_basic -timeout 180m === RUN TestAccS3Object_basic === PAUSE TestAccS3Object_basic === CONT TestAccS3Object_basic --- PASS: TestAccS3Object_basic (29.79s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 35.537s From 6f41bd4b407f66fd524b6aa1606397e563f6c268 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 13:42:42 -0400 Subject: [PATCH 21/61] Add 'TestAccS3Object_checksumAlgorithm'. --- internal/service/s3/object_test.go | 91 +++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index ed00d0f8647..19458f12948 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -81,7 +81,7 @@ func TestAccS3Object_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -146,7 +146,7 @@ func TestAccS3Object_source(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "source", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy", "source"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -176,7 +176,7 @@ func TestAccS3Object_content(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "content", "content_base64", "force_destroy"}, + ImportStateVerifyIgnore: []string{"content", "content_base64", "force_destroy"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -209,7 +209,7 @@ func TestAccS3Object_etagEncryption(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "source", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy", "source"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -287,7 +287,7 @@ func TestAccS3Object_sourceHashTrigger(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "content", "content_base64", "force_destroy", "source", "source_hash"}, + ImportStateVerifyIgnore: []string{"content", "content_base64", "force_destroy", "source", "source_hash"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -348,7 +348,7 @@ func TestAccS3Object_nonVersioned(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "source", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy", "source"}, ImportStateId: fmt.Sprintf("s3://%s/updateable-key", rName), }, }, @@ -398,7 +398,7 @@ func TestAccS3Object_updates(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "source", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy", "source"}, ImportStateId: fmt.Sprintf("s3://%s/updateable-key", rName), }, }, @@ -491,7 +491,7 @@ func TestAccS3Object_updatesWithVersioning(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "source", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy", "source"}, ImportStateId: fmt.Sprintf("s3://%s/updateable-key", rName), }, }, @@ -565,7 +565,7 @@ func TestAccS3Object_kms(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "source", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy", "source"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -599,7 +599,7 @@ func TestAccS3Object_sse(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "source", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy", "source"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -699,7 +699,7 @@ func TestAccS3Object_metadata(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"acl", "force_destroy"}, + ImportStateVerifyIgnore: []string{"force_destroy"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -762,7 +762,7 @@ func TestAccS3Object_storageClass(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"content", "acl", "force_destroy"}, + ImportStateVerifyIgnore: []string{"content", "force_destroy"}, ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), }, }, @@ -831,7 +831,7 @@ func TestAccS3Object_tags(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"content", "acl", "force_destroy"}, + ImportStateVerifyIgnore: []string{"content", "force_destroy"}, ImportStateId: fmt.Sprintf("s3://%s/%s", rName, key), }, }, @@ -900,7 +900,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"content", "acl", "force_destroy"}, + ImportStateVerifyIgnore: []string{"content", "force_destroy"}, ImportStateId: fmt.Sprintf("s3://%s/%s", rName, key), }, }, @@ -1350,6 +1350,53 @@ func TestAccS3Object_ignoreTags(t *testing.T) { }) } +func TestAccS3Object_checksumAlgorithm(t *testing.T) { + ctx := acctest.Context(t) + var obj s3.GetObjectOutput + resourceName := "aws_s3_object.object" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckObjectDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccObjectConfig_checksumAlgorithm(rName, "CRC32"), + Check: resource.ComposeTestCheckFunc( + testAccCheckObjectExists(ctx, resourceName, &obj), + testAccCheckObjectBody(&obj, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), + resource.TestCheckResourceAttr(resourceName, "checksum_algorithm", "CRC32"), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32", "q/d4Ig=="), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32c", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha1", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha256", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"checksum_algorithm", "checksum_crc32", "content", "force_destroy"}, + ImportStateId: fmt.Sprintf("s3://%s/test-key", rName), + }, + { + Config: testAccObjectConfig_checksumAlgorithm(rName, "SHA256"), + Check: resource.ComposeTestCheckFunc( + testAccCheckObjectExists(ctx, resourceName, &obj), + testAccCheckObjectBody(&obj, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), + resource.TestCheckResourceAttr(resourceName, "checksum_algorithm", "SHA256"), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32c", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha1", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha256", "1uxomN6H3axuWzYRcIp6ocLSmCkzScwabCmaHbcUnTg="), + ), + }, + }, + }) +} + func testAccCheckObjectVersionIdDiffers(first, second *s3.GetObjectOutput) resource.TestCheckFunc { return func(s *terraform.State) error { if first.VersionId == nil { @@ -2145,3 +2192,19 @@ resource "aws_s3_object" "object" { } `, rName, content) } + +func testAccObjectConfig_checksumAlgorithm(rName, checksumAlgorithm string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_s3_object" "object" { + bucket = aws_s3_bucket.test.bucket + key = "test-key" + content = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + checksum_algorithm = %[2]q +} +`, rName, checksumAlgorithm) +} From 21b5d4616daf1cbb863ff42e5144442e5d53877f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 13:42:58 -0400 Subject: [PATCH 22/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3Object_checksumAlgorithm' PKG=s3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 20 -run=TestAccS3Object_checksumAlgorithm -timeout 180m === RUN TestAccS3Object_checksumAlgorithm === PAUSE TestAccS3Object_checksumAlgorithm === CONT TestAccS3Object_checksumAlgorithm --- PASS: TestAccS3Object_checksumAlgorithm (47.84s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 53.042s From b87f312916d8550ac52fbd4701d10908b0680766 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 14:00:11 -0400 Subject: [PATCH 23/61] r/aws_s3_object_copy: Add `checksum_algorithm` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes. --- .changelog/33358.txt | 6 ++- internal/service/s3/object_copy.go | 32 +++++++++++- internal/service/s3/object_copy_test.go | 57 +++++++++++++++++++++ website/docs/r/s3_object_copy.html.markdown | 5 ++ 4 files changed, 98 insertions(+), 2 deletions(-) diff --git a/.changelog/33358.txt b/.changelog/33358.txt index 51aea8f4f5f..3b6d0e5326c 100644 --- a/.changelog/33358.txt +++ b/.changelog/33358.txt @@ -1,3 +1,7 @@ ```release-note:enhancement resource/aws_s3_object: Add `checksum_algorithm` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes -``` \ No newline at end of file +``` + +```release-note:enhancement +resource/aws_s3_object_copy: Add `checksum_algorithm` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes +``` diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index fcce5725031..81a60ba8275 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -65,6 +65,27 @@ func ResourceObjectCopy() *schema.Resource { Optional: true, Computed: true, }, + "checksum_algorithm": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.ChecksumAlgorithm](), + }, + "checksum_crc32": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_crc32c": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_sha1": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_sha256": { + Type: schema.TypeString, + Computed: true, + }, "content_disposition": { Type: schema.TypeString, Optional: true, @@ -316,7 +337,7 @@ func resourceObjectCopyRead(ctx context.Context, d *schema.ResourceData, meta in bucket := d.Get("bucket").(string) key := d.Get("key").(string) - output, err := findObjectByBucketAndKey(ctx, conn, bucket, key, "", "") + output, err := findObjectByBucketAndKey(ctx, conn, bucket, key, "", d.Get("checksum_algorithm").(string)) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] S3 Object (%s) not found, removing from state", d.Id()) @@ -330,6 +351,10 @@ func resourceObjectCopyRead(ctx context.Context, d *schema.ResourceData, meta in d.Set("bucket_key_enabled", output.BucketKeyEnabled) d.Set("cache_control", output.CacheControl) + d.Set("checksum_crc32", output.ChecksumCRC32) + d.Set("checksum_crc32c", output.ChecksumCRC32C) + d.Set("checksum_sha1", output.ChecksumSHA1) + d.Set("checksum_sha256", output.ChecksumSHA256) d.Set("content_disposition", output.ContentDisposition) d.Set("content_encoding", output.ContentEncoding) d.Set("content_language", output.ContentLanguage) @@ -390,6 +415,7 @@ func resourceObjectCopyUpdate(ctx context.Context, d *schema.ResourceData, meta "bucket", "bucket_key_enabled", "cache_control", + "checksum_algorithm", "content_disposition", "content_encoding", "content_language", @@ -476,6 +502,10 @@ func resourceObjectCopyDoCopy(ctx context.Context, d *schema.ResourceData, meta input.CacheControl = aws.String(v.(string)) } + if v, ok := d.GetOk("checksum_algorithm"); ok { + input.ChecksumAlgorithm = types.ChecksumAlgorithm(v.(string)) + } + if v, ok := d.GetOk("content_disposition"); ok { input.ContentDisposition = aws.String(v.(string)) } diff --git a/internal/service/s3/object_copy_test.go b/internal/service/s3/object_copy_test.go index 25e5050cf00..4eb6782f53e 100644 --- a/internal/service/s3/object_copy_test.go +++ b/internal/service/s3/object_copy_test.go @@ -41,6 +41,11 @@ func TestAccS3ObjectCopy_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "bucket", rName2), resource.TestCheckResourceAttr(resourceName, "bucket_key_enabled", "false"), resource.TestCheckResourceAttr(resourceName, "cache_control", ""), + resource.TestCheckNoResourceAttr(resourceName, "checksum_algorithm"), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32c", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha1", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha256", ""), resource.TestCheckResourceAttr(resourceName, "content_disposition", ""), resource.TestCheckResourceAttr(resourceName, "content_encoding", ""), resource.TestCheckResourceAttr(resourceName, "content_language", ""), @@ -297,6 +302,46 @@ func TestAccS3ObjectCopy_sourceWithSlashes(t *testing.T) { }) } +func TestAccS3ObjectCopy_checksumAlgorithm(t *testing.T) { + ctx := acctest.Context(t) + rName1 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object_copy.test" + sourceKey := "source" + targetKey := "target" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckObjectCopyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccObjectCopyConfig_checksumAlgorithm(rName1, sourceKey, rName2, targetKey, "CRC32C"), + Check: resource.ComposeTestCheckFunc( + testAccCheckObjectCopyExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "checksum_algorithm", "CRC32C"), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32c", "7y1BJA=="), + resource.TestCheckResourceAttr(resourceName, "checksum_sha1", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha256", ""), + ), + }, + { + Config: testAccObjectCopyConfig_checksumAlgorithm(rName1, sourceKey, rName2, targetKey, "SHA1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckObjectCopyExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "checksum_algorithm", "SHA1"), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32c", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha1", "7MuLDoLjuZB9Uv63Krr4E7U5x30="), + resource.TestCheckResourceAttr(resourceName, "checksum_sha256", ""), + ), + }, + }, + }) +} + func testAccCheckObjectCopyDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) @@ -515,3 +560,15 @@ resource "aws_s3_object_copy" "test" { } `, sourceKey, targetKey)) } + +func testAccObjectCopyConfig_checksumAlgorithm(sourceBucket, sourceKey, targetBucket, targetKey, checksumAlgorithm string) string { + return acctest.ConfigCompose(testAccObjectCopyConfig_baseSourceObject(sourceBucket, sourceKey, targetBucket), fmt.Sprintf(` +resource "aws_s3_object_copy" "test" { + bucket = aws_s3_bucket.target.bucket + key = %[1]q + source = "${aws_s3_bucket.source.bucket}/${aws_s3_object.source.key}" + + checksum_algorithm = %[2]q +} +`, targetKey, checksumAlgorithm)) +} diff --git a/website/docs/r/s3_object_copy.html.markdown b/website/docs/r/s3_object_copy.html.markdown index 6944ac3f48b..bb89f797585 100644 --- a/website/docs/r/s3_object_copy.html.markdown +++ b/website/docs/r/s3_object_copy.html.markdown @@ -38,6 +38,7 @@ The following arguments are optional: * `acl` - (Optional) [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) to apply. Valid values are `private`, `public-read`, `public-read-write`, `authenticated-read`, `aws-exec-read`, `bucket-owner-read`, and `bucket-owner-full-control`. Conflicts with `grant`. * `cache_control` - (Optional) Specifies caching behavior along the request/reply chain Read [w3c cache_control](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) for further details. +* `checksum_algorithm` - (Optional) Indicates the algorithm used to create the checksum for the object. If a value is specified and the object is encrypted with KMS, you must have permission to use the `kms:Decrypt` action. Valid values: `CRC32`, `CRC32C`, `SHA1`, `SHA256`. * `content_disposition` - (Optional) Specifies presentational information for the object. Read [w3c content_disposition](http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1) for further information. * `content_encoding` - (Optional) Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. Read [w3c content encoding](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11) for further information. * `content_language` - (Optional) Language the content is in e.g., en-US or en-GB. @@ -92,6 +93,10 @@ This configuration block has the following optional arguments (one of the three This resource exports the following attributes in addition to the arguments above: +* `checksum_crc32` - The base64-encoded, 32-bit CRC32 checksum of the object. +* `checksum_crc32c` - The base64-encoded, 32-bit CRC32C checksum of the object. +* `checksum_sha1` - The base64-encoded, 160-bit SHA-1 digest of the object. +* `checksum_sha256` - The base64-encoded, 256-bit SHA-256 digest of the object. * `etag` - ETag generated for the object (an MD5 sum of the object content). For plaintext objects or objects encrypted with an AWS-managed key, the hash is an MD5 digest of the object data. For objects encrypted with a KMS key or objects created by either the Multipart Upload or Part Copy operation, the hash is not an MD5 digest, regardless of the method of encryption. More information on possible values can be found on [Common Response Headers](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html). * `expiration` - If the object expiration is configured, this attribute will be set. * `id` - The `key` of the resource supplied above. From 0830d9932e45047d703ed7c66eaa06e136065875 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 14:00:32 -0400 Subject: [PATCH 24/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3ObjectCopy_checksumAlgorithm' PKG=s3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 20 -run=TestAccS3ObjectCopy_checksumAlgorithm -timeout 180m === RUN TestAccS3ObjectCopy_checksumAlgorithm === PAUSE TestAccS3ObjectCopy_checksumAlgorithm === CONT TestAccS3ObjectCopy_checksumAlgorithm --- PASS: TestAccS3ObjectCopy_checksumAlgorithm (48.57s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 53.907s From ffe2dcd618ad818cf69fafe17e1e3bca74fd3147 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 14:46:55 -0400 Subject: [PATCH 25/61] Fix 'Content-MD5 OR x-amz-checksum- HTTP header is required for Put Object requests with Object Lock parameters'. --- internal/service/s3/object.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 2d6e34fb9d5..ed24f273367 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -521,6 +521,12 @@ func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta inte input.WebsiteRedirectLocation = aws.String(v.(string)) } + if (input.ObjectLockLegalHoldStatus != "" || input.ObjectLockMode != "" || input.ObjectLockRetainUntilDate != nil) && input.ChecksumAlgorithm == "" { + // "Content-MD5 OR x-amz-checksum- HTTP header is required for Put Object requests with Object Lock parameters". + // AWS SDK for Go v1 transparently added a Content-MD4 header. + input.ChecksumAlgorithm = types.ChecksumAlgorithmCrc32 + } + if _, err := uploader.Upload(ctx, input); err != nil { return sdkdiag.AppendErrorf(diags, "uploading S3 Object (%s) to Bucket (%s): %s", key, bucket, err) } From 75e7b390fd2796f0c09d30a10fc404be1f777327 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 15:15:21 -0400 Subject: [PATCH 26/61] Add 'TestAccS3ObjectCopy_objectLockLegalHold'. --- internal/service/s3/object_copy_test.go | 73 +++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/internal/service/s3/object_copy_test.go b/internal/service/s3/object_copy_test.go index 4eb6782f53e..1a067a1384c 100644 --- a/internal/service/s3/object_copy_test.go +++ b/internal/service/s3/object_copy_test.go @@ -342,6 +342,38 @@ func TestAccS3ObjectCopy_checksumAlgorithm(t *testing.T) { }) } +func TestAccS3ObjectCopy_objectLockLegalHold(t *testing.T) { + ctx := acctest.Context(t) + rName1 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object_copy.test" + sourceKey := "source" + targetKey := "target" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckObjectCopyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccObjectCopyConfig_lockLegalHold(rName1, sourceKey, rName2, targetKey, "ON"), + Check: resource.ComposeTestCheckFunc( + testAccCheckObjectCopyExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", "ON"), + ), + }, + { + Config: testAccObjectCopyConfig_lockLegalHold(rName1, sourceKey, rName2, targetKey, "OFF"), + Check: resource.ComposeTestCheckFunc( + testAccCheckObjectCopyExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", "OFF"), + ), + }, + }, + }) +} + func testAccCheckObjectCopyDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) @@ -572,3 +604,44 @@ resource "aws_s3_object_copy" "test" { } `, targetKey, checksumAlgorithm)) } + +func testAccObjectCopyConfig_lockLegalHold(sourceBucket, sourceKey, targetBucket, targetKey, legalHoldStatus string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "source" { + bucket = %[1]q + + force_destroy = true +} + +resource "aws_s3_bucket" "target" { + bucket = %[3]q + + object_lock_enabled = true + + force_destroy = true +} + +resource "aws_s3_bucket_versioning" "target" { + bucket = aws_s3_bucket.target.id + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_object" "source" { + bucket = aws_s3_bucket.source.bucket + key = %[2]q + content = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +} + +resource "aws_s3_object_copy" "test" { + # Must have bucket versioning enabled first + bucket = aws_s3_bucket_versioning.target.bucket + key = %[4]q + source = "${aws_s3_bucket.source.bucket}/${aws_s3_object.source.key}" + + object_lock_legal_hold_status = %[5]q + force_destroy = true +} +`, sourceBucket, sourceKey, targetBucket, targetKey, legalHoldStatus) +} From 69f5c19228b12dfc273648194324d2d419fc05e6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 15:16:13 -0400 Subject: [PATCH 27/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3ObjectCopy_objectLockLegalHold' PKG=s3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 20 -run=TestAccS3ObjectCopy_objectLockLegalHold -timeout 180m === RUN TestAccS3ObjectCopy_objectLockLegalHold === PAUSE TestAccS3ObjectCopy_objectLockLegalHold === CONT TestAccS3ObjectCopy_objectLockLegalHold --- PASS: TestAccS3ObjectCopy_objectLockLegalHold (54.75s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 60.147s From 598090a77a902c000c58961090b387b3c0247b16 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 15:43:28 -0400 Subject: [PATCH 28/61] Fix 'TestAccS3ObjectCopy_basic'. --- internal/service/s3/object_copy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/s3/object_copy_test.go b/internal/service/s3/object_copy_test.go index 1a067a1384c..de77e7ff535 100644 --- a/internal/service/s3/object_copy_test.go +++ b/internal/service/s3/object_copy_test.go @@ -49,7 +49,7 @@ func TestAccS3ObjectCopy_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "content_disposition", ""), resource.TestCheckResourceAttr(resourceName, "content_encoding", ""), resource.TestCheckResourceAttr(resourceName, "content_language", ""), - resource.TestCheckResourceAttr(resourceName, "content_type", "binary/octet-stream"), + resource.TestCheckResourceAttr(resourceName, "content_type", "application/octet-stream"), resource.TestCheckNoResourceAttr(resourceName, "copy_if_match"), resource.TestCheckNoResourceAttr(resourceName, "copy_if_modified_since"), resource.TestCheckNoResourceAttr(resourceName, "copy_if_none_match"), From 7de05be926f4d98eabf867efa574015bd543e5ff Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 8 Sep 2023 16:40:43 -0400 Subject: [PATCH 29/61] d/aws_s3_object: Migrate to AWS SDK for Go v2. --- internal/service/s3/object_data_source.go | 134 +++++++++------------- 1 file changed, 57 insertions(+), 77 deletions(-) diff --git a/internal/service/s3/object_data_source.go b/internal/service/s3/object_data_source.go index 75c374f7271..a001fe00cdf 100644 --- a/internal/service/s3/object_data_source.go +++ b/internal/service/s3/object_data_source.go @@ -6,20 +6,18 @@ package s3 import ( "bytes" "context" - "fmt" - "log" "regexp" "strings" "time" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" - "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" ) @@ -45,6 +43,7 @@ func DataSourceObject() *schema.Resource { Type: schema.TypeString, Computed: true, }, + // TODO checksum_mode etc. "content_disposition": { Type: schema.TypeString, Computed: true, @@ -118,6 +117,7 @@ func DataSourceObject() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "tags": tftags.TagsSchemaComputed(), "version_id": { Type: schema.TypeString, Optional: true, @@ -127,21 +127,18 @@ func DataSourceObject() *schema.Resource { Type: schema.TypeString, Computed: true, }, - - "tags": tftags.TagsSchemaComputed(), }, } } func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).S3Conn(ctx) + conn := meta.(*conns.AWSClient).S3Client(ctx) ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig bucket := d.Get("bucket").(string) key := d.Get("key").(string) - - input := s3.HeadObjectInput{ + input := &s3.HeadObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), } @@ -152,94 +149,79 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte input.VersionId = aws.String(v.(string)) } - versionText := "" - uniqueId := bucket + "/" + key - if v, ok := d.GetOk("version_id"); ok { - versionText = fmt.Sprintf(" of version %q", v.(string)) - uniqueId += "@" + v.(string) - } + output, err := findObject(ctx, conn, input) - log.Printf("[DEBUG] Reading S3 Object: %s", input) - out, err := conn.HeadObjectWithContext(ctx, &input) if err != nil { - return sdkdiag.AppendErrorf(diags, "getting S3 Bucket (%s) Object (%s): %s", bucket, key, err) - } - if aws.BoolValue(out.DeleteMarker) { - return sdkdiag.AppendErrorf(diags, "Requested S3 object %q%s has been deleted", bucket+key, versionText) + return sdkdiag.AppendErrorf(diags, "reading S3 Bucket (%s) Object (%s): %s", bucket, key, err) } - log.Printf("[DEBUG] Received S3 object: %s", out) + if output.DeleteMarker { + return sdkdiag.AppendErrorf(diags, "S3 Bucket (%s) Object (%s) has been deleted", bucket, key) + } - d.SetId(uniqueId) + id := bucket + "/" + key + if v, ok := d.GetOk("version_id"); ok { + id += "@" + v.(string) + } + d.SetId(id) - d.Set("bucket_key_enabled", out.BucketKeyEnabled) - d.Set("cache_control", out.CacheControl) - d.Set("content_disposition", out.ContentDisposition) - d.Set("content_encoding", out.ContentEncoding) - d.Set("content_language", out.ContentLanguage) - d.Set("content_length", out.ContentLength) - d.Set("content_type", out.ContentType) + d.Set("bucket_key_enabled", output.BucketKeyEnabled) + d.Set("cache_control", output.CacheControl) + d.Set("content_disposition", output.ContentDisposition) + d.Set("content_encoding", output.ContentEncoding) + d.Set("content_language", output.ContentLanguage) + d.Set("content_length", output.ContentLength) + d.Set("content_type", output.ContentType) // See https://forums.aws.amazon.com/thread.jspa?threadID=44003 - d.Set("etag", strings.Trim(aws.StringValue(out.ETag), `"`)) - d.Set("expiration", out.Expiration) - d.Set("expires", out.Expires) - if out.LastModified != nil { - d.Set("last_modified", out.LastModified.Format(time.RFC1123)) + d.Set("etag", strings.Trim(aws.ToString(output.ETag), `"`)) + d.Set("expiration", output.Expiration) + d.Set("expires", output.Expires) + if output.LastModified != nil { + d.Set("last_modified", output.LastModified.Format(time.RFC1123)) } else { - d.Set("last_modified", "") + d.Set("last_modified", nil) } - d.Set("metadata", flex.PointersMapToStringList(out.Metadata)) - d.Set("object_lock_legal_hold_status", out.ObjectLockLegalHoldStatus) - d.Set("object_lock_mode", out.ObjectLockMode) - d.Set("object_lock_retain_until_date", flattenObjectDate(out.ObjectLockRetainUntilDate)) - d.Set("server_side_encryption", out.ServerSideEncryption) - d.Set("sse_kms_key_id", out.SSEKMSKeyId) - d.Set("version_id", out.VersionId) - d.Set("website_redirect_location", out.WebsiteRedirectLocation) - + d.Set("metadata", output.Metadata) + d.Set("object_lock_legal_hold_status", output.ObjectLockLegalHoldStatus) + d.Set("object_lock_mode", output.ObjectLockMode) + d.Set("object_lock_retain_until_date", flattenObjectDate(output.ObjectLockRetainUntilDate)) + d.Set("server_side_encryption", output.ServerSideEncryption) + d.Set("sse_kms_key_id", output.SSEKMSKeyId) // The "STANDARD" (which is also the default) storage // class when set would not be included in the results. - if out.StorageClass == nil { - d.Set("storage_class", s3.StorageClassStandard) - } else { - d.Set("storage_class", out.StorageClass) + d.Set("storage_class", types.ObjectStorageClassStandard) + if output.StorageClass != "" { + d.Set("storage_class", output.StorageClass) } + d.Set("version_id", output.VersionId) + d.Set("website_redirect_location", output.WebsiteRedirectLocation) - if isContentTypeAllowed(out.ContentType) { - input := s3.GetObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(key), + if isContentTypeAllowed(output.ContentType) { + input := &s3.GetObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(key), + VersionId: output.VersionId, } if v, ok := d.GetOk("range"); ok { input.Range = aws.String(v.(string)) } - if out.VersionId != nil { - input.VersionId = out.VersionId - } - out, err := conn.GetObjectWithContext(ctx, &input) + + output, err := conn.GetObject(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "Failed getting S3 object: %s", err) + return sdkdiag.AppendErrorf(diags, "getting S3 Bucket (%s) Object (%s): %s", bucket, key, err) } buf := new(bytes.Buffer) - bytesRead, err := buf.ReadFrom(out.Body) + _, err = buf.ReadFrom(output.Body) if err != nil { - return sdkdiag.AppendErrorf(diags, "Failed reading content of S3 object (%s): %s", uniqueId, err) - } - log.Printf("[INFO] Saving %d bytes from S3 object %s", bytesRead, uniqueId) - d.Set("body", buf.String()) - } else { - contentType := "" - if out.ContentType == nil { - contentType = "" - } else { - contentType = aws.StringValue(out.ContentType) + return sdkdiag.AppendFromErr(diags, err) } - log.Printf("[INFO] Ignoring body of S3 object %s with Content-Type %q", uniqueId, contentType) + d.Set("body", buf.String()) } - tags, err := ObjectListTagsV1(ctx, conn, bucket, key) + tags, err := ObjectListTags(ctx, conn, bucket, key) if err != nil { return sdkdiag.AppendErrorf(diags, "listing tags for S3 Bucket (%s) Object (%s): %s", bucket, key, err) @@ -252,9 +234,8 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte return diags } -// This is to prevent potential issues w/ binary files -// and generally unprintable characters -// See https://github.com/hashicorp/terraform/pull/3858#issuecomment-156856738 +// This is to prevent potential issues w/ binary files and generally unprintable characters. +// See https://github.com/hashicorp/terraform/pull/3858#issuecomment-156856738. func isContentTypeAllowed(contentType *string) bool { if contentType == nil { return false @@ -271,9 +252,8 @@ func isContentTypeAllowed(contentType *string) bool { regexache.MustCompile(`^application/xml$`), regexache.MustCompile(`^text/.+`), } - for _, r := range allowedContentTypes { - if r.MatchString(*contentType) { + if r.MatchString(aws.ToString(contentType)) { return true } } From 9db50a610ad7c7260ddfa2b54471d2ba9065a2a3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 9 Sep 2023 16:47:54 -0400 Subject: [PATCH 30/61] Remove 'testAccCheckObjectExistsDataSource'. --- .../s3/bucket_object_data_source_test.go | 62 ------------- .../service/s3/object_data_source_test.go | 93 +++---------------- 2 files changed, 13 insertions(+), 142 deletions(-) diff --git a/internal/service/s3/bucket_object_data_source_test.go b/internal/service/s3/bucket_object_data_source_test.go index ac54e24671b..d7ffe9399b3 100644 --- a/internal/service/s3/bucket_object_data_source_test.go +++ b/internal/service/s3/bucket_object_data_source_test.go @@ -23,9 +23,6 @@ func TestAccS3BucketObjectDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" @@ -38,8 +35,6 @@ func TestAccS3BucketObjectDataSource_basic(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_basic(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -56,7 +51,6 @@ func TestAccS3BucketObjectDataSource_basic(t *testing.T) { func TestAccS3BucketObjectDataSource_basicViaAccessPoint(t *testing.T) { ctx := acctest.Context(t) - var dsObj, rObj s3.GetObjectOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) dataSourceName := "data.aws_s3_object.test" @@ -71,9 +65,6 @@ func TestAccS3BucketObjectDataSource_basicViaAccessPoint(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_basicViaAccessPoint(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), resource.TestCheckResourceAttrPair(dataSourceName, "bucket", accessPointResourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "key", resourceName, "key"), ), @@ -86,9 +77,6 @@ func TestAccS3BucketObjectDataSource_readableBody(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" @@ -101,8 +89,6 @@ func TestAccS3BucketObjectDataSource_readableBody(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_readableBody(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -121,9 +107,6 @@ func TestAccS3BucketObjectDataSource_kmsEncrypted(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" @@ -136,8 +119,6 @@ func TestAccS3BucketObjectDataSource_kmsEncrypted(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_kmsEncrypted(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -158,9 +139,6 @@ func TestAccS3BucketObjectDataSource_bucketKeyEnabled(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" @@ -173,8 +151,6 @@ func TestAccS3BucketObjectDataSource_bucketKeyEnabled(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_keyEnabled(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -196,9 +172,6 @@ func TestAccS3BucketObjectDataSource_allParams(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" @@ -211,8 +184,6 @@ func TestAccS3BucketObjectDataSource_allParams(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_allParams(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "25"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -248,9 +219,6 @@ func TestAccS3BucketObjectDataSource_objectLockLegalHoldOff(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var rObj s3.GetObjectOutput - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" @@ -263,8 +231,6 @@ func TestAccS3BucketObjectDataSource_objectLockLegalHoldOff(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_lockLegalHoldOff(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -284,9 +250,6 @@ func TestAccS3BucketObjectDataSource_objectLockLegalHoldOn(t *testing.T) { rInt := sdkacctest.RandInt() retainUntilDate := time.Now().UTC().AddDate(0, 0, 10).Format(time.RFC3339) - var rObj s3.GetObjectOutput - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" @@ -299,8 +262,6 @@ func TestAccS3BucketObjectDataSource_objectLockLegalHoldOn(t *testing.T) { { Config: testAccBucketObjectDataSourceConfig_lockLegalHoldOn(rInt, retainUntilDate), Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -317,8 +278,6 @@ func TestAccS3BucketObjectDataSource_objectLockLegalHoldOn(t *testing.T) { func TestAccS3BucketObjectDataSource_leadingSlash(t *testing.T) { ctx := acctest.Context(t) - var rObj s3.GetObjectOutput - var dsObj1, dsObj2, dsObj3 s3.GetObjectOutput resourceName := "aws_s3_object.object" dataSourceName1 := "data.aws_s3_object.obj1" @@ -336,28 +295,22 @@ func TestAccS3BucketObjectDataSource_leadingSlash(t *testing.T) { Steps: []resource.TestStep{ { // nosemgrep:ci.test-config-funcs-correct-form Config: resourceOnlyConf, - Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName, &rObj), - ), }, { // nosemgrep:ci.test-config-funcs-correct-form Config: conf, Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName1, &dsObj1), resource.TestCheckResourceAttr(dataSourceName1, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName1, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName1, "etag", resourceName, "etag"), resource.TestMatchResourceAttr(dataSourceName1, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"), - testAccCheckObjectExistsDataSource(ctx, dataSourceName2, &dsObj2), resource.TestCheckResourceAttr(dataSourceName2, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName2, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName2, "etag", resourceName, "etag"), resource.TestMatchResourceAttr(dataSourceName2, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"), - testAccCheckObjectExistsDataSource(ctx, dataSourceName3, &dsObj3), resource.TestCheckResourceAttr(dataSourceName3, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName3, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName3, "etag", resourceName, "etag"), @@ -371,8 +324,6 @@ func TestAccS3BucketObjectDataSource_leadingSlash(t *testing.T) { func TestAccS3BucketObjectDataSource_multipleSlashes(t *testing.T) { ctx := acctest.Context(t) - var rObj1, rObj2 s3.GetObjectOutput - var dsObj1, dsObj2, dsObj3 s3.GetObjectOutput resourceName1 := "aws_s3_object.object1" resourceName2 := "aws_s3_object.object2" @@ -391,26 +342,18 @@ func TestAccS3BucketObjectDataSource_multipleSlashes(t *testing.T) { Steps: []resource.TestStep{ { // nosemgrep:ci.test-config-funcs-correct-form Config: resourceOnlyConf, - Check: resource.ComposeTestCheckFunc( - testAccCheckBucketObjectExists(ctx, resourceName1, &rObj1), - testAccCheckBucketObjectExists(ctx, resourceName2, &rObj2), - ), }, { // nosemgrep:ci.test-config-funcs-correct-form Config: conf, Check: resource.ComposeTestCheckFunc( - - testAccCheckObjectExistsDataSource(ctx, dataSourceName1, &dsObj1), resource.TestCheckResourceAttr(dataSourceName1, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName1, "content_type", resourceName1, "content_type"), resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"), - testAccCheckObjectExistsDataSource(ctx, dataSourceName2, &dsObj2), resource.TestCheckResourceAttr(dataSourceName2, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName2, "content_type", resourceName1, "content_type"), resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"), - testAccCheckObjectExistsDataSource(ctx, dataSourceName3, &dsObj3), resource.TestCheckResourceAttr(dataSourceName3, "content_length", "2"), resource.TestCheckResourceAttrPair(dataSourceName3, "content_type", resourceName2, "content_type"), resource.TestCheckResourceAttr(dataSourceName3, "body", "no"), @@ -422,8 +365,6 @@ func TestAccS3BucketObjectDataSource_multipleSlashes(t *testing.T) { func TestAccS3BucketObjectDataSource_singleSlashAsKey(t *testing.T) { ctx := acctest.Context(t) - var dsObj s3.GetObjectOutput - dataSourceName := "data.aws_s3_object.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ @@ -434,9 +375,6 @@ func TestAccS3BucketObjectDataSource_singleSlashAsKey(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccBucketObjectDataSourceConfig_singleSlashAsKey(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), - ), }, }, }) diff --git a/internal/service/s3/object_data_source_test.go b/internal/service/s3/object_data_source_test.go index c465212f624..aff5791b831 100644 --- a/internal/service/s3/object_data_source_test.go +++ b/internal/service/s3/object_data_source_test.go @@ -4,19 +4,15 @@ package s3_test import ( - "context" "fmt" "testing" "time" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" - "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/names" ) const rfc1123RegexPattern = `^[a-zA-Z]{3}, [0-9]+ [a-zA-Z]+ [0-9]{4} [0-9:]+ [A-Z]+$` @@ -25,21 +21,18 @@ func TestAccS3ObjectDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_basic(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -58,21 +51,18 @@ func TestAccS3ObjectDataSource_basicViaAccessPoint(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - var dsObj s3.GetObjectOutput - dataSourceName := "data.aws_s3_object.test" resourceName := "aws_s3_object.test" accessPointResourceName := "aws_s3_access_point.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_basicViaAccessPoint(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttrPair(dataSourceName, "bucket", accessPointResourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "key", resourceName, "key"), ), @@ -85,21 +75,18 @@ func TestAccS3ObjectDataSource_readableBody(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_readableBody(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -118,21 +105,18 @@ func TestAccS3ObjectDataSource_kmsEncrypted(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_kmsEncrypted(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -153,21 +137,18 @@ func TestAccS3ObjectDataSource_bucketKeyEnabled(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_bucketKeyEnabled(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -189,21 +170,18 @@ func TestAccS3ObjectDataSource_allParams(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_allParams(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "25"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -239,21 +217,18 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOff(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_lockLegalHoldOff(rInt), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -273,21 +248,18 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { rInt := sdkacctest.RandInt() retainUntilDate := time.Now().UTC().AddDate(0, 0, 10).Format(time.RFC3339) - var dsObj s3.GetObjectOutput - resourceName := "aws_s3_object.object" dataSourceName := "data.aws_s3_object.obj" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_lockLegalHoldOn(rInt, retainUntilDate), Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -304,7 +276,6 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { ctx := acctest.Context(t) - var dsObj1, dsObj2, dsObj3 s3.GetObjectOutput resourceName := "aws_s3_object.object" dataSourceName1 := "data.aws_s3_object.obj1" @@ -316,7 +287,7 @@ func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ @@ -326,21 +297,18 @@ func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { { // nosemgrep:ci.test-config-funcs-correct-form Config: conf, Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName1, &dsObj1), resource.TestCheckResourceAttr(dataSourceName1, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName1, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName1, "etag", resourceName, "etag"), resource.TestMatchResourceAttr(dataSourceName1, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"), - testAccCheckObjectExistsDataSource(ctx, dataSourceName2, &dsObj2), resource.TestCheckResourceAttr(dataSourceName2, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName2, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName2, "etag", resourceName, "etag"), resource.TestMatchResourceAttr(dataSourceName2, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"), - testAccCheckObjectExistsDataSource(ctx, dataSourceName3, &dsObj3), resource.TestCheckResourceAttr(dataSourceName3, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName3, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName3, "etag", resourceName, "etag"), @@ -354,7 +322,6 @@ func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { ctx := acctest.Context(t) - var dsObj1, dsObj2, dsObj3 s3.GetObjectOutput resourceName1 := "aws_s3_object.object1" resourceName2 := "aws_s3_object.object2" @@ -367,7 +334,7 @@ func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ @@ -378,17 +345,14 @@ func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { Config: conf, Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName1, &dsObj1), resource.TestCheckResourceAttr(dataSourceName1, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName1, "content_type", resourceName1, "content_type"), resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"), - testAccCheckObjectExistsDataSource(ctx, dataSourceName2, &dsObj2), resource.TestCheckResourceAttr(dataSourceName2, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName2, "content_type", resourceName1, "content_type"), resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"), - testAccCheckObjectExistsDataSource(ctx, dataSourceName3, &dsObj3), resource.TestCheckResourceAttr(dataSourceName3, "content_length", "2"), resource.TestCheckResourceAttrPair(dataSourceName3, "content_type", resourceName2, "content_type"), resource.TestCheckResourceAttr(dataSourceName3, "body", "no"), @@ -400,53 +364,22 @@ func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { func TestAccS3ObjectDataSource_singleSlashAsKey(t *testing.T) { ctx := acctest.Context(t) - var dsObj s3.GetObjectOutput - dataSourceName := "data.aws_s3_object.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID), + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_singleSlashAsKey(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckObjectExistsDataSource(ctx, dataSourceName, &dsObj), - ), + // TODO }, }, }) } -func testAccCheckObjectExistsDataSource(ctx context.Context, n string, obj *s3.GetObjectOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Can't find S3 object data source: %s", n) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("S3 object data source ID not set") - } - - conn := acctest.Provider.Meta().(*conns.AWSClient).S3Conn(ctx) - out, err := conn.GetObjectWithContext(ctx, &s3.GetObjectInput{ - Bucket: aws.String(rs.Primary.Attributes["bucket"]), - Key: aws.String(rs.Primary.Attributes["key"]), - }) - if err != nil { - return fmt.Errorf("Failed getting S3 Object from %s: %s", - rs.Primary.Attributes["bucket"]+"/"+rs.Primary.Attributes["key"], err) - } - - *obj = *out - - return nil - } -} - func testAccObjectDataSourceConfig_basic(randInt int) string { return fmt.Sprintf(` resource "aws_s3_bucket" "object_bucket" { From a1441734a38e43df0c40ef5b1d3f23fc38a51b43 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 9 Sep 2023 17:09:07 -0400 Subject: [PATCH 31/61] d/aws_s3_object: Migrate acceptance tests to AWS SDK for Go v2. --- .../service/s3/object_data_source_test.go | 406 +++++++++--------- 1 file changed, 199 insertions(+), 207 deletions(-) diff --git a/internal/service/s3/object_data_source_test.go b/internal/service/s3/object_data_source_test.go index aff5791b831..9506fcd390b 100644 --- a/internal/service/s3/object_data_source_test.go +++ b/internal/service/s3/object_data_source_test.go @@ -19,10 +19,9 @@ const rfc1123RegexPattern = `^[a-zA-Z]{3}, [0-9]+ [a-zA-Z]+ [0-9]{4} [0-9:]+ [A- func TestAccS3ObjectDataSource_basic(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() - - resourceName := "aws_s3_object.object" - dataSourceName := "data.aws_s3_object.obj" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object.test" + dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -31,8 +30,9 @@ func TestAccS3ObjectDataSource_basic(t *testing.T) { PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { - Config: testAccObjectDataSourceConfig_basic(rInt), + Config: testAccObjectDataSourceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr(dataSourceName, "body"), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -40,7 +40,6 @@ func TestAccS3ObjectDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_legal_hold_status", resourceName, "object_lock_legal_hold_status"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_mode", resourceName, "object_lock_mode"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_retain_until_date", resourceName, "object_lock_retain_until_date"), - resource.TestCheckNoResourceAttr(dataSourceName, "body"), ), }, }, @@ -50,7 +49,6 @@ func TestAccS3ObjectDataSource_basic(t *testing.T) { func TestAccS3ObjectDataSource_basicViaAccessPoint(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - dataSourceName := "data.aws_s3_object.test" resourceName := "aws_s3_object.test" accessPointResourceName := "aws_s3_access_point.test" @@ -73,10 +71,9 @@ func TestAccS3ObjectDataSource_basicViaAccessPoint(t *testing.T) { func TestAccS3ObjectDataSource_readableBody(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() - - resourceName := "aws_s3_object.object" - dataSourceName := "data.aws_s3_object.obj" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object.test" + dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -85,8 +82,9 @@ func TestAccS3ObjectDataSource_readableBody(t *testing.T) { PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { - Config: testAccObjectDataSourceConfig_readableBody(rInt), + Config: testAccObjectDataSourceConfig_readableBody(rName), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "body", "yes"), resource.TestCheckResourceAttr(dataSourceName, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -94,7 +92,6 @@ func TestAccS3ObjectDataSource_readableBody(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_legal_hold_status", resourceName, "object_lock_legal_hold_status"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_mode", resourceName, "object_lock_mode"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_retain_until_date", resourceName, "object_lock_retain_until_date"), - resource.TestCheckResourceAttr(dataSourceName, "body", "yes"), ), }, }, @@ -103,10 +100,9 @@ func TestAccS3ObjectDataSource_readableBody(t *testing.T) { func TestAccS3ObjectDataSource_kmsEncrypted(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() - - resourceName := "aws_s3_object.object" - dataSourceName := "data.aws_s3_object.obj" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object.test" + dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -115,18 +111,18 @@ func TestAccS3ObjectDataSource_kmsEncrypted(t *testing.T) { PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { - Config: testAccObjectDataSourceConfig_kmsEncrypted(rInt), + Config: testAccObjectDataSourceConfig_kmsEncrypted(rName), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "body", "Keep Calm and Carry On"), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), - resource.TestCheckResourceAttrPair(dataSourceName, "server_side_encryption", resourceName, "server_side_encryption"), - resource.TestCheckResourceAttrPair(dataSourceName, "sse_kms_key_id", resourceName, "kms_key_id"), resource.TestMatchResourceAttr(dataSourceName, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_legal_hold_status", resourceName, "object_lock_legal_hold_status"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_mode", resourceName, "object_lock_mode"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_retain_until_date", resourceName, "object_lock_retain_until_date"), - resource.TestCheckResourceAttr(dataSourceName, "body", "Keep Calm and Carry On"), + resource.TestCheckResourceAttrPair(dataSourceName, "server_side_encryption", resourceName, "server_side_encryption"), + resource.TestCheckResourceAttrPair(dataSourceName, "sse_kms_key_id", resourceName, "kms_key_id"), ), }, }, @@ -135,10 +131,9 @@ func TestAccS3ObjectDataSource_kmsEncrypted(t *testing.T) { func TestAccS3ObjectDataSource_bucketKeyEnabled(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() - - resourceName := "aws_s3_object.object" - dataSourceName := "data.aws_s3_object.obj" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object.test" + dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -147,19 +142,19 @@ func TestAccS3ObjectDataSource_bucketKeyEnabled(t *testing.T) { PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { - Config: testAccObjectDataSourceConfig_bucketKeyEnabled(rInt), + Config: testAccObjectDataSourceConfig_bucketKeyEnabled(rName), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "body", "Keep Calm and Carry On"), + resource.TestCheckResourceAttrPair(dataSourceName, "bucket_key_enabled", resourceName, "bucket_key_enabled"), resource.TestCheckResourceAttr(dataSourceName, "content_length", "22"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), - resource.TestCheckResourceAttrPair(dataSourceName, "server_side_encryption", resourceName, "server_side_encryption"), - resource.TestCheckResourceAttrPair(dataSourceName, "sse_kms_key_id", resourceName, "kms_key_id"), - resource.TestCheckResourceAttrPair(dataSourceName, "bucket_key_enabled", resourceName, "bucket_key_enabled"), resource.TestMatchResourceAttr(dataSourceName, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_legal_hold_status", resourceName, "object_lock_legal_hold_status"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_mode", resourceName, "object_lock_mode"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_retain_until_date", resourceName, "object_lock_retain_until_date"), - resource.TestCheckResourceAttr(dataSourceName, "body", "Keep Calm and Carry On"), + resource.TestCheckResourceAttrPair(dataSourceName, "server_side_encryption", resourceName, "server_side_encryption"), + resource.TestCheckResourceAttrPair(dataSourceName, "sse_kms_key_id", resourceName, "kms_key_id"), ), }, }, @@ -168,10 +163,9 @@ func TestAccS3ObjectDataSource_bucketKeyEnabled(t *testing.T) { func TestAccS3ObjectDataSource_allParams(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() - - resourceName := "aws_s3_object.object" - dataSourceName := "data.aws_s3_object.obj" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object.test" + dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -180,33 +174,33 @@ func TestAccS3ObjectDataSource_allParams(t *testing.T) { PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { - Config: testAccObjectDataSourceConfig_allParams(rInt), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(dataSourceName, "content_length", "25"), - resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), - resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), - resource.TestMatchResourceAttr(dataSourceName, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), - resource.TestCheckResourceAttrPair(dataSourceName, "version_id", resourceName, "version_id"), + Config: testAccObjectDataSourceConfig_allParams(rName), + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckNoResourceAttr(dataSourceName, "body"), resource.TestCheckResourceAttrPair(dataSourceName, "bucket_key_enabled", resourceName, "bucket_key_enabled"), resource.TestCheckResourceAttrPair(dataSourceName, "cache_control", resourceName, "cache_control"), resource.TestCheckResourceAttrPair(dataSourceName, "content_disposition", resourceName, "content_disposition"), resource.TestCheckResourceAttrPair(dataSourceName, "content_encoding", resourceName, "content_encoding"), resource.TestCheckResourceAttrPair(dataSourceName, "content_language", resourceName, "content_language"), - // Encryption is off - resource.TestCheckResourceAttrPair(dataSourceName, "server_side_encryption", resourceName, "server_side_encryption"), - resource.TestCheckResourceAttr(dataSourceName, "sse_kms_key_id", ""), - // Supported, but difficult to reproduce in short testing time - resource.TestCheckResourceAttrPair(dataSourceName, "storage_class", resourceName, "storage_class"), + resource.TestCheckResourceAttr(dataSourceName, "content_length", "25"), + resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), + resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), resource.TestCheckResourceAttr(dataSourceName, "expiration", ""), // Currently unsupported in aws_s3_object resource resource.TestCheckResourceAttr(dataSourceName, "expires", ""), - resource.TestCheckResourceAttrPair(dataSourceName, "website_redirect_location", resourceName, "website_redirect"), + resource.TestMatchResourceAttr(dataSourceName, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), resource.TestCheckResourceAttr(dataSourceName, "metadata.%", "0"), - resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_legal_hold_status", resourceName, "object_lock_legal_hold_status"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_mode", resourceName, "object_lock_mode"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_retain_until_date", resourceName, "object_lock_retain_until_date"), + // Encryption is off + resource.TestCheckResourceAttrPair(dataSourceName, "server_side_encryption", resourceName, "server_side_encryption"), + resource.TestCheckResourceAttr(dataSourceName, "sse_kms_key_id", ""), + // Supported, but difficult to reproduce in short testing time + resource.TestCheckResourceAttrPair(dataSourceName, "storage_class", resourceName, "storage_class"), + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "version_id", resourceName, "version_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "website_redirect_location", resourceName, "website_redirect"), ), }, }, @@ -215,10 +209,9 @@ func TestAccS3ObjectDataSource_allParams(t *testing.T) { func TestAccS3ObjectDataSource_objectLockLegalHoldOff(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() - - resourceName := "aws_s3_object.object" - dataSourceName := "data.aws_s3_object.obj" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object.test" + dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -227,8 +220,9 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOff(t *testing.T) { PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { - Config: testAccObjectDataSourceConfig_lockLegalHoldOff(rInt), + Config: testAccObjectDataSourceConfig_lockLegalHoldOff(rName), Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr(dataSourceName, "body"), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -236,7 +230,6 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOff(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_legal_hold_status", resourceName, "object_lock_legal_hold_status"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_mode", resourceName, "object_lock_mode"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_retain_until_date", resourceName, "object_lock_retain_until_date"), - resource.TestCheckNoResourceAttr(dataSourceName, "body"), ), }, }, @@ -245,11 +238,10 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOff(t *testing.T) { func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) retainUntilDate := time.Now().UTC().AddDate(0, 0, 10).Format(time.RFC3339) - - resourceName := "aws_s3_object.object" - dataSourceName := "data.aws_s3_object.obj" + resourceName := "aws_s3_object.test" + dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -258,8 +250,9 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { - Config: testAccObjectDataSourceConfig_lockLegalHoldOn(rInt, retainUntilDate), + Config: testAccObjectDataSourceConfig_lockLegalHoldOn(rName, retainUntilDate), Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr(dataSourceName, "body"), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -267,7 +260,6 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_legal_hold_status", resourceName, "object_lock_legal_hold_status"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_mode", resourceName, "object_lock_mode"), resource.TestCheckResourceAttrPair(dataSourceName, "object_lock_retain_until_date", resourceName, "object_lock_retain_until_date"), - resource.TestCheckNoResourceAttr(dataSourceName, "body"), ), }, }, @@ -276,14 +268,13 @@ func TestAccS3ObjectDataSource_objectLockLegalHoldOn(t *testing.T) { func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object.test" + dataSourceName1 := "data.aws_s3_object.test1" + dataSourceName2 := "data.aws_s3_object.test2" + dataSourceName3 := "data.aws_s3_object.test3" - resourceName := "aws_s3_object.object" - dataSourceName1 := "data.aws_s3_object.obj1" - dataSourceName2 := "data.aws_s3_object.obj2" - dataSourceName3 := "data.aws_s3_object.obj3" - - rInt := sdkacctest.RandInt() - resourceOnlyConf, conf := testAccObjectDataSourceConfig_leadingSlash(rInt) + resourceOnlyConf, conf := testAccObjectDataSourceConfig_leadingSlash(rName) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -297,23 +288,23 @@ func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { { // nosemgrep:ci.test-config-funcs-correct-form Config: conf, Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"), resource.TestCheckResourceAttr(dataSourceName1, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName1, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName1, "etag", resourceName, "etag"), resource.TestMatchResourceAttr(dataSourceName1, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), - resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"), + resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"), resource.TestCheckResourceAttr(dataSourceName2, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName2, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName2, "etag", resourceName, "etag"), resource.TestMatchResourceAttr(dataSourceName2, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), - resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"), + resource.TestCheckResourceAttr(dataSourceName3, "body", "yes"), resource.TestCheckResourceAttr(dataSourceName3, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName3, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName3, "etag", resourceName, "etag"), resource.TestMatchResourceAttr(dataSourceName3, "last_modified", regexache.MustCompile(rfc1123RegexPattern)), - resource.TestCheckResourceAttr(dataSourceName3, "body", "yes"), ), }, }, @@ -322,15 +313,14 @@ func TestAccS3ObjectDataSource_leadingSlash(t *testing.T) { func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName1 := "aws_s3_object.test1" + resourceName2 := "aws_s3_object.test2" + dataSourceName1 := "data.aws_s3_object.test1" + dataSourceName2 := "data.aws_s3_object.test2" + dataSourceName3 := "data.aws_s3_object.test3" - resourceName1 := "aws_s3_object.object1" - resourceName2 := "aws_s3_object.object2" - dataSourceName1 := "data.aws_s3_object.obj1" - dataSourceName2 := "data.aws_s3_object.obj2" - dataSourceName3 := "data.aws_s3_object.obj3" - - rInt := sdkacctest.RandInt() - resourceOnlyConf, conf := testAccObjectDataSourceConfig_multipleSlashes(rInt) + resourceOnlyConf, conf := testAccObjectDataSourceConfig_multipleSlashes(rName) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -344,18 +334,17 @@ func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { { // nosemgrep:ci.test-config-funcs-correct-form Config: conf, Check: resource.ComposeTestCheckFunc( - + resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"), resource.TestCheckResourceAttr(dataSourceName1, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName1, "content_type", resourceName1, "content_type"), - resource.TestCheckResourceAttr(dataSourceName1, "body", "yes"), + resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"), resource.TestCheckResourceAttr(dataSourceName2, "content_length", "3"), resource.TestCheckResourceAttrPair(dataSourceName2, "content_type", resourceName1, "content_type"), - resource.TestCheckResourceAttr(dataSourceName2, "body", "yes"), + resource.TestCheckResourceAttr(dataSourceName3, "body", "no"), resource.TestCheckResourceAttr(dataSourceName3, "content_length", "2"), resource.TestCheckResourceAttrPair(dataSourceName3, "content_type", resourceName2, "content_type"), - resource.TestCheckResourceAttr(dataSourceName3, "body", "no"), ), }, }, @@ -365,6 +354,7 @@ func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { func TestAccS3ObjectDataSource_singleSlashAsKey(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -374,29 +364,31 @@ func TestAccS3ObjectDataSource_singleSlashAsKey(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_singleSlashAsKey(rName), - // TODO + Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr(dataSourceName, "body"), + ), }, }, }) } -func testAccObjectDataSourceConfig_basic(randInt int) string { +func testAccObjectDataSourceConfig_basic(rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } -resource "aws_s3_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket - key = "tf-testing-obj-%[1]d" +resource "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = "%[1]s-key" content = "Hello World" } -data "aws_s3_object" "obj" { - bucket = aws_s3_bucket.object_bucket.bucket - key = aws_s3_object.object.key +data "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = aws_s3_object.test.key } -`, randInt) +`, rName) } func testAccObjectDataSourceConfig_basicViaAccessPoint(rName string) string { @@ -412,7 +404,7 @@ resource "aws_s3_access_point" "test" { resource "aws_s3_object" "test" { bucket = aws_s3_bucket.test.bucket - key = %[1]q + key = "%[1]s-key" content = "Hello World" } @@ -423,98 +415,98 @@ data "aws_s3_object" "test" { `, rName) } -func testAccObjectDataSourceConfig_readableBody(randInt int) string { +func testAccObjectDataSourceConfig_readableBody(rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } -resource "aws_s3_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket - key = "tf-testing-obj-%[1]d-readable" +resource "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = "%[1]s-key" content = "yes" content_type = "text/plain" } -data "aws_s3_object" "obj" { - bucket = aws_s3_bucket.object_bucket.bucket - key = aws_s3_object.object.key +data "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = aws_s3_object.test.key } -`, randInt) +`, rName) } -func testAccObjectDataSourceConfig_kmsEncrypted(randInt int) string { +func testAccObjectDataSourceConfig_kmsEncrypted(rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } -resource "aws_kms_key" "example" { - description = "TF Acceptance Test KMS key" +resource "aws_kms_key" "test" { + description = %[1]q deletion_window_in_days = 7 } -resource "aws_s3_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket - key = "tf-testing-obj-%[1]d-encrypted" +resource "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = "%[1]s-key" content = "Keep Calm and Carry On" content_type = "text/plain" - kms_key_id = aws_kms_key.example.arn + kms_key_id = aws_kms_key.test.arn } -data "aws_s3_object" "obj" { - bucket = aws_s3_bucket.object_bucket.bucket - key = aws_s3_object.object.key +data "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = aws_s3_object.test.key } -`, randInt) +`, rName) } -func testAccObjectDataSourceConfig_bucketKeyEnabled(randInt int) string { +func testAccObjectDataSourceConfig_bucketKeyEnabled(rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } -resource "aws_kms_key" "example" { - description = "TF Acceptance Test KMS key" +resource "aws_kms_key" "test" { + description = %[1]q deletion_window_in_days = 7 } -resource "aws_s3_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket - key = "tf-testing-obj-%[1]d-encrypted" +resource "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = "%[1]s-key" content = "Keep Calm and Carry On" content_type = "text/plain" - kms_key_id = aws_kms_key.example.arn + kms_key_id = aws_kms_key.test.arn bucket_key_enabled = true } -data "aws_s3_object" "obj" { - bucket = aws_s3_bucket.object_bucket.bucket - key = aws_s3_object.object.key +data "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = aws_s3_object.test.key } -`, randInt) +`, rName) } -func testAccObjectDataSourceConfig_allParams(randInt int) string { +func testAccObjectDataSourceConfig_allParams(rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } -resource "aws_s3_bucket_versioning" "object_bucket" { - bucket = aws_s3_bucket.object_bucket.id +resource "aws_s3_bucket_versioning" "test" { + bucket = aws_s3_bucket.test.id versioning_configuration { status = "Enabled" } } -resource "aws_s3_object" "object" { +resource "aws_s3_object" "test" { # Must have bucket versioning enabled first - depends_on = [aws_s3_bucket_versioning.object_bucket] + depends_on = [aws_s3_bucket_versioning.test] - bucket = aws_s3_bucket.object_bucket.bucket - key = "tf-testing-obj-%[1]d-all-params" + bucket = aws_s3_bucket.test.bucket + key = "%[1]s-key" content = < Date: Sat, 9 Sep 2023 17:36:15 -0400 Subject: [PATCH 32/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3ObjectDataSource_' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3ObjectDataSource_ -timeout 180m === RUN TestAccS3ObjectDataSource_basic === PAUSE TestAccS3ObjectDataSource_basic === RUN TestAccS3ObjectDataSource_basicViaAccessPoint === PAUSE TestAccS3ObjectDataSource_basicViaAccessPoint === RUN TestAccS3ObjectDataSource_readableBody === PAUSE TestAccS3ObjectDataSource_readableBody === RUN TestAccS3ObjectDataSource_kmsEncrypted === PAUSE TestAccS3ObjectDataSource_kmsEncrypted === RUN TestAccS3ObjectDataSource_bucketKeyEnabled === PAUSE TestAccS3ObjectDataSource_bucketKeyEnabled === RUN TestAccS3ObjectDataSource_allParams === PAUSE TestAccS3ObjectDataSource_allParams === RUN TestAccS3ObjectDataSource_objectLockLegalHoldOff === PAUSE TestAccS3ObjectDataSource_objectLockLegalHoldOff === RUN TestAccS3ObjectDataSource_objectLockLegalHoldOn === PAUSE TestAccS3ObjectDataSource_objectLockLegalHoldOn === RUN TestAccS3ObjectDataSource_leadingSlash === PAUSE TestAccS3ObjectDataSource_leadingSlash === RUN TestAccS3ObjectDataSource_multipleSlashes === PAUSE TestAccS3ObjectDataSource_multipleSlashes === RUN TestAccS3ObjectDataSource_singleSlashAsKey === PAUSE TestAccS3ObjectDataSource_singleSlashAsKey === CONT TestAccS3ObjectDataSource_basic === CONT TestAccS3ObjectDataSource_objectLockLegalHoldOff === CONT TestAccS3ObjectDataSource_multipleSlashes object_data_source_test.go:325: Step 2/2 error: Error running pre-apply refresh: exit status 1 Error: reading S3 Bucket (tf-acc-test-5577438982701294343) Object (first/second/third/): couldn't find resource with data.aws_s3_object.test1, on terraform_plugin_test.tf line 23, in data "aws_s3_object" "test1": 23: data "aws_s3_object" "test1" { Error: reading S3 Bucket (tf-acc-test-5577438982701294343) Object (first/second/third): couldn't find resource with data.aws_s3_object.test3, on terraform_plugin_test.tf line 33, in data "aws_s3_object" "test3": 33: data "aws_s3_object" "test3" { --- PASS: TestAccS3ObjectDataSource_basic (29.85s) === CONT TestAccS3ObjectDataSource_singleSlashAsKey --- FAIL: TestAccS3ObjectDataSource_multipleSlashes (33.94s) === CONT TestAccS3ObjectDataSource_leadingSlash --- PASS: TestAccS3ObjectDataSource_objectLockLegalHoldOff (34.09s) === CONT TestAccS3ObjectDataSource_kmsEncrypted === NAME TestAccS3ObjectDataSource_singleSlashAsKey object_data_source_test.go:359: Step 1/1 error: Error running apply: exit status 1 Error: reading S3 Bucket (tf-acc-test-1229759036124842497) Object (/): couldn't find resource with data.aws_s3_object.test, on terraform_plugin_test.tf line 6, in data "aws_s3_object" "test": 6: data "aws_s3_object" "test" { --- FAIL: TestAccS3ObjectDataSource_singleSlashAsKey (16.30s) === CONT TestAccS3ObjectDataSource_allParams === NAME TestAccS3ObjectDataSource_leadingSlash object_data_source_test.go:279: Step 2/2 error: Error running pre-apply refresh: exit status 1 Error: reading S3 Bucket (tf-acc-test-4957693144032449233) Object (tf-acc-test-4957693144032449233-key): couldn't find resource with data.aws_s3_object.test1, on terraform_plugin_test.tf line 15, in data "aws_s3_object" "test1": 15: data "aws_s3_object" "test1" { Error: reading S3 Bucket (tf-acc-test-4957693144032449233) Object (/tf-acc-test-4957693144032449233-key): couldn't find resource with data.aws_s3_object.test2, on terraform_plugin_test.tf line 20, in data "aws_s3_object" "test2": 20: data "aws_s3_object" "test2" { --- PASS: TestAccS3ObjectDataSource_kmsEncrypted (30.50s) === CONT TestAccS3ObjectDataSource_bucketKeyEnabled --- FAIL: TestAccS3ObjectDataSource_leadingSlash (34.06s) === CONT TestAccS3ObjectDataSource_readableBody --- PASS: TestAccS3ObjectDataSource_allParams (32.35s) === CONT TestAccS3ObjectDataSource_objectLockLegalHoldOn --- PASS: TestAccS3ObjectDataSource_bucketKeyEnabled (28.40s) === CONT TestAccS3ObjectDataSource_basicViaAccessPoint --- PASS: TestAccS3ObjectDataSource_readableBody (29.02s) --- PASS: TestAccS3ObjectDataSource_objectLockLegalHoldOn (32.54s) --- PASS: TestAccS3ObjectDataSource_basicViaAccessPoint (27.82s) FAIL FAIL github.com/hashicorp/terraform-provider-aws/internal/service/s3 126.112s FAIL make: *** [testacc] Error 1 From 7552904dab003a0783711b62f066987221351d8b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 9 Sep 2023 17:54:33 -0400 Subject: [PATCH 33/61] Add 'TestAccS3ObjectCopy_targetWithMultipleSlashes'. --- internal/service/s3/object_copy_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/internal/service/s3/object_copy_test.go b/internal/service/s3/object_copy_test.go index de77e7ff535..195e1bbab4a 100644 --- a/internal/service/s3/object_copy_test.go +++ b/internal/service/s3/object_copy_test.go @@ -374,6 +374,31 @@ func TestAccS3ObjectCopy_objectLockLegalHold(t *testing.T) { }) } +func TestAccS3ObjectCopy_targetWithMultipleSlashes(t *testing.T) { + ctx := acctest.Context(t) + rName1 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object_copy.test" + sourceKey := "source" + targetKey := "/dir/target//" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckObjectCopyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccObjectCopyConfig_basic(rName1, sourceKey, rName2, targetKey), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "key", targetKey), + resource.TestCheckResourceAttr(resourceName, "source", fmt.Sprintf("%s/%s", rName1, sourceKey)), + ), + }, + }, + }) +} + func testAccCheckObjectCopyDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) From 7014254ad5eeb640b6445dc7ae150f32a5870aa7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 9 Sep 2023 17:54:48 -0400 Subject: [PATCH 34/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3ObjectCopy_targetWithMultipleSlashes' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3ObjectCopy_targetWithMultipleSlashes -timeout 180m === RUN TestAccS3ObjectCopy_targetWithMultipleSlashes === PAUSE TestAccS3ObjectCopy_targetWithMultipleSlashes === CONT TestAccS3ObjectCopy_targetWithMultipleSlashes --- PASS: TestAccS3ObjectCopy_targetWithMultipleSlashes (31.14s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 37.126s From ca409e7e11002669b507af436bb7b7a86cb01fb8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 10 Sep 2023 16:31:28 -0400 Subject: [PATCH 35/61] Add TODO comments. --- internal/conns/awsclient.go | 4 ++++ internal/service/s3/object.go | 3 +++ internal/service/s3/object_copy.go | 3 +++ 3 files changed, 10 insertions(+) diff --git a/internal/conns/awsclient.go b/internal/conns/awsclient.go index ef6d43bf95f..9ddf9c8133a 100644 --- a/internal/conns/awsclient.go +++ b/internal/conns/awsclient.go @@ -58,6 +58,10 @@ func (client *AWSClient) RegionalHostname(prefix string) string { return fmt.Sprintf("%s.%s.%s", prefix, client.Region, client.DNSSuffix) } +// **************** +// TODO: REVIEW +// TODO: AWS SDK for Go v2 does NO URL cleaning. +// **************** func (client *AWSClient) S3ConnURICleaningDisabled(ctx context.Context) *s3_sdkv1.S3 { config := client.S3Conn(ctx).Config config.DisableRestProtocolURICleaning = aws_sdkv1.Bool(true) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index ed24f273367..cc0bf3d599d 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -362,10 +362,13 @@ func resourceObjectDelete(ctx context.Context, d *schema.ResourceData, meta inte bucket := d.Get("bucket").(string) key := d.Get("key").(string) + // **************** + // TODO: REVIEW // We are effectively ignoring all leading '/'s in the key name and // treating multiple '/'s as a single '/' as aws.Config.DisableRestProtocolURICleaning is false key = strings.TrimLeft(key, "/") key = regexache.MustCompile(`/+`).ReplaceAllString(key, "/") + // **************** var err error if _, ok := d.GetOk("version_id"); ok { diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index 81a60ba8275..40dda451096 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -460,10 +460,13 @@ func resourceObjectCopyDelete(ctx context.Context, d *schema.ResourceData, meta bucket := d.Get("bucket").(string) key := d.Get("key").(string) + // **************** + // TODO: REVIEW // We are effectively ignoring all leading '/'s in the key name and // treating multiple '/'s as a single '/' as aws.Config.DisableRestProtocolURICleaning is false key = strings.TrimLeft(key, "/") key = regexache.MustCompile(`/+`).ReplaceAllString(key, "/") + // **************** var err error if _, ok := d.GetOk("version_id"); ok { From e1bee5b9016c3cc2a1778b056cd6128f3e086587 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 10 Sep 2023 16:35:38 -0400 Subject: [PATCH 36/61] Fix providerlint 'R004: ResourceData.Set() incompatible value type: *time.Time'. --- internal/service/s3/object_data_source.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/service/s3/object_data_source.go b/internal/service/s3/object_data_source.go index a001fe00cdf..de4cc4a27ff 100644 --- a/internal/service/s3/object_data_source.go +++ b/internal/service/s3/object_data_source.go @@ -175,7 +175,11 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte // See https://forums.aws.amazon.com/thread.jspa?threadID=44003 d.Set("etag", strings.Trim(aws.ToString(output.ETag), `"`)) d.Set("expiration", output.Expiration) - d.Set("expires", output.Expires) + if output.Expires != nil { + d.Set("expires", output.Expires.Format(time.RFC1123)) + } else { + d.Set("expires", nil) + } if output.LastModified != nil { d.Set("last_modified", output.LastModified.Format(time.RFC1123)) } else { From 1e1f1257f328b4198de0e790555dc9f577dd1d40 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 10 Sep 2023 16:47:59 -0400 Subject: [PATCH 37/61] r/aws_s3_object_copy: Remove 'aws_s3_bucket.force_destroy' from acceptance test configurations to prevent problem coverup. --- internal/service/s3/object_copy_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/s3/object_copy_test.go b/internal/service/s3/object_copy_test.go index 195e1bbab4a..0bbb741f7ed 100644 --- a/internal/service/s3/object_copy_test.go +++ b/internal/service/s3/object_copy_test.go @@ -445,13 +445,13 @@ func testAccObjectCopyConfig_baseSourceAndTargetBuckets(sourceBucket, targetBuck resource "aws_s3_bucket" "source" { bucket = %[1]q - force_destroy = true + # force_destroy = true } resource "aws_s3_bucket" "target" { bucket = %[2]q - force_destroy = true + # force_destroy = true } `, sourceBucket, targetBucket) } From 139ce33920d82dd65c0d8aaa9277ef98bb323aba Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 10 Sep 2023 17:15:38 -0400 Subject: [PATCH 38/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3ObjectCopy_' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3ObjectCopy_ -timeout 180m === RUN TestAccS3ObjectCopy_basic === PAUSE TestAccS3ObjectCopy_basic === RUN TestAccS3ObjectCopy_disappears === PAUSE TestAccS3ObjectCopy_disappears === RUN TestAccS3ObjectCopy_tags === PAUSE TestAccS3ObjectCopy_tags === RUN TestAccS3ObjectCopy_metadata === PAUSE TestAccS3ObjectCopy_metadata === RUN TestAccS3ObjectCopy_grant === PAUSE TestAccS3ObjectCopy_grant === RUN TestAccS3ObjectCopy_BucketKeyEnabled_bucket === PAUSE TestAccS3ObjectCopy_BucketKeyEnabled_bucket === RUN TestAccS3ObjectCopy_BucketKeyEnabled_object === PAUSE TestAccS3ObjectCopy_BucketKeyEnabled_object === RUN TestAccS3ObjectCopy_sourceWithSlashes === PAUSE TestAccS3ObjectCopy_sourceWithSlashes === RUN TestAccS3ObjectCopy_checksumAlgorithm === PAUSE TestAccS3ObjectCopy_checksumAlgorithm === RUN TestAccS3ObjectCopy_objectLockLegalHold === PAUSE TestAccS3ObjectCopy_objectLockLegalHold === RUN TestAccS3ObjectCopy_targetWithMultipleSlashes === PAUSE TestAccS3ObjectCopy_targetWithMultipleSlashes === CONT TestAccS3ObjectCopy_basic === CONT TestAccS3ObjectCopy_BucketKeyEnabled_object === CONT TestAccS3ObjectCopy_metadata --- PASS: TestAccS3ObjectCopy_basic (36.86s) === CONT TestAccS3ObjectCopy_tags --- PASS: TestAccS3ObjectCopy_metadata (36.87s) === CONT TestAccS3ObjectCopy_BucketKeyEnabled_bucket --- PASS: TestAccS3ObjectCopy_BucketKeyEnabled_object (37.23s) === CONT TestAccS3ObjectCopy_objectLockLegalHold --- PASS: TestAccS3ObjectCopy_BucketKeyEnabled_bucket (30.52s) === CONT TestAccS3ObjectCopy_targetWithMultipleSlashes testing_new.go:90: Error running post-test destroy, there may be dangling resources: exit status 1 Error: deleting Amazon S3 (Simple Storage) Bucket (tf-acc-test-8258963431803478976): BucketNotEmpty: The bucket you tried to delete is not empty status code: 409, request id: WATRYPRSTW2A9WP0, host id: mDH039auB4yTj92Q9eBhq2lMR0mE9mGbRjuXscF1W1vZ/Te3JrgnlvhGaLAcKY83/Q3CEcJTJ8BTz7Xcgz5X2Q== --- FAIL: TestAccS3ObjectCopy_targetWithMultipleSlashes (40.29s) === CONT TestAccS3ObjectCopy_checksumAlgorithm --- PASS: TestAccS3ObjectCopy_objectLockLegalHold (70.89s) === CONT TestAccS3ObjectCopy_grant --- PASS: TestAccS3ObjectCopy_tags (90.01s) === CONT TestAccS3ObjectCopy_sourceWithSlashes --- PASS: TestAccS3ObjectCopy_grant (31.10s) === CONT TestAccS3ObjectCopy_disappears --- PASS: TestAccS3ObjectCopy_checksumAlgorithm (54.04s) --- PASS: TestAccS3ObjectCopy_disappears (29.72s) === NAME TestAccS3ObjectCopy_sourceWithSlashes testing_new.go:90: Error running post-test destroy, there may be dangling resources: exit status 1 Error: deleting Amazon S3 (Simple Storage) Bucket (tf-acc-test-1114803916746401278): BucketNotEmpty: The bucket you tried to delete is not empty status code: 409, request id: A8103SJB3TJTWEC8, host id: C5YRMZXjq2ezgh/TWPQDBVD+rBXU+asAWkM6q0VJfipibh0Dzj2huX7raNLU293DAXvcPiLslA4= --- FAIL: TestAccS3ObjectCopy_sourceWithSlashes (48.84s) FAIL FAIL github.com/hashicorp/terraform-provider-aws/internal/service/s3 182.614s FAIL make: *** [testacc] Error 1 From 860e0d36b9519f0c59918d9b29e80b5513baca45 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 10 Sep 2023 18:22:48 -0400 Subject: [PATCH 39/61] d/aws_s3_object: Add `checksum_mode` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes. --- .changelog/33358.txt | 4 ++ internal/service/s3/object_data_source.go | 30 +++++++++- .../service/s3/object_data_source_test.go | 57 ++++++++++++++++++- website/docs/d/s3_object.html.markdown | 5 ++ 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/.changelog/33358.txt b/.changelog/33358.txt index 3b6d0e5326c..b07527cf79a 100644 --- a/.changelog/33358.txt +++ b/.changelog/33358.txt @@ -5,3 +5,7 @@ resource/aws_s3_object: Add `checksum_algorithm` argument and `checksum_crc32`, ```release-note:enhancement resource/aws_s3_object_copy: Add `checksum_algorithm` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes ``` + +```release-note:enhancement +data-source/aws_s3_object: Add `checksum_mode` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes +``` \ No newline at end of file diff --git a/internal/service/s3/object_data_source.go b/internal/service/s3/object_data_source.go index de4cc4a27ff..9f6785dfa7b 100644 --- a/internal/service/s3/object_data_source.go +++ b/internal/service/s3/object_data_source.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" ) @@ -43,7 +44,27 @@ func DataSourceObject() *schema.Resource { Type: schema.TypeString, Computed: true, }, - // TODO checksum_mode etc. + "checksum_mode": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.ChecksumMode](), + }, + "checksum_crc32": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_crc32c": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_sha1": { + Type: schema.TypeString, + Computed: true, + }, + "checksum_sha256": { + Type: schema.TypeString, + Computed: true, + }, "content_disposition": { Type: schema.TypeString, Computed: true, @@ -142,6 +163,9 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte Bucket: aws.String(bucket), Key: aws.String(key), } + if v, ok := d.GetOk("checksum_mode"); ok { + input.ChecksumMode = types.ChecksumMode(v.(string)) + } if v, ok := d.GetOk("range"); ok { input.Range = aws.String(v.(string)) } @@ -167,6 +191,10 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte d.Set("bucket_key_enabled", output.BucketKeyEnabled) d.Set("cache_control", output.CacheControl) + d.Set("checksum_crc32", output.ChecksumCRC32) + d.Set("checksum_crc32c", output.ChecksumCRC32C) + d.Set("checksum_sha1", output.ChecksumSHA1) + d.Set("checksum_sha256", output.ChecksumSHA256) d.Set("content_disposition", output.ContentDisposition) d.Set("content_encoding", output.ContentEncoding) d.Set("content_language", output.ContentLanguage) diff --git a/internal/service/s3/object_data_source_test.go b/internal/service/s3/object_data_source_test.go index 9506fcd390b..756be91cfee 100644 --- a/internal/service/s3/object_data_source_test.go +++ b/internal/service/s3/object_data_source_test.go @@ -31,8 +31,13 @@ func TestAccS3ObjectDataSource_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccObjectDataSourceConfig_basic(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckNoResourceAttr(dataSourceName, "body"), + resource.TestCheckNoResourceAttr(dataSourceName, "checksum_mode"), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_crc32c", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha1", ""), + resource.TestCheckResourceAttr(resourceName, "checksum_sha256", ""), resource.TestCheckResourceAttr(dataSourceName, "content_length", "11"), resource.TestCheckResourceAttrPair(dataSourceName, "content_type", resourceName, "content_type"), resource.TestCheckResourceAttrPair(dataSourceName, "etag", resourceName, "etag"), @@ -372,6 +377,33 @@ func TestAccS3ObjectDataSource_singleSlashAsKey(t *testing.T) { }) } +func TestAccS3ObjectDataSource_checksumMode(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object.test" + dataSourceName := "data.aws_s3_object.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + PreventPostDestroyRefresh: true, + Steps: []resource.TestStep{ + { + Config: testAccObjectDataSourceConfig_checksumMode(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "checksum_mode", "ENABLED"), + resource.TestCheckResourceAttrPair(dataSourceName, "checksum_crc32", resourceName, "checksum_crc32"), + resource.TestCheckResourceAttrPair(dataSourceName, "checksum_crc32c", resourceName, "checksum_crc32c"), + resource.TestCheckResourceAttrPair(dataSourceName, "checksum_sha1", resourceName, "checksum_sha1"), + resource.TestCheckResourceAttrPair(dataSourceName, "checksum_sha256", resourceName, "checksum_sha256"), + resource.TestCheckResourceAttrSet(dataSourceName, "checksum_sha256"), + ), + }, + }, + }) +} + func testAccObjectDataSourceConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { @@ -686,3 +718,26 @@ data "aws_s3_object" "test" { } `, rName) } + +func testAccObjectDataSourceConfig_checksumMode(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = "%[1]s-key" + content = "Keep Calm and Carry On" + + checksum_algorithm = "SHA256" +} + +data "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = aws_s3_object.test.key + + checksum_mode = "ENABLED" +} +`, rName) +} diff --git a/website/docs/d/s3_object.html.markdown b/website/docs/d/s3_object.html.markdown index c5d04996880..e692408ea86 100644 --- a/website/docs/d/s3_object.html.markdown +++ b/website/docs/d/s3_object.html.markdown @@ -58,6 +58,7 @@ resource "aws_lambda_function" "test_lambda" { This data source supports the following arguments: * `bucket` - (Required) Name of the bucket to read the object from. Alternatively, an [S3 access point](https://docs.aws.amazon.com/AmazonS3/latest/dev/using-access-points.html) ARN can be specified +* `checksum_mode` - (Optional) To retrieve the object's checksum, this argument must be `ENABLED`. If you enable `checksum_mode` and the object is encrypted with KMS, you must have permission to use the `kms:Decrypt` action. Valid values: `ENABLED` * `key` - (Required) Full path to the object inside the bucket * `version_id` - (Optional) Specific version ID of the object returned (defaults to latest version) @@ -68,6 +69,10 @@ This data source exports the following attributes in addition to the arguments a * `body` - Object data (see **limitations above** to understand cases in which this field is actually available) * `bucket_key_enabled` - (Optional) Whether or not to use [Amazon S3 Bucket Keys](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html) for SSE-KMS. * `cache_control` - Caching behavior along the request/reply chain. +* `checksum_crc32` - The base64-encoded, 32-bit CRC32 checksum of the object. +* `checksum_crc32c` - The base64-encoded, 32-bit CRC32C checksum of the object. +* `checksum_sha1` - The base64-encoded, 160-bit SHA-1 digest of the object. +* `checksum_sha256` - The base64-encoded, 256-bit SHA-256 digest of the object. * `content_disposition` - Presentational information for the object. * `content_encoding` - What content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. * `content_language` - Language the content is in. From 9c401dbf21d17d5099b2a2fd06ea8f106d9b64d9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 10 Sep 2023 18:23:11 -0400 Subject: [PATCH 40/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3ObjectDataSource_basic$$\|TestAccS3ObjectDataSource_checksumMode' PKG=s3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 20 -run=TestAccS3ObjectDataSource_basic$\|TestAccS3ObjectDataSource_checksumMode -timeout 180m === RUN TestAccS3ObjectDataSource_basic === PAUSE TestAccS3ObjectDataSource_basic === RUN TestAccS3ObjectDataSource_checksumMode === PAUSE TestAccS3ObjectDataSource_checksumMode === CONT TestAccS3ObjectDataSource_basic === CONT TestAccS3ObjectDataSource_checksumMode --- PASS: TestAccS3ObjectDataSource_checksumMode (28.10s) --- PASS: TestAccS3ObjectDataSource_basic (28.11s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 33.403s From 3bb4cac8d663e257c85390acb64334a1b53b8f23 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 11:41:37 -0400 Subject: [PATCH 41/61] d/aws_s3_object: Use S3 downloader. --- internal/service/s3/object_data_source.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/internal/service/s3/object_data_source.go b/internal/service/s3/object_data_source.go index 9f6785dfa7b..e9ffb3f158d 100644 --- a/internal/service/s3/object_data_source.go +++ b/internal/service/s3/object_data_source.go @@ -4,7 +4,6 @@ package s3 import ( - "bytes" "context" "regexp" "strings" @@ -12,6 +11,7 @@ import ( "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -229,6 +229,8 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte d.Set("website_redirect_location", output.WebsiteRedirectLocation) if isContentTypeAllowed(output.ContentType) { + downloader := manager.NewDownloader(conn) + buf := manager.NewWriteAtBuffer(make([]byte, 0)) input := &s3.GetObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), @@ -238,19 +240,13 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte input.Range = aws.String(v.(string)) } - output, err := conn.GetObject(ctx, input) + _, err := downloader.Download(ctx, buf, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "getting S3 Bucket (%s) Object (%s): %s", bucket, key, err) + return sdkdiag.AppendErrorf(diags, "downloading S3 Bucket (%s) Object (%s): %s", bucket, key, err) } - buf := new(bytes.Buffer) - _, err = buf.ReadFrom(output.Body) - if err != nil { - return sdkdiag.AppendFromErr(diags, err) - } - - d.Set("body", buf.String()) + d.Set("body", string(buf.Bytes())) } tags, err := ObjectListTags(ctx, conn, bucket, key) From fbec9d9d4f4fcf14347912246bc7538a8f3a6f8e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 14:47:01 -0400 Subject: [PATCH 42/61] r/aws_s3_object: Tidy up acceptance test check functions. --- internal/service/s3/object_test.go | 112 +++++++++++++---------------- 1 file changed, 48 insertions(+), 64 deletions(-) diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index 19458f12948..e49f650d436 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -6,6 +6,7 @@ package s3_test import ( "context" "encoding/base64" + "errors" "fmt" "io" "os" @@ -484,7 +485,7 @@ func TestAccS3Object_updatesWithVersioning(t *testing.T) { testAccCheckObjectExists(ctx, resourceName, &modifiedObj), testAccCheckObjectBody(&modifiedObj, "modified versioned object"), resource.TestCheckResourceAttr(resourceName, "etag", "00b8c73b1b50e7cc932362c7225b8e29"), - testAccCheckObjectVersionIdDiffers(&modifiedObj, &originalObj), + testAccCheckObjectVersionIDDiffers(&modifiedObj, &originalObj), ), }, { @@ -531,7 +532,7 @@ func TestAccS3Object_updatesWithVersioningViaAccessPoint(t *testing.T) { testAccCheckObjectExists(ctx, resourceName, &modifiedObj), testAccCheckObjectBody(&modifiedObj, "modified versioned object"), resource.TestCheckResourceAttr(resourceName, "etag", "00b8c73b1b50e7cc932362c7225b8e29"), - testAccCheckObjectVersionIdDiffers(&modifiedObj, &originalObj), + testAccCheckObjectVersionIDDiffers(&modifiedObj, &originalObj), ), }, }, @@ -631,7 +632,7 @@ func TestAccS3Object_acl(t *testing.T) { Config: testAccObjectConfig_acl(rName, "some_bucket_content", string(types.BucketCannedACLPublicRead), false), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "some_bucket_content"), resource.TestCheckResourceAttr(resourceName, "acl", string(types.BucketCannedACLPublicRead)), testAccCheckObjectACL(ctx, resourceName, []string{"FULL_CONTROL", "READ"}), @@ -641,7 +642,7 @@ func TestAccS3Object_acl(t *testing.T) { Config: testAccObjectConfig_acl(rName, "changed_some_bucket_content", string(types.BucketCannedACLPrivate), true), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), - testAccCheckObjectVersionIdDiffers(&obj3, &obj2), + testAccCheckObjectVersionIDDiffers(&obj3, &obj2), testAccCheckObjectBody(&obj3, "changed_some_bucket_content"), resource.TestCheckResourceAttr(resourceName, "acl", string(types.BucketCannedACLPrivate)), testAccCheckObjectACL(ctx, resourceName, []string{"FULL_CONTROL"}), @@ -797,7 +798,7 @@ func TestAccS3Object_tags(t *testing.T) { Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "B@BB"), @@ -810,7 +811,7 @@ func TestAccS3Object_tags(t *testing.T) { Config: testAccObjectConfig_noTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), - testAccCheckObjectVersionIdEquals(&obj3, &obj2), + testAccCheckObjectVersionIDEquals(&obj3, &obj2), testAccCheckObjectBody(&obj3, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), @@ -819,7 +820,7 @@ func TestAccS3Object_tags(t *testing.T) { Config: testAccObjectConfig_tags(rName, key, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), - testAccCheckObjectVersionIdDiffers(&obj4, &obj3), + testAccCheckObjectVersionIDDiffers(&obj4, &obj3), testAccCheckObjectBody(&obj4, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), @@ -866,7 +867,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "B@BB"), @@ -879,7 +880,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { Config: testAccObjectConfig_noTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), - testAccCheckObjectVersionIdEquals(&obj3, &obj2), + testAccCheckObjectVersionIDEquals(&obj3, &obj2), testAccCheckObjectBody(&obj3, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), @@ -888,7 +889,7 @@ func TestAccS3Object_tagsLeadingSingleSlash(t *testing.T) { Config: testAccObjectConfig_tags(rName, key, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), - testAccCheckObjectVersionIdDiffers(&obj4, &obj3), + testAccCheckObjectVersionIDDiffers(&obj4, &obj3), testAccCheckObjectBody(&obj4, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), @@ -935,7 +936,7 @@ func TestAccS3Object_tagsLeadingMultipleSlashes(t *testing.T) { Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "B@BB"), @@ -948,7 +949,7 @@ func TestAccS3Object_tagsLeadingMultipleSlashes(t *testing.T) { Config: testAccObjectConfig_noTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), - testAccCheckObjectVersionIdEquals(&obj3, &obj2), + testAccCheckObjectVersionIDEquals(&obj3, &obj2), testAccCheckObjectBody(&obj3, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), @@ -957,7 +958,7 @@ func TestAccS3Object_tagsLeadingMultipleSlashes(t *testing.T) { Config: testAccObjectConfig_tags(rName, key, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), - testAccCheckObjectVersionIdDiffers(&obj4, &obj3), + testAccCheckObjectVersionIDDiffers(&obj4, &obj3), testAccCheckObjectBody(&obj4, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), @@ -997,7 +998,7 @@ func TestAccS3Object_tagsMultipleSlashes(t *testing.T) { Config: testAccObjectConfig_updatedTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "B@BB"), @@ -1010,7 +1011,7 @@ func TestAccS3Object_tagsMultipleSlashes(t *testing.T) { Config: testAccObjectConfig_noTags(rName, key, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), - testAccCheckObjectVersionIdEquals(&obj3, &obj2), + testAccCheckObjectVersionIDEquals(&obj3, &obj2), testAccCheckObjectBody(&obj3, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), @@ -1019,7 +1020,7 @@ func TestAccS3Object_tagsMultipleSlashes(t *testing.T) { Config: testAccObjectConfig_tags(rName, key, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), - testAccCheckObjectVersionIdDiffers(&obj4, &obj3), + testAccCheckObjectVersionIDDiffers(&obj4, &obj3), testAccCheckObjectBody(&obj4, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), @@ -1057,7 +1058,7 @@ func TestAccS3Object_objectLockLegalHoldStartWithNone(t *testing.T) { Config: testAccObjectConfig_lockLegalHold(rName, "stuff", "ON"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", "ON"), resource.TestCheckResourceAttr(resourceName, "object_lock_mode", ""), @@ -1069,7 +1070,7 @@ func TestAccS3Object_objectLockLegalHoldStartWithNone(t *testing.T) { Config: testAccObjectConfig_lockLegalHold(rName, "changed stuff", "OFF"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), - testAccCheckObjectVersionIdDiffers(&obj3, &obj2), + testAccCheckObjectVersionIDDiffers(&obj3, &obj2), testAccCheckObjectBody(&obj3, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", "OFF"), resource.TestCheckResourceAttr(resourceName, "object_lock_mode", ""), @@ -1106,7 +1107,7 @@ func TestAccS3Object_objectLockLegalHoldStartWithOn(t *testing.T) { Config: testAccObjectConfig_lockLegalHold(rName, "stuff", "OFF"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", "OFF"), resource.TestCheckResourceAttr(resourceName, "object_lock_mode", ""), @@ -1144,7 +1145,7 @@ func TestAccS3Object_objectLockRetentionStartWithNone(t *testing.T) { Config: testAccObjectConfig_lockRetention(rName, "stuff", retainUntilDate), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", ""), resource.TestCheckResourceAttr(resourceName, "object_lock_mode", "GOVERNANCE"), @@ -1156,7 +1157,7 @@ func TestAccS3Object_objectLockRetentionStartWithNone(t *testing.T) { Config: testAccObjectConfig_noLockRetention(rName, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), - testAccCheckObjectVersionIdDiffers(&obj3, &obj2), + testAccCheckObjectVersionIDDiffers(&obj3, &obj2), testAccCheckObjectBody(&obj3, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", ""), resource.TestCheckResourceAttr(resourceName, "object_lock_mode", ""), @@ -1196,7 +1197,7 @@ func TestAccS3Object_objectLockRetentionStartWithSet(t *testing.T) { Config: testAccObjectConfig_lockRetention(rName, "stuff", retainUntilDate2), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj2), - testAccCheckObjectVersionIdEquals(&obj2, &obj1), + testAccCheckObjectVersionIDEquals(&obj2, &obj1), testAccCheckObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", ""), resource.TestCheckResourceAttr(resourceName, "object_lock_mode", "GOVERNANCE"), @@ -1207,7 +1208,7 @@ func TestAccS3Object_objectLockRetentionStartWithSet(t *testing.T) { Config: testAccObjectConfig_lockRetention(rName, "stuff", retainUntilDate3), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj3), - testAccCheckObjectVersionIdEquals(&obj3, &obj2), + testAccCheckObjectVersionIDEquals(&obj3, &obj2), testAccCheckObjectBody(&obj3, "stuff"), resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", ""), resource.TestCheckResourceAttr(resourceName, "object_lock_mode", "GOVERNANCE"), @@ -1218,7 +1219,7 @@ func TestAccS3Object_objectLockRetentionStartWithSet(t *testing.T) { Config: testAccObjectConfig_noLockRetention(rName, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj4), - testAccCheckObjectVersionIdEquals(&obj4, &obj3), + testAccCheckObjectVersionIDEquals(&obj4, &obj3), testAccCheckObjectBody(&obj4, "stuff"), resource.TestCheckResourceAttr(resourceName, "object_lock_legal_hold_status", ""), resource.TestCheckResourceAttr(resourceName, "object_lock_mode", ""), @@ -1320,7 +1321,7 @@ func TestAccS3Object_ignoreTags(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckObjectExists(ctx, resourceName, &obj), testAccCheckObjectBody(&obj, "stuff"), - testAccCheckObjectUpdateTagsV1(ctx, resourceName, nil, map[string]string{"ignorekey1": "ignorevalue1"}), + testAccCheckObjectUpdateTags(ctx, resourceName, nil, map[string]string{"ignorekey1": "ignorevalue1"}), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), testAccCheckObjectCheckTags(ctx, resourceName, map[string]string{ "ignorekey1": "ignorevalue1", @@ -1397,34 +1398,20 @@ func TestAccS3Object_checksumAlgorithm(t *testing.T) { }) } -func testAccCheckObjectVersionIdDiffers(first, second *s3.GetObjectOutput) resource.TestCheckFunc { +func testAccCheckObjectVersionIDDiffers(first, second *s3.GetObjectOutput) resource.TestCheckFunc { return func(s *terraform.State) error { - if first.VersionId == nil { - return fmt.Errorf("Expected first object to have VersionId: %v", first) - } - if second.VersionId == nil { - return fmt.Errorf("Expected second object to have VersionId: %v", second) - } - - if *first.VersionId == *second.VersionId { - return fmt.Errorf("Expected Version IDs to differ, but they are equal (%s)", *first.VersionId) + if aws.ToString(first.VersionId) == aws.ToString(second.VersionId) { + return errors.New("S3 Object version IDs are equal") } return nil } } -func testAccCheckObjectVersionIdEquals(first, second *s3.GetObjectOutput) resource.TestCheckFunc { +func testAccCheckObjectVersionIDEquals(first, second *s3.GetObjectOutput) resource.TestCheckFunc { return func(s *terraform.State) error { - if first.VersionId == nil { - return fmt.Errorf("Expected first object to have VersionId: %v", first) - } - if second.VersionId == nil { - return fmt.Errorf("Expected second object to have VersionId: %v", second) - } - - if *first.VersionId != *second.VersionId { - return fmt.Errorf("Expected Version IDs to be equal, but they differ (%s, %s)", *first.VersionId, *second.VersionId) + if aws.ToString(first.VersionId) != aws.ToString(second.VersionId) { + return errors.New("S3 Object version IDs differ") } return nil @@ -1488,19 +1475,19 @@ func testAccCheckObjectBody(obj *s3.GetObjectOutput, want string) resource.TestC return func(s *terraform.State) error { body, err := io.ReadAll(obj.Body) if err != nil { - return fmt.Errorf("failed to read body: %s", err) + return err } obj.Body.Close() if got := string(body); got != want { - return fmt.Errorf("wrong result body %q; want %q", got, want) + return fmt.Errorf("S3 Object body = %v, want %v", got, want) } return nil } } -func testAccCheckObjectACL(ctx context.Context, n string, expectedPerms []string) resource.TestCheckFunc { +func testAccCheckObjectACL(ctx context.Context, n string, want []string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) @@ -1514,21 +1501,21 @@ func testAccCheckObjectACL(ctx context.Context, n string, expectedPerms []string return err } - var perms []string + var got []string for _, v := range output.Grants { - perms = append(perms, string(v.Permission)) + got = append(got, string(v.Permission)) } - sort.Strings(perms) + sort.Strings(got) - if diff := cmp.Diff(perms, expectedPerms); diff != "" { - return fmt.Errorf("unexpected diff (+wanted, -got): %s", diff) + if diff := cmp.Diff(got, want); diff != "" { + return fmt.Errorf("unexpected S3 Object ACL diff (+wanted, -got): %s", diff) } return nil } } -func testAccCheckObjectStorageClass(ctx context.Context, n, expectedClass string) resource.TestCheckFunc { +func testAccCheckObjectStorageClass(ctx context.Context, n, want string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) @@ -1546,16 +1533,15 @@ func testAccCheckObjectStorageClass(ctx context.Context, n, expectedClass string storageClass = output.StorageClass } - if string(storageClass) != expectedClass { - return fmt.Errorf("Expected Storage Class to be %v, got %v", - expectedClass, storageClass) + if got := string(storageClass); got != want { + return fmt.Errorf("S3 Object storage class = %v, want %v", got, want) } return nil } } -func testAccCheckObjectSSE(ctx context.Context, n, expectedSSE string) resource.TestCheckFunc { +func testAccCheckObjectSSE(ctx context.Context, n, want string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) @@ -1566,10 +1552,8 @@ func testAccCheckObjectSSE(ctx context.Context, n, expectedSSE string) resource. return err } - sse := output.ServerSideEncryption - if string(sse) != expectedSSE { - return fmt.Errorf("Expected Server Side Encryption %v, got %v.", - expectedSSE, sse) + if got := string(output.ServerSideEncryption); got != want { + return fmt.Errorf("S3 Object server-side encryption = %v, want %v", got, want) } return nil @@ -1592,7 +1576,7 @@ func testAccObjectCreateTempFile(t *testing.T, data string) string { return filename } -func testAccCheckObjectUpdateTagsV1(ctx context.Context, n string, oldTags, newTags map[string]string) resource.TestCheckFunc { +func testAccCheckObjectUpdateTags(ctx context.Context, n string, oldTags, newTags map[string]string) resource.TestCheckFunc { return func(s *terraform.State) error { rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) @@ -1613,7 +1597,7 @@ func testAccCheckObjectCheckTags(ctx context.Context, n string, expectedTags map want := tftags.New(ctx, expectedTags) if diff := cmp.Diff(got, want); diff != "" { - return fmt.Errorf("unexpected diff (+wanted, -got): %s", diff) + return fmt.Errorf("unexpected S3 Object tags diff (+wanted, -got): %s", diff) } return nil From 0b2e33fc4af8b064880b99a0800ce2504ee556ae Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 15:04:45 -0400 Subject: [PATCH 43/61] Add 'TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated'. --- internal/service/s3/object_copy_test.go | 38 ++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/internal/service/s3/object_copy_test.go b/internal/service/s3/object_copy_test.go index 0bbb741f7ed..85fe13a1cec 100644 --- a/internal/service/s3/object_copy_test.go +++ b/internal/service/s3/object_copy_test.go @@ -380,7 +380,7 @@ func TestAccS3ObjectCopy_targetWithMultipleSlashes(t *testing.T) { rName2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_s3_object_copy.test" sourceKey := "source" - targetKey := "/dir/target//" + targetKey := "/dir//target/" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -399,6 +399,42 @@ func TestAccS3ObjectCopy_targetWithMultipleSlashes(t *testing.T) { }) } +func TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated(t *testing.T) { + ctx := acctest.Context(t) + rName1 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_object_copy.test" + sourceKey := "source" + targetKey := "/dir//target/" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), + CheckDestroy: testAccCheckObjectCopyDestroy(ctx), + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + // Final version for aws_s3_object_copy using AWS SDK for Go v1. + "aws": { + Source: "hashicorp/aws", + VersionConstraint: "5.15.0", + }, + }, + Config: testAccObjectCopyConfig_basic(rName1, sourceKey, rName2, targetKey), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "key", targetKey), + resource.TestCheckResourceAttr(resourceName, "source", fmt.Sprintf("%s/%s", rName1, sourceKey)), + ), + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Config: testAccObjectCopyConfig_basic(rName1, sourceKey, rName2, targetKey), + PlanOnly: true, + }, + }, + }) +} + func testAccCheckObjectCopyDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) From 2a72e7635d1da551d46ba4c6ac51baf9f2e2e0de Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 15:05:46 -0400 Subject: [PATCH 44/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated' PKG=s3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 20 -run=TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated -timeout 180m === RUN TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated === PAUSE TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated === CONT TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated object_copy_test.go:410: Step 2/2 error: After applying this test step, the plan was not empty. stdout: Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_s3_object_copy.test will be created + resource "aws_s3_object_copy" "test" { + acl = (known after apply) + bucket = "tf-acc-test-1456995116566564165" + bucket_key_enabled = (known after apply) + cache_control = (known after apply) + checksum_crc32 = (known after apply) + checksum_crc32c = (known after apply) + checksum_sha1 = (known after apply) + checksum_sha256 = (known after apply) + content_disposition = (known after apply) + content_encoding = (known after apply) + content_language = (known after apply) + content_type = (known after apply) + customer_algorithm = (known after apply) + customer_key_md5 = (known after apply) + etag = (known after apply) + expiration = (known after apply) + force_destroy = false + id = (known after apply) + key = "/dir//target/" + kms_encryption_context = (sensitive value) + kms_key_id = (sensitive value) + last_modified = (known after apply) + metadata = (known after apply) + object_lock_legal_hold_status = (known after apply) + object_lock_mode = (known after apply) + object_lock_retain_until_date = (known after apply) + request_charged = (known after apply) + server_side_encryption = (known after apply) + source = "tf-acc-test-5545993207091720636/source" + source_version_id = (known after apply) + storage_class = (known after apply) + tags_all = (known after apply) + version_id = (known after apply) + website_redirect = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. testing_new.go:90: Error running post-test destroy, there may be dangling resources: exit status 1 Error: deleting Amazon S3 (Simple Storage) Bucket (tf-acc-test-1456995116566564165): BucketNotEmpty: The bucket you tried to delete is not empty status code: 409, request id: T854HGG8TFCW5D83, host id: 4NuguXdIOeZCx6GV2eHHEmaMVM/qOc1alnm8W/9OTSoz2y8eCSQkgbzcGgFqim6jxYgVlUrWdDzr2VssNzUtoA== --- FAIL: TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated (95.93s) FAIL FAIL github.com/hashicorp/terraform-provider-aws/internal/service/s3 101.864s FAIL make: *** [testacc] Error 1 From 594609a7188d3e4aff17ea29074fad9550f3dd36 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 15:30:26 -0400 Subject: [PATCH 45/61] s3: Add 'sdkv1CompatibleCleanKey'. --- internal/service/s3/exports_test.go | 1 + internal/service/s3/object.go | 12 +++++ internal/service/s3/object_test.go | 70 +++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/internal/service/s3/exports_test.go b/internal/service/s3/exports_test.go index 15c502515b9..c8ecf70dfda 100644 --- a/internal/service/s3/exports_test.go +++ b/internal/service/s3/exports_test.go @@ -7,4 +7,5 @@ package s3 var ( DeleteAllObjectVersions = deleteAllObjectVersions FindObjectByBucketAndKey = findObjectByBucketAndKey + SDKv1CompatibleCleanKey = sdkv1CompatibleCleanKey ) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index cc0bf3d599d..fb398a8102f 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -804,3 +804,15 @@ func flattenObjectDate(t *time.Time) string { return t.Format(time.RFC3339) } + +// sdkv1CompatibleCleanKey returns an AWS SDK for Go v1 compatible clean key. +// DisableRestProtocolURICleaning was false on the standard S3Conn, so to ensure backwards +// compatibility we must "clean" the configured key before passing to AWS SDK for Go v2 APIs. +// See https://docs.aws.amazon.com/sdk-for-go/api/service/s3/#hdr-Automatic_URI_cleaning. +// See https://github.com/aws/aws-sdk-go/blob/cf903c8c543034654bb8f53b5f9d6454fdb2117f/private/protocol/rest/build.go#L247-L258. +func sdkv1CompatibleCleanKey(key string) string { + // We are effectively ignoring all leading '/'s and treating multiple '/'s as a single '/'. + key = strings.TrimLeft(key, "/") + key = regexache.MustCompile(`/+`).ReplaceAllString(key, "/") + return key +} diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index e49f650d436..f99b33871f6 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -29,6 +29,76 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) +func TestSDKv1CompatibleCleanKey(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + key string + want string + }{ + { + name: "empty string", + }, + { + name: "no slashes", + key: "test-key", + want: "test-key", + }, + { + name: "simple slashes", + key: "dir1/dir2/test-key", + want: "dir1/dir2/test-key", + }, + { + name: "trailing slash", + key: "a/b/c/", + want: "a/b/c/", + }, + { + name: "leading slash", + key: "/a/b/c", + want: "a/b/c", + }, + { + name: "leading and trailing slashes", + key: "/a/b/c/", + want: "a/b/c/", + }, + { + name: "multiple leading slashes", + key: "/////a/b/c", + want: "a/b/c", + }, + { + name: "multiple trailing slashes", + key: "a/b/c/////", + want: "a/b/c/", + }, + { + name: "repeated inner slashes", + key: "a/b//c///d/////e", + want: "a/b/c/d/e", + }, + { + name: "all the slashes", + key: "/a/b//c///d/////e/", + want: "a/b/c/d/e/", + }, + } + + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + if got, want := tfs3.SDKv1CompatibleCleanKey(testCase.key), testCase.want; got != want { + t.Errorf("SDKv1CompatibleCleanKey(%q) = %v, want %v", testCase.key, got, want) + } + }) + } +} + func TestAccS3Object_basic(t *testing.T) { ctx := acctest.Context(t) var obj s3.GetObjectOutput From b41213f99c5b222eab4769193e6026b44c06c29f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 15:50:39 -0400 Subject: [PATCH 46/61] r/aws_s3_object_copy: Use 'sdkv1CompatibleCleanKey'. --- internal/service/s3/object.go | 38 ++++++++++++++++++ internal/service/s3/object_copy.go | 53 ++----------------------- internal/service/s3/object_copy_test.go | 8 ++-- 3 files changed, 44 insertions(+), 55 deletions(-) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index fb398a8102f..df2810a4f4d 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "log" + "net/http" "os" "strings" "time" @@ -22,6 +23,7 @@ import ( "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -612,6 +614,42 @@ func hasObjectContentChanges(d verify.ResourceDiffer) bool { return false } +func findObjectByBucketAndKey(ctx context.Context, conn *s3.Client, bucket, key, etag, checksumAlgorithm string) (*s3.HeadObjectOutput, error) { + input := &s3.HeadObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(key), + } + if checksumAlgorithm != "" { + input.ChecksumMode = types.ChecksumModeEnabled + } + if etag != "" { + input.IfMatch = aws.String(etag) + } + + return findObject(ctx, conn, input) +} + +func findObject(ctx context.Context, conn *s3.Client, input *s3.HeadObjectInput) (*s3.HeadObjectOutput, error) { + output, err := conn.HeadObject(ctx, input) + + if tfawserr.ErrHTTPStatusCodeEquals(err, http.StatusNotFound) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + // deleteAllObjectVersions deletes all versions of a specified key from an S3 bucket. // If key is empty then all versions of all objects are deleted. // Set force to true to override any S3 object lock protections on object lock enabled buckets. diff --git a/internal/service/s3/object_copy.go b/internal/service/s3/object_copy.go index 40dda451096..8cc595685b9 100644 --- a/internal/service/s3/object_copy.go +++ b/internal/service/s3/object_copy.go @@ -8,17 +8,13 @@ import ( "context" "fmt" "log" - "net/http" "net/url" "strings" - "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -336,7 +332,7 @@ func resourceObjectCopyRead(ctx context.Context, d *schema.ResourceData, meta in conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) - key := d.Get("key").(string) + key := sdkv1CompatibleCleanKey(d.Get("key").(string)) output, err := findObjectByBucketAndKey(ctx, conn, bucket, key, "", d.Get("checksum_algorithm").(string)) if !d.IsNewResource() && tfresource.NotFound(err) { @@ -459,14 +455,7 @@ func resourceObjectCopyDelete(ctx context.Context, d *schema.ResourceData, meta conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) - key := d.Get("key").(string) - // **************** - // TODO: REVIEW - // We are effectively ignoring all leading '/'s in the key name and - // treating multiple '/'s as a single '/' as aws.Config.DisableRestProtocolURICleaning is false - key = strings.TrimLeft(key, "/") - key = regexache.MustCompile(`/+`).ReplaceAllString(key, "/") - // **************** + key := sdkv1CompatibleCleanKey(d.Get("key").(string)) var err error if _, ok := d.GetOk("version_id"); ok { @@ -490,7 +479,7 @@ func resourceObjectCopyDoCopy(ctx context.Context, d *schema.ResourceData, meta input := &s3.CopyObjectInput{ Bucket: aws.String(d.Get("bucket").(string)), CopySource: aws.String(url.QueryEscape(d.Get("source").(string))), - Key: aws.String(d.Get("key").(string)), + Key: aws.String(sdkv1CompatibleCleanKey(d.Get("key").(string))), } if v, ok := d.GetOk("acl"); ok { @@ -658,42 +647,6 @@ func resourceObjectCopyDoCopy(ctx context.Context, d *schema.ResourceData, meta return append(diags, resourceObjectCopyRead(ctx, d, meta)...) } -func findObjectByBucketAndKey(ctx context.Context, conn *s3.Client, bucket, key, etag, checksumAlgorithm string) (*s3.HeadObjectOutput, error) { - input := &s3.HeadObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(key), - } - if checksumAlgorithm != "" { - input.ChecksumMode = types.ChecksumModeEnabled - } - if etag != "" { - input.IfMatch = aws.String(etag) - } - - return findObject(ctx, conn, input) -} - -func findObject(ctx context.Context, conn *s3.Client, input *s3.HeadObjectInput) (*s3.HeadObjectOutput, error) { - output, err := conn.HeadObject(ctx, input) - - if tfawserr.ErrHTTPStatusCodeEquals(err, http.StatusNotFound) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if err != nil { - return nil, err - } - - if output == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output, nil -} - type s3Grants struct { FullControl *string Read *string diff --git a/internal/service/s3/object_copy_test.go b/internal/service/s3/object_copy_test.go index 85fe13a1cec..def0d35abb6 100644 --- a/internal/service/s3/object_copy_test.go +++ b/internal/service/s3/object_copy_test.go @@ -444,7 +444,7 @@ func testAccCheckObjectCopyDestroy(ctx context.Context) resource.TestCheckFunc { continue } - _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"], "") + _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"]), rs.Primary.Attributes["etag"], "") if tfresource.NotFound(err) { continue @@ -470,7 +470,7 @@ func testAccCheckObjectCopyExists(ctx context.Context, n string) resource.TestCh conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"], "") + _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"]), rs.Primary.Attributes["etag"], "") return err } @@ -481,13 +481,11 @@ func testAccObjectCopyConfig_baseSourceAndTargetBuckets(sourceBucket, targetBuck resource "aws_s3_bucket" "source" { bucket = %[1]q - # force_destroy = true + force_destroy = true } resource "aws_s3_bucket" "target" { bucket = %[2]q - - # force_destroy = true } `, sourceBucket, targetBucket) } From 91fcd0ce19bb5de4943d7511f91317e3f98462f6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 15:51:11 -0400 Subject: [PATCH 47/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3ObjectCopy_' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3ObjectCopy_ -timeout 180m === RUN TestAccS3ObjectCopy_basic === PAUSE TestAccS3ObjectCopy_basic === RUN TestAccS3ObjectCopy_disappears === PAUSE TestAccS3ObjectCopy_disappears === RUN TestAccS3ObjectCopy_tags === PAUSE TestAccS3ObjectCopy_tags === RUN TestAccS3ObjectCopy_metadata === PAUSE TestAccS3ObjectCopy_metadata === RUN TestAccS3ObjectCopy_grant === PAUSE TestAccS3ObjectCopy_grant === RUN TestAccS3ObjectCopy_BucketKeyEnabled_bucket === PAUSE TestAccS3ObjectCopy_BucketKeyEnabled_bucket === RUN TestAccS3ObjectCopy_BucketKeyEnabled_object === PAUSE TestAccS3ObjectCopy_BucketKeyEnabled_object === RUN TestAccS3ObjectCopy_sourceWithSlashes === PAUSE TestAccS3ObjectCopy_sourceWithSlashes === RUN TestAccS3ObjectCopy_checksumAlgorithm === PAUSE TestAccS3ObjectCopy_checksumAlgorithm === RUN TestAccS3ObjectCopy_objectLockLegalHold === PAUSE TestAccS3ObjectCopy_objectLockLegalHold === RUN TestAccS3ObjectCopy_targetWithMultipleSlashes === PAUSE TestAccS3ObjectCopy_targetWithMultipleSlashes === RUN TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated === PAUSE TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated === CONT TestAccS3ObjectCopy_basic === CONT TestAccS3ObjectCopy_BucketKeyEnabled_object === CONT TestAccS3ObjectCopy_metadata --- PASS: TestAccS3ObjectCopy_basic (35.69s) === CONT TestAccS3ObjectCopy_objectLockLegalHold --- PASS: TestAccS3ObjectCopy_metadata (36.18s) === CONT TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated --- PASS: TestAccS3ObjectCopy_BucketKeyEnabled_object (36.27s) === CONT TestAccS3ObjectCopy_targetWithMultipleSlashes --- PASS: TestAccS3ObjectCopy_targetWithMultipleSlashes (31.51s) === CONT TestAccS3ObjectCopy_BucketKeyEnabled_bucket --- PASS: TestAccS3ObjectCopy_objectLockLegalHold (62.17s) === CONT TestAccS3ObjectCopy_checksumAlgorithm --- PASS: TestAccS3ObjectCopy_BucketKeyEnabled_bucket (32.30s) === CONT TestAccS3ObjectCopy_grant --- PASS: TestAccS3ObjectCopy_grant (30.83s) === CONT TestAccS3ObjectCopy_tags --- PASS: TestAccS3ObjectCopy_checksumAlgorithm (54.27s) === CONT TestAccS3ObjectCopy_sourceWithSlashes --- PASS: TestAccS3ObjectCopy_targetWithMultipleSlashesMigrated (122.31s) === CONT TestAccS3ObjectCopy_disappears --- PASS: TestAccS3ObjectCopy_disappears (35.41s) --- PASS: TestAccS3ObjectCopy_sourceWithSlashes (57.83s) --- PASS: TestAccS3ObjectCopy_tags (83.01s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 219.296s From 4182f2bf8e44ce23e7ebf5d991af1a1247cc65a0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 16:54:23 -0400 Subject: [PATCH 48/61] Add 'TestAccS3Object_keyWithSlashesMigrated'. --- internal/service/s3/object_test.go | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index f99b33871f6..e061887225d 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -1468,6 +1468,42 @@ func TestAccS3Object_checksumAlgorithm(t *testing.T) { }) } +func TestAccS3Object_keyWithSlashesMigrated(t *testing.T) { + ctx := acctest.Context(t) + // var obj s3.GetObjectOutput + resourceName := "aws_s3_object.object" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3EndpointID), + CheckDestroy: testAccCheckObjectDestroy(ctx), + Steps: []resource.TestStep{ + { + ExternalProviders: map[string]resource.ExternalProvider{ + // Final version for aws_s3_object_copy using AWS SDK for Go v1. + "aws": { + Source: "hashicorp/aws", + VersionConstraint: "5.16.0", + }, + }, + Config: testAccObjectConfig_keyWithSlashes(rName), + Check: resource.ComposeTestCheckFunc( + // Currently fails as we need to wrap key with SDKv1CompatibleCleanKey. + // testAccCheckObjectExists(ctx, resourceName, &obj), + resource.TestCheckResourceAttr(resourceName, "bucket", rName), + resource.TestCheckResourceAttr(resourceName, "key", "/a/b//c///d/////e/"), + ), + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Config: testAccObjectConfig_keyWithSlashes(rName), + PlanOnly: true, + }, + }, + }) +} + func testAccCheckObjectVersionIDDiffers(first, second *s3.GetObjectOutput) resource.TestCheckFunc { return func(s *terraform.State) error { if aws.ToString(first.VersionId) == aws.ToString(second.VersionId) { @@ -2262,3 +2298,16 @@ resource "aws_s3_object" "object" { } `, rName, checksumAlgorithm) } + +func testAccObjectConfig_keyWithSlashes(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_s3_object" "object" { + bucket = aws_s3_bucket.test.bucket + key = "/a/b//c///d/////e/" +} +`, rName) +} From ca8c798fd196232bacd9131e22ac0eb132fa929a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 16:54:39 -0400 Subject: [PATCH 49/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3Object_keyWithSlashesMigrated' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3Object_keyWithSlashesMigrated -timeout 180m internal/service/s3/object_test.go:1473:6: obj declared and not used FAIL github.com/hashicorp/terraform-provider-aws/internal/service/s3 [build failed] FAIL make: *** [testacc] Error 1 ewbankkit@ewbankkit-C02F408DML85 terraform-provider-aws % make testacc TESTARGS='-run=TestAccS3Object_keyWithSlashesMigrated' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3Object_keyWithSlashesMigrated -timeout 180m === RUN TestAccS3Object_keyWithSlashesMigrated === PAUSE TestAccS3Object_keyWithSlashesMigrated === CONT TestAccS3Object_keyWithSlashesMigrated object_test.go:1477: Step 2/2 error: After applying this test step, the plan was not empty. stdout: Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_s3_object.object will be created + resource "aws_s3_object" "object" { + acl = (known after apply) + bucket = "tf-acc-test-5235500162442053697" + bucket_key_enabled = (known after apply) + checksum_crc32 = (known after apply) + checksum_crc32c = (known after apply) + checksum_sha1 = (known after apply) + checksum_sha256 = (known after apply) + content_type = (known after apply) + etag = (known after apply) + force_destroy = false + id = (known after apply) + key = "/a/b//c///d/////e/" + kms_key_id = (known after apply) + server_side_encryption = (known after apply) + storage_class = (known after apply) + tags_all = (known after apply) + version_id = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. testing_new.go:90: Error running post-test destroy, there may be dangling resources: exit status 1 Error: deleting Amazon S3 (Simple Storage) Bucket (tf-acc-test-5235500162442053697): BucketNotEmpty: The bucket you tried to delete is not empty status code: 409, request id: CGPGV5JWNKZB60MX, host id: IQ9eFJ2HrOpri+/LPXr5GGi14Joqx+xlBU4qEpyINMq4bThDlJxsqUYwAe3RgmUZwk3RAjc9Evw= --- FAIL: TestAccS3Object_keyWithSlashesMigrated (70.50s) FAIL FAIL github.com/hashicorp/terraform-provider-aws/internal/service/s3 76.113s FAIL make: *** [testacc] Error 1 From 55f8d29d68369fa1d7da00353c4c239eba106baf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 17:06:15 -0400 Subject: [PATCH 50/61] r/aws_s3_object: Use 'sdkv1CompatibleCleanKey'. --- internal/service/s3/object.go | 23 +++++++---------------- internal/service/s3/object_test.go | 19 +++++++++---------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index df2810a4f4d..da45e66d2d5 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -225,7 +225,7 @@ func resourceObjectRead(ctx context.Context, d *schema.ResourceData, meta interf conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) - key := d.Get("key").(string) + key := sdkv1CompatibleCleanKey(d.Get("key").(string)) output, err := findObjectByBucketAndKey(ctx, conn, bucket, key, "", d.Get("checksum_algorithm").(string)) if !d.IsNewResource() && tfresource.NotFound(err) { @@ -288,7 +288,7 @@ func resourceObjectUpdate(ctx context.Context, d *schema.ResourceData, meta inte conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) - key := d.Get("key").(string) + key := sdkv1CompatibleCleanKey(d.Get("key").(string)) if d.HasChange("acl") { input := &s3.PutObjectAclInput{ @@ -363,14 +363,7 @@ func resourceObjectDelete(ctx context.Context, d *schema.ResourceData, meta inte conn := meta.(*conns.AWSClient).S3Client(ctx) bucket := d.Get("bucket").(string) - key := d.Get("key").(string) - // **************** - // TODO: REVIEW - // We are effectively ignoring all leading '/'s in the key name and - // treating multiple '/'s as a single '/' as aws.Config.DisableRestProtocolURICleaning is false - key = strings.TrimLeft(key, "/") - key = regexache.MustCompile(`/+`).ReplaceAllString(key, "/") - // **************** + key := sdkv1CompatibleCleanKey(d.Get("key").(string)) var err error if _, ok := d.GetOk("version_id"); ok { @@ -448,12 +441,10 @@ func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta inte body = bytes.NewReader([]byte{}) } - bucket := d.Get("bucket").(string) - key := d.Get("key").(string) input := &s3.PutObjectInput{ Body: body, - Bucket: aws.String(bucket), - Key: aws.String(key), + Bucket: aws.String(d.Get("bucket").(string)), + Key: aws.String(sdkv1CompatibleCleanKey(d.Get("key").(string))), } if v, ok := d.GetOk("acl"); ok { @@ -533,11 +524,11 @@ func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta inte } if _, err := uploader.Upload(ctx, input); err != nil { - return sdkdiag.AppendErrorf(diags, "uploading S3 Object (%s) to Bucket (%s): %s", key, bucket, err) + return sdkdiag.AppendErrorf(diags, "uploading S3 Object (%s) to Bucket (%s): %s", aws.ToString(input.Key), aws.ToString(input.Bucket), err) } if d.IsNewResource() { - d.SetId(key) + d.SetId(d.Get("key").(string)) } return append(diags, resourceObjectRead(ctx, d, meta)...) diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index e061887225d..bce1c01a321 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -1470,7 +1470,7 @@ func TestAccS3Object_checksumAlgorithm(t *testing.T) { func TestAccS3Object_keyWithSlashesMigrated(t *testing.T) { ctx := acctest.Context(t) - // var obj s3.GetObjectOutput + var obj s3.GetObjectOutput resourceName := "aws_s3_object.object" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -1489,8 +1489,7 @@ func TestAccS3Object_keyWithSlashesMigrated(t *testing.T) { }, Config: testAccObjectConfig_keyWithSlashes(rName), Check: resource.ComposeTestCheckFunc( - // Currently fails as we need to wrap key with SDKv1CompatibleCleanKey. - // testAccCheckObjectExists(ctx, resourceName, &obj), + testAccCheckObjectExists(ctx, resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "bucket", rName), resource.TestCheckResourceAttr(resourceName, "key", "/a/b//c///d/////e/"), ), @@ -1533,7 +1532,7 @@ func testAccCheckObjectDestroy(ctx context.Context) resource.TestCheckFunc { continue } - _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], rs.Primary.Attributes["etag"], rs.Primary.Attributes["checksum_algorithm"]) + _, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"]), rs.Primary.Attributes["etag"], rs.Primary.Attributes["checksum_algorithm"]) if tfresource.NotFound(err) { continue @@ -1561,7 +1560,7 @@ func testAccCheckObjectExists(ctx context.Context, n string, v *s3.GetObjectOutp input := &s3.GetObjectInput{ Bucket: aws.String(rs.Primary.Attributes["bucket"]), - Key: aws.String(rs.Primary.Attributes["key"]), + Key: aws.String(tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"])), IfMatch: aws.String(rs.Primary.Attributes["etag"]), } @@ -1600,7 +1599,7 @@ func testAccCheckObjectACL(ctx context.Context, n string, want []string) resourc output, err := conn.GetObjectAcl(ctx, &s3.GetObjectAclInput{ Bucket: aws.String(rs.Primary.Attributes["bucket"]), - Key: aws.String(rs.Primary.Attributes["key"]), + Key: aws.String(tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"])), }) if err != nil { @@ -1626,7 +1625,7 @@ func testAccCheckObjectStorageClass(ctx context.Context, n, want string) resourc rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - output, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "", "") + output, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"]), "", "") if err != nil { return err @@ -1652,7 +1651,7 @@ func testAccCheckObjectSSE(ctx context.Context, n, want string) resource.TestChe rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - output, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], "", "") + output, err := tfs3.FindObjectByBucketAndKey(ctx, conn, rs.Primary.Attributes["bucket"], tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"]), "", "") if err != nil { return err @@ -1687,7 +1686,7 @@ func testAccCheckObjectUpdateTags(ctx context.Context, n string, oldTags, newTag rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - return tfs3.ObjectUpdateTags(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"], oldTags, newTags) + return tfs3.ObjectUpdateTags(ctx, conn, rs.Primary.Attributes["bucket"], tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"]), oldTags, newTags) } } @@ -1696,7 +1695,7 @@ func testAccCheckObjectCheckTags(ctx context.Context, n string, expectedTags map rs := s.RootModule().Resources[n] conn := acctest.Provider.Meta().(*conns.AWSClient).S3Client(ctx) - got, err := tfs3.ObjectListTags(ctx, conn, rs.Primary.Attributes["bucket"], rs.Primary.Attributes["key"]) + got, err := tfs3.ObjectListTags(ctx, conn, rs.Primary.Attributes["bucket"], tfs3.SDKv1CompatibleCleanKey(rs.Primary.Attributes["key"])) if err != nil { return err } From 55100be418034e579986349a26d0aff530363c90 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 Sep 2023 17:20:50 -0400 Subject: [PATCH 51/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3Object_' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3Object_ -timeout 180m === RUN TestAccS3Object_basic === PAUSE TestAccS3Object_basic === RUN TestAccS3Object_upgradeFromV4 === PAUSE TestAccS3Object_upgradeFromV4 === RUN TestAccS3Object_source === PAUSE TestAccS3Object_source === RUN TestAccS3Object_content === PAUSE TestAccS3Object_content === RUN TestAccS3Object_etagEncryption === PAUSE TestAccS3Object_etagEncryption === RUN TestAccS3Object_contentBase64 === PAUSE TestAccS3Object_contentBase64 === RUN TestAccS3Object_sourceHashTrigger === PAUSE TestAccS3Object_sourceHashTrigger === RUN TestAccS3Object_withContentCharacteristics === PAUSE TestAccS3Object_withContentCharacteristics === RUN TestAccS3Object_nonVersioned === PAUSE TestAccS3Object_nonVersioned === RUN TestAccS3Object_updates === PAUSE TestAccS3Object_updates === RUN TestAccS3Object_updateSameFile === PAUSE TestAccS3Object_updateSameFile === RUN TestAccS3Object_updatesWithVersioning === PAUSE TestAccS3Object_updatesWithVersioning === RUN TestAccS3Object_updatesWithVersioningViaAccessPoint === PAUSE TestAccS3Object_updatesWithVersioningViaAccessPoint === RUN TestAccS3Object_kms === PAUSE TestAccS3Object_kms === RUN TestAccS3Object_sse === PAUSE TestAccS3Object_sse === RUN TestAccS3Object_acl === PAUSE TestAccS3Object_acl === RUN TestAccS3Object_metadata === PAUSE TestAccS3Object_metadata === RUN TestAccS3Object_storageClass === PAUSE TestAccS3Object_storageClass === RUN TestAccS3Object_tags === PAUSE TestAccS3Object_tags === RUN TestAccS3Object_tagsLeadingSingleSlash === PAUSE TestAccS3Object_tagsLeadingSingleSlash === RUN TestAccS3Object_tagsLeadingMultipleSlashes === PAUSE TestAccS3Object_tagsLeadingMultipleSlashes === RUN TestAccS3Object_tagsMultipleSlashes === PAUSE TestAccS3Object_tagsMultipleSlashes === RUN TestAccS3Object_objectLockLegalHoldStartWithNone === PAUSE TestAccS3Object_objectLockLegalHoldStartWithNone === RUN TestAccS3Object_objectLockLegalHoldStartWithOn === PAUSE TestAccS3Object_objectLockLegalHoldStartWithOn === RUN TestAccS3Object_objectLockRetentionStartWithNone === PAUSE TestAccS3Object_objectLockRetentionStartWithNone === RUN TestAccS3Object_objectLockRetentionStartWithSet === PAUSE TestAccS3Object_objectLockRetentionStartWithSet === RUN TestAccS3Object_objectBucketKeyEnabled === PAUSE TestAccS3Object_objectBucketKeyEnabled === RUN TestAccS3Object_bucketBucketKeyEnabled === PAUSE TestAccS3Object_bucketBucketKeyEnabled === RUN TestAccS3Object_defaultBucketSSE === PAUSE TestAccS3Object_defaultBucketSSE === RUN TestAccS3Object_ignoreTags === PAUSE TestAccS3Object_ignoreTags === RUN TestAccS3Object_checksumAlgorithm === PAUSE TestAccS3Object_checksumAlgorithm === RUN TestAccS3Object_keyWithSlashesMigrated === PAUSE TestAccS3Object_keyWithSlashesMigrated === CONT TestAccS3Object_basic === CONT TestAccS3Object_metadata === CONT TestAccS3Object_keyWithSlashesMigrated --- PASS: TestAccS3Object_basic (35.73s) === CONT TestAccS3Object_checksumAlgorithm --- PASS: TestAccS3Object_metadata (91.09s) === CONT TestAccS3Object_ignoreTags --- PASS: TestAccS3Object_checksumAlgorithm (66.46s) === CONT TestAccS3Object_defaultBucketSSE --- PASS: TestAccS3Object_keyWithSlashesMigrated (102.42s) === CONT TestAccS3Object_bucketBucketKeyEnabled --- PASS: TestAccS3Object_bucketBucketKeyEnabled (31.73s) === CONT TestAccS3Object_objectBucketKeyEnabled --- PASS: TestAccS3Object_defaultBucketSSE (32.00s) === CONT TestAccS3Object_objectLockRetentionStartWithSet --- PASS: TestAccS3Object_ignoreTags (63.44s) === CONT TestAccS3Object_objectLockRetentionStartWithNone --- PASS: TestAccS3Object_objectBucketKeyEnabled (29.37s) === CONT TestAccS3Object_objectLockLegalHoldStartWithOn --- PASS: TestAccS3Object_objectLockLegalHoldStartWithOn (57.65s) === CONT TestAccS3Object_objectLockLegalHoldStartWithNone --- PASS: TestAccS3Object_objectLockRetentionStartWithNone (84.30s) === CONT TestAccS3Object_tagsMultipleSlashes --- PASS: TestAccS3Object_objectLockRetentionStartWithSet (110.53s) === CONT TestAccS3Object_tagsLeadingMultipleSlashes --- PASS: TestAccS3Object_objectLockLegalHoldStartWithNone (86.08s) === CONT TestAccS3Object_tagsLeadingSingleSlash --- PASS: TestAccS3Object_tagsMultipleSlashes (111.42s) === CONT TestAccS3Object_tags --- PASS: TestAccS3Object_tagsLeadingMultipleSlashes (111.12s) === CONT TestAccS3Object_storageClass --- PASS: TestAccS3Object_tagsLeadingSingleSlash (121.41s) === CONT TestAccS3Object_nonVersioned acctest.go:1604: skipping test; environment variable TF_ACC_ASSUME_ROLE_ARN must be set. Usage: Amazon Resource Name (ARN) of existing IAM Role to assume for testing restricted permissions --- SKIP: TestAccS3Object_nonVersioned (0.00s) === CONT TestAccS3Object_acl --- PASS: TestAccS3Object_tags (121.68s) === CONT TestAccS3Object_sse --- PASS: TestAccS3Object_storageClass (133.60s) === CONT TestAccS3Object_kms --- PASS: TestAccS3Object_sse (35.77s) === CONT TestAccS3Object_updatesWithVersioningViaAccessPoint --- PASS: TestAccS3Object_kms (36.58s) === CONT TestAccS3Object_updatesWithVersioning --- PASS: TestAccS3Object_acl (97.87s) === CONT TestAccS3Object_updateSameFile --- PASS: TestAccS3Object_updatesWithVersioningViaAccessPoint (62.88s) === CONT TestAccS3Object_updates --- PASS: TestAccS3Object_updateSameFile (61.68s) === CONT TestAccS3Object_etagEncryption --- PASS: TestAccS3Object_updatesWithVersioning (63.81s) === CONT TestAccS3Object_withContentCharacteristics --- PASS: TestAccS3Object_withContentCharacteristics (36.69s) === CONT TestAccS3Object_sourceHashTrigger --- PASS: TestAccS3Object_etagEncryption (40.60s) === CONT TestAccS3Object_contentBase64 --- PASS: TestAccS3Object_updates (75.49s) === CONT TestAccS3Object_source --- PASS: TestAccS3Object_contentBase64 (39.54s) === CONT TestAccS3Object_content --- PASS: TestAccS3Object_source (42.97s) === CONT TestAccS3Object_upgradeFromV4 --- PASS: TestAccS3Object_sourceHashTrigger (80.21s) --- PASS: TestAccS3Object_content (51.50s) --- PASS: TestAccS3Object_upgradeFromV4 (94.80s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 789.434s From 53d08ef1a465ab17571e40891920ee088545ee7a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 10:21:29 -0400 Subject: [PATCH 52/61] Tweak comment. --- internal/service/s3/object_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index bce1c01a321..1d1a85e6ab8 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -1481,7 +1481,7 @@ func TestAccS3Object_keyWithSlashesMigrated(t *testing.T) { Steps: []resource.TestStep{ { ExternalProviders: map[string]resource.ExternalProvider{ - // Final version for aws_s3_object_copy using AWS SDK for Go v1. + // Final version for aws_s3_object using AWS SDK for Go v1. "aws": { Source: "hashicorp/aws", VersionConstraint: "5.16.0", From 31cdf170d32d0ea019c67119b581f22102088572 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 11:06:12 -0400 Subject: [PATCH 53/61] Add AWSClient.S3UsePathStyle -- used by S3 sweepers. --- internal/conns/awsclient.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/conns/awsclient.go b/internal/conns/awsclient.go index 9ddf9c8133a..15bf9794b2f 100644 --- a/internal/conns/awsclient.go +++ b/internal/conns/awsclient.go @@ -58,6 +58,11 @@ func (client *AWSClient) RegionalHostname(prefix string) string { return fmt.Sprintf("%s.%s.%s", prefix, client.Region, client.DNSSuffix) } +// S3UsePathStyle returns the s3_force_path_style provider configuration value. +func (client *AWSClient) S3UsePathStyle() bool { + return client.s3UsePathStyle +} + // **************** // TODO: REVIEW // TODO: AWS SDK for Go v2 does NO URL cleaning. From 62f2c2b0c1c69f859cf7c193b1affcffe1074d3a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 11:07:38 -0400 Subject: [PATCH 54/61] s3: Migrate sweepers to AWS SDK for Go v2. --- internal/service/s3/sweep.go | 166 ++++++++++++----------------------- 1 file changed, 57 insertions(+), 109 deletions(-) diff --git a/internal/service/s3/sweep.go b/internal/service/s3/sweep.go index 5fbb9465c0e..078bd3af9d4 100644 --- a/internal/service/s3/sweep.go +++ b/internal/service/s3/sweep.go @@ -14,15 +14,15 @@ import ( "time" "github.com/YakDriver/regexache" - s3_sdkv2 "github.com/aws/aws-sdk-go-v2/service/s3" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3manager" - "github.com/hashicorp/go-multierror" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/feature/s3/manager" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/sweep" + "github.com/hashicorp/terraform-provider-aws/internal/sweep/awsv2" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) @@ -49,16 +49,16 @@ func sweepObjects(region string) error { if err != nil { return fmt.Errorf("getting client: %s", err) } - - conn := client.S3ConnURICleaningDisabled(ctx) - connV2 := client.S3Client(ctx) + conn := client.S3Client(ctx) input := &s3.ListBucketsInput{} - output, err := conn.ListBucketsWithContext(ctx, input) - if sweep.SkipSweepError(err) { + output, err := conn.ListBuckets(ctx, input) + + if awsv2.SkipSweepError(err) { log.Printf("[WARN] Skipping S3 Objects sweep for %s: %s", region, err) return nil } + if err != nil { return fmt.Errorf("listing S3 Buckets: %w", err) } @@ -68,53 +68,36 @@ func sweepObjects(region string) error { return nil } + buckets := tfslices.Filter(output.Buckets, bucketRegionFilter(ctx, conn, region, client.S3UsePathStyle())) + buckets = tfslices.Filter(buckets, bucketNameFilter) sweepables := make([]sweep.Sweepable, 0) - var errs *multierror.Error - - buckets, err := filterBuckets(output.Buckets, bucketRegionFilter(ctx, conn, region)) - if err != nil { - errs = multierror.Append(errs, err) - } - - buckets, err = filterBuckets(buckets, bucketNameFilter) - if err != nil { - errs = multierror.Append(errs, err) - } for _, bucket := range buckets { - bucketName := aws.StringValue(bucket.Name) - - objectLockEnabled, err := objectLockEnabled(ctx, conn, bucketName) - if err != nil { - errs = multierror.Append(errs, fmt.Errorf("reading S3 Bucket (%s) object lock: %w", bucketName, err)) - continue - } - sweepables = append(sweepables, objectSweeper{ - conn: connV2, - name: bucketName, - locked: objectLockEnabled, + conn: conn, + name: aws.ToString(bucket.Name), }) } - if err := sweep.SweepOrchestrator(ctx, sweepables); err != nil { - errs = multierror.Append(errs, fmt.Errorf("sweeping DynamoDB Backups for %s: %w", region, err)) + err = sweep.SweepOrchestrator(ctx, sweepables) + + if err != nil { + return fmt.Errorf("error sweeping S3 Objects (%s): %w", region, err) } - return errs.ErrorOrNil() + return nil } type objectSweeper struct { - conn *s3_sdkv2.Client - name string - locked bool + conn *s3.Client + name string } func (os objectSweeper) Delete(ctx context.Context, timeout time.Duration, optFns ...tfresource.OptionsFunc) error { - // Delete everything including locked objects - _, err := deleteAllObjectVersions(ctx, os.conn, os.name, "", os.locked, true) + // Delete everything including locked objects. + _, err := deleteAllObjectVersions(ctx, os.conn, os.name, "", true, true) if err != nil { - return fmt.Errorf("deleting S3 Bucket (%s) contents: %w", os.name, err) + return fmt.Errorf("deleting S3 Bucket (%s) objects: %w", os.name, err) } return nil } @@ -125,13 +108,12 @@ func sweepBuckets(region string) error { if err != nil { return fmt.Errorf("getting client: %s", err) } - - conn := client.S3Conn(ctx) + conn := client.S3Client(ctx) input := &s3.ListBucketsInput{} - output, err := conn.ListBucketsWithContext(ctx, input) + output, err := conn.ListBuckets(ctx, input) - if sweep.SkipSweepError(err) { + if awsv2.SkipSweepError(err) { log.Printf("[WARN] Skipping S3 Buckets sweep for %s: %s", region, err) return nil } @@ -145,44 +127,38 @@ func sweepBuckets(region string) error { return nil } - var errs *multierror.Error - sweepResources := make([]sweep.Sweepable, 0) - - buckets, err := filterBuckets(output.Buckets, bucketRegionFilter(ctx, conn, region)) - if err != nil { - errs = multierror.Append(errs, err) - } - - buckets, err = filterBuckets(buckets, bucketNameFilter) - if err != nil { - errs = multierror.Append(errs, err) - } + buckets := tfslices.Filter(output.Buckets, bucketRegionFilter(ctx, conn, region, client.S3UsePathStyle())) + buckets = tfslices.Filter(buckets, bucketNameFilter) + sweepables := make([]sweep.Sweepable, 0) for _, bucket := range buckets { - name := aws.StringValue(bucket.Name) + name := aws.ToString(bucket.Name) r := ResourceBucket() d := r.Data(nil) d.SetId(name) - sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) + sweepables = append(sweepables, sweep.NewSweepResource(r, d, client)) } - if err := sweep.SweepOrchestrator(ctx, sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("sweeping S3 Buckets for %s: %w", region, err)) + err = sweep.SweepOrchestrator(ctx, sweepables) + + if err != nil { + return fmt.Errorf("error sweeping S3 Buckets (%s): %w", region, err) } - return errs.ErrorOrNil() + return nil } -func bucketRegion(ctx context.Context, conn *s3.S3, bucket string) (string, error) { - region, err := s3manager.GetBucketRegionWithClient(ctx, conn, bucket, func(r *request.Request) { +func bucketRegion(ctx context.Context, conn *s3.Client, bucket string, s3UsePathStyle bool) (string, error) { + region, err := manager.GetBucketRegion(ctx, conn, bucket, func(o *s3.Options) { // By default, GetBucketRegion forces virtual host addressing, which // is not compatible with many non-AWS implementations. Instead, pass // the provider s3_force_path_style configuration, which defaults to // false, but allows override. - r.Config.S3ForcePathStyle = conn.Config.S3ForcePathStyle + o.UsePathStyle = s3UsePathStyle }) + if err != nil { return "", err } @@ -190,39 +166,8 @@ func bucketRegion(ctx context.Context, conn *s3.S3, bucket string) (string, erro return region, nil } -func objectLockEnabled(ctx context.Context, conn *s3.S3, bucket string) (bool, error) { - output, err := FindObjectLockConfiguration(ctx, conn, bucket, "") - - if tfresource.NotFound(err) { - return false, nil - } - - if err != nil { - return false, err - } - - return aws.StringValue(output.ObjectLockEnabled) == s3.ObjectLockEnabledEnabled, nil -} - -type bucketFilter func(*s3.Bucket) (bool, error) - -func filterBuckets(in []*s3.Bucket, f bucketFilter) ([]*s3.Bucket, error) { - var errs *multierror.Error - var out []*s3.Bucket - - for _, b := range in { - if ok, err := f(b); err != nil { - errs = multierror.Append(errs, err) - } else if ok { - out = append(out, b) - } - } - - return out, errs.ErrorOrNil() -} - -func bucketNameFilter(bucket *s3.Bucket) (bool, error) { - name := aws.StringValue(bucket.Name) +func bucketNameFilter(bucket types.Bucket) bool { + name := aws.ToString(bucket.Name) prefixes := []string{ "tf-acc", @@ -232,35 +177,38 @@ func bucketNameFilter(bucket *s3.Bucket) (bool, error) { } for _, prefix := range prefixes { if strings.HasPrefix(name, prefix) { - return true, nil + return true } } if defaultNameRegexp.MatchString(name) { - return true, nil + return true } log.Printf("[INFO] Skipping S3 Bucket (%s): not in prefix list", name) - return false, nil + return false } var ( defaultNameRegexp = regexache.MustCompile(fmt.Sprintf(`^%s\d+$`, id.UniqueIdPrefix)) ) -func bucketRegionFilter(ctx context.Context, conn *s3.S3, region string) bucketFilter { - return func(bucket *s3.Bucket) (bool, error) { - name := aws.StringValue(bucket.Name) +func bucketRegionFilter(ctx context.Context, conn *s3.Client, region string, s3UsePathStyle bool) tfslices.Predicate[types.Bucket] { + return func(bucket types.Bucket) bool { + name := aws.ToString(bucket.Name) + + bucketRegion, err := bucketRegion(ctx, conn, name, s3UsePathStyle) - bucketRegion, err := bucketRegion(ctx, conn, name) if err != nil { - return false, err + log.Printf("[WARN] Getting S3 Bucket (%s) region: %s", name, err) + return false } + if bucketRegion != region { log.Printf("[INFO] Skipping S3 Bucket (%s): not in %s", name, region) - return false, nil + return false } - return true, nil + return true } } From 56fc1aff75acc09e885ae90af7e043c79d8bbd13 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 11:10:26 -0400 Subject: [PATCH 55/61] Revert "r/aws_s3_object(test): fixed _tags post destroy bucket deletion error" This reverts commit e2177f13c54287d8aa09a92af00a1180e8149cf7. --- internal/service/s3/object_test.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index 1d1a85e6ab8..af736b712d4 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -1958,8 +1958,7 @@ resource "aws_s3_object" "object" { func testAccObjectConfig_tags(rName, key, content string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { - bucket = %[1]q - force_destroy = true + bucket = %[1]q } resource "aws_s3_bucket_versioning" "test" { @@ -1987,8 +1986,7 @@ resource "aws_s3_object" "object" { func testAccObjectConfig_updatedTags(rName, key, content string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { - bucket = %[1]q - force_destroy = true + bucket = %[1]q } resource "aws_s3_bucket_versioning" "test" { @@ -2017,8 +2015,7 @@ resource "aws_s3_object" "object" { func testAccObjectConfig_noTags(rName, key, content string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { - bucket = %[1]q - force_destroy = true + bucket = %[1]q } resource "aws_s3_bucket_versioning" "test" { From e7046aaf494f0648a7a7524067f35883c5ee4841 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 11:34:02 -0400 Subject: [PATCH 56/61] Acceptance test output: % make testacc TESTARGS='-run=TestAccS3Object_' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3Object_ -timeout 180m === RUN TestAccS3Object_basic === PAUSE TestAccS3Object_basic === RUN TestAccS3Object_upgradeFromV4 === PAUSE TestAccS3Object_upgradeFromV4 === RUN TestAccS3Object_source === PAUSE TestAccS3Object_source === RUN TestAccS3Object_content === PAUSE TestAccS3Object_content === RUN TestAccS3Object_etagEncryption === PAUSE TestAccS3Object_etagEncryption === RUN TestAccS3Object_contentBase64 === PAUSE TestAccS3Object_contentBase64 === RUN TestAccS3Object_sourceHashTrigger === PAUSE TestAccS3Object_sourceHashTrigger === RUN TestAccS3Object_withContentCharacteristics === PAUSE TestAccS3Object_withContentCharacteristics === RUN TestAccS3Object_nonVersioned === PAUSE TestAccS3Object_nonVersioned === RUN TestAccS3Object_updates === PAUSE TestAccS3Object_updates === RUN TestAccS3Object_updateSameFile === PAUSE TestAccS3Object_updateSameFile === RUN TestAccS3Object_updatesWithVersioning === PAUSE TestAccS3Object_updatesWithVersioning === RUN TestAccS3Object_updatesWithVersioningViaAccessPoint === PAUSE TestAccS3Object_updatesWithVersioningViaAccessPoint === RUN TestAccS3Object_kms === PAUSE TestAccS3Object_kms === RUN TestAccS3Object_sse === PAUSE TestAccS3Object_sse === RUN TestAccS3Object_acl === PAUSE TestAccS3Object_acl === RUN TestAccS3Object_metadata === PAUSE TestAccS3Object_metadata === RUN TestAccS3Object_storageClass === PAUSE TestAccS3Object_storageClass === RUN TestAccS3Object_tags === PAUSE TestAccS3Object_tags === RUN TestAccS3Object_tagsLeadingSingleSlash === PAUSE TestAccS3Object_tagsLeadingSingleSlash === RUN TestAccS3Object_tagsLeadingMultipleSlashes === PAUSE TestAccS3Object_tagsLeadingMultipleSlashes === RUN TestAccS3Object_tagsMultipleSlashes === PAUSE TestAccS3Object_tagsMultipleSlashes === RUN TestAccS3Object_objectLockLegalHoldStartWithNone === PAUSE TestAccS3Object_objectLockLegalHoldStartWithNone === RUN TestAccS3Object_objectLockLegalHoldStartWithOn === PAUSE TestAccS3Object_objectLockLegalHoldStartWithOn === RUN TestAccS3Object_objectLockRetentionStartWithNone === PAUSE TestAccS3Object_objectLockRetentionStartWithNone === RUN TestAccS3Object_objectLockRetentionStartWithSet === PAUSE TestAccS3Object_objectLockRetentionStartWithSet === RUN TestAccS3Object_objectBucketKeyEnabled === PAUSE TestAccS3Object_objectBucketKeyEnabled === RUN TestAccS3Object_bucketBucketKeyEnabled === PAUSE TestAccS3Object_bucketBucketKeyEnabled === RUN TestAccS3Object_defaultBucketSSE === PAUSE TestAccS3Object_defaultBucketSSE === RUN TestAccS3Object_ignoreTags === PAUSE TestAccS3Object_ignoreTags === RUN TestAccS3Object_checksumAlgorithm === PAUSE TestAccS3Object_checksumAlgorithm === RUN TestAccS3Object_keyWithSlashesMigrated === PAUSE TestAccS3Object_keyWithSlashesMigrated === CONT TestAccS3Object_basic === CONT TestAccS3Object_metadata === CONT TestAccS3Object_objectLockRetentionStartWithNone --- PASS: TestAccS3Object_basic (33.76s) === CONT TestAccS3Object_keyWithSlashesMigrated --- PASS: TestAccS3Object_metadata (77.59s) === CONT TestAccS3Object_checksumAlgorithm --- PASS: TestAccS3Object_objectLockRetentionStartWithNone (84.78s) === CONT TestAccS3Object_ignoreTags --- PASS: TestAccS3Object_keyWithSlashesMigrated (88.10s) === CONT TestAccS3Object_defaultBucketSSE --- PASS: TestAccS3Object_checksumAlgorithm (55.77s) === CONT TestAccS3Object_bucketBucketKeyEnabled --- PASS: TestAccS3Object_ignoreTags (60.84s) === CONT TestAccS3Object_objectBucketKeyEnabled --- PASS: TestAccS3Object_defaultBucketSSE (31.46s) === CONT TestAccS3Object_objectLockRetentionStartWithSet --- PASS: TestAccS3Object_bucketBucketKeyEnabled (30.85s) === CONT TestAccS3Object_tagsLeadingMultipleSlashes --- PASS: TestAccS3Object_objectBucketKeyEnabled (29.55s) === CONT TestAccS3Object_objectLockLegalHoldStartWithOn --- PASS: TestAccS3Object_objectLockLegalHoldStartWithOn (57.64s) === CONT TestAccS3Object_objectLockLegalHoldStartWithNone --- PASS: TestAccS3Object_objectLockRetentionStartWithSet (111.16s) === CONT TestAccS3Object_tagsMultipleSlashes --- PASS: TestAccS3Object_tagsLeadingMultipleSlashes (111.68s) === CONT TestAccS3Object_tags --- PASS: TestAccS3Object_objectLockLegalHoldStartWithNone (86.24s) === CONT TestAccS3Object_tagsLeadingSingleSlash --- PASS: TestAccS3Object_tagsMultipleSlashes (114.27s) === CONT TestAccS3Object_updatesWithVersioningViaAccessPoint --- PASS: TestAccS3Object_tags (118.60s) === CONT TestAccS3Object_acl --- PASS: TestAccS3Object_tagsLeadingSingleSlash (115.49s) === CONT TestAccS3Object_sse --- PASS: TestAccS3Object_updatesWithVersioningViaAccessPoint (60.27s) === CONT TestAccS3Object_kms --- PASS: TestAccS3Object_sse (35.29s) === CONT TestAccS3Object_etagEncryption --- PASS: TestAccS3Object_kms (35.48s) === CONT TestAccS3Object_withContentCharacteristics --- PASS: TestAccS3Object_acl (93.05s) === CONT TestAccS3Object_sourceHashTrigger --- PASS: TestAccS3Object_etagEncryption (35.19s) === CONT TestAccS3Object_contentBase64 --- PASS: TestAccS3Object_withContentCharacteristics (30.58s) === CONT TestAccS3Object_source --- PASS: TestAccS3Object_contentBase64 (30.87s) === CONT TestAccS3Object_nonVersioned acctest.go:1604: skipping test; environment variable TF_ACC_ASSUME_ROLE_ARN must be set. Usage: Amazon Resource Name (ARN) of existing IAM Role to assume for testing restricted permissions --- SKIP: TestAccS3Object_nonVersioned (0.00s) === CONT TestAccS3Object_updatesWithVersioning --- PASS: TestAccS3Object_source (35.54s) === CONT TestAccS3Object_updateSameFile --- PASS: TestAccS3Object_sourceHashTrigger (60.89s) === CONT TestAccS3Object_updates --- PASS: TestAccS3Object_updatesWithVersioning (61.58s) === CONT TestAccS3Object_content --- PASS: TestAccS3Object_updateSameFile (59.03s) === CONT TestAccS3Object_storageClass --- PASS: TestAccS3Object_updates (62.77s) === CONT TestAccS3Object_upgradeFromV4 --- PASS: TestAccS3Object_content (33.20s) --- PASS: TestAccS3Object_upgradeFromV4 (83.10s) --- PASS: TestAccS3Object_storageClass (117.16s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 722.434s From c54bf83aa22e219e7844dee761b3adc6020c368b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 11:38:53 -0400 Subject: [PATCH 57/61] d/aws_s3_object: Use 'sdkv1CompatibleCleanKey'. --- internal/service/s3/object_data_source.go | 4 ++-- internal/service/s3/object_data_source_test.go | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/internal/service/s3/object_data_source.go b/internal/service/s3/object_data_source.go index e9ffb3f158d..44068b8d1c3 100644 --- a/internal/service/s3/object_data_source.go +++ b/internal/service/s3/object_data_source.go @@ -158,7 +158,7 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig bucket := d.Get("bucket").(string) - key := d.Get("key").(string) + key := sdkv1CompatibleCleanKey(d.Get("key").(string)) input := &s3.HeadObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), @@ -183,7 +183,7 @@ func dataSourceObjectRead(ctx context.Context, d *schema.ResourceData, meta inte return sdkdiag.AppendErrorf(diags, "S3 Bucket (%s) Object (%s) has been deleted", bucket, key) } - id := bucket + "/" + key + id := bucket + "/" + d.Get("key").(string) if v, ok := d.GetOk("version_id"); ok { id += "@" + v.(string) } diff --git a/internal/service/s3/object_data_source_test.go b/internal/service/s3/object_data_source_test.go index 756be91cfee..3d3b0e32d0c 100644 --- a/internal/service/s3/object_data_source_test.go +++ b/internal/service/s3/object_data_source_test.go @@ -630,8 +630,6 @@ func testAccObjectDataSourceConfig_leadingSlash(rName string) (string, string) { resources := fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q - - force_destroy = true } resource "aws_s3_object" "test" { @@ -666,8 +664,6 @@ func testAccObjectDataSourceConfig_multipleSlashes(rName string) (string, string resources := fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q - - force_destroy = true } resource "aws_s3_object" "test1" { From 6c2d11567a36c1911f4df002c5c7ce139c885b27 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 12:27:49 -0400 Subject: [PATCH 58/61] d/aws_s3_object: 'key = "/"' is no longer supported. --- .changelog/33358.txt | 4 ++++ internal/service/s3/object_data_source_test.go | 7 ++----- internal/service/s3/object_test.go | 5 +++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.changelog/33358.txt b/.changelog/33358.txt index b07527cf79a..1aad7087d09 100644 --- a/.changelog/33358.txt +++ b/.changelog/33358.txt @@ -8,4 +8,8 @@ resource/aws_s3_object_copy: Add `checksum_algorithm` argument and `checksum_crc ```release-note:enhancement data-source/aws_s3_object: Add `checksum_mode` argument and `checksum_crc32`, `checksum_crc32c`, `checksum_sha1` and `checksum_sha256` attributes +``` + +```release-note:note +data-source/aws_s3_object: Migration to [AWS SDK for Go v2](https://aws.github.io/aws-sdk-go-v2/) means that the edge case of specifying a single `/` as the value for `key` is no longer supported ``` \ No newline at end of file diff --git a/internal/service/s3/object_data_source_test.go b/internal/service/s3/object_data_source_test.go index 3d3b0e32d0c..4f10ca59402 100644 --- a/internal/service/s3/object_data_source_test.go +++ b/internal/service/s3/object_data_source_test.go @@ -359,7 +359,6 @@ func TestAccS3ObjectDataSource_multipleSlashes(t *testing.T) { func TestAccS3ObjectDataSource_singleSlashAsKey(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - dataSourceName := "data.aws_s3_object.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -368,10 +367,8 @@ func TestAccS3ObjectDataSource_singleSlashAsKey(t *testing.T) { PreventPostDestroyRefresh: true, Steps: []resource.TestStep{ { - Config: testAccObjectDataSourceConfig_singleSlashAsKey(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckNoResourceAttr(dataSourceName, "body"), - ), + Config: testAccObjectDataSourceConfig_singleSlashAsKey(rName), + ExpectError: regexache.MustCompile(`input member Key must not be empty`), }, }, }) diff --git a/internal/service/s3/object_test.go b/internal/service/s3/object_test.go index af736b712d4..7d743a679b4 100644 --- a/internal/service/s3/object_test.go +++ b/internal/service/s3/object_test.go @@ -45,6 +45,11 @@ func TestSDKv1CompatibleCleanKey(t *testing.T) { key: "test-key", want: "test-key", }, + { + name: "just a slash", + key: "/", + want: "", + }, { name: "simple slashes", key: "dir1/dir2/test-key", From b8ad2c4fff0707305f6d3156bf4993d69e552df0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 12:32:20 -0400 Subject: [PATCH 59/61] % make testacc TESTARGS='-run=TestAccS3ObjectDataSource_' PKG=s3 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/s3/... -v -count 1 -parallel 3 -run=TestAccS3ObjectDataSource_ -timeout 180m === RUN TestAccS3ObjectDataSource_basic === PAUSE TestAccS3ObjectDataSource_basic === RUN TestAccS3ObjectDataSource_basicViaAccessPoint === PAUSE TestAccS3ObjectDataSource_basicViaAccessPoint === RUN TestAccS3ObjectDataSource_readableBody === PAUSE TestAccS3ObjectDataSource_readableBody === RUN TestAccS3ObjectDataSource_kmsEncrypted === PAUSE TestAccS3ObjectDataSource_kmsEncrypted === RUN TestAccS3ObjectDataSource_bucketKeyEnabled === PAUSE TestAccS3ObjectDataSource_bucketKeyEnabled === RUN TestAccS3ObjectDataSource_allParams === PAUSE TestAccS3ObjectDataSource_allParams === RUN TestAccS3ObjectDataSource_objectLockLegalHoldOff === PAUSE TestAccS3ObjectDataSource_objectLockLegalHoldOff === RUN TestAccS3ObjectDataSource_objectLockLegalHoldOn === PAUSE TestAccS3ObjectDataSource_objectLockLegalHoldOn === RUN TestAccS3ObjectDataSource_leadingSlash === PAUSE TestAccS3ObjectDataSource_leadingSlash === RUN TestAccS3ObjectDataSource_multipleSlashes === PAUSE TestAccS3ObjectDataSource_multipleSlashes === RUN TestAccS3ObjectDataSource_singleSlashAsKey === PAUSE TestAccS3ObjectDataSource_singleSlashAsKey === RUN TestAccS3ObjectDataSource_checksumMode === PAUSE TestAccS3ObjectDataSource_checksumMode === CONT TestAccS3ObjectDataSource_basic === CONT TestAccS3ObjectDataSource_objectLockLegalHoldOff === CONT TestAccS3ObjectDataSource_kmsEncrypted --- PASS: TestAccS3ObjectDataSource_basic (29.02s) === CONT TestAccS3ObjectDataSource_readableBody --- PASS: TestAccS3ObjectDataSource_kmsEncrypted (29.71s) === CONT TestAccS3ObjectDataSource_allParams --- PASS: TestAccS3ObjectDataSource_objectLockLegalHoldOff (32.95s) === CONT TestAccS3ObjectDataSource_bucketKeyEnabled --- PASS: TestAccS3ObjectDataSource_readableBody (28.65s) === CONT TestAccS3ObjectDataSource_basicViaAccessPoint --- PASS: TestAccS3ObjectDataSource_bucketKeyEnabled (29.35s) === CONT TestAccS3ObjectDataSource_multipleSlashes --- PASS: TestAccS3ObjectDataSource_allParams (33.10s) === CONT TestAccS3ObjectDataSource_checksumMode --- PASS: TestAccS3ObjectDataSource_basicViaAccessPoint (29.29s) === CONT TestAccS3ObjectDataSource_singleSlashAsKey --- PASS: TestAccS3ObjectDataSource_checksumMode (28.50s) === CONT TestAccS3ObjectDataSource_leadingSlash --- PASS: TestAccS3ObjectDataSource_singleSlashAsKey (14.84s) === CONT TestAccS3ObjectDataSource_objectLockLegalHoldOn --- PASS: TestAccS3ObjectDataSource_multipleSlashes (49.07s) --- PASS: TestAccS3ObjectDataSource_objectLockLegalHoldOn (31.20s) --- PASS: TestAccS3ObjectDataSource_leadingSlash (47.08s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 143.605s From c541b6f781b8c3d42ff1e23e4b1e4c44b50f19cc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 13:11:07 -0400 Subject: [PATCH 60/61] Fix terrafmt errors. --- internal/service/s3/object_data_source_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/s3/object_data_source_test.go b/internal/service/s3/object_data_source_test.go index 20fd1a2612a..2e0d9c28d11 100644 --- a/internal/service/s3/object_data_source_test.go +++ b/internal/service/s3/object_data_source_test.go @@ -719,9 +719,9 @@ resource "aws_s3_bucket" "test" { } resource "aws_s3_object" "test" { - bucket = aws_s3_bucket.test.bucket - key = "%[1]s-key" - content = "Keep Calm and Carry On" + bucket = aws_s3_bucket.test.bucket + key = "%[1]s-key" + content = "Keep Calm and Carry On" checksum_algorithm = "SHA256" } From 26b1cd8c22c13f615a0d8f2902fdf79c7e729062 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 Sep 2023 13:37:18 -0400 Subject: [PATCH 61/61] Fix terrafmt errors. --- internal/service/s3/object_data_source_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/s3/object_data_source_test.go b/internal/service/s3/object_data_source_test.go index 2e0d9c28d11..53c5c87958b 100644 --- a/internal/service/s3/object_data_source_test.go +++ b/internal/service/s3/object_data_source_test.go @@ -719,8 +719,8 @@ resource "aws_s3_bucket" "test" { } resource "aws_s3_object" "test" { - bucket = aws_s3_bucket.test.bucket - key = "%[1]s-key" + bucket = aws_s3_bucket.test.bucket + key = "%[1]s-key" content = "Keep Calm and Carry On" checksum_algorithm = "SHA256"