Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] r/aws_route: Correctly handle update of route target #15723

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
506e02a
r/aws_route: Tidy up 'testAccAWSRouteConfigBasic()'.
ewbankkit Jun 25, 2020
ced4ed4
r/aws_route: Rename 'TestAccAWSRoute_ipv6Support' to 'TestAccAWSRoute…
ewbankkit Jun 25, 2020
5616e6e
Remove 'TestAccAWSRoute_noopdiff'. Test steps implicitly test this fu…
ewbankkit Jun 25, 2020
7bee10c
r/aws_route: Tidy up 'TestAccAWSRoute_doesNotCrashWithVPCEndpoint'.
ewbankkit Jun 25, 2020
5f5df4d
r/aws_route: Tidy up 'TestAccAWSRoute_ipv6ToInternetGateway'.
ewbankkit Jun 26, 2020
e20367d
r/aws_route: Tidy up 'TestAccAWSRoute_ipv6ToInstance'.
ewbankkit Jun 26, 2020
f814658
r/aws_route: Tidy up 'TestAccAWSRoute_ipv6ToNetworkInterface'.
ewbankkit Jun 26, 2020
ff0c8ff
r/aws_route: Tidy up 'TestAccAWSRoute_ipv6ToVpcPeeringConnection'.
ewbankkit Jun 26, 2020
a4f74f5
r/aws_route: Tidy up 'TestAccAWSRoute_TransitGatewayID_DestinationCid…
ewbankkit Jun 26, 2020
3e1e97b
r/aws_route: Add 'TestAccAWSRoute_IPv4_To_Instance'.
ewbankkit Jun 26, 2020
9f0582e
r/aws_route: Add 'TestAccAWSRoute_IPv4_To_NetworkInterface'.
ewbankkit Jun 26, 2020
7092c9b
r/aws_route: Add 'TestAccAWSRoute_IPv4_To_VpcPeeringConnection'.
ewbankkit Jun 26, 2020
cc60308
r/aws_route: Add 'TestAccAWSRoute_IPv4_To_NatGateway'.
ewbankkit Jun 26, 2020
ce1eafa
r/aws_route: Comment out failing target update test.
ewbankkit Jun 26, 2020
e10fe8e
r/aws_route: Add 'TestAccAWSRoute_IPv4_To_VpnGateway'.
ewbankkit Jun 27, 2020
e268014
r/aws_route: Add 'TestAccAWSRoute_IPv6_To_VpnGateway'.
ewbankkit Jun 27, 2020
1301e3a
r/aws_route: Test computed attributes.
ewbankkit Jun 27, 2020
31f03f2
r/aws_route: Changes for #13766, #13771.
ewbankkit Jun 27, 2020
afdac6a
r/aws_route: 'testAccCheckAWSRouteNumberOfRoutes' -> 'testAccCheckAWS…
ewbankkit Jun 29, 2020
520326e
r/aws_route: Add 'TestAccAWSRoute_routeTableDisappears'.
ewbankkit Jun 29, 2020
35926b6
r/aws_route: Rework 'TestAccAWSRoute_ConditionalCidrBlock'.
ewbankkit Jul 1, 2020
40284fe
r/aws_route: Add 'TestAccAWSRoute_IPv4_To_NetworkInterface_Attached' …
ewbankkit Jul 4, 2020
522991a
r/aws_route: Add 'TestAccAWSRoute_IPv4_To_NetworkInterface_TwoAttachm…
ewbankkit Jul 4, 2020
8ff2620
r/aws_route: Comment out failing 'TestAccAWSRoute_IPv4_To_NetworkInte…
ewbankkit Jul 4, 2020
929f26c
r/aws_route: Use 'available' as the name of the 'aws_availability_zon…
ewbankkit Jul 6, 2020
c9ab348
r/aws_route: Use Amazon NAT instance AMI for instance tests.
ewbankkit Jul 15, 2020
91701e8
Use 'testAccAvailableAZsNoOptInDefaultExcludeConfig'.
ewbankkit Aug 9, 2020
7899f7e
r/aws_route: Add 'TestAccAWSRoute_IPv6_To_TransitGateway'.
ewbankkit Sep 4, 2020
d4c008a
r/aws_route: Add 'TestAccAWSRoute_IPv6_To_LocalGateway'.
ewbankkit Sep 4, 2020
4641c61
r/aws_route: Add 'TestAccAWSRoute_IPv4_Update_Target'. Currently fails.
ewbankkit Jun 27, 2020
5cc7bbd
r/aws_route: Add 'TestAccAWSRoute_IPv6_Update_Target'. Currently fails.
ewbankkit Jun 28, 2020
811a052
r/aws_route: Better validation.
ewbankkit Jul 1, 2020
c21f5b1
r/aws_route: Correctly handle route target updates.
ewbankkit Jul 3, 2020
c960f54
r/aws_route: Uncommented 'TestAccAWSRoute_IPv4_To_NetworkInterface_Tw…
ewbankkit Jul 4, 2020
8fcb952
Acceptance test output:
ewbankkit Jul 4, 2020
6f5c10e
r/aws_route: Use 'available' as the name of the 'aws_availability_zon…
ewbankkit Jul 6, 2020
b007c1d
r/aws_route: Add 'TestAccAWSRoute_LocalRoute' to test ability to impo…
ewbankkit Jul 8, 2020
f152179
r/aws_route: Add error constants to 'aws/internal/service/ec2'. Tweak…
ewbankkit Jul 10, 2020
e168bcc
r/aw3s_route: Move route finders to 'aws/internal/service/ec2/finder'…
ewbankkit Jul 10, 2020
9ff470f
r/aws_route: Add 'createRoute' function.
ewbankkit Jul 10, 2020
aeac5f7
Use 'testAccAvailableAZsNoOptInDefaultExcludeConfig'.
ewbankkit Aug 10, 2020
f5a5857
Use 'RouteCreateID' in 'internal/service/ec2' package.
ewbankkit Aug 10, 2020
92d9bd9
Tweak EC2 error code constants.
ewbankkit Aug 23, 2020
c0bea54
Use 'tfnet.CIDRBlocksEqual' for IPv4 destination CIDR blocks.
ewbankkit Aug 23, 2020
c2b4ea2
Tidy up route destination and target attribute checking in an attempt…
ewbankkit Aug 25, 2020
a2340ea
r/aws_route: 'gateway_id', 'egress_only_gateway_id' and 'nat_gateway_…
ewbankkit Aug 25, 2020
20a7b48
r/aws_route: Add 'getRouteDestinationAndTargetAttributeKeysFromMap' w…
ewbankkit Aug 25, 2020
cf94b8c
r/aws_route: Minor tweak to error messages.
ewbankkit Aug 25, 2020
d46f23f
r/aws_route: Tweak route attribute IP version support.
ewbankkit Aug 26, 2020
c085819
r/aws_route: Use interface to abstract over '*schema.ResourceData' an…
ewbankkit Aug 26, 2020
8b3f977
r/aws_route: Add 'local_gateway_id' to attribute checking.
ewbankkit Sep 6, 2020
d766708
r/aws_route: Add plan-time validation that multiple destination and t…
ewbankkit Sep 6, 2020
a0bce7d
Acceptance test output:
ewbankkit Oct 19, 2020
51c1b21
Exclude 'resource_aws_route_test.go' from acceptance test Terraform l…
ewbankkit Oct 19, 2020
130f945
r/aws_route: Use attribute-level 'ConflictsWith' for IPv4 and IPv6-on…
ewbankkit Oct 20, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/acctest-terraform-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
| grep -v resource_aws_kinesis_stream_test.go \
| grep -v resource_aws_kms_grant_test.go \
| grep -v resource_aws_quicksight_user_test.go \
| grep -v resource_aws_route_test.go \
| grep -v resource_aws_s3_bucket_object_test.go \
| grep -v resource_aws_sns_platform_application_test.go \
| xargs -I {} terrafmt diff --check --quiet --fmtcompat {}
Expand Down Expand Up @@ -90,6 +91,7 @@ jobs:
| grep -v resource_aws_kms_grant_test.go \
| grep -v resource_aws_lambda_permission_test.go \
| grep -v resource_aws_quicksight_user_test.go \
| grep -v resource_aws_route_test.go \
| grep -v resource_aws_s3_bucket_object_test.go \
| grep -v resource_aws_sns_platform_application_test.go \
| ./scripts/validate-terraform.sh
15 changes: 15 additions & 0 deletions aws/data_source_aws_route.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"fmt"
"log"

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

