Skip to content

Commit

Permalink
Merge pull request #3548 from MDL/aws_route
Browse files Browse the repository at this point in the history
provider/aws: add aws_route resource (finish)
  • Loading branch information
catsby committed Oct 29, 2015
2 parents 8f5f34f + e0aad68 commit 5c3c1e2
Show file tree
Hide file tree
Showing 7 changed files with 673 additions and 0 deletions.
1 change: 1 addition & 0 deletions builtin/providers/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,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(),
Expand Down
304 changes: 304 additions & 0 deletions builtin/providers/aws/resource_aws_route.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
)

// AWS Route resource Schema declaration
func resourceAwsRoute() *schema.Resource {
return &schema.Resource{
Create: resourceAwsRouteCreate,
Read: resourceAwsRouteRead,
Update: resourceAwsRouteUpdate,
Delete: resourceAwsRouteDelete,
Exists: resourceAwsRouteExists,

Schema: map[string]*schema.Schema{
"destination_cidr_block": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: 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",
}

// 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.")
}

createOpts := &ec2.CreateRouteInput{}
// 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", 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", 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.GatewayId)
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)),
//NOOP: Ensure we don't blow away network interface id that is set after instance is launched
NetworkInterfaceId: aws.String(d.Get("network_interface_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", 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{
RouteTableId: aws.String(d.Get("route_table_id").(string)),
DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)),
}
log.Printf("[DEBUG] Route delete opts: %s", deleteOpts)

resp, err := conn.DeleteRoute(deleteOpts)
log.Printf("[DEBUG] Route delete result: %s", resp)
if err != nil {
return err
}

d.SetId("")
return nil
}

func resourceAwsRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) {
conn := meta.(*AWSClient).ec2conn
routeTableId := d.Get("route_table_id").(string)

findOpts := &ec2.DescribeRouteTablesInput{
RouteTableIds: []*string{&routeTableId},
}

res, err := conn.DescribeRouteTables(findOpts)
if err != nil {
return false, err
}

cidr := d.Get("destination_cidr_block").(string)
for _, route := range (*res.RouteTables[0]).Routes {
if *route.DestinationCidrBlock == cidr {
return true, nil
}
}

return false, 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
}
1 change: 1 addition & 0 deletions builtin/providers/aws/resource_aws_route_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func resourceAwsRouteTable() *schema.Resource {

"route": &schema.Schema{
Type: schema.TypeSet,
Computed: true,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
Expand Down
Loading

0 comments on commit 5c3c1e2

Please sign in to comment.