Skip to content

Commit

Permalink
Merge pull request #17319 from ewbankkit/f-r/aws_route_table-managed_…
Browse files Browse the repository at this point in the history
…prefix_list-destination

r/aws_(default)_route_table: 'destination_prefix_list_id' attribute can be specified for managed prefix list destinations
  • Loading branch information
YakDriver authored Mar 29, 2021
2 parents e19a646 + f36fc0a commit 2bf0416
Show file tree
Hide file tree
Showing 12 changed files with 626 additions and 206 deletions.
19 changes: 19 additions & 0 deletions .changelog/17319.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
```release-notes:enhancement
resource/aws_default_route_table: Add `destination_prefix_list_id` attribute
```

```release-notes:enhancement
resource/aws_route_table: Add `destination_prefix_list_id` attribute
```

```release-note:bug
resource/aws_vpn_gateway_route_propagation: Improve eventual consistency handling and handling of out-of-band resource removal
```

```release-note:bug
resource/aws_route_table: Improve eventual consistency handling and handling of out-of-band resource removal
```

```release-note:bug
resource/aws_route_table_association: Improve eventual consistency handling and handling of out-of-band resource removal
```
27 changes: 27 additions & 0 deletions aws/internal/service/ec2/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder"
tfiam "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

const (
Expand Down Expand Up @@ -245,6 +246,32 @@ func InstanceIamInstanceProfile(conn *ec2.EC2, id string) resource.StateRefreshF
}
}

const (
ErrCodeInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound"

RouteTableStatusReady = "ready"
)

func RouteTableStatus(conn *ec2.EC2, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := finder.RouteTableByID(conn, id)

if tfresource.NotFound(err) {
return nil, "", nil
}

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

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

return output, RouteTableStatusReady, nil
}
}

const (
SecurityGroupStatusCreated = "Created"

Expand Down
43 changes: 43 additions & 0 deletions aws/internal/service/ec2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,49 @@ const (
NetworkAclEntryPropagationTimeout = 5 * time.Minute
)

const (
RouteTableReadyTimeout = 10 * time.Minute
RouteTableDeletedTimeout = 5 * time.Minute
RouteTableUpdateTimeout = 5 * time.Minute

RouteTableNotFoundChecks = 40
)

func RouteTableReady(conn *ec2.EC2, id string) (*ec2.RouteTable, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{},
Target: []string{RouteTableStatusReady},
Refresh: RouteTableStatus(conn, id),
Timeout: RouteTableReadyTimeout,
NotFoundChecks: RouteTableNotFoundChecks,
}

outputRaw, err := stateConf.WaitForState()

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

return nil, err
}

func RouteTableDeleted(conn *ec2.EC2, id string) (*ec2.RouteTable, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{RouteTableStatusReady},
Target: []string{},
Refresh: RouteTableStatus(conn, id),
Timeout: RouteTableDeletedTimeout,
}

outputRaw, err := stateConf.WaitForState()

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

return nil, err
}

