Merge pull request #1170 from hashicorp/aws-go-route-table

provider/aws: Convert AWS Route Table to aws-sdk-go
This commit is contained in:
Clint 2015-03-10 16:42:56 -05:00
commit 357ef9f313
3 changed files with 111 additions and 57 deletions

View File

@ -6,10 +6,11 @@ import (
"log" "log"
"time" "time"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/ec2"
) )
func resourceAwsRouteTable() *schema.Resource { func resourceAwsRouteTable() *schema.Resource {
@ -61,11 +62,11 @@ func resourceAwsRouteTable() *schema.Resource {
} }
func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn ec2conn := meta.(*AWSClient).awsEC2conn
// Create the routing table // Create the routing table
createOpts := &ec2.CreateRouteTable{ createOpts := &ec2.CreateRouteTableRequest{
VpcId: d.Get("vpc_id").(string), VPCID: aws.String(d.Get("vpc_id").(string)),
} }
log.Printf("[DEBUG] RouteTable create config: %#v", createOpts) log.Printf("[DEBUG] RouteTable create config: %#v", createOpts)
@ -75,8 +76,8 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error
} }
// Get the ID and store it // Get the ID and store it
rt := &resp.RouteTable rt := resp.RouteTable
d.SetId(rt.RouteTableId) d.SetId(*rt.RouteTableID)
log.Printf("[INFO] Route Table ID: %s", d.Id()) log.Printf("[INFO] Route Table ID: %s", d.Id())
// Wait for the route table to become available // Wait for the route table to become available
@ -86,7 +87,7 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error
stateConf := &resource.StateChangeConf{ stateConf := &resource.StateChangeConf{
Pending: []string{"pending"}, Pending: []string{"pending"},
Target: "ready", Target: "ready",
Refresh: resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id()), Refresh: resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id()),
Timeout: 1 * time.Minute, Timeout: 1 * time.Minute,
} }
if _, err := stateConf.WaitForState(); err != nil { if _, err := stateConf.WaitForState(); err != nil {
@ -99,9 +100,9 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error
} }
func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn ec2conn := meta.(*AWSClient).awsEC2conn
rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id())() rtRaw, _, err := resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id())()
if err != nil { if err != nil {
return err return err
} }
@ -110,40 +111,48 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error {
} }
rt := rtRaw.(*ec2.RouteTable) rt := rtRaw.(*ec2.RouteTable)
d.Set("vpc_id", rt.VpcId) d.Set("vpc_id", rt.VPCID)
// Create an empty schema.Set to hold all routes // Create an empty schema.Set to hold all routes
route := &schema.Set{F: resourceAwsRouteTableHash} route := &schema.Set{F: resourceAwsRouteTableHash}
// Loop through the routes and add them to the set // Loop through the routes and add them to the set
for _, r := range rt.Routes { for _, r := range rt.Routes {
if r.GatewayId == "local" { if r.GatewayID != nil && *r.GatewayID == "local" {
continue continue
} }
if r.Origin == "EnableVgwRoutePropagation" { if r.Origin != nil && *r.Origin == "EnableVgwRoutePropagation" {
continue continue
} }
m := make(map[string]interface{}) m := make(map[string]interface{})
m["cidr_block"] = r.DestinationCidrBlock
m["gateway_id"] = r.GatewayId if r.DestinationCIDRBlock != nil {
m["instance_id"] = r.InstanceId m["cidr_block"] = *r.DestinationCIDRBlock
m["vpc_peering_connection_id"] = r.VpcPeeringConnectionId }
if r.GatewayID != nil {
m["gateway_id"] = *r.GatewayID
}
if r.InstanceID != nil {
m["instance_id"] = *r.InstanceID
}
if r.VPCPeeringConnectionID != nil {
m["vpc_peering_connection_id"] = *r.VPCPeeringConnectionID
}
route.Add(m) route.Add(m)
} }
d.Set("route", route) d.Set("route", route)
// Tags // Tags
d.Set("tags", tagsToMap(rt.Tags)) d.Set("tags", tagsToMapSDK(rt.Tags))
return nil return nil
} }
func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error { func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn ec2conn := meta.(*AWSClient).awsEC2conn
// Check if the route set as a whole has changed // Check if the route set as a whole has changed
if d.HasChange("route") { if d.HasChange("route") {
@ -159,8 +168,10 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
log.Printf( log.Printf(
"[INFO] Deleting route from %s: %s", "[INFO] Deleting route from %s: %s",
d.Id(), m["cidr_block"].(string)) d.Id(), m["cidr_block"].(string))
_, err := ec2conn.DeleteRoute( err := ec2conn.DeleteRoute(&ec2.DeleteRouteRequest{
d.Id(), m["cidr_block"].(string)) RouteTableID: aws.String(d.Id()),
DestinationCIDRBlock: aws.String(m["cidr_block"].(string)),
})
if err != nil { if err != nil {
return err return err
} }
@ -174,17 +185,16 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
for _, route := range nrs.List() { for _, route := range nrs.List() {
m := route.(map[string]interface{}) m := route.(map[string]interface{})
opts := ec2.CreateRoute{ opts := ec2.CreateRouteRequest{
RouteTableId: d.Id(), RouteTableID: aws.String(d.Id()),
DestinationCidrBlock: m["cidr_block"].(string), DestinationCIDRBlock: aws.String(m["cidr_block"].(string)),
GatewayId: m["gateway_id"].(string), GatewayID: aws.String(m["gateway_id"].(string)),
InstanceId: m["instance_id"].(string), InstanceID: aws.String(m["instance_id"].(string)),
VpcPeeringConnectionId: m["vpc_peering_connection_id"].(string), VPCPeeringConnectionID: aws.String(m["vpc_peering_connection_id"].(string)),
} }
log.Printf("[INFO] Creating route for %s: %#v", d.Id(), opts) log.Printf("[INFO] Creating route for %s: %#v", d.Id(), opts)
_, err := ec2conn.CreateRoute(&opts) if err := ec2conn.CreateRoute(&opts); err != nil {
if err != nil {
return err return err
} }
@ -193,7 +203,7 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
} }
} }
if err := setTags(ec2conn, d); err != nil { if err := setTagsSDK(ec2conn, d); err != nil {
return err return err
} else { } else {
d.SetPartial("tags") d.SetPartial("tags")
@ -203,11 +213,11 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
} }
func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error { func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn ec2conn := meta.(*AWSClient).awsEC2conn
// First request the routing table since we'll have to disassociate // First request the routing table since we'll have to disassociate
// all the subnets first. // all the subnets first.
rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id())() rtRaw, _, err := resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id())()
if err != nil { if err != nil {
return err return err
} }
@ -218,16 +228,22 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error
// Do all the disassociations // Do all the disassociations
for _, a := range rt.Associations { for _, a := range rt.Associations {
log.Printf("[INFO] Disassociating association: %s", a.AssociationId) log.Printf("[INFO] Disassociating association: %s", *a.RouteTableAssociationID)
if _, err := ec2conn.DisassociateRouteTable(a.AssociationId); err != nil { err := ec2conn.DisassociateRouteTable(&ec2.DisassociateRouteTableRequest{
AssociationID: a.RouteTableAssociationID,
})
if err != nil {
return err return err
} }
} }
// Delete the route table // Delete the route table
log.Printf("[INFO] Deleting Route Table: %s", d.Id()) log.Printf("[INFO] Deleting Route Table: %s", d.Id())
if _, err := ec2conn.DeleteRouteTable(d.Id()); err != nil { err = ec2conn.DeleteRouteTable(&ec2.DeleteRouteTableRequest{
ec2err, ok := err.(*ec2.Error) RouteTableID: aws.String(d.Id()),
})
if err != nil {
ec2err, ok := err.(aws.APIError)
if ok && ec2err.Code == "InvalidRouteTableID.NotFound" { if ok && ec2err.Code == "InvalidRouteTableID.NotFound" {
return nil return nil
} }
@ -243,7 +259,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error
stateConf := &resource.StateChangeConf{ stateConf := &resource.StateChangeConf{
Pending: []string{"ready"}, Pending: []string{"ready"},
Target: "", Target: "",
Refresh: resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id()), Refresh: resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id()),
Timeout: 1 * time.Minute, Timeout: 1 * time.Minute,
} }
if _, err := stateConf.WaitForState(); err != nil { if _, err := stateConf.WaitForState(); err != nil {
@ -275,13 +291,15 @@ func resourceAwsRouteTableHash(v interface{}) int {
return hashcode.String(buf.String()) return hashcode.String(buf.String())
} }
// resourceAwsRouteTableStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // resourceAwsRouteTableStateRefreshFuncSDK returns a resource.StateRefreshFunc that is used to watch
// a RouteTable. // a RouteTable.
func resourceAwsRouteTableStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { func resourceAwsRouteTableStateRefreshFuncSDK(conn *ec2.EC2, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) { return func() (interface{}, string, error) {
resp, err := conn.DescribeRouteTables([]string{id}, ec2.NewFilter()) resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
RouteTableIDs: []string{id},
})
if err != nil { if err != nil {
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidRouteTableID.NotFound" { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidRouteTableID.NotFound" {
resp = nil resp = nil
} else { } else {
log.Printf("Error on RouteTableStateRefresh: %s", err) log.Printf("Error on RouteTableStateRefresh: %s", err)

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/ec2"
) )
@ -129,3 +130,29 @@ func resourceAwsRouteTableAssociationDelete(d *schema.ResourceData, meta interfa
return nil return nil
} }
// TODO: remove this method when converting to aws-sdk-go
// resourceAwsRouteTableStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a RouteTable.
func resourceAwsRouteTableStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
resp, err := conn.DescribeRouteTables([]string{id}, ec2.NewFilter())
if err != nil {
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidRouteTableID.NotFound" {
resp = nil
} else {
log.Printf("Error on RouteTableStateRefresh: %s", err)
return nil, "", err
}
}
if resp == nil {
// Sometimes AWS just has consistency issues and doesn't see
// our instance yet. Return an empty state.
return nil, "", nil
}
rt := &resp.RouteTables[0]
return rt, "ready", nil
}
}

