Skip to content

Commit

Permalink
Merge pull request #39519 from hashicorp/b-tgw.security_group_referen…
Browse files Browse the repository at this point in the history
…cing_support

r/aws_ec2_transit_gateway_vpc_attachment: Prevent drift for existing resources
  • Loading branch information
ewbankkit authored Sep 27, 2024
2 parents cc1d368 + acefc23 commit a0a3b9b
Show file tree
Hide file tree
Showing 9 changed files with 358 additions and 12 deletions.
3 changes: 3 additions & 0 deletions .changelog/39519.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_ec2_transit_gateway_vpc_attachment: Remove default value for `security_group_referencing_support` argument and mark as Computed. This suppresses the diffs shown for resources created with v5.68.0 (or earlier)
```
51 changes: 51 additions & 0 deletions internal/acctest/plancheck/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package plancheck

import (
"fmt"

tfjson "github.com/hashicorp/terraform-json"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
)

type Base struct {
resourceAddress string
}

func NewBase(resourceAddress string) Base {
return Base{
resourceAddress: resourceAddress,
}
}

func (b Base) ResourceFromState(req plancheck.CheckPlanRequest, resp *plancheck.CheckPlanResponse) (*tfjson.ResourceChange, bool) {
var resource *tfjson.ResourceChange

if req.Plan == nil {
resp.Error = fmt.Errorf("plan is nil")

return nil, false
}

for _, r := range req.Plan.ResourceChanges {
if b.resourceAddress == r.Address {
resource = r

break
}
}

if resource == nil {
resp.Error = fmt.Errorf("%s - Resource not found in plan", b.resourceAddress)

return nil, false
}

return resource, true
}

func (b Base) ResourceAddress() string {
return b.resourceAddress
}
61 changes: 61 additions & 0 deletions internal/acctest/plancheck/expect_known_value_change.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package plancheck

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
)

type expectKnownValueChangeCheck struct {
base Base
attributePath tfjsonpath.Path
oldValue, newValue knownvalue.Check
}

func (e expectKnownValueChangeCheck) CheckPlan(ctx context.Context, request plancheck.CheckPlanRequest, response *plancheck.CheckPlanResponse) {
resource, ok := e.base.ResourceFromState(request, response)
if !ok {
return
}

old, err := tfjsonpath.Traverse(resource.Change.Before, e.attributePath)
if err != nil {
response.Error = err

return
}

if err := e.oldValue.CheckValue(old); err != nil {
response.Error = fmt.Errorf("checking old value for attribute at path: %s.%s, err: %s", resource.Address, e.attributePath.String(), err)

return
}

new, err := tfjsonpath.Traverse(resource.Change.After, e.attributePath)
if err != nil {
response.Error = err

return
}

if err := e.newValue.CheckValue(new); err != nil {
response.Error = fmt.Errorf("checking new value for attribute at path: %s.%s, err: %s", resource.Address, e.attributePath.String(), err)

return
}
}

func ExpectKnownValueChange(resourceAddress string, attributePath tfjsonpath.Path, oldValue, newValue knownvalue.Check) plancheck.PlanCheck {
return expectKnownValueChangeCheck{
base: NewBase(resourceAddress),
attributePath: attributePath,
oldValue: oldValue,
newValue: newValue,
}
}
37 changes: 37 additions & 0 deletions internal/acctest/statecheck/expect_no_value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package statecheck

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
)

type expectNoValueCheck struct {
base Base
attributePath tfjsonpath.Path
}

func (e expectNoValueCheck) CheckState(ctx context.Context, request statecheck.CheckStateRequest, response *statecheck.CheckStateResponse) {
resource, ok := e.base.ResourceFromState(request, response)
if !ok {
return
}

if _, err := tfjsonpath.Traverse(resource.AttributeValues, e.attributePath); err == nil {
response.Error = fmt.Errorf("value for attribute at path: %s.%s exists", resource.Address, e.attributePath.String())

return
}
}

func ExpectNoValue(resourceAddress string, attributePath tfjsonpath.Path) statecheck.StateCheck {
return expectNoValueCheck{
base: NewBase(resourceAddress),
attributePath: attributePath,
}
}
68 changes: 66 additions & 2 deletions internal/service/ec2/transitgateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ import (
"github.com/hashicorp/aws-sdk-go-base/v2/tfawserr"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
tfsync "github.com/hashicorp/terraform-provider-aws/internal/experimental/sync"
tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2"
Expand Down Expand Up @@ -59,6 +64,7 @@ func TestAccTransitGateway_serial(t *testing.T) {
"Description": testAccTransitGateway_Description,
"DnsSupport": testAccTransitGateway_DNSSupport,
"SecurityGroupReferencingSupport": testAccTransitGateway_SecurityGroupReferencingSupport,
"SecurityGroupReferencingSupportExistingResource": testAccTransitGateway_SecurityGroupReferencingSupportExistingResource,
"VpnEcmpSupport": testAccTransitGateway_VPNECMPSupport,
},
"MulticastDomain": {
Expand Down Expand Up @@ -142,8 +148,10 @@ func TestAccTransitGateway_serial(t *testing.T) {
"DnsSupport": testAccTransitGatewayVPCAttachment_DNSSupport,
"Ipv6Support": testAccTransitGatewayVPCAttachment_IPv6Support,
"SecurityGroupReferencingSupport": testAccTransitGatewayVPCAttachment_SecurityGroupReferencingSupport,
"SharedTransitGateway": testAccTransitGatewayVPCAttachment_SharedTransitGateway,
"SubnetIds": testAccTransitGatewayVPCAttachment_SubnetIDs,
"SecurityGroupReferencingSupportV5690Diff": testAccTransitGatewayVPCAttachment_SecurityGroupReferencingSupportV5690Diff,
"SecurityGroupReferencingSupportExistingResource": testAccTransitGatewayVPCAttachment_SecurityGroupReferencingSupportExistingResource,
"SharedTransitGateway": testAccTransitGatewayVPCAttachment_SharedTransitGateway,
"SubnetIds": testAccTransitGatewayVPCAttachment_SubnetIDs,
"TransitGatewayDefaultRouteTableAssociation": testAccTransitGatewayVPCAttachment_TransitGatewayDefaultRouteTableAssociation,
"TransitGatewayDefaultRouteTableAssociationAndPropagationDisabled": testAccTransitGatewayVPCAttachment_TransitGatewayDefaultRouteTableAssociationAndPropagationDisabled,
"TransitGatewayDefaultRouteTablePropagation": testAccTransitGatewayVPCAttachment_TransitGatewayDefaultRouteTablePropagation,
Expand Down Expand Up @@ -575,6 +583,62 @@ func testAccTransitGateway_SecurityGroupReferencingSupport(t *testing.T, semapho
})
}

func testAccTransitGateway_SecurityGroupReferencingSupportExistingResource(t *testing.T, semaphore tfsync.Semaphore) {
ctx := acctest.Context(t)
var transitGateway1 awstypes.TransitGateway
resourceName := "aws_ec2_transit_gateway.test"

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheckTransitGatewaySynchronize(t, semaphore)
acctest.PreCheck(ctx, t)
testAccPreCheckTransitGateway(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID),
CheckDestroy: testAccCheckTransitGatewayDestroy(ctx),
Steps: []resource.TestStep{
{
ExternalProviders: map[string]resource.ExternalProvider{
"aws": {
Source: "hashicorp/aws",
VersionConstraint: "5.68.0",
},
},
Config: testAccTransitGatewayConfig_basic(),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate),
},
},
ConfigStateChecks: []statecheck.StateCheck{
tfstatecheck.ExpectNoValue(resourceName, tfjsonpath.New("security_group_referencing_support")),
},
Check: resource.ComposeTestCheckFunc(
testAccCheckTransitGatewayExists(ctx, resourceName, &transitGateway1),
),
},
{
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Config: testAccTransitGatewayConfig_basic(),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop),
},
PostApplyPostRefresh: []plancheck.PlanCheck{
plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop),
},
},
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("security_group_referencing_support"), knownvalue.StringExact(string(awstypes.SecurityGroupReferencingSupportValueDisable))),
},
Check: resource.ComposeTestCheckFunc(
testAccCheckTransitGatewayExists(ctx, resourceName, &transitGateway1),
),
},
},
})
}

func testAccTransitGateway_VPNECMPSupport(t *testing.T, semaphore tfsync.Semaphore) {
ctx := acctest.Context(t)
var transitGateway1, transitGateway2 awstypes.TransitGateway
Expand Down
14 changes: 8 additions & 6 deletions internal/service/ec2/transitgateway_vpc_attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func resourceTransitGatewayVPCAttachment() *schema.Resource {
"security_group_referencing_support": {
Type: schema.TypeString,
Optional: true,
Default: awstypes.SecurityGroupReferencingSupportValueDisable,
Computed: true,
ValidateDiagFunc: enum.Validate[awstypes.SecurityGroupReferencingSupportValue](),
},
names.AttrSubnetIDs: {
Expand Down Expand Up @@ -110,18 +110,20 @@ func resourceTransitGatewayVPCAttachmentCreate(ctx context.Context, d *schema.Re
transitGatewayID := d.Get(names.AttrTransitGatewayID).(string)
input := &ec2.CreateTransitGatewayVpcAttachmentInput{
Options: &awstypes.CreateTransitGatewayVpcAttachmentRequestOptions{
ApplianceModeSupport: awstypes.ApplianceModeSupportValue(d.Get("appliance_mode_support").(string)),
DnsSupport: awstypes.DnsSupportValue(d.Get("dns_support").(string)),
Ipv6Support: awstypes.Ipv6SupportValue(d.Get("ipv6_support").(string)),
SecurityGroupReferencingSupport: awstypes.SecurityGroupReferencingSupportValue(d.Get("security_group_referencing_support").(string)),
ApplianceModeSupport: awstypes.ApplianceModeSupportValue(d.Get("appliance_mode_support").(string)),
DnsSupport: awstypes.DnsSupportValue(d.Get("dns_support").(string)),
Ipv6Support: awstypes.Ipv6SupportValue(d.Get("ipv6_support").(string)),
},
SubnetIds: flex.ExpandStringValueSet(d.Get(names.AttrSubnetIDs).(*schema.Set)),
TransitGatewayId: aws.String(transitGatewayID),
TagSpecifications: getTagSpecificationsIn(ctx, awstypes.ResourceTypeTransitGatewayAttachment),
VpcId: aws.String(d.Get(names.AttrVPCID).(string)),
}

log.Printf("[DEBUG] Creating EC2 Transit Gateway VPC Attachment: %+v", input)
if v, ok := d.GetOk("security_group_referencing_support"); ok {
input.Options.SecurityGroupReferencingSupport = awstypes.SecurityGroupReferencingSupportValue(v.(string))
}

output, err := conn.CreateTransitGatewayVpcAttachment(ctx, input)

if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ func resourceTransitGatewayVPCAttachmentAccepter() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"security_group_referencing_support": {
"ipv6_support": {
Type: schema.TypeString,
Computed: true,
},
"ipv6_support": {
"security_group_referencing_support": {
Type: schema.TypeString,
Computed: true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ func testAccTransitGatewayVPCAttachmentAccepter_basic(t *testing.T, semaphore tf
resource.TestCheckResourceAttr(resourceName, "appliance_mode_support", string(awstypes.ApplianceModeSupportValueDisable)),
resource.TestCheckResourceAttr(resourceName, "dns_support", string(awstypes.DnsSupportValueEnable)),
resource.TestCheckResourceAttr(resourceName, "ipv6_support", string(awstypes.Ipv6SupportValueDisable)),
resource.TestCheckResourceAttr(resourceName, "security_group_referencing_support", string(awstypes.SecurityGroupReferencingSupportValueEnable)),
resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "security_group_referencing_support", string(awstypes.SecurityGroupReferencingSupportValueDisable)),
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct0),
resource.TestCheckResourceAttrPair(resourceName, names.AttrTransitGatewayID, transitGatewayResourceName, names.AttrID),
resource.TestCheckResourceAttrPair(resourceName, names.AttrTransitGatewayAttachmentID, vpcAttachmentName, names.AttrID),
Expand Down
Loading

0 comments on commit a0a3b9b

Please sign in to comment.