Add aws_route resource

This commit is contained in:
gkze 2015-06-23 20:44:02 -07:00 committed by BSick7
parent 5930771615
commit ac0afad6e9
6 changed files with 456 additions and 0 deletions

View File

@ -231,6 +231,7 @@ func Provider() terraform.ResourceProvider {
"aws_route53_zone_association": resourceAwsRoute53ZoneAssociation(),
"aws_route53_zone": resourceAwsRoute53Zone(),
"aws_route53_health_check": resourceAwsRoute53HealthCheck(),
"aws_route": resourceAwsRoute(),
"aws_route_table": resourceAwsRouteTable(),
"aws_route_table_association": resourceAwsRouteTableAssociation(),
"aws_s3_bucket": resourceAwsS3Bucket(),

View File

@ -0,0 +1,278 @@
package aws
import (
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
)
// AWS Route resource Schema delcaration
func resourceAwsRoute() *schema.Resource {
return &schema.Resource{
Create: resourceAwsRouteCreate,
Read: resourceAwsRouteRead,
Update: resourceAwsRouteUpdate,
Delete: resourceAwsRouteDelete,
Schema: map[string]*schema.Schema{
"destination_cidr_block": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"destination_prefix_list_id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"gateway_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"instance_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"instance_owner_id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"network_interface_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"origin": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"state": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"route_table_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"vpc_peering_connection_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
}
}
func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
var numTargets int
var setTarget string
allowedTargets := []string{
"gateway_id",
"instance_id",
"network_interface_id",
"vpc_peering_connection_id",
}
createOpts := &ec2.CreateRouteInput{}
// Check if more than 1 target is specified
for _, target := range allowedTargets {
if len(d.Get(target).(string)) > 0 {
numTargets++
setTarget = target
}
}
if numTargets > 1 {
fmt.Errorf("Error: more than 1 target specified. Only 1 of gateway_id" +
"instance_id, network_interface_id, route_table_id or" +
"vpc_peering_connection_id is allowed.")
}
// Formulate CreateRouteInput based on the target type
switch setTarget {
case "gateway_id":
createOpts = &ec2.CreateRouteInput{
RouteTableID: aws.String(d.Get("route_table_id").(string)),
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
GatewayID: aws.String(d.Get("gateway_id").(string)),
}
case "instance_id":
createOpts = &ec2.CreateRouteInput{
RouteTableID: aws.String(d.Get("route_table_id").(string)),
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
InstanceID: aws.String(d.Get("instance_id").(string)),
}
case "network_interface_id":
createOpts = &ec2.CreateRouteInput{
RouteTableID: aws.String(d.Get("route_table_id").(string)),
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
NetworkInterfaceID: aws.String(d.Get("network_interface_id").(string)),
}
case "vpc_peering_connection_id":
createOpts = &ec2.CreateRouteInput{
RouteTableID: aws.String(d.Get("route_table_id").(string)),
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
VPCPeeringConnectionID: aws.String(d.Get("vpc_peering_connection_id").(string)),
}
default:
fmt.Errorf("Error: invalid target type specified.")
}
log.Printf("[DEBUG] Route create config: %s", awsutil.Prettify(createOpts))
// Create the route
_, err := conn.CreateRoute(createOpts)
if err != nil {
return fmt.Errorf("Error creating route: %s", err)
}
route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string))
if err != nil {
fmt.Errorf("Error: %s", awsutil.Prettify(err))
}
d.SetId(routeIDHash(d, route))
return resourceAwsRouteRead(d, meta)
}
func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string))
if err != nil {
return err
}
d.Set("destination_prefix_list_id", route.DestinationPrefixListID)
d.Set("gateway_id", route.DestinationPrefixListID)
d.Set("instance_id", route.InstanceID)
d.Set("instance_owner_id", route.InstanceOwnerID)
d.Set("network_interface_id", route.NetworkInterfaceID)
d.Set("origin", route.Origin)
d.Set("state", route.State)
d.Set("vpc_peering_connection_id", route.VPCPeeringConnectionID)
return nil
}
func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
var numTargets int
var setTarget string
allowedTargets := []string{
"gateway_id",
"instance_id",
"network_interface_id",
"vpc_peering_connection_id",
}
replaceOpts := &ec2.ReplaceRouteInput{}
// Check if more than 1 target is specified
for _, target := range allowedTargets {
if len(d.Get(target).(string)) > 0 {
numTargets++
setTarget = target
}
}
if numTargets > 1 {
fmt.Errorf("Error: more than 1 target specified. Only 1 of gateway_id" +
"instance_id, network_interface_id, route_table_id or" +
"vpc_peering_connection_id is allowed.")
}
// Formulate ReplaceRouteInput based on the target type
switch setTarget {
case "gateway_id":
replaceOpts = &ec2.ReplaceRouteInput{
RouteTableID: aws.String(d.Get("route_table_id").(string)),
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
GatewayID: aws.String(d.Get("gateway_id").(string)),
}
case "instance_id":
replaceOpts = &ec2.ReplaceRouteInput{
RouteTableID: aws.String(d.Get("route_table_id").(string)),
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
InstanceID: aws.String(d.Get("instance_id").(string)),
}
case "network_interface_id":
replaceOpts = &ec2.ReplaceRouteInput{
RouteTableID: aws.String(d.Get("route_table_id").(string)),
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
NetworkInterfaceID: aws.String(d.Get("network_interface_id").(string)),
}
case "vpc_peering_connection_id":
replaceOpts = &ec2.ReplaceRouteInput{
RouteTableID: aws.String(d.Get("route_table_id").(string)),
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
VPCPeeringConnectionID: aws.String(d.Get("vpc_peering_connection_id").(string)),
}
default:
fmt.Errorf("Error: invalid target type specified.")
}
log.Printf("[DEBUG] Route replace config: %s", awsutil.Prettify(replaceOpts))
// Replace the route
_, err := conn.ReplaceRoute(replaceOpts)
if err != nil {
return err
}
return nil
}
func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
deleteOpts := &ec2.DeleteRouteInput{
DestinationCIDRBlock: aws.String(d.Get("destination_cidr_block").(string)),
RouteTableID: aws.String(d.Get("route_table_id").(string)),
}
log.Printf("[DEBUG] Route delete opts: %s", awsutil.Prettify(deleteOpts))
resp, err := conn.DeleteRoute(deleteOpts)
log.Printf("[DEBUG] Route delete result: %s", awsutil.Prettify(resp))
if err != nil {
return err
}
d.SetId("")
return nil
}
// Create an ID for a route
func routeIDHash(d *schema.ResourceData, r *ec2.Route) string {
return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationCIDRBlock))
}
// Helper: retrieve a route
func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string) (*ec2.Route, error) {
routeTableID := rtbid
findOpts := &ec2.DescribeRouteTablesInput{
RouteTableIDs: []*string{&routeTableID},
}
resp, err := conn.DescribeRouteTables(findOpts)
if err != nil {
return nil, err
}
for _, route := range (*resp.RouteTables[0]).Routes {
if *route.DestinationCIDRBlock == cidr {
return route, nil
}
}
return nil, nil
}