View File

@ -4,9 +4,10 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/ec2"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/goamz/ec2"
) )
func TestAccAWSRouteTable_normal(t *testing.T) { func TestAccAWSRouteTable_normal(t *testing.T) {
@ -19,7 +20,7 @@ func TestAccAWSRouteTable_normal(t *testing.T) {
routes := make(map[string]ec2.Route) routes := make(map[string]ec2.Route)
for _, r := range v.Routes { for _, r := range v.Routes {
routes[r.DestinationCidrBlock] = r routes[*r.DestinationCIDRBlock] = r
} }
if _, ok := routes["10.1.0.0/16"]; !ok { if _, ok := routes["10.1.0.0/16"]; !ok {
@ -39,7 +40,7 @@ func TestAccAWSRouteTable_normal(t *testing.T) {
routes := make(map[string]ec2.Route) routes := make(map[string]ec2.Route)
for _, r := range v.Routes { for _, r := range v.Routes {
routes[r.DestinationCidrBlock] = r routes[*r.DestinationCIDRBlock] = r
} }
if _, ok := routes["10.1.0.0/16"]; !ok { if _, ok := routes["10.1.0.0/16"]; !ok {
@ -91,7 +92,7 @@ func TestAccAWSRouteTable_instance(t *testing.T) {
routes := make(map[string]ec2.Route) routes := make(map[string]ec2.Route)
for _, r := range v.Routes { for _, r := range v.Routes {
routes[r.DestinationCidrBlock] = r routes[*r.DestinationCIDRBlock] = r
} }
if _, ok := routes["10.1.0.0/16"]; !ok { if _, ok := routes["10.1.0.0/16"]; !ok {
@ -133,7 +134,7 @@ func TestAccAWSRouteTable_tags(t *testing.T) {
Config: testAccRouteTableConfigTags, Config: testAccRouteTableConfigTags,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckRouteTableExists("aws_route_table.foo", &route_table), testAccCheckRouteTableExists("aws_route_table.foo", &route_table),
testAccCheckTags(&route_table.Tags, "foo", "bar"), testAccCheckTagsSDK(&route_table.Tags, "foo", "bar"),
), ),
}, },
@ -141,8 +142,8 @@ func TestAccAWSRouteTable_tags(t *testing.T) {
Config: testAccRouteTableConfigTagsUpdate, Config: testAccRouteTableConfigTagsUpdate,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckRouteTableExists("aws_route_table.foo", &route_table), testAccCheckRouteTableExists("aws_route_table.foo", &route_table),
testAccCheckTags(&route_table.Tags, "foo", ""), testAccCheckTagsSDK(&route_table.Tags, "foo", ""),
testAccCheckTags(&route_table.Tags, "bar", "baz"), testAccCheckTagsSDK(&route_table.Tags, "bar", "baz"),
), ),
}, },
}, },
@ -150,7 +151,7 @@ func TestAccAWSRouteTable_tags(t *testing.T) {
} }
func testAccCheckRouteTableDestroy(s *terraform.State) error { func testAccCheckRouteTableDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ec2conn conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
for _, rs := range s.RootModule().Resources { for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route_table" { if rs.Type != "aws_route_table" {
@ -158,8 +159,9 @@ func testAccCheckRouteTableDestroy(s *terraform.State) error {
} }
// Try to find the resource // Try to find the resource
resp, err := conn.DescribeRouteTables( resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
[]string{rs.Primary.ID}, ec2.NewFilter()) RouteTableIDs: []string{rs.Primary.ID},
})
if err == nil { if err == nil {
if len(resp.RouteTables) > 0 { if len(resp.RouteTables) > 0 {
return fmt.Errorf("still exist.") return fmt.Errorf("still exist.")
@ -169,7 +171,7 @@ func testAccCheckRouteTableDestroy(s *terraform.State) error {
} }
// Verify the error is what we want // Verify the error is what we want
ec2err, ok := err.(*ec2.Error) ec2err, ok := err.(aws.APIError)
if !ok { if !ok {
return err return err
} }
@ -192,9 +194,10 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec
return fmt.Errorf("No ID is set") return fmt.Errorf("No ID is set")
} }
conn := testAccProvider.Meta().(*AWSClient).ec2conn conn := testAccProvider.Meta().(*AWSClient).awsEC2conn
resp, err := conn.DescribeRouteTables( resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{
[]string{rs.Primary.ID}, ec2.NewFilter()) RouteTableIDs: []string{rs.Primary.ID},
})
if err != nil { if err != nil {
return err return err
} }
@ -208,7 +211,10 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec
} }
} }
func TestAccAWSRouteTable_vpcPeering(t *testing.T) { // TODO: re-enable this test.
// VPC Peering connections are prefixed with pcx
// Right now there is no VPC Peering resource
func _TestAccAWSRouteTable_vpcPeering(t *testing.T) {
var v ec2.RouteTable var v ec2.RouteTable
testCheck := func(*terraform.State) error { testCheck := func(*terraform.State) error {
@ -218,7 +224,7 @@ func TestAccAWSRouteTable_vpcPeering(t *testing.T) {
routes := make(map[string]ec2.Route) routes := make(map[string]ec2.Route)
for _, r := range v.Routes { for _, r := range v.Routes {
routes[r.DestinationCidrBlock] = r routes[*r.DestinationCIDRBlock] = r
} }
if _, ok := routes["10.1.0.0/16"]; !ok { if _, ok := routes["10.1.0.0/16"]; !ok {
@ -345,6 +351,9 @@ resource "aws_route_table" "foo" {
} }
` `
// TODO: re-enable this test.
// VPC Peering connections are prefixed with pcx
// Right now there is no VPC Peering resource
const testAccRouteTableVpcPeeringConfig = ` const testAccRouteTableVpcPeeringConfig = `
resource "aws_vpc" "foo" { resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16" cidr_block = "10.1.0.0/16"
@ -359,7 +368,7 @@ resource "aws_route_table" "foo" {
route { route {
cidr_block = "10.2.0.0/16" cidr_block = "10.2.0.0/16"
vpc_peering_connection_id = "vpc-12345" vpc_peering_connection_id = "pcx-12345"
} }
} }
` `