Skip to content

Commit

Permalink
Merge pull request #5687 from YakDriver/support-route-import
Browse files Browse the repository at this point in the history
resource/aws_route: Support route import
  • Loading branch information
bflad authored Aug 30, 2018
2 parents 79a3745 + 3404a0b commit 4ff0de7
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 11 deletions.
2 changes: 1 addition & 1 deletion aws/data_source_aws_route.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func dataSourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error {
}
route := results[0]

d.SetId(routeIDHash(d, route)) // using function from "resource_aws_route.go"
d.SetId(resourceAwsRouteID(d, route)) // using function from "resource_aws_route.go"
d.Set("destination_cidr_block", route.DestinationCidrBlock)
d.Set("destination_ipv6_cidr_block", route.DestinationIpv6CidrBlock)
d.Set("egress_only_gateway_id", route.EgressOnlyInternetGatewayId)
Expand Down
2 changes: 1 addition & 1 deletion aws/import_aws_route_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func resourceAwsRouteTableImportState(
d.Set("route_table_id", id)
d.Set("destination_cidr_block", route.DestinationCidrBlock)
d.Set("destination_ipv6_cidr_block", route.DestinationIpv6CidrBlock)
d.SetId(routeIDHash(d, route))
d.SetId(resourceAwsRouteID(d, route))
results = append(results, d)
}
}
Expand Down
32 changes: 25 additions & 7 deletions aws/resource_aws_route.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ func resourceAwsRoute() *schema.Resource {
Update: resourceAwsRouteUpdate,
Delete: resourceAwsRouteDelete,
Exists: resourceAwsRouteExists,
Importer: &schema.ResourceImporter{
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
idParts := strings.Split(d.Id(), "_")
if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
return nil, fmt.Errorf("unexpected format of ID (%q), expected ROUTETABLEID_DESTINATION", d.Id())
}
routeTableID := idParts[0]
destination := idParts[1]
d.Set("route_table_id", routeTableID)
if strings.Contains(destination, ":") {
d.Set("destination_ipv6_cidr_block", destination)
} else {
d.Set("destination_cidr_block", destination)
}
d.SetId(fmt.Sprintf("r-%s%d", routeTableID, hashcode.String(destination)))
return []*schema.ResourceData{d}, nil
},
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(2 * time.Minute),
Expand Down Expand Up @@ -240,7 +258,7 @@ func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error {

if v, ok := d.GetOk("destination_cidr_block"); ok {
err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError {
route, err = findResourceRoute(conn, d.Get("route_table_id").(string), v.(string), "")
route, err = resourceAwsRouteFindRoute(conn, d.Get("route_table_id").(string), v.(string), "")
return resource.RetryableError(err)
})
if err != nil {
Expand All @@ -250,15 +268,15 @@ func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error {

if v, ok := d.GetOk("destination_ipv6_cidr_block"); ok {
err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError {
route, err = findResourceRoute(conn, d.Get("route_table_id").(string), "", v.(string))
route, err = resourceAwsRouteFindRoute(conn, d.Get("route_table_id").(string), "", v.(string))
return resource.RetryableError(err)
})
if err != nil {
return fmt.Errorf("Error finding route after creating it: %s", err)
}
}

d.SetId(routeIDHash(d, route))
d.SetId(resourceAwsRouteID(d, route))
resourceAwsRouteSetResourceData(d, route)
return nil
}
Expand All @@ -270,7 +288,7 @@ func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error {
destinationCidrBlock := d.Get("destination_cidr_block").(string)
destinationIpv6CidrBlock := d.Get("destination_ipv6_cidr_block").(string)

route, err := findResourceRoute(conn, routeTableId, destinationCidrBlock, destinationIpv6CidrBlock)
route, err := resourceAwsRouteFindRoute(conn, routeTableId, destinationCidrBlock, destinationIpv6CidrBlock)
if err != nil {
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidRouteTableID.NotFound" {
log.Printf("[WARN] Route Table %q could not be found. Removing Route from state.",
Expand Down Expand Up @@ -472,8 +490,8 @@ func resourceAwsRouteExists(d *schema.ResourceData, meta interface{}) (bool, err
return false, nil
}

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

if r.DestinationIpv6CidrBlock != nil && *r.DestinationIpv6CidrBlock != "" {
return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationIpv6CidrBlock))
Expand All @@ -483,7 +501,7 @@ func routeIDHash(d *schema.ResourceData, r *ec2.Route) string {
}

// Helper: retrieve a route
func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string, ipv6cidr string) (*ec2.Route, error) {
func resourceAwsRouteFindRoute(conn *ec2.EC2, rtbid string, cidr string, ipv6cidr string) (*ec2.Route, error) {
routeTableID := rtbid

findOpts := &ec2.DescribeRouteTablesInput{
Expand Down
80 changes: 78 additions & 2 deletions aws/resource_aws_route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ func TestAccAWSRoute_basic(t *testing.T) {
testCheck,
),
},
{
ResourceName: "aws_route.bar",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.bar"),
ImportStateVerify: true,
},
},
})
}
Expand Down Expand Up @@ -82,6 +88,12 @@ func TestAccAWSRoute_ipv6Support(t *testing.T) {
testCheck,
),
},
{
ResourceName: "aws_route.bar",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.bar"),
ImportStateVerify: true,
},
},
})
}
Expand All @@ -102,6 +114,12 @@ func TestAccAWSRoute_ipv6ToInternetGateway(t *testing.T) {
testAccCheckAWSRouteExists("aws_route.igw", &route),
),
},
{
ResourceName: "aws_route.igw",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.igw"),
ImportStateVerify: true,
},
},
})
}
Expand All @@ -122,6 +140,12 @@ func TestAccAWSRoute_ipv6ToInstance(t *testing.T) {
testAccCheckAWSRouteExists("aws_route.internal-default-route-ipv6", &route),
),
},
{
ResourceName: "aws_route.internal-default-route-ipv6",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.internal-default-route-ipv6"),
ImportStateVerify: true,
},
},
})
}
Expand All @@ -142,6 +166,12 @@ func TestAccAWSRoute_ipv6ToNetworkInterface(t *testing.T) {
testAccCheckAWSRouteExists("aws_route.internal-default-route-ipv6", &route),
),
},
{
ResourceName: "aws_route.internal-default-route-ipv6",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.internal-default-route-ipv6"),
ImportStateVerify: true,
},
},
})
}
Expand All @@ -162,6 +192,12 @@ func TestAccAWSRoute_ipv6ToPeeringConnection(t *testing.T) {
testAccCheckAWSRouteExists("aws_route.pc", &route),
),
},
{
ResourceName: "aws_route.pc",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.pc"),
ImportStateVerify: true,
},
},
})
}
Expand Down Expand Up @@ -189,6 +225,12 @@ func TestAccAWSRoute_changeRouteTable(t *testing.T) {
testAccCheckAWSRouteExists("aws_route.bar", &after),
),
},
{
ResourceName: "aws_route.bar",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.bar"),
ImportStateVerify: true,
},
},
})
}
Expand Down Expand Up @@ -260,6 +302,12 @@ func TestAccAWSRoute_changeCidr(t *testing.T) {
testCheckChange,
),
},
{
ResourceName: "aws_route.bar",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.bar"),
ImportStateVerify: true,
},
},
})
}
Expand Down Expand Up @@ -298,6 +346,12 @@ func TestAccAWSRoute_noopdiff(t *testing.T) {
testCheckChange,
),
},
{
ResourceName: "aws_route.test",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.test"),
ImportStateVerify: true,
},
},
})
}
Expand All @@ -316,6 +370,12 @@ func TestAccAWSRoute_doesNotCrashWithVPCEndpoint(t *testing.T) {
testAccCheckAWSRouteExists("aws_route.bar", &route),
),
},
{
ResourceName: "aws_route.bar",
ImportState: true,
ImportStateIdFunc: testAccAWSRouteImportStateIdFunc("aws_route.bar"),
ImportStateVerify: true,
},
},
})
}
Expand All @@ -332,7 +392,7 @@ func testAccCheckAWSRouteExists(n string, res *ec2.Route) resource.TestCheckFunc
}

