Skip to content

Commit

Permalink
Merge pull request #38816 from DanielRieske/f/migrate-s3outposts-sdkv2
Browse files Browse the repository at this point in the history
Migrate `S3 on Outposts` resource to AWS SDK v2
  • Loading branch information
ewbankkit authored Aug 12, 2024
2 parents 91ff9cd + 2bfdf14 commit 0e574fb
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 138 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/rum v1.19.3
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3
github.com/aws/aws-sdk-go-v2/service/s3control v1.46.3
github.com/aws/aws-sdk-go-v2/service/s3outposts v1.26.3
github.com/aws/aws-sdk-go-v2/service/scheduler v1.10.3
github.com/aws/aws-sdk-go-v2/service/schemas v1.26.3
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.4
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 h1:hT8ZAZRIfqBqHbzKTII+CIiY8G2oC
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE=
github.com/aws/aws-sdk-go-v2/service/s3control v1.46.3 h1:3De8/YQpup0mLNKh0G9JHWJLEkWNdghd5z84vw4v+yw=
github.com/aws/aws-sdk-go-v2/service/s3control v1.46.3/go.mod h1:sUA7DOI2fdRHQQUpvRVfYKTo9P0+UAsWYBHvyqFHcC0=
github.com/aws/aws-sdk-go-v2/service/s3outposts v1.26.3 h1:Hg1FVxD9pelFS8j3ilHJDUe6J/Q/VVwzWaNtN8vyNUQ=
github.com/aws/aws-sdk-go-v2/service/s3outposts v1.26.3/go.mod h1:GVq0lM4BUD3GyiLzlNWXUq9U/H5t+2eytsEDirQSAn4=
github.com/aws/aws-sdk-go-v2/service/scheduler v1.10.3 h1:gmpU7E0ntMzXr+yQQIXbiiueOewf/1BQ9WgeaXo6BcQ=
github.com/aws/aws-sdk-go-v2/service/scheduler v1.10.3/go.mod h1:jnQp5kPPvEgPmVPm0h/XZPmlx7DQ0pqUiISRO4s6U3s=
github.com/aws/aws-sdk-go-v2/service/schemas v1.26.3 h1:ZJW2OQNpkR8P7URtISmF8twpvz2V0tUN/OgMenlxkao=
Expand Down
6 changes: 3 additions & 3 deletions internal/conns/awsclient_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