func SecurityGroupCreated(conn *ec2.EC2, id string, timeout time.Duration) (*ec2.SecurityGroup, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{SecurityGroupStatusNotFound},
Expand Down
101 changes: 52 additions & 49 deletions aws/resource_aws_default_route_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package aws
import (
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder"
)

func resourceAwsDefaultRouteTable() *schema.Resource {
Expand Down Expand Up @@ -50,6 +52,9 @@ func resourceAwsDefaultRouteTable() *schema.Resource {
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
///
// Destinations.
///
"cidr_block": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -68,6 +73,14 @@ func resourceAwsDefaultRouteTable() *schema.Resource {
),
},

"destination_prefix_list_id": {
Type: schema.TypeString,
Optional: true,
},

//
// Targets.
//
"egress_only_gateway_id": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -88,22 +101,22 @@ func resourceAwsDefaultRouteTable() *schema.Resource {
Optional: true,
},

"transit_gateway_id": {
"network_interface_id": {
Type: schema.TypeString,
Optional: true,
},

"vpc_endpoint_id": {
"transit_gateway_id": {
Type: schema.TypeString,
Optional: true,
},

"vpc_peering_connection_id": {
"vpc_endpoint_id": {
Type: schema.TypeString,
Optional: true,
},

"network_interface_id": {
"vpc_peering_connection_id": {
Type: schema.TypeString,
Optional: true,
},
Expand All @@ -128,31 +141,28 @@ func resourceAwsDefaultRouteTable() *schema.Resource {
}

func resourceAwsDefaultRouteTableCreate(d *schema.ResourceData, meta interface{}) error {
d.SetId(d.Get("default_route_table_id").(string))

conn := meta.(*AWSClient).ec2conn
rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(conn, d.Id())()
routeTableID := d.Get("default_route_table_id").(string)

routeTable, err := finder.RouteTableByID(conn, routeTableID)

if err != nil {
return fmt.Errorf("error reading EC2 Default Route Table (%s): %s", d.Id(), err)
}
if rtRaw == nil {
return fmt.Errorf("error reading EC2 Default Route Table (%s): not found", d.Id())
return fmt.Errorf("error reading EC2 Default Route Table (%s): %w", routeTableID, err)
}

rt := rtRaw.(*ec2.RouteTable)

d.Set("vpc_id", rt.VpcId)
d.SetId(routeTableID)
d.Set("vpc_id", routeTable.VpcId)

// revoke all default and pre-existing routes on the default route table.
// In the UPDATE method, we'll apply only the rules in the configuration.
log.Printf("[DEBUG] Revoking default routes for Default Route Table for %s", d.Id())
if err := revokeAllRouteTableRules(d.Id(), meta); err != nil {
if err := revokeAllRouteTableRules(conn, routeTable); err != nil {
return err
}

if v := d.Get("tags").(map[string]interface{}); len(v) > 0 {
if err := keyvaluetags.Ec2CreateTags(conn, d.Id(), v); err != nil {
return fmt.Errorf("error adding tags: %s", err)
return fmt.Errorf("error adding tags: %w", err)
}
}

Expand Down Expand Up @@ -203,75 +213,68 @@ func resourceAwsDefaultRouteTableDelete(d *schema.ResourceData, meta interface{}

// revokeAllRouteTableRules revoke all routes on the Default Route Table
// This should only be ran once at creation time of this resource
func revokeAllRouteTableRules(defaultRouteTableId string, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
log.Printf("\n***\nrevokeAllRouteTableRules\n***\n")

resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{
RouteTableIds: []*string{aws.String(defaultRouteTableId)},
})
if err != nil {
return err
}

if len(resp.RouteTables) < 1 || resp.RouteTables[0] == nil {
return fmt.Errorf("Default Route table not found")
}

rt := resp.RouteTables[0]

func revokeAllRouteTableRules(conn *ec2.EC2, routeTable *ec2.RouteTable) error {
// Remove all Gateway association
for _, r := range rt.PropagatingVgws {
log.Printf(
"[INFO] Deleting VGW propagation from %s: %s",
defaultRouteTableId, *r.GatewayId)
for _, r := range routeTable.PropagatingVgws {
_, err := conn.DisableVgwRoutePropagation(&ec2.DisableVgwRoutePropagationInput{
RouteTableId: aws.String(defaultRouteTableId),
RouteTableId: routeTable.RouteTableId,
GatewayId: r.GatewayId,
})

if err != nil {
return err
}
}

// Delete all routes
for _, r := range rt.Routes {
for _, r := range routeTable.Routes {
// you cannot delete the local route
if r.GatewayId != nil && *r.GatewayId == "local" {
if aws.StringValue(r.GatewayId) == "local" {
continue
}
if r.DestinationPrefixListId != nil {

if aws.StringValue(r.Origin) == ec2.RouteOriginEnableVgwRoutePropagation {
continue
}

if r.DestinationPrefixListId != nil && strings.HasPrefix(aws.StringValue(r.GatewayId), "vpce-") {
// Skipping because VPC endpoint routes are handled separately
// See aws_vpc_endpoint
continue
}

if r.DestinationCidrBlock != nil {
log.Printf(
"[INFO] Deleting route from %s: %s",
defaultRouteTableId, *r.DestinationCidrBlock)
_, err := conn.DeleteRoute(&ec2.DeleteRouteInput{
RouteTableId: aws.String(defaultRouteTableId),
RouteTableId: routeTable.RouteTableId,
DestinationCidrBlock: r.DestinationCidrBlock,
})

if err != nil {
return err
}
}

if r.DestinationIpv6CidrBlock != nil {
log.Printf(
"[INFO] Deleting route from %s: %s",
defaultRouteTableId, *r.DestinationIpv6CidrBlock)
_, err := conn.DeleteRoute(&ec2.DeleteRouteInput{
RouteTableId: aws.String(defaultRouteTableId),
RouteTableId: routeTable.RouteTableId,
DestinationIpv6CidrBlock: r.DestinationIpv6CidrBlock,
})

if err != nil {
return err
}
}

if r.DestinationPrefixListId != nil {
_, err := conn.DeleteRoute(&ec2.DeleteRouteInput{
RouteTableId: routeTable.RouteTableId,
DestinationPrefixListId: r.DestinationPrefixListId,
})

if err != nil {
return err
}
}
}

return nil
Expand Down
Loading

0 comments on commit 2bf0416

Please sign in to comment.