Skip to content

Commit

Permalink
Merge pull request #32658 from nmoutschen/b-aws_vpclattice_service_ne…
Browse files Browse the repository at this point in the history
…twork_vpc_association-service_network_identifier

fix: fix `aws_vpclattice_service_network_vpc_association` forced replacement
  • Loading branch information
ewbankkit committed Jul 26, 2023
2 parents 121145a + b292a28 commit 3004b33
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 143 deletions.
7 changes: 7 additions & 0 deletions .changelog/32658.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_vpclattice_service_network_vpc_association: Avoid recreating resource when passing an ARN as `service_network_identifier`
```

```release-note:bug
resource/aws_vpclattice_service_network_service_association: Avoid recreating resource when passing an ARN as `service_identifier` or `service_network_identifier`
```
22 changes: 7 additions & 15 deletions internal/service/ec2/vpc_.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/hashicorp/aws-sdk-go-base/v2/tfawserr"
tfawserr_sdkv2 "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
Expand Down Expand Up @@ -213,18 +213,10 @@ func resourceVPCCreate(ctx context.Context, d *schema.ResourceData, meta interfa
input.Ipv6NetmaskLength = aws.Int32(int32(v.(int)))
}

outputRaw, err := tfresource.RetryWhen(ctx, ec2PropagationTimeout,
func() (interface{}, error) {
return conn.CreateVpc(ctx, input)
},
func(err error) (bool, error) {
// "UnsupportedOperation: The operation AllocateIpamPoolCidr is not supported. Account 123456789012 is not monitored by IPAM ipam-07b079e3392782a55."
if tfawserr.ErrMessageContains(err, errCodeUnsupportedOperation, "is not monitored by IPAM") {
return true, err
}
return false, err
},
)
// "UnsupportedOperation: The operation AllocateIpamPoolCidr is not supported. Account 123456789012 is not monitored by IPAM ipam-07b079e3392782a55."
outputRaw, err := tfresource.RetryWhenAWSErrMessageContainsV2(ctx, ec2PropagationTimeout, func() (interface{}, error) {
return conn.CreateVpc(ctx, input)
}, errCodeUnsupportedOperation, "is not monitored by IPAM")

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating EC2 VPC: %s", err)
Expand Down Expand Up @@ -458,11 +450,11 @@ func resourceVPCDelete(ctx context.Context, d *schema.ResourceData, meta interfa
}

log.Printf("[INFO] Deleting EC2 VPC: %s", d.Id())
_, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, vpcDeletedTimeout, func() (interface{}, error) {
_, err := tfresource.RetryWhenAWSErrCodeEqualsV2(ctx, vpcDeletedTimeout, func() (interface{}, error) {
return conn.DeleteVpc(ctx, input)
}, errCodeDependencyViolation)

if tfawserr.ErrCodeEquals(err, errCodeInvalidVPCIDNotFound) {
if tfawserr_sdkv2.ErrCodeEquals(err, errCodeInvalidVPCIDNotFound) {
return diags
}

Expand Down
11 changes: 9 additions & 2 deletions internal/service/vpclattice/exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ package vpclattice

// Exports for use in tests only.
var (
FindTargetByThreePartKey = findTargetByThreePartKey
FindServiceNetworkServiceAssociationByID = findServiceNetworkServiceAssociationByID
FindServiceNetworkVPCAssociationByID = findServiceNetworkVPCAssociationByID
FindTargetByThreePartKey = findTargetByThreePartKey

ResourceTargetGroupAttachment = resourceTargetGroupAttachment
IDFromIDOrARN = idFromIDOrARN
SuppressEquivalentIDOrARN = suppressEquivalentIDOrARN

ResourceServiceNetworkServiceAssociation = resourceServiceNetworkServiceAssociation
ResourceServiceNetworkVPCAssociation = resourceServiceNetworkVPCAssociation
ResourceTargetGroupAttachment = resourceTargetGroupAttachment
)
14 changes: 14 additions & 0 deletions internal/service/vpclattice/service_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"errors"
"log"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/vpclattice"
Expand Down Expand Up @@ -181,3 +182,16 @@ func findServiceNetworkByID(ctx context.Context, conn *vpclattice.Client, id str

return out, nil
}

// idFromIDOrARN return a resource ID from an ID or ARN.
func idFromIDOrARN(idOrARN string) string {
// e.g. "sn-1234567890abcdefg" or
// "arn:aws:vpc-lattice:us-east-1:123456789012:servicenetwork/sn-1234567890abcdefg".
return idOrARN[strings.LastIndex(idOrARN, "/")+1:]
}

// suppressEquivalentIDOrARN provides custom difference suppression
// for strings that represent equal resource IDs or ARNs.
func suppressEquivalentIDOrARN(_, old, new string, _ *schema.ResourceData) bool {
return idFromIDOrARN(old) == idFromIDOrARN(new)
}
40 changes: 21 additions & 19 deletions internal/service/vpclattice/service_network_service_association.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/enum"
"github.com/hashicorp/terraform-provider-aws/internal/errs"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
Expand All @@ -27,7 +28,7 @@ import (

// @SDKResource("aws_vpclattice_service_network_service_association", name="Service Network Service Association")
// @Tags(identifierAttribute="arn")
func ResourceServiceNetworkServiceAssociation() *schema.Resource {
func resourceServiceNetworkServiceAssociation() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceServiceNetworkServiceAssociationCreate,
ReadWithoutTimeout: resourceServiceNetworkServiceAssociationRead,
Expand Down Expand Up @@ -74,14 +75,16 @@ func ResourceServiceNetworkServiceAssociation() *schema.Resource {
},
},
"service_identifier": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Required: true,
ForceNew: true,
DiffSuppressFunc: suppressEquivalentIDOrARN,
},
"service_network_identifier": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Required: true,
ForceNew: true,
DiffSuppressFunc: suppressEquivalentIDOrARN,
},
"status": {
Type: schema.TypeString,
Expand Down Expand Up @@ -173,12 +176,11 @@ func resourceServiceNetworkServiceAssociationDelete(ctx context.Context, d *sche
ServiceNetworkServiceAssociationIdentifier: aws.String(d.Id()),
})

if err != nil {
var nfe *types.ResourceNotFoundException
if errors.As(err, &nfe) {
return nil
}
if errs.IsA[*types.ResourceNotFoundException](err) {
return nil
}

if err != nil {
return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameServiceNetworkAssociation, d.Id(), err)
}

Expand All @@ -194,15 +196,15 @@ func findServiceNetworkServiceAssociationByID(ctx context.Context, conn *vpclatt
ServiceNetworkServiceAssociationIdentifier: aws.String(id),
}
out, err := conn.GetServiceNetworkServiceAssociation(ctx, in)
if err != nil {
var nfe *types.ResourceNotFoundException
if errors.As(err, &nfe) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: in,
}

if errs.IsA[*types.ResourceNotFoundException](err) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: in,
}
}

if err != nil {
return nil, err
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ import (
"regexp"
"testing"

"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"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
tfvpclattice "github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

Expand Down Expand Up @@ -56,6 +55,39 @@ func TestAccVPCLatticeServiceNetworkServiceAssociation_basic(t *testing.T) {
})
}

func TestAccVPCLatticeServiceNetworkServiceAssociation_arn(t *testing.T) {
ctx := acctest.Context(t)

var servicenetworkasc vpclattice.GetServiceNetworkServiceAssociationOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_vpclattice_service_network_service_association.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckServiceNetworkServiceAssociationDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccServiceNetworkServiceAssociationConfig_arn(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckServiceNetworkServiceAssociationExists(ctx, resourceName, &servicenetworkasc),
acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("servicenetworkserviceassociation/.+$")),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccVPCLatticeServiceNetworkServiceAssociation_disappears(t *testing.T) {
ctx := acctest.Context(t)

Expand Down Expand Up @@ -144,18 +176,17 @@ func testAccCheckServiceNetworkServiceAssociationDestroy(ctx context.Context) re
continue
}

_, err := conn.GetServiceNetworkServiceAssociation(ctx, &vpclattice.GetServiceNetworkServiceAssociationInput{
ServiceNetworkServiceAssociationIdentifier: aws.String(rs.Primary.ID),
})
_, err := tfvpclattice.FindServiceNetworkServiceAssociationByID(ctx, conn, rs.Primary.ID)

if tfresource.NotFound(err) {
continue
}

if err != nil {
var nfe *types.ResourceNotFoundException
if errors.As(err, &nfe) {
return nil
}
return err
}

return create.Error(names.VPCLattice, create.ErrActionCheckingDestroyed, tfvpclattice.ResNameService, rs.Primary.ID, errors.New("not destroyed"))
return fmt.Errorf("VPC Lattice Service Network Service Association %s still exists", rs.Primary.ID)
}

return nil
Expand All @@ -174,12 +205,10 @@ func testAccCheckServiceNetworkServiceAssociationExists(ctx context.Context, nam
}

conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient(ctx)
resp, err := conn.GetServiceNetworkServiceAssociation(ctx, &vpclattice.GetServiceNetworkServiceAssociationInput{
ServiceNetworkServiceAssociationIdentifier: aws.String(rs.Primary.ID),
})
resp, err := tfvpclattice.FindServiceNetworkServiceAssociationByID(ctx, conn, rs.Primary.ID)

if err != nil {
return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, rs.Primary.ID, err)
return err
}

*service = *resp
Expand All @@ -188,7 +217,7 @@ func testAccCheckServiceNetworkServiceAssociationExists(ctx context.Context, nam
}
}

func testAccServiceNetworkServiceAssociationConfig_basic(rName string) string {
func testAccServiceNetworkServiceAssociationConfig_base(rName string) string {
return fmt.Sprintf(`
resource "aws_vpclattice_service" "test" {
name = %[1]q
Expand All @@ -197,53 +226,50 @@ resource "aws_vpclattice_service" "test" {
resource "aws_vpclattice_service_network" "test" {
name = %[1]q
}
`, rName)
}

func testAccServiceNetworkServiceAssociationConfig_basic(rName string) string {
return acctest.ConfigCompose(testAccServiceNetworkServiceAssociationConfig_base(rName), `
resource "aws_vpclattice_service_network_service_association" "test" {
service_identifier = aws_vpclattice_service.test.id
service_network_identifier = aws_vpclattice_service_network.test.id
}
`, rName)
`)
}