View File

@ -0,0 +1,120 @@
package aws
import (
"fmt"
"testing"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSRoute_basic(t *testing.T) {
var route ec2.Route
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRouteDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSRouteConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRouteExists("aws_route.bar", &route),
testAccCheckAWSRouteAttributes(&route),
),
},
},
})
}
func testAccCheckAWSRouteExists(n string, res *ec2.Route) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s\n", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
conn := testAccProvider.Meta().(*AWSClient).ec2conn
r, err := findResourceRoute(
conn,
rs.Primary.ID,
rs.Primary.Attributes["destination_cidr_block"],
)
if err != nil {
return err
}
if r == nil {
return fmt.Errorf("Route not found")
}
return nil
}
}
func testAccCheckAWSRouteAttributes(route *ec2.Route) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route" {
continue
}
if *route.DestinationCIDRBlock != rs.Primary.Attributes["destination_cidr_block"] {
return fmt.Errorf("Bad Destination CIDR Block on Route\n\t expected: %s\n\tgot %s\n", rs.Primary.Attributes["destination_cidr_block"], *route.DestinationCIDRBlock)
}
}
return nil
}
}
func testAccCheckAWSRouteDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route" {
continue
}
conn := testAccProvider.Meta().(*AWSClient).ec2conn
route, err := findResourceRoute(
conn,
rs.Primary.ID,
rs.Primary.Attributes["destination_cidr_block"],
)
if route == nil && err == nil {
return nil
}
}
return nil
}
var testAccAWSRouteConfig = fmt.Sprint(`
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
}
resource "aws_internet_gateway" "foo" {
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_route_table" "foo" {
vpc_id = "${aws_vpc.foo.id}"
route {
cidr_block = "10.2.0.0/16"
gateway_id = "${aws_internet_gateway.foo.id}"
}
}
resource "aws_route" "foo" {
route_table_id = "${aws_route_table.foo.id}"
destination_cidr_block = "${aws_vpc.foo.cidr_block}"
gateway_id = "${aws_internet_gateway.foo.id}"
}
`)