func dataSourceAwsRoute() *schema.Resource {
Expand Down Expand Up @@ -202,3 +204,16 @@ func getRoutes(table *ec2.RouteTable, d *schema.ResourceData) []*ec2.Route {
}
return routes
}

// Helper: Create an ID for a route
func resourceAwsRouteID(d *schema.ResourceData, r *ec2.Route) string {
routeTableID := d.Get("route_table_id").(string)

if destination := aws.StringValue(r.DestinationCidrBlock); destination != "" {
return tfec2.RouteCreateID(routeTableID, destination)
} else if destination := aws.StringValue(r.DestinationIpv6CidrBlock); destination != "" {
return tfec2.RouteCreateID(routeTableID, destination)
}

return ""
}
23 changes: 23 additions & 0 deletions aws/internal/net/cidr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package net

import (
"net"
)

// CIDRBlocksEqual returns whether or not two CIDR blocks are equal:
// - Both CIDR blocks parse to an IP address and network
// - The string representation of the IP addresses are equal
// - The string representation of the networks are equal
// This function is especially useful for IPv6 CIDR blocks which have multiple valid representations.
func CIDRBlocksEqual(cidr1, cidr2 string) bool {
ip1, ipnet1, err := net.ParseCIDR(cidr1)
if err != nil {
return false
}
ip2, ipnet2, err := net.ParseCIDR(cidr2)
if err != nil {
return false
}

return ip2.String() == ip1.String() && ipnet2.String() == ipnet1.String()
}
26 changes: 26 additions & 0 deletions aws/internal/net/cidr_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package net

