Skip to content

Commit

Permalink
Merge pull request #21060 from farhanangullia/f-aws_s3_multi_region_a…
Browse files Browse the repository at this point in the history
…ccess_point

r/aws_s3_multi_region_access_point and r/aws_s3_multi_region_access_point_policy : New resource
  • Loading branch information
ewbankkit authored Nov 13, 2021
2 parents 41f678b + 50c2a09 commit 5ba427d
Show file tree
Hide file tree
Showing 18 changed files with 1,855 additions and 51 deletions.
7 changes: 7 additions & 0 deletions .changelog/21060.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:new-resource
aws_s3control_multi_region_access_point
```

```release-note:new-resource
aws_s3control_multi_region_access_point_policy
```
15 changes: 15 additions & 0 deletions internal/acctest/acctest.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,21 @@ func MatchResourceAttrRegionalHostname(resourceName, attributeName, serviceName
}
}

// MatchResourceAttrGlobalHostname ensures the Terraform state regexp matches a formatted DNS hostname with partition DNS suffix and without region
func MatchResourceAttrGlobalHostname(resourceName, attributeName, serviceName string, hostnamePrefixRegexp *regexp.Regexp) resource.TestCheckFunc {
return func(s *terraform.State) error {
hostnameRegexpPattern := fmt.Sprintf("%s\\.%s\\.%s$", hostnamePrefixRegexp.String(), serviceName, PartitionDNSSuffix())

hostnameRegexp, err := regexp.Compile(hostnameRegexpPattern)

if err != nil {
return fmt.Errorf("Unable to compile hostname regexp (%s): %w", hostnameRegexp, err)
}

return resource.TestMatchResourceAttr(resourceName, attributeName, hostnameRegexp)(s)
}
}

// CheckResourceAttrGlobalARN ensures the Terraform state exactly matches a formatted ARN without region
func CheckResourceAttrGlobalARN(resourceName, attributeName, arnService, arnResource string) resource.TestCheckFunc {
return func(s *terraform.State) error {
Expand Down
12 changes: 7 additions & 5 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1478,11 +1478,13 @@ func Provider() *schema.Provider {
"aws_s3_bucket_public_access_block": s3.ResourceBucketPublicAccessBlock(),
"aws_s3_object_copy": s3.ResourceObjectCopy(),

"aws_s3_access_point": s3control.ResourceAccessPoint(),
"aws_s3_account_public_access_block": s3control.ResourceAccountPublicAccessBlock(),
"aws_s3control_bucket": s3control.ResourceBucket(),
"aws_s3control_bucket_lifecycle_configuration": s3control.ResourceBucketLifecycleConfiguration(),
"aws_s3control_bucket_policy": s3control.ResourceBucketPolicy(),
"aws_s3_access_point": s3control.ResourceAccessPoint(),
"aws_s3_account_public_access_block": s3control.ResourceAccountPublicAccessBlock(),
"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(),

"aws_s3outposts_endpoint": s3outposts.ResourceEndpoint(),

Expand Down
34 changes: 22 additions & 12 deletions internal/service/s3control/access_point.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func resourceAccessPointCreate(d *schema.ResourceData, meta interface{}) error {
func resourceAccessPointRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).S3ControlConn

accountId, name, err := AccessPointParseID(d.Id())
accountId, name, err := AccessPointParseResourceID(d.Id())
if err != nil {
return err
}
Expand Down Expand Up @@ -291,7 +291,7 @@ func resourceAccessPointRead(d *schema.ResourceData, meta interface{}) error {
func resourceAccessPointUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).S3ControlConn

accountId, name, err := AccessPointParseID(d.Id())
accountId, name, err := AccessPointParseResourceID(d.Id())
if err != nil {
return err
}
Expand Down Expand Up @@ -327,7 +327,7 @@ func resourceAccessPointUpdate(d *schema.ResourceData, meta interface{}) error {
func resourceAccessPointDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).S3ControlConn

accountId, name, err := AccessPointParseID(d.Id())
accountId, name, err := AccessPointParseResourceID(d.Id())
if err != nil {
return err
}
Expand All @@ -349,21 +349,31 @@ func resourceAccessPointDelete(d *schema.ResourceData, meta interface{}) error {
return nil
}

// AccessPointParseID returns the Account ID and Access Point Name (S3) or ARN (S3 on Outposts)
func AccessPointParseID(id string) (string, string, error) {
parsedARN, err := arn.Parse(id)
const accessPointResourceIDSeparator = ":"

if err == nil {
return parsedARN.AccountID, id, nil
func AccessPointCreateResourceID(accessPointARN, accountID, accessPointName string) string {
if v, err := arn.Parse(accessPointARN); err != nil && v.Service == "s3-outposts" {
return accessPointARN
}

parts := strings.SplitN(id, ":", 2)
parts := []string{accountID, accessPointName}
id := strings.Join(parts, accessPointResourceIDSeparator)

if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return "", "", fmt.Errorf("unexpected format of ID (%s), expected ACCOUNT_ID:NAME", id)
return id
}

func AccessPointParseResourceID(id string) (string, string, error) {
if v, err := arn.Parse(id); err == nil {
return v.AccountID, id, nil
}

parts := strings.Split(id, multiRegionAccessPointResourceIDSeparator)

if len(parts) == 2 && parts[0] != "" && parts[1] != "" {
return parts[0], parts[1], nil
}

return parts[0], parts[1], nil
return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected account-id%[2]saccess-point-name", id, accessPointResourceIDSeparator)
}

func expandS3AccessPointVpcConfiguration(vConfig []interface{}) *s3control.VpcConfiguration {
Expand Down
8 changes: 4 additions & 4 deletions internal/service/s3control/access_point_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ func testAccCheckAccessPointDisappears(n string) resource.TestCheckFunc {
return fmt.Errorf("No S3 Access Point ID is set")
}

accountId, name, err := tfs3control.AccessPointParseID(rs.Primary.ID)
accountId, name, err := tfs3control.AccessPointParseResourceID(rs.Primary.ID)
if err != nil {
return err
}
Expand All @@ -360,7 +360,7 @@ func testAccCheckAccessPointDestroy(s *terraform.State) error {
continue
}

accountId, name, err := tfs3control.AccessPointParseID(rs.Primary.ID)
accountId, name, err := tfs3control.AccessPointParseResourceID(rs.Primary.ID)
if err != nil {
return err
}
Expand All @@ -387,7 +387,7 @@ func testAccCheckAccessPointExists(n string, output *s3control.GetAccessPointOut
return fmt.Errorf("No S3 Access Point ID is set")
}

accountId, name, err := tfs3control.AccessPointParseID(rs.Primary.ID)
accountId, name, err := tfs3control.AccessPointParseResourceID(rs.Primary.ID)
if err != nil {
return err
}
Expand Down Expand Up @@ -419,7 +419,7 @@ func testAccCheckAccessPointHasPolicy(n string, fn func() string) resource.TestC
return fmt.Errorf("No S3 Access Point ID is set")
}

accountId, name, err := tfs3control.AccessPointParseID(rs.Primary.ID)
accountId, name, err := tfs3control.AccessPointParseResourceID(rs.Primary.ID)
if err != nil {
return err
}
Expand Down
7 changes: 7 additions & 0 deletions internal/service/s3control/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package s3control

// AsyncOperation.RequestStatus values.
const (
RequestStatusFailed = "FAILED"
RequestStatusSucceeded = "SUCCEEDED"
)
6 changes: 4 additions & 2 deletions internal/service/s3control/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package s3control
// https://docs.aws.amazon.com/sdk-for-go/api/service/s3control/#pkg-constants
//nolint:deadcode,varcheck // These constants are missing from the AWS SDK
const (
errCodeNoSuchAccessPoint = "NoSuchAccessPoint"
errCodeNoSuchAccessPointPolicy = "NoSuchAccessPointPolicy"
errCodeNoSuchAccessPoint = "NoSuchAccessPoint"
errCodeNoSuchAccessPointPolicy = "NoSuchAccessPointPolicy"
errCodeNoSuchAsyncRequest = "NoSuchAsyncRequest"
errCodeNoSuchMultiRegionAccessPoint = "NoSuchMultiRegionAccessPoint"
)
81 changes: 81 additions & 0 deletions internal/service/s3control/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package s3control
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3control"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func findPublicAccessBlockConfiguration(conn *s3control.S3Control, accountID string) (*s3control.PublicAccessBlockConfiguration, error) {
Expand All @@ -22,3 +25,81 @@ func findPublicAccessBlockConfiguration(conn *s3control.S3Control, accountID str

return output.PublicAccessBlockConfiguration, nil
}

func FindMultiRegionAccessPointByAccountIDAndName(conn *s3control.S3Control, accountID string, name string) (*s3control.MultiRegionAccessPointReport, error) {
input := &s3control.GetMultiRegionAccessPointInput{
AccountId: aws.String(accountID),
Name: aws.String(name),
}

output, err := conn.GetMultiRegionAccessPoint(input)

if tfawserr.ErrCodeEquals(err, errCodeNoSuchMultiRegionAccessPoint) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.AccessPoint == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.AccessPoint, nil
}

func findMultiRegionAccessPointOperationByAccountIDAndTokenARN(conn *s3control.S3Control, accountID string, requestTokenARN string) (*s3control.AsyncOperation, error) {
input := &s3control.DescribeMultiRegionAccessPointOperationInput{
AccountId: aws.String(accountID),
RequestTokenARN: aws.String(requestTokenARN),
}

output, err := conn.DescribeMultiRegionAccessPointOperation(input)

if tfawserr.ErrCodeEquals(err, errCodeNoSuchAsyncRequest) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.AsyncOperation == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.AsyncOperation, nil
}

func FindMultiRegionAccessPointPolicyDocumentByAccountIDAndName(conn *s3control.S3Control, accountID string, name string) (*s3control.MultiRegionAccessPointPolicyDocument, error) {
input := &s3control.GetMultiRegionAccessPointPolicyInput{
AccountId: aws.String(accountID),
Name: aws.String(name),
}

output, err := conn.GetMultiRegionAccessPointPolicy(input)

if tfawserr.ErrCodeEquals(err, errCodeNoSuchMultiRegionAccessPoint) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.Policy == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.Policy, nil
}
Loading

0 comments on commit 5ba427d

Please sign in to comment.