Skip to content

Commit

Permalink
resource/aws_ec2_transit_gateway_route_table_propagation: Wait for en…
Browse files Browse the repository at this point in the history
…able and disable operations to complete (#18470)

* resource/aws_ec2_transit_gateway_route_table_propagation: Wait for enable and disable operations to complete

Reference: #14043
Reference: #16796

The waiter should help prevent the read-after-create eventual consistency issue, but also added the `d.IsNewResource()` checks to ensure the confusing Terraform CLI error is prevented.

Output from acceptance testing in AWS Commercial:

```
--- PASS: TestAccAWSEc2TransitGatewayRouteTablePropagation_basic (385.06s)
```

Output from acceptance testing in AWS GovCloud (US):

```
--- PASS: TestAccAWSEc2TransitGatewayRouteTablePropagation_basic (348.55s)
```

* Update CHANGELOG for #18470
  • Loading branch information
bflad authored Mar 31, 2021
1 parent b609054 commit a4973d9
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .changelog/18470.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_ec2_transit_gateway_route_table_propagation: Wait for enable and disable operations to complete
```
35 changes: 35 additions & 0 deletions aws/internal/service/ec2/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,41 @@ func TransitGatewayPrefixListReferenceByID(conn *ec2.EC2, resourceID string) (*e
return TransitGatewayPrefixListReference(conn, transitGatewayRouteTableID, prefixListID)
}

func TransitGatewayRouteTablePropagation(conn *ec2.EC2, transitGatewayRouteTableID string, transitGatewayAttachmentID string) (*ec2.TransitGatewayRouteTablePropagation, error) {
input := &ec2.GetTransitGatewayRouteTablePropagationsInput{
Filters: []*ec2.Filter{
{
Name: aws.String("transit-gateway-attachment-id"),
Values: aws.StringSlice([]string{transitGatewayAttachmentID}),
},
},
TransitGatewayRouteTableId: aws.String(transitGatewayRouteTableID),
}

var result *ec2.TransitGatewayRouteTablePropagation

err := conn.GetTransitGatewayRouteTablePropagationsPages(input, func(page *ec2.GetTransitGatewayRouteTablePropagationsOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, transitGatewayRouteTablePropagation := range page.TransitGatewayRouteTablePropagations {
if transitGatewayRouteTablePropagation == nil {
continue
}

if aws.StringValue(transitGatewayRouteTablePropagation.TransitGatewayAttachmentId) == transitGatewayAttachmentID {
result = transitGatewayRouteTablePropagation
return false
}
}

return !lastPage
})

return result, err
}

// VpcAttribute looks up a VPC attribute.
func VpcAttribute(conn *ec2.EC2, vpcID string, attribute string) (*bool, error) {
input := &ec2.DescribeVpcAttributeInput{
Expand Down
16 changes: 16 additions & 0 deletions aws/internal/service/ec2/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,22 @@ func TransitGatewayPrefixListReferenceState(conn *ec2.EC2, transitGatewayRouteTa
}
}

func TransitGatewayRouteTablePropagationState(conn *ec2.EC2, transitGatewayRouteTableID string, transitGatewayAttachmentID string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
transitGatewayRouteTablePropagation, err := finder.TransitGatewayRouteTablePropagation(conn, transitGatewayRouteTableID, transitGatewayAttachmentID)

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

if transitGatewayRouteTablePropagation == nil {
return nil, "", nil
}

return transitGatewayRouteTablePropagation, aws.StringValue(transitGatewayRouteTablePropagation.State), nil
}
}

// VpcAttribute fetches the Vpc and its attribute value
func VpcAttribute(conn *ec2.EC2, id string, attribute string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
Expand Down
42 changes: 42 additions & 0 deletions aws/internal/service/ec2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,48 @@ func TransitGatewayPrefixListReferenceStateUpdated(conn *ec2.EC2, transitGateway
return nil, err
}

const (
TransitGatewayRouteTablePropagationTimeout = 5 * time.Minute
)

func TransitGatewayRouteTablePropagationStateEnabled(conn *ec2.EC2, transitGatewayRouteTableID string, transitGatewayAttachmentID string) (*ec2.TransitGatewayRouteTablePropagation, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{ec2.TransitGatewayPropagationStateEnabling},
Target: []string{ec2.TransitGatewayPropagationStateEnabled},
Timeout: TransitGatewayRouteTablePropagationTimeout,
Refresh: TransitGatewayRouteTablePropagationState(conn, transitGatewayRouteTableID, transitGatewayAttachmentID),
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ec2.TransitGatewayRouteTablePropagation); ok {
return output, err
}

return nil, err
}

func TransitGatewayRouteTablePropagationStateDisabled(conn *ec2.EC2, transitGatewayRouteTableID string, transitGatewayAttachmentID string) (*ec2.TransitGatewayRouteTablePropagation, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{ec2.TransitGatewayPropagationStateDisabling},
Target: []string{},
Timeout: TransitGatewayRouteTablePropagationTimeout,
Refresh: TransitGatewayRouteTablePropagationState(conn, transitGatewayRouteTableID, transitGatewayAttachmentID),
}

outputRaw, err := stateConf.WaitForState()

if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidRouteTableIDNotFound) {
return nil, nil
}

if output, ok := outputRaw.(*ec2.TransitGatewayRouteTablePropagation); ok {
return output, err
}

return nil, err
}

const (
VpcPropagationTimeout = 2 * time.Minute
VpcAttributePropagationTimeout = 5 * time.Minute
Expand Down
17 changes: 16 additions & 1 deletion aws/resource_aws_ec2_transit_gateway_route_table_propagation.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter"
)

func resourceAwsEc2TransitGatewayRouteTablePropagation() *schema.Resource {
Expand Down Expand Up @@ -62,6 +65,10 @@ func resourceAwsEc2TransitGatewayRouteTablePropagationCreate(d *schema.ResourceD

d.SetId(fmt.Sprintf("%s_%s", transitGatewayRouteTableID, transitGatewayAttachmentID))

if _, err := waiter.TransitGatewayRouteTablePropagationStateEnabled(conn, transitGatewayRouteTableID, transitGatewayAttachmentID); err != nil {
return fmt.Errorf("error waiting for EC2 Transit Gateway Route Table (%s) propagation (%s) to enable: %w", transitGatewayRouteTableID, transitGatewayAttachmentID, err)
}

return resourceAwsEc2TransitGatewayRouteTablePropagationRead(d, meta)
}

Expand All @@ -75,7 +82,7 @@ func resourceAwsEc2TransitGatewayRouteTablePropagationRead(d *schema.ResourceDat

transitGatewayPropagation, err := ec2DescribeTransitGatewayRouteTablePropagation(conn, transitGatewayRouteTableID, transitGatewayAttachmentID)

if isAWSErr(err, "InvalidRouteTableID.NotFound", "") {
if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidRouteTableIDNotFound) {
log.Printf("[WARN] EC2 Transit Gateway Route Table (%s) not found, removing from state", transitGatewayRouteTableID)
d.SetId("")
return nil
Expand All @@ -86,6 +93,10 @@ func resourceAwsEc2TransitGatewayRouteTablePropagationRead(d *schema.ResourceDat
}

if transitGatewayPropagation == nil {
if d.IsNewResource() {
return fmt.Errorf("error reading EC2 Transit Gateway Route Table (%s) Propagation (%s): not found after creation", transitGatewayRouteTableID, transitGatewayAttachmentID)
}

log.Printf("[WARN] EC2 Transit Gateway Route Table (%s) Propagation (%s) not found, removing from state", transitGatewayRouteTableID, transitGatewayAttachmentID)
d.SetId("")
return nil
Expand Down Expand Up @@ -123,5 +134,9 @@ func resourceAwsEc2TransitGatewayRouteTablePropagationDelete(d *schema.ResourceD
return fmt.Errorf("error disabling EC2 Transit Gateway Route Table (%s) Propagation (%s): %s", transitGatewayRouteTableID, transitGatewayAttachmentID, err)
}

if _, err := waiter.TransitGatewayRouteTablePropagationStateDisabled(conn, transitGatewayRouteTableID, transitGatewayAttachmentID); err != nil {
return fmt.Errorf("error waiting for EC2 Transit Gateway Route Table (%s) propagation (%s) to disable: %w", transitGatewayRouteTableID, transitGatewayAttachmentID, err)
}

return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
Expand Down Expand Up @@ -69,6 +70,10 @@ func testAccCheckAWSEc2TransitGatewayRouteTablePropagationExists(resourceName st
return fmt.Errorf("EC2 Transit Gateway Route Table Propagation not found")
}

if aws.StringValue(propagation.State) != ec2.TransitGatewayPropagationStateEnabled {
return fmt.Errorf("EC2 Transit Gateway Route Table Propagation not in enabled state: %s", aws.StringValue(propagation.State))
}

*transitGatewayRouteTablePropagation = *propagation

return nil
Expand Down

0 comments on commit a4973d9

Please sign in to comment.