conn := testAccProvider.Meta().(*AWSClient).ec2conn
r, err := findResourceRoute(
r, err := resourceAwsRouteFindRoute(
conn,
rs.Primary.Attributes["route_table_id"],
rs.Primary.Attributes["destination_cidr_block"],
Expand Down Expand Up @@ -360,7 +420,7 @@ func testAccCheckAWSRouteDestroy(s *terraform.State) error {
}

conn := testAccProvider.Meta().(*AWSClient).ec2conn
route, err := findResourceRoute(
route, err := resourceAwsRouteFindRoute(
conn,
rs.Primary.Attributes["route_table_id"],
rs.Primary.Attributes["destination_cidr_block"],
Expand All @@ -375,6 +435,22 @@ func testAccCheckAWSRouteDestroy(s *terraform.State) error {
return nil
}

func testAccAWSRouteImportStateIdFunc(resourceName string) resource.ImportStateIdFunc {
return func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return "", fmt.Errorf("not found: %s", resourceName)
}

destination := rs.Primary.Attributes["destination_cidr_block"]
if _, ok := rs.Primary.Attributes["destination_ipv6_cidr_block"]; ok {
destination = rs.Primary.Attributes["destination_ipv6_cidr_block"]
}

return fmt.Sprintf("%s_%s", rs.Primary.Attributes["route_table_id"], destination), nil
}
}

var testAccAWSRouteBasicConfig = fmt.Sprint(`
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
Expand Down
16 changes: 16 additions & 0 deletions website/docs/r/route.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,19 @@ will be exported as an attribute once the resource is created.

- `create` - (Default `2 minutes`) Used for route creation
- `delete` - (Default `5 minutes`) Used for route deletion

## Import

Individual routes can be imported using `ROUTETABLEID_DESTINATION`.

For example, import a route in route table `rtb-656C65616E6F72` with an IPv4 destination CIDR of `10.42.0.0/16` like this:

```console
$ terraform import aws_route.my_route rtb-656C65616E6F72_10.42.0.0/16
```

Import a route in route table `rtb-656C65616E6F72` with an IPv6 destination CIDR of `2620:0:2d0:200::8/125` similarly:

```console
$ terraform import aws_route.my_route rtb-656C65616E6F72_2620:0:2d0:200::8/125
```

0 comments on commit 4ff0de7

Please sign in to comment.