Skip to content

Commit

Permalink
Merge pull request #19859 from hashicorp/b-aws_datasync_location_s3-o…
Browse files Browse the repository at this point in the history
…utposts-location-arn

r/aws_datasync_location_s3: Correctly parse S3 on Outposts location URI
  • Loading branch information
ewbankkit committed Jul 9, 2021
2 parents 3670534 + 8cc7cd9 commit 69619c0
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 69 deletions.
3 changes: 3 additions & 0 deletions .changelog/19859.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_datasync_location_s3: Correctly parse S3 on Outposts location URI
```
12 changes: 0 additions & 12 deletions aws/datasync.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
package aws

import (
"net/url"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/datasync"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSyncParseLocationURI(uri string) (string, error) {
parsedURL, err := url.ParseRequestURI(uri)

if err != nil {
return "", err
}

return parsedURL.Path, nil
}

func expandDataSyncEc2Config(l []interface{}) *datasync.Ec2Config {
if len(l) == 0 || l[0] == nil {
return nil
Expand Down
47 changes: 0 additions & 47 deletions aws/datasync_test.go

This file was deleted.

45 changes: 45 additions & 0 deletions aws/internal/service/datasync/uri.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package datasync

import (
"fmt"
"regexp"

"github.com/aws/aws-sdk-go/aws/arn"
)

var (
locationURIPattern = regexp.MustCompile(`^(efs|nfs|s3|smb|fsxw)://(.+)$`)
locationURIGlobalIDAndSubdirPattern = regexp.MustCompile(`^([a-zA-Z0-9.\-]+)(/.*)$`)
s3OutpostsAccessPointARNResourcePattern = regexp.MustCompile(`^outpost/.*/accesspoint/.*?(/.*)$`)
)

// SubdirectoryFromLocationURI extracts the subdirectory from a location URI.
// https://docs.aws.amazon.com/datasync/latest/userguide/API_LocationListEntry.html#DataSync-Type-LocationListEntry-LocationUri
func SubdirectoryFromLocationURI(uri string) (string, error) {
submatches := locationURIPattern.FindStringSubmatch(uri)

if len(submatches) != 3 {
return "", fmt.Errorf("location URI (%s) does not match pattern %q", uri, locationURIPattern)
}

globalIDAndSubdir := submatches[2]
parsedARN, err := arn.Parse(globalIDAndSubdir)

if err == nil {
submatches = s3OutpostsAccessPointARNResourcePattern.FindStringSubmatch(parsedARN.Resource)

if len(submatches) != 2 {
return "", fmt.Errorf("location URI S3 on Outposts access point ARN resource (%s) does not match pattern %q", parsedARN.Resource, s3OutpostsAccessPointARNResourcePattern)
}

return submatches[1], nil
}

submatches = locationURIGlobalIDAndSubdirPattern.FindStringSubmatch(globalIDAndSubdir)

if len(submatches) != 3 {
return "", fmt.Errorf("location URI global ID and subdirectory (%s) does not match pattern %q", globalIDAndSubdir, locationURIGlobalIDAndSubdirPattern)
}

return submatches[2], nil
}
145 changes: 145 additions & 0 deletions aws/internal/service/datasync/uri_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package datasync_test

import (
"testing"

tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync"
)

func TestSubdirectoryFromLocationURI(t *testing.T) {
testCases := []struct {
TestName string
InputURI string
ExpectedError bool
ExpectedSubdirectory string
}{
{
TestName: "empty URI",
InputURI: "",
ExpectedError: true,
},
{
TestName: "invalid URI scheme",
InputURI: "test://testing/",
ExpectedError: true,
},
{
TestName: "S3 bucket URI no bucket name (1)",
InputURI: "s3://",
ExpectedError: true,
},
{
TestName: "S3 bucket URI no bucket name (2)",
InputURI: "s3:///",
ExpectedError: true,
},
{
TestName: "S3 bucket URI top level",
InputURI: "s3://bucket/",
ExpectedSubdirectory: "/",
},
{
TestName: "S3 bucket URI one level",
InputURI: "s3://bucket/my-folder-1/",
ExpectedSubdirectory: "/my-folder-1/",
},
{
TestName: "S3 bucket URI two levels",
InputURI: "s3://bucket/my-folder-1/my-folder-2",
ExpectedSubdirectory: "/my-folder-1/my-folder-2",
},
{
TestName: "S3 Outposts ARN URI top level",
InputURI: "s3://arn:aws:s3-outposts:eu-west-3:123456789012:outpost/op-YYYYYYYYYY/accesspoint/my-access-point/",
ExpectedSubdirectory: "/",
},
{
TestName: "S3 Outposts ARN URI one level",
InputURI: "s3://arn:aws:s3-outposts:eu-west-3:123456789012:outpost/op-YYYYYYYYYY/accesspoint/my-access-point/my-folder-1/",
ExpectedSubdirectory: "/my-folder-1/",
},
{
TestName: "S3 Outposts ARN URI two levels",
InputURI: "s3://arn:aws:s3-outposts:eu-west-3:123456789012:outpost/op-YYYYYYYYYY/accesspoint/my-access-point/my-folder-1/my-folder-2",
ExpectedSubdirectory: "/my-folder-1/my-folder-2",
},
{
TestName: "EFS URI top level",
InputURI: "efs://us-west-2.fs-abcdef01/",
ExpectedSubdirectory: "/",
},
{
TestName: "EFS URI one level",
InputURI: "efs://us-west-2.fs-abcdef01/my-folder-1/",
ExpectedSubdirectory: "/my-folder-1/",
},
{
TestName: "EFS URI two levels",
InputURI: "efs://us-west-2.fs-abcdef01/my-folder-1/my-folder-2",
ExpectedSubdirectory: "/my-folder-1/my-folder-2",
},
{
TestName: "NFS URI top level",
InputURI: "nfs://example.com/",
ExpectedSubdirectory: "/",
},
{
TestName: "NFS URI one level",
InputURI: "nfs://example.com/my-folder-1/",
ExpectedSubdirectory: "/my-folder-1/",
},
{
TestName: "NFS URI two levels",
InputURI: "nfs://example.com/my-folder-1/my-folder-2",
ExpectedSubdirectory: "/my-folder-1/my-folder-2",
},
{
TestName: "SMB URI top level",
InputURI: "smb://192.168.1.1/",
ExpectedSubdirectory: "/",
},
{
TestName: "SMB URI one level",
InputURI: "smb://192.168.1.1/my-folder-1/",
ExpectedSubdirectory: "/my-folder-1/",
},
{
TestName: "SMB URI two levels",
InputURI: "smb://192.168.1.1/my-folder-1/my-folder-2",
ExpectedSubdirectory: "/my-folder-1/my-folder-2",
},
{
TestName: "FSx Windows URI top level",
InputURI: "fsxw://us-west-2.fs-abcdef012345678901/",
ExpectedSubdirectory: "/",
},
{
TestName: "FSx Windows URI one level",
InputURI: "fsxw://us-west-2.fs-abcdef012345678901/my-folder-1/",
ExpectedSubdirectory: "/my-folder-1/",
},
{
TestName: "FSx Windows URI two levels",
InputURI: "fsxw://us-west-2.fs-abcdef012345678901/my-folder-1/my-folder-2",
ExpectedSubdirectory: "/my-folder-1/my-folder-2",
},
}

for _, testCase := range testCases {
t.Run(testCase.TestName, func(t *testing.T) {
got, err := tfdatasync.SubdirectoryFromLocationURI(testCase.InputURI)

if err == nil && testCase.ExpectedError {
t.Fatalf("expected error")
}

if err != nil && !testCase.ExpectedError {
t.Fatalf("unexpected error: %s", err)
}

if got != testCase.ExpectedSubdirectory {
t.Errorf("got %s, expected %s", got, testCase.ExpectedSubdirectory)
}
})
}
}
5 changes: 3 additions & 2 deletions aws/resource_aws_datasync_location_efs.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync"
)