View File

@ -0,0 +1,51 @@
---
layout: "aws"
page_title: "AWS: aws_route_table"
sidebar_current: "docs-aws-resource-route-table|"
description: |-
Provides a resource to create a routing entry in a VPC routing table.
---
# aws\_route
Provides a resource to create a routing table entry (a route) in a VPC routing table.
## Example usage:
```
resource "aws_route" "r" {
route_table_id = "rtb-4fbb3ac4"
destination_cidr_block = "10.0.1.0/22"
vpc_peering_connection_id = "pcx-45ff3dc1"
depends_on = ["aws_route_table.testing"]
}
```
## Argument Reference
The following arguments are supported:
* `route_table_id` - (Required) The ID of the routing table.
* `destination_cidr_block` - (Required) The destination CIDR block.
* `vpc_peering_connection_id` - (Optional) An ID of a VPC peering connection.
* `gateway_id` - (Optional) An ID of a VPC internet gateway or a virtual private gateway.
* `instance_id` - (Optional) An ID of a NAT instance.
* `network_interface_id` - (Optional) An ID of a network interface.
Each route must contain either a `gateway_id`, an `instance_id` or a `vpc_peering_connection_id`
or a `network_interface_id`. Note that the default route, mapping the VPC's CIDR block to "local",
is created implicitly and cannot be specified.
## Attributes Reference
The following attributes are exported:
~> **NOTE:** Only the target type that is specified (one of the above)
will be exported as an attribute once the resource is created.
* `route_table_id` - The ID of the routing table.
* `destination_cidr_block` - The destination CIDR block.
* `vpc_peering_connection_id` - An ID of a VPC peering connection.
* `gateway_id` - An ID of a VPC internet gateway or a virtual private gateway.
* `instance_id` - An ID of a NAT instance.
* `network_interface_id` - An ID of a network interface.

View File

@ -50,5 +50,7 @@ is created implicitly and cannot be specified.
## Attributes Reference
The following attributes are exported:
~> **NOTE:** Only the target that is entered is exported as a readable
attribute once the route resource is created.
* `id` - The ID of the routing table

View File

@ -401,6 +401,10 @@
<a href="/docs/providers/aws/r/route53_zone_association.html">aws_route53_zone_association</a>
</li>
<li<%= sidebar_current("docs-aws-resource-route|") %>>
<a href="/docs/providers/aws/r/route.html">aws_route</a>
</li>
</ul>
</li>