105 changes: 50 additions & 55 deletions internal/service/s3outposts/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,24 @@ import (
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/s3outposts"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/aws/aws-sdk-go-v2/service/s3outposts"
awstypes "github.com/aws/aws-sdk-go-v2/service/s3outposts/types"
"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"
"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/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @SDKResource("aws_s3outposts_endpoint")
func ResourceEndpoint() *schema.Resource {
// @SDKResource("aws_s3outposts_endpoint", name="Endpoint")
func resourceEndpoint() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceEndpointCreate,
ReadWithoutTimeout: resourceEndpointRead,
Expand All @@ -36,11 +39,11 @@ func ResourceEndpoint() *schema.Resource {

Schema: map[string]*schema.Schema{
"access_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(s3outposts.EndpointAccessType_Values(), false),
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateDiagFunc: enum.Validate[awstypes.EndpointAccessType](),
},
names.AttrARN: {
Type: schema.TypeString,
Expand Down Expand Up @@ -96,7 +99,7 @@ func ResourceEndpoint() *schema.Resource {

func resourceEndpointCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).S3OutpostsConn(ctx)
conn := meta.(*conns.AWSClient).S3OutpostsClient(ctx)

input := &s3outposts.CreateEndpointInput{
OutpostId: aws.String(d.Get("outpost_id").(string)),
Expand All @@ -105,20 +108,20 @@ func resourceEndpointCreate(ctx context.Context, d *schema.ResourceData, meta in
}

if v, ok := d.GetOk("access_type"); ok {
input.AccessType = aws.String(v.(string))
input.AccessType = awstypes.EndpointAccessType(v.(string))
}

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

output, err := conn.CreateEndpointWithContext(ctx, input)
output, err := conn.CreateEndpoint(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating S3 Outposts Endpoint: %s", err)
}

d.SetId(aws.StringValue(output.EndpointArn))
d.SetId(aws.ToString(output.EndpointArn))

if _, err := waitEndpointStatusCreated(ctx, conn, d.Id()); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for S3 Outposts Endpoint (%s) create: %s", d.Id(), err)
Expand All @@ -129,9 +132,9 @@ func resourceEndpointCreate(ctx context.Context, d *schema.ResourceData, meta in

func resourceEndpointRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).S3OutpostsConn(ctx)
conn := meta.(*conns.AWSClient).S3OutpostsClient(ctx)

endpoint, err := FindEndpointByARN(ctx, conn, d.Id())
endpoint, err := findEndpointByARN(ctx, conn, d.Id())

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] S3 Outposts Endpoint %s not found, removing from state", d.Id())
Expand All @@ -147,7 +150,7 @@ func resourceEndpointRead(ctx context.Context, d *schema.ResourceData, meta inte
d.Set(names.AttrARN, endpoint.EndpointArn)
d.Set(names.AttrCIDRBlock, endpoint.CidrBlock)
if endpoint.CreationTime != nil {
d.Set(names.AttrCreationTime, aws.TimeValue(endpoint.CreationTime).Format(time.RFC3339))
d.Set(names.AttrCreationTime, aws.ToTime(endpoint.CreationTime).Format(time.RFC3339))
}
d.Set("customer_owned_ipv4_pool", endpoint.CustomerOwnedIpv4Pool)
if err := d.Set("network_interfaces", flattenNetworkInterfaces(endpoint.NetworkInterfaces)); err != nil {
Expand All @@ -160,7 +163,7 @@ func resourceEndpointRead(ctx context.Context, d *schema.ResourceData, meta inte

func resourceEndpointDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).S3OutpostsConn(ctx)
conn := meta.(*conns.AWSClient).S3OutpostsClient(ctx)

parsedArn, err := arn.Parse(d.Id())

Expand All @@ -176,7 +179,7 @@ func resourceEndpointDelete(ctx context.Context, d *schema.ResourceData, meta in
}

log.Printf("[DEBUG] Deleting S3 Outposts Endpoint: %s", d.Id())
_, err = conn.DeleteEndpointWithContext(ctx, &s3outposts.DeleteEndpointInput{
_, err = conn.DeleteEndpoint(ctx, &s3outposts.DeleteEndpointInput{
EndpointId: aws.String(arnResourceParts[3]),
OutpostId: aws.String(arnResourceParts[1]),
})
Expand Down Expand Up @@ -206,7 +209,7 @@ func resourceEndpointImportState(ctx context.Context, d *schema.ResourceData, me
return []*schema.ResourceData{d}, nil
}

func FindEndpointByARN(ctx context.Context, conn *s3outposts.S3Outposts, arn string) (*s3outposts.Endpoint, error) {
func findEndpointByARN(ctx context.Context, conn *s3outposts.Client, arn string) (*awstypes.Endpoint, error) {
input := &s3outposts.ListEndpointsInput{}

output, err := findEndpoints(ctx, conn, input)
Expand All @@ -216,41 +219,41 @@ func FindEndpointByARN(ctx context.Context, conn *s3outposts.S3Outposts, arn str
}

for _, v := range output {
if aws.StringValue(v.EndpointArn) == arn && aws.StringValue(v.Status) != s3outposts.EndpointStatusDeleting && aws.StringValue(v.Status) != s3outposts.EndpointStatusDeleteFailed {
return v, nil
if aws.ToString(v.EndpointArn) == arn && v.Status != awstypes.EndpointStatusDeleting && v.Status != awstypes.EndpointStatusDeleteFailed {
return &v, nil
}
}

return nil, &retry.NotFoundError{}
return nil, tfresource.NewEmptyResultError(input)
}

func findEndpoints(ctx context.Context, conn *s3outposts.S3Outposts, input *s3outposts.ListEndpointsInput) ([]*s3outposts.Endpoint, error) {
var output []*s3outposts.Endpoint
func findEndpoints(ctx context.Context, conn *s3outposts.Client, input *s3outposts.ListEndpointsInput) ([]awstypes.Endpoint, error) {
var output []awstypes.Endpoint

err := conn.ListEndpointsPagesWithContext(ctx, input, func(page *s3outposts.ListEndpointsOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}
pages := s3outposts.NewListEndpointsPaginator(conn, input)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)

for _, v := range page.Endpoints {
if v != nil {
output = append(output, v)
if errs.IsA[*awstypes.ResourceNotFoundException](err) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

return !lastPage
})
if err != nil {
return nil, err
}

if err != nil {
return nil, err
output = append(output, page.Endpoints...)
}

return output, nil
}

func statusEndpoint(ctx context.Context, conn *s3outposts.S3Outposts, arn string) retry.StateRefreshFunc {
func statusEndpoint(ctx context.Context, conn *s3outposts.Client, arn string) retry.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := FindEndpointByARN(ctx, conn, arn)
output, err := findEndpointByARN(ctx, conn, arn)

if tfresource.NotFound(err) {
return nil, "", nil
Expand All @@ -260,26 +263,26 @@ func statusEndpoint(ctx context.Context, conn *s3outposts.S3Outposts, arn string
return nil, "", err
}

return output, aws.StringValue(output.Status), nil
return output, string(output.Status), nil
}
}

func waitEndpointStatusCreated(ctx context.Context, conn *s3outposts.S3Outposts, arn string) (*s3outposts.Endpoint, error) {
func waitEndpointStatusCreated(ctx context.Context, conn *s3outposts.Client, arn string) (*awstypes.Endpoint, error) {
const (
timeout = 20 * time.Minute
)
stateConf := &retry.StateChangeConf{
Pending: []string{s3outposts.EndpointStatusPending},
Target: []string{s3outposts.EndpointStatusAvailable},
Pending: enum.Slice(awstypes.EndpointStatusPending),
Target: enum.Slice(awstypes.EndpointStatusAvailable),
Refresh: statusEndpoint(ctx, conn, arn),
Timeout: timeout,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)

if output, ok := outputRaw.(*s3outposts.Endpoint); ok {
if output, ok := outputRaw.(*awstypes.Endpoint); ok {
if failedReason := output.FailedReason; failedReason != nil {
tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.StringValue(failedReason.ErrorCode), aws.StringValue(failedReason.Message)))
tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.ToString(failedReason.ErrorCode), aws.ToString(failedReason.Message)))
}

return output, err
Expand All @@ -288,29 +291,21 @@ func waitEndpointStatusCreated(ctx context.Context, conn *s3outposts.S3Outposts,
return nil, err
}

func flattenNetworkInterfaces(apiObjects []*s3outposts.NetworkInterface) []interface{} {
func flattenNetworkInterfaces(apiObjects []awstypes.NetworkInterface) []interface{} {
var tfList []interface{}

for _, apiObject := range apiObjects {
if apiObject == nil {
continue
}

tfList = append(tfList, flattenNetworkInterface(apiObject))
}

return tfList
}

func flattenNetworkInterface(apiObject *s3outposts.NetworkInterface) map[string]interface{} {
if apiObject == nil {
return nil
}

func flattenNetworkInterface(apiObject awstypes.NetworkInterface) map[string]interface{} {
tfMap := map[string]interface{}{}

if v := apiObject.NetworkInterfaceId; v != nil {
tfMap[names.AttrNetworkInterfaceID] = aws.StringValue(v)
tfMap[names.AttrNetworkInterfaceID] = aws.ToString(v)
}

return tfMap
Expand Down
4 changes: 2 additions & 2 deletions internal/service/s3outposts/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestAccS3OutpostsEndpoint_disappears(t *testing.T) {

func testAccCheckEndpointDestroy(ctx context.Context) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).S3OutpostsConn(ctx)
conn := acctest.Provider.Meta().(*conns.AWSClient).S3OutpostsClient(ctx)

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_s3outposts_endpoint" {
Expand Down Expand Up @@ -188,7 +188,7 @@ func testAccCheckEndpointExists(ctx context.Context, n string) resource.TestChec
return fmt.Errorf("No S3 Outposts Endpoint ID is set")
}

conn := acctest.Provider.Meta().(*conns.AWSClient).S3OutpostsConn(ctx)
conn := acctest.Provider.Meta().(*conns.AWSClient).S3OutpostsClient(ctx)

_, err := tfs3outposts.FindEndpointByARN(ctx, conn, rs.Primary.ID)

Expand Down
11 changes: 11 additions & 0 deletions internal/service/s3outposts/exports_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package s3outposts

// Exports for use in tests only.
var (
FindEndpointByARN = findEndpointByARN

ResourceEndpoint = resourceEndpoint
)
Loading

0 comments on commit 0e574fb

Please sign in to comment.