func resourceAwsDataSyncLocationEfs() *schema.Resource {
Expand Down Expand Up @@ -128,10 +129,10 @@ func resourceAwsDataSyncLocationEfsRead(d *schema.ResourceData, meta interface{}
return fmt.Errorf("error reading DataSync Location EFS (%s): %s", d.Id(), err)
}

subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri))
subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri))

if err != nil {
return fmt.Errorf("error parsing Location EFS (%s) URI (%s): %s", d.Id(), aws.StringValue(output.LocationUri), err)
return err
}

d.Set("arn", output.LocationArn)
Expand Down
5 changes: 3 additions & 2 deletions aws/resource_aws_datasync_location_fsx_windows_file_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync"
)

func resourceAwsDataSyncLocationFsxWindowsFileSystem() *schema.Resource {
Expand Down Expand Up @@ -155,10 +156,10 @@ func resourceAwsDataSyncLocationFsxWindowsFileSystemRead(d *schema.ResourceData,
return fmt.Errorf("error reading DataSync Location Fsx Windows (%s): %w", d.Id(), err)
}

subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri))
subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri))

if err != nil {
return fmt.Errorf("error parsing Location Fsx Windows File System (%s) URI (%s): %w", d.Id(), aws.StringValue(output.LocationUri), err)
return err
}

d.Set("arn", output.LocationArn)
Expand Down
5 changes: 3 additions & 2 deletions aws/resource_aws_datasync_location_nfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync"
)

func resourceAwsDataSyncLocationNfs() *schema.Resource {
Expand Down Expand Up @@ -144,10 +145,10 @@ func resourceAwsDataSyncLocationNfsRead(d *schema.ResourceData, meta interface{}
return fmt.Errorf("error reading DataSync Location NFS (%s): %w", d.Id(), err)
}

subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri))
subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri))

if err != nil {
return fmt.Errorf("error parsing Location NFS (%s) URI (%s): %w", d.Id(), aws.StringValue(output.LocationUri), err)
return err
}

d.Set("arn", output.LocationArn)
Expand Down
5 changes: 3 additions & 2 deletions aws/resource_aws_datasync_location_s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync"
iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter"
)

Expand Down Expand Up @@ -172,10 +173,10 @@ func resourceAwsDataSyncLocationS3Read(d *schema.ResourceData, meta interface{})
return fmt.Errorf("error reading DataSync Location S3 (%s): %s", d.Id(), err)
}

subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri))
subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri))

if err != nil {
return fmt.Errorf("error parsing Location S3 (%s) URI (%s): %s", d.Id(), aws.StringValue(output.LocationUri), err)
return err
}

d.Set("agent_arns", flattenStringSet(output.AgentArns))
Expand Down
5 changes: 3 additions & 2 deletions aws/resource_aws_datasync_location_smb.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync"
)

func resourceAwsDataSyncLocationSmb() *schema.Resource {
Expand Down Expand Up @@ -164,10 +165,10 @@ func resourceAwsDataSyncLocationSmbRead(d *schema.ResourceData, meta interface{}
return fmt.Errorf("error reading DataSync Location SMB (%s) tags: %w", d.Id(), err)
}

subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri))
subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri))

if err != nil {
return fmt.Errorf("error parsing Location SMB (%s) URI (%s): %w", d.Id(), aws.StringValue(output.LocationUri), err)
return err
}

d.Set("agent_arns", flattenStringSet(output.AgentArns))
Expand Down

0 comments on commit 69619c0

Please sign in to comment.