Skip to content

Commit

Permalink
Merge pull request #32939 from bryantbiggs/fix/vpc-lattice-tags
Browse files Browse the repository at this point in the history
fix: Skip listing tags on `aws_vpclattice_service_network` data source when shared via RAM
  • Loading branch information
ewbankkit committed Aug 10, 2023
2 parents 63c9cda + f7039a0 commit 9e2fbfb
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 83 deletions.
7 changes: 7 additions & 0 deletions .changelog/32939.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
data-source/aws_vpclattice_service_network: Avoid listing tags when the service network has been shared to the current account via AWS Resource Access Manager (RAM)
```

```release-note:bug
data-source/aws_vpclattice_service: Avoid listing tags when the service has been shared to the current account via AWS Resource Access Manager (RAM)
```
38 changes: 24 additions & 14 deletions internal/service/vpclattice/service_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/vpclattice"
"github.com/aws/aws-sdk-go-v2/service/vpclattice/types"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
Expand All @@ -18,6 +19,7 @@ import (
)

// @SDKDataSource("aws_vpclattice_service")
// @Tags
func dataSourceService() *schema.Resource {
return &schema.Resource{
ReadWithoutTimeout: dataSourceServiceRead,
Expand Down Expand Up @@ -76,15 +78,11 @@ func dataSourceService() *schema.Resource {
}
}

const (
DSNameService = "Service Data Source"
)

func dataSourceServiceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
var out *vpclattice.GetServiceOutput
conn := meta.(*conns.AWSClient).VPCLatticeClient(ctx)

var out *vpclattice.GetServiceOutput
if v, ok := d.GetOk("service_identifier"); ok {
serviceID := v.(string)
service, err := findServiceByID(ctx, conn, serviceID)
Expand Down Expand Up @@ -113,16 +111,9 @@ func dataSourceServiceRead(ctx context.Context, d *schema.ResourceData, meta int
out = service
}

//
// If you don't set the ID, the data source will not be stored in state. In
// fact, that's how a resource can be removed from state - clearing its ID.
//
// If this data source is a companion to a resource, often both will use the
// same ID. Otherwise, the ID will be a unique identifier such as an AWS
// identifier, ARN, or name.
d.SetId(aws.ToString(out.Id))

d.Set("arn", out.Arn)
serviceARN := aws.ToString(out.Arn)
d.Set("arn", serviceARN)
d.Set("auth_type", out.AuthType)
d.Set("certificate_arn", out.CertificateArn)
d.Set("custom_domain_name", out.CustomDomainName)
Expand All @@ -134,7 +125,26 @@ func dataSourceServiceRead(ctx context.Context, d *schema.ResourceData, meta int
d.Set("dns_entry", nil)
}
d.Set("name", out.Name)
d.Set("service_identifier", out.Id)
d.Set("status", out.Status)

// https://docs.aws.amazon.com/vpc-lattice/latest/ug/sharing.html#sharing-perms
// Owners and consumers can list tags and can tag/untag resources in a service network that the account created.
// They can't list tags and tag/untag resources in a service network that aren't created by the account.
parsedARN, err := arn.Parse(serviceARN)
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}

if parsedARN.AccountID == meta.(*conns.AWSClient).AccountID {
tags, err := listTags(ctx, conn, serviceARN)

if err != nil {
return sdkdiag.AppendErrorf(diags, "listing tags for VPC Lattice Service (%s): %s", serviceARN, err)
}

setTagsOut(ctx, Tags(tags))
}

return nil
}
119 changes: 103 additions & 16 deletions internal/service/vpclattice/service_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ package vpclattice_test

import (
"fmt"
"regexp"
"testing"

"github.com/aws/aws-sdk-go-v2/service/vpclattice"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
Expand All @@ -17,8 +15,8 @@ import (

func TestAccVPCLatticeServiceDataSource_basic(t *testing.T) {
ctx := acctest.Context(t)
var service vpclattice.GetServiceOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_vpclattice_service.test"
dataSourceName := "data.aws_vpclattice_service.test"

resource.ParallelTest(t, resource.TestCase{
Expand All @@ -29,15 +27,18 @@ func TestAccVPCLatticeServiceDataSource_basic(t *testing.T) {
},
ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckServiceDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccServiceDataSourceConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckServiceExists(ctx, dataSourceName, &service),
resource.TestCheckResourceAttr(dataSourceName, "name", rName),
resource.TestCheckResourceAttr(dataSourceName, "auth_type", "NONE"),
acctest.MatchResourceAttrRegionalARN(dataSourceName, "arn", "vpc-lattice", regexp.MustCompile(`service/.+$`)),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"),
resource.TestCheckResourceAttrPair(resourceName, "auth_type", dataSourceName, "auth_type"),
resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", dataSourceName, "certificate_arn"),
resource.TestCheckResourceAttrPair(resourceName, "custom_domain_name", dataSourceName, "custom_domain_name"),
resource.TestCheckResourceAttrPair(resourceName, "dns_entry.#", dataSourceName, "dns_entry.#"),
resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"),
resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"),
resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"),
),
},
},
Expand All @@ -46,8 +47,8 @@ func TestAccVPCLatticeServiceDataSource_basic(t *testing.T) {

func TestAccVPCLatticeServiceDataSource_byName(t *testing.T) {
ctx := acctest.Context(t)
var service vpclattice.GetServiceOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_vpclattice_service.test"
dataSourceName := "data.aws_vpclattice_service.test"

resource.ParallelTest(t, resource.TestCase{
Expand All @@ -58,15 +59,52 @@ func TestAccVPCLatticeServiceDataSource_byName(t *testing.T) {
},
ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckServiceDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccServiceDataSourceConfig_byName(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckServiceExists(ctx, dataSourceName, &service),
resource.TestCheckResourceAttr(dataSourceName, "name", rName),
resource.TestCheckResourceAttr(dataSourceName, "auth_type", "NONE"),
acctest.MatchResourceAttrRegionalARN(dataSourceName, "arn", "vpc-lattice", regexp.MustCompile(`service/.+$`)),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"),
resource.TestCheckResourceAttrPair(resourceName, "auth_type", dataSourceName, "auth_type"),
resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", dataSourceName, "certificate_arn"),
resource.TestCheckResourceAttrPair(resourceName, "custom_domain_name", dataSourceName, "custom_domain_name"),
resource.TestCheckResourceAttrPair(resourceName, "dns_entry.#", dataSourceName, "dns_entry.#"),
resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"),
resource.TestCheckResourceAttrSet(dataSourceName, "service_identifier"),
resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"),
resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"),
),
},
},
})
}

func TestAccVPCLatticeServiceDataSource_shared(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_vpclattice_service.test"
dataSourceName := "data.aws_vpclattice_service.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckAlternateAccount(t)
acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5FactoriesAlternate(ctx, t),
Steps: []resource.TestStep{
{
Config: testAccServiceDataSourceConfig_shared(rName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"),
resource.TestCheckResourceAttrPair(resourceName, "auth_type", dataSourceName, "auth_type"),
resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", dataSourceName, "certificate_arn"),
resource.TestCheckResourceAttrPair(resourceName, "custom_domain_name", dataSourceName, "custom_domain_name"),
resource.TestCheckResourceAttrPair(resourceName, "dns_entry.#", dataSourceName, "dns_entry.#"),
resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"),
resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"),
resource.TestCheckNoResourceAttr(dataSourceName, "tags.%"),
),
},
},
Expand All @@ -77,6 +115,10 @@ func testAccServiceDataSourceConfig_basic(rName string) string {
return fmt.Sprintf(`
resource "aws_vpclattice_service" "test" {
name = %[1]q
tags = {
Name = %[1]q
}
}
data "aws_vpclattice_service" "test" {
Expand All @@ -89,10 +131,55 @@ func testAccServiceDataSourceConfig_byName(rName string) string {
return fmt.Sprintf(`
resource "aws_vpclattice_service" "test" {
name = %[1]q
tags = {
Name = %[1]q
}
}
data "aws_vpclattice_service" "test" {
name = aws_vpclattice_service.test.name
}
`, rName)
}

func testAccServiceDataSourceConfig_shared(rName string) string {
return acctest.ConfigCompose(acctest.ConfigAlternateAccountProvider(), fmt.Sprintf(`
data "aws_caller_identity" "source" {}
data "aws_caller_identity" "target" {
provider = "awsalternate"
}
resource "aws_vpclattice_service" "test" {
name = %[1]q
tags = {
Name = %[1]q
}
}
resource "aws_ram_resource_share" "test" {
name = %[1]q
allow_external_principals = false
}
resource "aws_ram_resource_association" "test" {
resource_arn = aws_vpclattice_service.test.arn
resource_share_arn = aws_ram_resource_share.test.arn
}
resource "aws_ram_principal_association" "test" {
principal = data.aws_caller_identity.target.arn
resource_share_arn = aws_ram_resource_share.test.arn
}
data "aws_vpclattice_service" "test" {
provider = "awsalternate"
service_identifier = aws_vpclattice_service.test.id
depends_on = [aws_ram_resource_association.test, aws_ram_principal_association.test]
}
`, rName))
}
40 changes: 23 additions & 17 deletions internal/service/vpclattice/service_network_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ import (
"context"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @SDKDataSource("aws_vpclattice_service_network")
func DataSourceServiceNetwork() *schema.Resource {
// @Tags
func dataSourceServiceNetwork() *schema.Resource {
return &schema.Resource{
ReadWithoutTimeout: dataSourceServiceNetworkRead,

Expand Down Expand Up @@ -53,27 +55,25 @@ func DataSourceServiceNetwork() *schema.Resource {
Type: schema.TypeString,
Required: true,
},
"tags": tftags.TagsSchemaComputed(),
names.AttrTags: tftags.TagsSchemaComputed(),
},
}
}

const (
DSNameServiceNetwork = "Service Network Data Source"
)

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

serviceNetworkID := d.Get("service_network_identifier").(string)
out, err := findServiceNetworkByID(ctx, conn, serviceNetworkID)

if err != nil {
return create.DiagError(names.VPCLattice, create.ErrActionReading, DSNameServiceNetwork, serviceNetworkID, err)
return sdkdiag.AppendFromErr(diags, err)
}

d.SetId(aws.ToString(out.Id))
d.Set("arn", out.Arn)
serviceNetworkARN := aws.ToString(out.Arn)
d.Set("arn", serviceNetworkARN)
d.Set("auth_type", out.AuthType)
d.Set("created_at", aws.ToTime(out.CreatedAt).String())
d.Set("last_updated_at", aws.ToTime(out.LastUpdatedAt).String())
Expand All @@ -82,17 +82,23 @@ func dataSourceServiceNetworkRead(ctx context.Context, d *schema.ResourceData, m
d.Set("number_of_associated_vpcs", out.NumberOfAssociatedVPCs)
d.Set("service_network_identifier", out.Id)

ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig
tags, err := listTags(ctx, conn, aws.ToString(out.Arn))

// https://docs.aws.amazon.com/vpc-lattice/latest/ug/sharing.html#sharing-perms
// Owners and consumers can list tags and can tag/untag resources in a service network that the account created.
// They can't list tags and tag/untag resources in a service network that aren't created by the account.
parsedARN, err := arn.Parse(serviceNetworkARN)
if err != nil {
return create.DiagError(names.VPCLattice, create.ErrActionReading, DSNameServiceNetwork, serviceNetworkID, err)
return sdkdiag.AppendFromErr(diags, err)
}

//lintignore:AWSR002
if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return create.DiagError(names.VPCLattice, create.ErrActionSetting, DSNameServiceNetwork, d.Id(), err)
if parsedARN.AccountID == meta.(*conns.AWSClient).AccountID {
tags, err := listTags(ctx, conn, serviceNetworkARN)

if err != nil {
return sdkdiag.AppendErrorf(diags, "listing tags for VPC Lattice Service Network (%s): %s", serviceNetworkARN, err)
}

setTagsOut(ctx, Tags(tags))
}

return nil
return diags
}
Loading

0 comments on commit 9e2fbfb

Please sign in to comment.