func testAccServiceNetworkServiceAssociationConfig_tags1(rName, tagKey1, tagValue1 string) string {
return fmt.Sprintf(`
resource "aws_vpclattice_service" "test" {
name = %[1]q
func testAccServiceNetworkServiceAssociationConfig_arn(rName string) string {
return acctest.ConfigCompose(testAccServiceNetworkServiceAssociationConfig_base(rName), `
resource "aws_vpclattice_service_network_service_association" "test" {
service_identifier = aws_vpclattice_service.test.arn
service_network_identifier = aws_vpclattice_service_network.test.arn
}
resource "aws_vpclattice_service_network" "test" {
name = %[1]q
`)
}

func testAccServiceNetworkServiceAssociationConfig_tags1(rName, tagKey1, tagValue1 string) string {
return acctest.ConfigCompose(testAccServiceNetworkServiceAssociationConfig_base(rName), fmt.Sprintf(`
resource "aws_vpclattice_service_network_service_association" "test" {
service_identifier = aws_vpclattice_service.test.id
service_network_identifier = aws_vpclattice_service_network.test.id
tags = {
%[2]q = %[3]q
%[1]q = %[2]q
}
}
`, rName, tagKey1, tagValue1)
`, tagKey1, tagValue1))
}

func testAccServiceNetworkServiceAssociationConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string {
return fmt.Sprintf(`
resource "aws_vpclattice_service" "test" {
name = %[1]q
}
resource "aws_vpclattice_service_network" "test" {
name = %[1]q
}
return acctest.ConfigCompose(testAccServiceNetworkServiceAssociationConfig_base(rName), fmt.Sprintf(`
resource "aws_vpclattice_service_network_service_association" "test" {
service_identifier = aws_vpclattice_service.test.id
service_network_identifier = aws_vpclattice_service_network.test.id
tags = {
%[2]q = %[3]q
%[4]q = %[5]q
%[1]q = %[2]q
%[3]q = %[4]q
}
}
`, rName, tagKey1, tagValue1, tagKey2, tagValue2)
`, tagKey1, tagValue1, tagKey2, tagValue2))
}
Loading

0 comments on commit 3004b33

Please sign in to comment.