diff --git a/.changelog/36072.txt b/.changelog/36072.txt new file mode 100644 index 000000000000..bdb320d66f63 --- /dev/null +++ b/.changelog/36072.txt @@ -0,0 +1,19 @@ +```release-note:bug +resource/aws_datasync_location_azure_blob: Fix missing `container_url` attribute value and bad `subdirectory` attribute value from state read/refresh +``` + +```release-note:bug +resource/aws_datasync_location_efs: Fix missing `efs_file_system_arn` attribute value from state read/refresh +``` + +```release-note:bug +resource/aws_datasync_location_nfs: Fix missing `server_hostname` attribute value from state read/refresh +``` + +```release-note:bug +resource/aws_datasync_location_s3: Fix missing `s3_bucket_arn` attribute value from state read/refresh +``` + +```release-note:bug +resource/aws_datasync_location_smb: Fix missing `server_hostname` attribute value from state read/refresh +``` \ No newline at end of file diff --git a/internal/service/datasync/location_azure_blob.go b/internal/service/datasync/location_azure_blob.go index 605f01d07422..9e1b233884fc 100644 --- a/internal/service/datasync/location_azure_blob.go +++ b/internal/service/datasync/location_azure_blob.go @@ -5,6 +5,7 @@ package datasync import ( "context" + "fmt" "log" "strings" @@ -167,11 +168,19 @@ func resourceLocationAzureBlobRead(ctx context.Context, d *schema.ResourceData, } uri := aws.StringValue(output.LocationUri) + accountHostName, err := globalIdFromLocationURI(aws.StringValue(output.LocationUri)) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } subdirectory, err := subdirectoryFromLocationURI(uri) if err != nil { return sdkdiag.AppendFromErr(diags, err) } + containerName := subdirectory[:strings.IndexAny(subdirectory[1:], "/")+1] + containerUrl := fmt.Sprintf("https://%s%s", accountHostName, containerName) + d.Set("container_url", containerUrl) + d.Set("access_tier", output.AccessTier) d.Set("agent_arns", aws.StringValueSlice(output.AgentArns)) d.Set("arn", output.LocationArn) @@ -179,7 +188,7 @@ func resourceLocationAzureBlobRead(ctx context.Context, d *schema.ResourceData, d.Set("blob_type", output.BlobType) d.Set("container_url", d.Get("container_url")) d.Set("sas_configuration", d.Get("sas_configuration")) - d.Set("subdirectory", subdirectory) + d.Set("subdirectory", subdirectory[strings.IndexAny(subdirectory[1:], "/")+1:]) d.Set("uri", uri) return diags diff --git a/internal/service/datasync/location_azure_blob_test.go b/internal/service/datasync/location_azure_blob_test.go index 30b7465aeb65..80032142df5d 100644 --- a/internal/service/datasync/location_azure_blob_test.go +++ b/internal/service/datasync/location_azure_blob_test.go @@ -41,10 +41,10 @@ func TestAccDataSyncLocationAzureBlob_basic(t *testing.T) { acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "datasync", regexache.MustCompile(`location/loc-.+`)), resource.TestCheckResourceAttr(resourceName, "authentication_type", "SAS"), resource.TestCheckResourceAttr(resourceName, "blob_type", "BLOCK"), - resource.TestCheckResourceAttr(resourceName, "container_url", "https://example.com/path"), + resource.TestCheckResourceAttr(resourceName, "container_url", "https://myaccount.blob.core.windows.net/mycontainer"), resource.TestCheckResourceAttr(resourceName, "sas_configuration.#", "1"), resource.TestCheckResourceAttrSet(resourceName, "sas_configuration.0.token"), - resource.TestCheckResourceAttr(resourceName, "subdirectory", "/path/"), + resource.TestCheckResourceAttr(resourceName, "subdirectory", "/myvdir1/myvdir2/"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestMatchResourceAttr(resourceName, "uri", regexache.MustCompile(`^azure-blob://.+/`)), ), @@ -53,7 +53,7 @@ func TestAccDataSyncLocationAzureBlob_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"container_url", "sas_configuration"}, + ImportStateVerifyIgnore: []string{"sas_configuration"}, }, }, }) @@ -107,7 +107,7 @@ func TestAccDataSyncLocationAzureBlob_tags(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"container_url", "sas_configuration"}, + ImportStateVerifyIgnore: []string{"sas_configuration"}, }, { Config: testAccLocationAzureBlobConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), @@ -151,10 +151,10 @@ func TestAccDataSyncLocationAzureBlob_update(t *testing.T) { acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "datasync", regexache.MustCompile(`location/loc-.+`)), resource.TestCheckResourceAttr(resourceName, "authentication_type", "SAS"), resource.TestCheckResourceAttr(resourceName, "blob_type", "BLOCK"), - resource.TestCheckResourceAttr(resourceName, "container_url", "https://example.com/path"), + resource.TestCheckResourceAttr(resourceName, "container_url", "https://myaccount.blob.core.windows.net/mycontainer"), resource.TestCheckResourceAttr(resourceName, "sas_configuration.#", "1"), resource.TestCheckResourceAttrSet(resourceName, "sas_configuration.0.token"), - resource.TestCheckResourceAttr(resourceName, "subdirectory", "/path/"), + resource.TestCheckResourceAttr(resourceName, "subdirectory", "/myvdir1/myvdir2/"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestMatchResourceAttr(resourceName, "uri", regexache.MustCompile(`^azure-blob://.+/`)), ), @@ -168,10 +168,10 @@ func TestAccDataSyncLocationAzureBlob_update(t *testing.T) { acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "datasync", regexache.MustCompile(`location/loc-.+`)), resource.TestCheckResourceAttr(resourceName, "authentication_type", "SAS"), resource.TestCheckResourceAttr(resourceName, "blob_type", "BLOCK"), - resource.TestCheckResourceAttr(resourceName, "container_url", "https://example.com/path"), + resource.TestCheckResourceAttr(resourceName, "container_url", "https://myaccount.blob.core.windows.net/mycontainer"), resource.TestCheckResourceAttr(resourceName, "sas_configuration.#", "1"), resource.TestCheckResourceAttrSet(resourceName, "sas_configuration.0.token"), - resource.TestCheckResourceAttr(resourceName, "subdirectory", "/path/"), + resource.TestCheckResourceAttr(resourceName, "subdirectory", "/"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestMatchResourceAttr(resourceName, "uri", regexache.MustCompile(`^azure-blob://.+/`)), ), @@ -241,7 +241,8 @@ func testAccLocationAzureBlobConfig_basic(rName string) string { resource "aws_datasync_location_azure_blob" "test" { agent_arns = [aws_datasync_agent.test.arn] authentication_type = "SAS" - container_url = "https://example.com/path" + container_url = "https://myaccount.blob.core.windows.net/mycontainer" + subdirectory = "/myvdir1/myvdir2" sas_configuration { token = "sp=r&st=2023-12-20T14:54:52Z&se=2023-12-20T22:54:52Z&spr=https&sv=2021-06-08&sr=c&sig=aBBKDWQvyuVcTPH9EBp%%2FXTI9E%%2F%%2Fmq171%%2BZU178wcwqU%%3D" @@ -255,7 +256,7 @@ func testAccLocationAzureBlobConfig_tags1(rName, key1, value1 string) string { resource "aws_datasync_location_azure_blob" "test" { agent_arns = [aws_datasync_agent.test.arn] authentication_type = "SAS" - container_url = "https://example.com/path" + container_url = "https://myaccount.blob.core.windows.net/mycontainer" sas_configuration { token = "sp=r&st=2023-12-20T14:54:52Z&se=2023-12-20T22:54:52Z&spr=https&sv=2021-06-08&sr=c&sig=aBBKDWQvyuVcTPH9EBp%%2FXTI9E%%2F%%2Fmq171%%2BZU178wcwqU%%3D" @@ -273,7 +274,7 @@ func testAccLocationAzureBlobConfig_tags2(rName, key1, value1, key2, value2 stri resource "aws_datasync_location_azure_blob" "test" { agent_arns = [aws_datasync_agent.test.arn] authentication_type = "SAS" - container_url = "https://example.com/path" + container_url = "https://myaccount.blob.core.windows.net/mycontainer" sas_configuration { token = "sp=r&st=2023-12-20T14:54:52Z&se=2023-12-20T22:54:52Z&spr=https&sv=2021-06-08&sr=c&sig=aBBKDWQvyuVcTPH9EBp%%2FXTI9E%%2F%%2Fmq171%%2BZU178wcwqU%%3D" @@ -293,7 +294,8 @@ resource "aws_datasync_location_azure_blob" "test" { access_tier = "COOL" agent_arns = [aws_datasync_agent.test.arn] authentication_type = "SAS" - container_url = "https://example.com/path" + container_url = "https://myaccount.blob.core.windows.net/mycontainer" + subdirectory = "/" sas_configuration { token = "sp=r&st=2023-12-20T14:54:52Z&se=2023-12-20T22:54:52Z&spr=https&sv=2021-06-08&sr=c&sig=aBBKDWQvyuVcTPH9EBp%%2FXTI9E%%2F%%2Fmq171%%2BZU178wcwqU%%3D" diff --git a/internal/service/datasync/location_efs.go b/internal/service/datasync/location_efs.go index 9f85450dcb35..e185d429285b 100644 --- a/internal/service/datasync/location_efs.go +++ b/internal/service/datasync/location_efs.go @@ -5,10 +5,12 @@ package datasync import ( "context" + "fmt" "log" "strings" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/datasync" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -170,11 +172,23 @@ func resourceLocationEFSRead(ctx context.Context, d *schema.ResourceData, meta i } uri := aws.StringValue(output.LocationUri) + globalId, err := globalIdFromLocationURI(uri) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } subdirectory, err := subdirectoryFromLocationURI(uri) if err != nil { return sdkdiag.AppendFromErr(diags, err) } + locationArn, err := arn.Parse(d.Id()) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + globalIdParts := strings.Split(globalId, ".") // Global ID format for EFS location is . + efsFileSystemArn := fmt.Sprintf("arn:%s:elasticfilesystem:%s:%s:file-system/%s", locationArn.Partition, globalIdParts[0], locationArn.AccountID, globalIdParts[1]) + d.Set("efs_file_system_arn", efsFileSystemArn) + d.Set("access_point_arn", output.AccessPointArn) d.Set("arn", output.LocationArn) if err := d.Set("ec2_config", flattenEC2Config(output.Ec2Config)); err != nil { diff --git a/internal/service/datasync/location_efs_test.go b/internal/service/datasync/location_efs_test.go index f53b84b62f27..1933e0e5a176 100644 --- a/internal/service/datasync/location_efs_test.go +++ b/internal/service/datasync/location_efs_test.go @@ -49,10 +49,9 @@ func TestAccDataSyncLocationEFS_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"efs_file_system_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -79,10 +78,9 @@ func TestAccDataSyncLocationEFS_accessPointARN(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"efs_file_system_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -133,10 +131,9 @@ func TestAccDataSyncLocationEFS_subdirectory(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"efs_file_system_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -163,10 +160,9 @@ func TestAccDataSyncLocationEFS_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"efs_file_system_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccLocationEFSConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), diff --git a/internal/service/datasync/location_nfs.go b/internal/service/datasync/location_nfs.go index 904bd8cb1be6..6da5fb5594d8 100644 --- a/internal/service/datasync/location_nfs.go +++ b/internal/service/datasync/location_nfs.go @@ -153,6 +153,10 @@ func resourceLocationNFSRead(ctx context.Context, d *schema.ResourceData, meta i } uri := aws.StringValue(output.LocationUri) + serverHostName, err := globalIdFromLocationURI(uri) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } subdirectory, err := subdirectoryFromLocationURI(uri) if err != nil { return sdkdiag.AppendFromErr(diags, err) @@ -165,6 +169,7 @@ func resourceLocationNFSRead(ctx context.Context, d *schema.ResourceData, meta i if err := d.Set("on_prem_config", flattenOnPremConfig(output.OnPremConfig)); err != nil { return sdkdiag.AppendErrorf(diags, "setting on_prem_config: %s", err) } + d.Set("server_hostname", serverHostName) d.Set("subdirectory", subdirectory) d.Set("uri", uri) diff --git a/internal/service/datasync/location_nfs_test.go b/internal/service/datasync/location_nfs_test.go index 64470dcc57f2..15eb279b4b20 100644 --- a/internal/service/datasync/location_nfs_test.go +++ b/internal/service/datasync/location_nfs_test.go @@ -48,10 +48,9 @@ func TestAccDataSyncLocationNFS_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"server_hostname"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -77,10 +76,9 @@ func TestAccDataSyncLocationNFS_mountOptions(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"server_hostname"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccLocationNFSConfig_mountOptions(rName, "NFS4_1"), @@ -138,10 +136,9 @@ func TestAccDataSyncLocationNFS_AgentARNs_multiple(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"server_hostname"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -167,10 +164,9 @@ func TestAccDataSyncLocationNFS_subdirectory(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"server_hostname"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccLocationNFSConfig_subdirectory(rName, "/subdirectory2/"), @@ -204,10 +200,9 @@ func TestAccDataSyncLocationNFS_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"server_hostname"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccLocationNFSConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), diff --git a/internal/service/datasync/location_s3.go b/internal/service/datasync/location_s3.go index e4211f2271e4..3f3f1980031e 100644 --- a/internal/service/datasync/location_s3.go +++ b/internal/service/datasync/location_s3.go @@ -5,10 +5,12 @@ package datasync import ( "context" + "fmt" "log" "strings" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/datasync" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -172,11 +174,22 @@ func resourceLocationS3Read(ctx context.Context, d *schema.ResourceData, meta in } uri := aws.StringValue(output.LocationUri) + s3BucketName, err := globalIdFromLocationURI(aws.StringValue(output.LocationUri)) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } subdirectory, err := subdirectoryFromLocationURI(aws.StringValue(output.LocationUri)) if err != nil { return sdkdiag.AppendFromErr(diags, err) } + locationArn, err := arn.Parse(d.Id()) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + s3BucketArn := fmt.Sprintf("arn:%s:s3:::%s", locationArn.Partition, s3BucketName) + d.Set("s3_bucket_arn", s3BucketArn) + d.Set("agent_arns", aws.StringValueSlice(output.AgentArns)) d.Set("arn", output.LocationArn) if err := d.Set("s3_config", flattenS3Config(output.S3Config)); err != nil { diff --git a/internal/service/datasync/location_s3_test.go b/internal/service/datasync/location_s3_test.go index 3ae18effd005..9fc082383158 100644 --- a/internal/service/datasync/location_s3_test.go +++ b/internal/service/datasync/location_s3_test.go @@ -50,10 +50,9 @@ func TestAccDataSyncLocationS3_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"s3_bucket_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -87,10 +86,9 @@ func TestAccDataSyncLocationS3_storageClass(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"s3_bucket_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -141,10 +139,9 @@ func TestAccDataSyncLocationS3_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"s3_bucket_arn"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccLocationS3Config_tags2(rName, "key1", "value1updated", "key2", "value2"), diff --git a/internal/service/datasync/location_smb.go b/internal/service/datasync/location_smb.go index ba7dcd526a23..49f3d8763db4 100644 --- a/internal/service/datasync/location_smb.go +++ b/internal/service/datasync/location_smb.go @@ -162,6 +162,10 @@ func resourceLocationSMBRead(ctx context.Context, d *schema.ResourceData, meta i } uri := aws.StringValue(output.LocationUri) + serverHostName, err := globalIdFromLocationURI(uri) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } subdirectory, err := subdirectoryFromLocationURI(aws.StringValue(output.LocationUri)) if err != nil { return sdkdiag.AppendFromErr(diags, err) @@ -173,6 +177,7 @@ func resourceLocationSMBRead(ctx context.Context, d *schema.ResourceData, meta i if err := d.Set("mount_options", flattenSMBMountOptions(output.MountOptions)); err != nil { return sdkdiag.AppendErrorf(diags, "setting mount_options: %s", err) } + d.Set("server_hostname", serverHostName) d.Set("subdirectory", subdirectory) d.Set("uri", uri) d.Set("user", output.User) diff --git a/internal/service/datasync/location_smb_test.go b/internal/service/datasync/location_smb_test.go index 504667d014a1..df4f78345616 100644 --- a/internal/service/datasync/location_smb_test.go +++ b/internal/service/datasync/location_smb_test.go @@ -49,7 +49,7 @@ func TestAccDataSyncLocationSMB_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"password", "server_hostname"}, + ImportStateVerifyIgnore: []string{"password"}, }, { Config: testAccLocationSMBConfig_basic(rName, "/test2/"), @@ -116,7 +116,7 @@ func TestAccDataSyncLocationSMB_tags(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"password", "server_hostname"}, + ImportStateVerifyIgnore: []string{"password"}, }, { Config: testAccLocationSMBConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), diff --git a/internal/service/datasync/uri.go b/internal/service/datasync/uri.go index f99c702f0769..205e0cb8a9e1 100644 --- a/internal/service/datasync/uri.go +++ b/internal/service/datasync/uri.go @@ -16,6 +16,26 @@ var ( s3OutpostsAccessPointARNResourcePattern = regexache.MustCompile(`^outpost/.*/accesspoint/.*?(/.*)$`) ) +// globalIDFromLocationURI extracts the global ID from a location URI. +// https://docs.aws.amazon.com/datasync/latest/userguide/API_LocationListEntry.html#DataSync-Type-LocationListEntry-LocationUri +func globalIdFromLocationURI(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] + + 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[1], nil +} + // 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) {