import (
"testing"
)

func Test_CIDRBlocksEqual(t *testing.T) {
for _, ts := range []struct {
cidr1 string
cidr2 string
equal bool
}{
{"10.2.2.0/24", "10.2.2.0/24", true},
{"10.2.2.0/1234", "10.2.2.0/24", false},
{"10.2.2.0/24", "10.2.2.0/1234", false},
{"2001::/15", "2001::/15", true},
{"::/0", "2001::/15", false},
{"::/0", "::0/0", true},
{"", "", false},
} {
equal := CIDRBlocksEqual(ts.cidr1, ts.cidr2)
if ts.equal != equal {
t.Fatalf("CIDRBlocksEqual(%q, %q) should be: %t", ts.cidr1, ts.cidr2, ts.equal)
}
}
}
20 changes: 20 additions & 0 deletions aws/internal/service/ec2/errors.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
package ec2

// Common.
const (
ErrCodeInvalidParameterException = "InvalidParameterException"
ErrCodeInvalidParameterValue = "InvalidParameterValue"
)

// Client VPN.
const (
ErrCodeClientVpnEndpointIdNotFound = "InvalidClientVpnEndpointId.NotFound"
ErrCodeClientVpnAuthorizationRuleNotFound = "InvalidClientVpnEndpointAuthorizationRuleNotFound"
ErrCodeClientVpnAssociationIdNotFound = "InvalidClientVpnAssociationId.NotFound"
ErrCodeClientVpnRouteNotFound = "InvalidClientVpnRouteNotFound"
)

