diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 1f1adfef9573..b9b5ed64a283 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -2006,7 +2006,6 @@ func New(ctx context.Context) (*schema.Provider, error) { "aws_s3_bucket_object": s3.ResourceBucketObject(), // DEPRECATED: use aws_s3_object instead "aws_s3control_bucket": s3control.ResourceBucket(), - "aws_s3control_bucket_lifecycle_configuration": s3control.ResourceBucketLifecycleConfiguration(), "aws_s3control_bucket_policy": s3control.ResourceBucketPolicy(), "aws_s3control_multi_region_access_point": s3control.ResourceMultiRegionAccessPoint(), "aws_s3control_multi_region_access_point_policy": s3control.ResourceMultiRegionAccessPointPolicy(), diff --git a/internal/service/s3control/bucket_lifecycle_configuration.go b/internal/service/s3control/bucket_lifecycle_configuration.go index 5aaabeefbde5..64bec6a5ed90 100644 --- a/internal/service/s3control/bucket_lifecycle_configuration.go +++ b/internal/service/s3control/bucket_lifecycle_configuration.go @@ -1,6 +1,7 @@ package s3control import ( + "context" "fmt" "log" "time" @@ -9,19 +10,26 @@ import ( "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/s3control" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) -func ResourceBucketLifecycleConfiguration() *schema.Resource { +func init() { + _sp.registerSDKResourceFactory("aws_s3control_bucket_lifecycle_configuration", resourceBucketLifecycleConfiguration) +} + +func resourceBucketLifecycleConfiguration() *schema.Resource { return &schema.Resource{ - Create: resourceBucketLifecycleConfigurationCreate, - Read: resourceBucketLifecycleConfigurationRead, - Update: resourceBucketLifecycleConfigurationUpdate, - Delete: resourceBucketLifecycleConfigurationDelete, + CreateWithoutTimeout: resourceBucketLifecycleConfigurationCreate, + ReadWithoutTimeout: resourceBucketLifecycleConfigurationRead, + UpdateWithoutTimeout: resourceBucketLifecycleConfigurationUpdate, + DeleteWithoutTimeout: resourceBucketLifecycleConfigurationDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -117,7 +125,7 @@ func ResourceBucketLifecycleConfiguration() *schema.Resource { } } -func resourceBucketLifecycleConfigurationCreate(d *schema.ResourceData, meta interface{}) error { +func resourceBucketLifecycleConfigurationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).S3ControlConn() bucket := d.Get("bucket").(string) @@ -125,11 +133,11 @@ func resourceBucketLifecycleConfigurationCreate(d *schema.ResourceData, meta int parsedArn, err := arn.Parse(bucket) if err != nil { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", bucket, err) + return diag.FromErr(err) } if parsedArn.AccountID == "" { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): unknown format", d.Id()) + return diag.Errorf("parsing S3 Control Bucket ARN (%s): unknown format", d.Id()) } input := &s3control.PutBucketLifecycleConfigurationInput{ @@ -140,83 +148,62 @@ func resourceBucketLifecycleConfigurationCreate(d *schema.ResourceData, meta int }, } - _, err = conn.PutBucketLifecycleConfiguration(input) + _, err = conn.PutBucketLifecycleConfigurationWithContext(ctx, input) if err != nil { - return fmt.Errorf("error creating S3 Control Lifecycle Configuration (%s): %w", bucket, err) + return diag.Errorf("creating S3 Control Bucket Lifecycle Configuration (%s): %s", bucket, err) } d.SetId(bucket) - return resourceBucketLifecycleConfigurationRead(d, meta) + return resourceBucketLifecycleConfigurationRead(ctx, d, meta) } -func resourceBucketLifecycleConfigurationRead(d *schema.ResourceData, meta interface{}) error { +func resourceBucketLifecycleConfigurationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).S3ControlConn() parsedArn, err := arn.Parse(d.Id()) if err != nil { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", d.Id(), err) + return diag.FromErr(err) } if parsedArn.AccountID == "" { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): unknown format", d.Id()) + return diag.Errorf("parsing S3 Control Bucket ARN (%s): unknown format", d.Id()) } - input := &s3control.GetBucketLifecycleConfigurationInput{ - AccountId: aws.String(parsedArn.AccountID), - Bucket: aws.String(d.Id()), - } - - output, err := conn.GetBucketLifecycleConfiguration(input) + output, err := FindBucketLifecycleConfigurationByTwoPartKey(ctx, conn, parsedArn.AccountID, d.Id()) - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, "NoSuchBucket") { - log.Printf("[WARN] S3 Control Lifecycle Configuration (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, "NoSuchLifecycleConfiguration") { - log.Printf("[WARN] S3 Control Lifecycle Configuration (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, "NoSuchOutpost") { - log.Printf("[WARN] S3 Control Lifecycle Configuration (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] S3 Control Bucket Lifecycle Configuration (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error reading S3 Control Lifecycle Configuration (%s): %w", d.Id(), err) - } - - if output == nil { - return fmt.Errorf("error reading S3 Control Lifecycle Configuration (%s): empty response", d.Id()) + return diag.Errorf("reading S3 Control Bucket Lifecycle Configuration (%s): %s", d.Id(), err) } d.Set("bucket", d.Id()) if err := d.Set("rule", flattenLifecycleRules(output.Rules)); err != nil { - return fmt.Errorf("error setting rule: %w", err) + return diag.Errorf("setting rule: %s", err) } return nil } -func resourceBucketLifecycleConfigurationUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceBucketLifecycleConfigurationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).S3ControlConn() parsedArn, err := arn.Parse(d.Id()) if err != nil { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", d.Id(), err) + return diag.FromErr(err) } if parsedArn.AccountID == "" { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): unknown format", d.Id()) + return diag.Errorf("parsing S3 Control Bucket ARN (%s): unknown format", d.Id()) } input := &s3control.PutBucketLifecycleConfigurationInput{ @@ -227,26 +214,26 @@ func resourceBucketLifecycleConfigurationUpdate(d *schema.ResourceData, meta int }, } - _, err = conn.PutBucketLifecycleConfiguration(input) + _, err = conn.PutBucketLifecycleConfigurationWithContext(ctx, input) if err != nil { - return fmt.Errorf("error updating S3 Control Lifecycle Configuration (%s): %w", d.Id(), err) + return diag.Errorf("updating S3 Control Bucket Lifecycle Configuration (%s): %s", d.Id(), err) } - return resourceBucketLifecycleConfigurationRead(d, meta) + return resourceBucketLifecycleConfigurationRead(ctx, d, meta) } -func resourceBucketLifecycleConfigurationDelete(d *schema.ResourceData, meta interface{}) error { +func resourceBucketLifecycleConfigurationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).S3ControlConn() parsedArn, err := arn.Parse(d.Id()) if err != nil { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", d.Id(), err) + return diag.FromErr(err) } if parsedArn.AccountID == "" { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): unknown format", d.Id()) + return diag.Errorf("parsing S3 Control Bucket ARN (%s): unknown format", d.Id()) } input := &s3control.DeleteBucketLifecycleConfigurationInput{ @@ -254,25 +241,43 @@ func resourceBucketLifecycleConfigurationDelete(d *schema.ResourceData, meta int Bucket: aws.String(d.Id()), } - _, err = conn.DeleteBucketLifecycleConfiguration(input) + _, err = conn.DeleteBucketLifecycleConfigurationWithContext(ctx, input) - if tfawserr.ErrCodeEquals(err, "NoSuchBucket") { + if tfawserr.ErrCodeEquals(err, errCodeNoSuchBucket, errCodeNoSuchLifecycleConfiguration, errCodeNoSuchOutpost) { return nil } - if tfawserr.ErrCodeEquals(err, "NoSuchLifecycleConfiguration") { - return nil + if err != nil { + return diag.Errorf("deleting S3 Control Bucket Lifecycle Configuration (%s): %s", d.Id(), err) } - if tfawserr.ErrCodeEquals(err, "NoSuchOutpost") { - return nil + return nil +} + +func FindBucketLifecycleConfigurationByTwoPartKey(ctx context.Context, conn *s3control.S3Control, accountID, bucket string) (*s3control.GetBucketLifecycleConfigurationOutput, error) { + input := &s3control.GetBucketLifecycleConfigurationInput{ + AccountId: aws.String(accountID), + Bucket: aws.String(bucket), + } + + output, err := conn.GetBucketLifecycleConfigurationWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, errCodeNoSuchBucket, errCodeNoSuchLifecycleConfiguration, errCodeNoSuchOutpost) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } } if err != nil { - return fmt.Errorf("error deleting S3 Control Lifecycle Configuration (%s): %w", d.Id(), err) + return nil, err } - return nil + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil } func expandAbortIncompleteMultipartUpload(tfList []interface{}) *s3control.AbortIncompleteMultipartUpload { diff --git a/internal/service/s3control/bucket_lifecycle_configuration_test.go b/internal/service/s3control/bucket_lifecycle_configuration_test.go index 82cc5d76f35a..4d783620ca8c 100644 --- a/internal/service/s3control/bucket_lifecycle_configuration_test.go +++ b/internal/service/s3control/bucket_lifecycle_configuration_test.go @@ -1,20 +1,20 @@ package s3control_test import ( + "context" "fmt" "testing" "time" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/s3control" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfs3control "github.com/hashicorp/terraform-provider-aws/internal/service/s3control" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccS3ControlBucketLifecycleConfiguration_basic(t *testing.T) { @@ -428,25 +428,12 @@ func testAccCheckBucketLifecycleConfigurationDestroy(s *terraform.State) error { parsedArn, err := arn.Parse(rs.Primary.ID) if err != nil { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", rs.Primary.ID, err) - } - - input := &s3control.GetBucketLifecycleConfigurationInput{ - AccountId: aws.String(parsedArn.AccountID), - Bucket: aws.String(rs.Primary.ID), - } - - _, err = conn.GetBucketLifecycleConfiguration(input) - - if tfawserr.ErrCodeEquals(err, "NoSuchBucket") { - continue + return err } - if tfawserr.ErrCodeEquals(err, "NoSuchLifecycleConfiguration") { - continue - } + _, err = tfs3control.FindBucketLifecycleConfigurationByTwoPartKey(context.Background(), conn, parsedArn.AccountID, rs.Primary.ID) - if tfawserr.ErrCodeEquals(err, "NoSuchOutpost") { + if tfresource.NotFound(err) { continue } @@ -454,21 +441,21 @@ func testAccCheckBucketLifecycleConfigurationDestroy(s *terraform.State) error { return err } - return fmt.Errorf("S3 Control Bucket Lifecycle Configuration (%s) still exists", rs.Primary.ID) + return fmt.Errorf("S3 Control Bucket Lifecycle Configuration %s still exists", rs.Primary.ID) } return nil } -func testAccCheckBucketLifecycleConfigurationExists(resourceName string) resource.TestCheckFunc { +func testAccCheckBucketLifecycleConfigurationExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[resourceName] + rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("not found: %s", resourceName) + return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("no resource ID is set") + return fmt.Errorf("No S3 Control Bucket Lifecycle Configuration ID is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).S3ControlConn() @@ -476,15 +463,10 @@ func testAccCheckBucketLifecycleConfigurationExists(resourceName string) resourc parsedArn, err := arn.Parse(rs.Primary.ID) if err != nil { - return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", rs.Primary.ID, err) - } - - input := &s3control.GetBucketLifecycleConfigurationInput{ - AccountId: aws.String(parsedArn.AccountID), - Bucket: aws.String(rs.Primary.ID), + return err } - _, err = conn.GetBucketLifecycleConfiguration(input) + _, err = tfs3control.FindBucketLifecycleConfigurationByTwoPartKey(context.Background(), conn, parsedArn.AccountID, rs.Primary.ID) return err } diff --git a/internal/service/s3control/errors.go b/internal/service/s3control/errors.go index aa7c0b058313..911d67a2b310 100644 --- a/internal/service/s3control/errors.go +++ b/internal/service/s3control/errors.go @@ -3,9 +3,11 @@ package s3control // Error code constants missing from AWS Go SDK: // https://docs.aws.amazon.com/sdk-for-go/api/service/s3control/#pkg-constants const ( - errCodeNoSuchAccessPoint = "NoSuchAccessPoint" - errCodeNoSuchAccessPointPolicy = "NoSuchAccessPointPolicy" - errCodeNoSuchAsyncRequest = "NoSuchAsyncRequest" - // errCodeNoSuchConfiguration = "NoSuchConfiguration" + errCodeNoSuchAccessPoint = "NoSuchAccessPoint" + errCodeNoSuchAccessPointPolicy = "NoSuchAccessPointPolicy" + errCodeNoSuchAsyncRequest = "NoSuchAsyncRequest" + errCodeNoSuchBucket = "NoSuchBucket" + errCodeNoSuchLifecycleConfiguration = "NoSuchLifecycleConfiguration" errCodeNoSuchMultiRegionAccessPoint = "NoSuchMultiRegionAccessPoint" + errCodeNoSuchOutpost = "NoSuchOutpost" ) diff --git a/internal/service/s3control/exports_test.go b/internal/service/s3control/exports_test.go index 82e2a3ab3a11..c175a7f96e3f 100644 --- a/internal/service/s3control/exports_test.go +++ b/internal/service/s3control/exports_test.go @@ -2,8 +2,9 @@ package s3control // Exports for use in tests only. var ( - ResourceAccessPoint = resourceAccessPoint - ResourceAccessPointPolicy = resourceAccessPointPolicy - ResourceAccountPublicAccessBlock = resourceAccountPublicAccessBlock - ResourceStorageLensConfiguration = resourceStorageLensConfiguration + ResourceAccessPoint = resourceAccessPoint + ResourceAccessPointPolicy = resourceAccessPointPolicy + ResourceAccountPublicAccessBlock = resourceAccountPublicAccessBlock + ResourceBucketLifecycleConfiguration = resourceBucketLifecycleConfiguration + ResourceStorageLensConfiguration = resourceStorageLensConfiguration )