// Security Group.
const (
InvalidSecurityGroupIDNotFound = "InvalidSecurityGroupID.NotFound"
InvalidGroupNotFound = "InvalidGroup.NotFound"
)

// Route and Route Table.
const (
ErrCodeInvalidRouteNotFound = "InvalidRoute.NotFound"
ErrCodeInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound"
)

// Transit Gateway.
const (
ErrCodeInvalidTransitGatewayIDNotFound = "InvalidTransitGatewayID.NotFound"
)

// VPN Gateway.
const (
InvalidVpnGatewayAttachmentNotFound = "InvalidVpnGatewayAttachment.NotFound"
InvalidVpnGatewayIDNotFound = "InvalidVpnGatewayID.NotFound"
Expand Down
56 changes: 56 additions & 0 deletions aws/internal/service/ec2/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package finder
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net"
tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2"
)

Expand Down Expand Up @@ -55,6 +56,61 @@ func ClientVpnRouteByID(conn *ec2.EC2, routeID string) (*ec2.DescribeClientVpnRo
return ClientVpnRoute(conn, endpointID, targetSubnetID, destinationCidr)
}

// RouteTableByID returns the route table corresponding to the specified identifier.
// Returns nil if no route table is found.
func RouteTableByID(conn *ec2.EC2, routeTableID string) (*ec2.RouteTable, error) {
input := &ec2.DescribeRouteTablesInput{
RouteTableIds: aws.StringSlice([]string{routeTableID}),
}

output, err := conn.DescribeRouteTables(input)
if err != nil {
return nil, err
}

if output == nil || len(output.RouteTables) == 0 || output.RouteTables[0] == nil {
return nil, nil
}

return output.RouteTables[0], nil
}

type RouteFinder func(*ec2.EC2, string, string) (*ec2.Route, error)

// RouteByIpv4Destination returns the route corresponding to the specified IPv4 destination.
// Returns nil if no route is found.
func RouteByIpv4Destination(conn *ec2.EC2, routeTableID, destinationCidr string) (*ec2.Route, error) {
routeTable, err := RouteTableByID(conn, routeTableID)
if err != nil {
return nil, err
}

for _, route := range routeTable.Routes {
if tfnet.CIDRBlocksEqual(aws.StringValue(route.DestinationCidrBlock), destinationCidr) {
return route, nil
}
}

return nil, nil
}

// RouteByIpv6Destination returns the route corresponding to the specified IPv6 destination.
// Returns nil if no route is found.
func RouteByIpv6Destination(conn *ec2.EC2, routeTableID, destinationIpv6Cidr string) (*ec2.Route, error) {
routeTable, err := RouteTableByID(conn, routeTableID)
if err != nil {
return nil, err
}

for _, route := range routeTable.Routes {
if tfnet.CIDRBlocksEqual(aws.StringValue(route.DestinationIpv6CidrBlock), destinationIpv6Cidr) {
return route, nil
}
}

return nil, nil
}

// SecurityGroupByID looks up a security group by ID. When not found, returns nil and potentially an API error.
func SecurityGroupByID(conn *ec2.EC2, id string) (*ec2.SecurityGroup, error) {
req := &ec2.DescribeSecurityGroupsInput{
Expand Down
5 changes: 5 additions & 0 deletions aws/internal/service/ec2/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ func ClientVpnRouteParseID(id string) (string, string, string, error) {
"target-subnet-id"+clientVpnRouteIDSeparator+"destination-cidr-block", id)
}

// RouteCreateID returns a route resource ID.
func RouteCreateID(routeTableID, destination string) string {
return fmt.Sprintf("r-%s%d", routeTableID, hashcode.String(destination))
}

func VpnGatewayVpcAttachmentCreateID(vpnGatewayID, vpcID string) string {
return fmt.Sprintf("vpn-attachment-%x", hashcode.String(fmt.Sprintf("%s-%s", vpcID, vpnGatewayID)))
}
Loading