Merge pull request #963 from julienba/master

providers/aws: vpc_peering_connection
This commit is contained in:
Mitchell Hashimoto 2015-02-18 06:56:28 -08:00
commit 44c45994c8
7 changed files with 375 additions and 22 deletions

View File

@ -66,6 +66,7 @@ func Provider() terraform.ResourceProvider {
"aws_security_group": resourceAwsSecurityGroup(), "aws_security_group": resourceAwsSecurityGroup(),
"aws_subnet": resourceAwsSubnet(), "aws_subnet": resourceAwsSubnet(),
"aws_vpc": resourceAwsVpc(), "aws_vpc": resourceAwsVpc(),
"aws_vpc_peering_connection": resourceAwsVpcPeeringConnection(),
}, },
ConfigureFunc: providerConfigure, ConfigureFunc: providerConfigure,

View File

@ -47,6 +47,11 @@ func resourceAwsRouteTable() *schema.Resource {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
"vpc_peering_connection_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
}, },
}, },
Set: resourceAwsRouteTableHash, Set: resourceAwsRouteTableHash,
@ -125,6 +130,7 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error {
m["gateway_id"] = r.GatewayId m["gateway_id"] = r.GatewayId
m["instance_id"] = r.InstanceId m["instance_id"] = r.InstanceId
m["vpc_peering_connection_id"] = r.VpcPeeringConnectionId
route.Add(m) route.Add(m)
} }
@ -173,6 +179,7 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error
DestinationCidrBlock: m["cidr_block"].(string), DestinationCidrBlock: m["cidr_block"].(string),
GatewayId: m["gateway_id"].(string), GatewayId: m["gateway_id"].(string),
InstanceId: m["instance_id"].(string), InstanceId: m["instance_id"].(string),
VpcPeeringConnectionId: 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)
@ -261,6 +268,10 @@ func resourceAwsRouteTableHash(v interface{}) int {
buf.WriteString(fmt.Sprintf("%s-", v.(string))) buf.WriteString(fmt.Sprintf("%s-", v.(string)))
} }
if v, ok := m["vpc_peering_connection_id"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
return hashcode.String(buf.String()) return hashcode.String(buf.String())
} }

View File

@ -149,7 +149,6 @@ 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).ec2conn
@ -209,6 +208,45 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec
} }
} }
func TestAccAWSRouteTable_vpcPeering(t *testing.T) {
var v ec2.RouteTable
testCheck := func(*terraform.State) error {
if len(v.Routes) != 2 {
return fmt.Errorf("bad routes: %#v", v.Routes)
}
routes := make(map[string]ec2.Route)
for _, r := range v.Routes {
routes[r.DestinationCidrBlock] = r
}
if _, ok := routes["10.1.0.0/16"]; !ok {
return fmt.Errorf("bad routes: %#v", v.Routes)
}
if _, ok := routes["10.2.0.0/16"]; !ok {
return fmt.Errorf("bad routes: %#v", v.Routes)
}
return nil
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckRouteTableDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRouteTableVpcPeeringConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckRouteTableExists(
"aws_route_table.foo", &v),
testCheck,
),
},
},
})
}
const testAccRouteTableConfig = ` const testAccRouteTableConfig = `
resource "aws_vpc" "foo" { resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16" cidr_block = "10.1.0.0/16"
@ -306,3 +344,22 @@ resource "aws_route_table" "foo" {
} }
} }
` `
const testAccRouteTableVpcPeeringConfig = `
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"
vpc_peering_connection_id = "vpc-12345"
}
}
`

View File

@ -0,0 +1,145 @@
package aws
import (
"fmt"
"log"
"time"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/ec2"
)
func resourceAwsVpcPeeringConnection() *schema.Resource {
return &schema.Resource{
Create: resourceAwsVpcPeeringCreate,
Read: resourceAwsVpcPeeringRead,
Update: resourceAwsVpcPeeringUpdate,
Delete: resourceAwsVpcPeeringDelete,
Schema: map[string]*schema.Schema{
"peer_owner_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"peer_vpc_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"vpc_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"tags": tagsSchema(),
},
}
}
func resourceAwsVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn
// Create the vpc peering connection
createOpts := &ec2.CreateVpcPeeringConnection{
PeerOwnerId: d.Get("peer_owner_id").(string),
PeerVpcId: d.Get("peer_vpc_id").(string),
VpcId: d.Get("vpc_id").(string),
}
log.Printf("[DEBUG] VpcPeeringCreate create config: %#v", createOpts)
resp, err := ec2conn.CreateVpcPeeringConnection(createOpts)
if err != nil {
return fmt.Errorf("Error creating vpc peering connection: %s", err)
}
// Get the ID and store it
rt := &resp.VpcPeeringConnection
d.SetId(rt.VpcPeeringConnectionId)
log.Printf("[INFO] Vpc Peering Connection ID: %s", d.Id())
// Wait for the vpc peering connection to become available
log.Printf(
"[DEBUG] Waiting for vpc peering connection (%s) to become available",
d.Id())
stateConf := &resource.StateChangeConf{
Pending: []string{"pending"},
Target: "ready",
Refresh: resourceAwsVpcPeeringConnectionStateRefreshFunc(ec2conn, d.Id()),
Timeout: 1 * time.Minute,
}
if _, err := stateConf.WaitForState(); err != nil {
return fmt.Errorf(
"Error waiting for vpc peering (%s) to become available: %s",
d.Id(), err)
}
return nil
}
func resourceAwsVpcPeeringRead(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn
pcRaw, _, err := resourceAwsVpcPeeringConnectionStateRefreshFunc(ec2conn, d.Id())()
if err != nil {
return err
}
if pcRaw == nil {
d.SetId("")
return nil
}
pc := pcRaw.(*ec2.VpcPeeringConnection)
d.Set("peer_owner_id", pc.AccepterVpcInfo.OwnerId)
d.Set("peer_vpc_id", pc.AccepterVpcInfo.VpcId)
d.Set("vpc_id", pc.RequesterVpcInfo.VpcId)
d.Set("tags", tagsToMap(pc.Tags))
return nil
}
func resourceAwsVpcPeeringUpdate(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn
if err := setTags(ec2conn, d); err != nil {
return err
} else {
d.SetPartial("tags")
}
return resourceAwsRouteTableRead(d, meta)
}
func resourceAwsVpcPeeringDelete(d *schema.ResourceData, meta interface{}) error {
ec2conn := meta.(*AWSClient).ec2conn
_, err := ec2conn.DeleteVpcPeeringConnection(d.Id())
return err
}
// resourceAwsVpcPeeringConnectionStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VpcPeeringConnection.
func resourceAwsVpcPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
resp, err := conn.DescribeVpcPeeringConnection([]string{id}, ec2.NewFilter())
if err != nil {
if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidVpcPeeringConnectionID.NotFound" {
resp = nil
} else {
log.Printf("Error on VpcPeeringConnectionStateRefresh: %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
}
pc := &resp.VpcPeeringConnections[0]
return pc, "ready", nil
}
}

View File

@ -0,0 +1,79 @@
package aws
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/goamz/ec2"
)
func TestAccAWSVPCPeeringConnection_normal(t *testing.T) {
var conf ec2.Address
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSVpcPeeringConnectionDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccVpcPeeringConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSVpcPeeringConnectionExists("aws_vpc_peering_connection.foo", &conf),
),
},
},
})
}
func testAccCheckAWSVpcPeeringConnectionDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ec2conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_vpc_peering_connection" {
continue
}
describe, err := conn.DescribeVpcPeeringConnection([]string{rs.Primary.ID}, ec2.NewFilter())
if err == nil {
if len(describe.VpcPeeringConnections) != 0 {
return fmt.Errorf("vpc peering connection still exists")
}
}
}
return nil
}
func testAccCheckAWSVpcPeeringConnectionExists(n string, res *ec2.Address) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No vpc peering connection id is set")
}
return nil
}
}
const testAccVpcPeeringConfig = `
resource "aws_vpc" "foo" {
cidr_block = "10.0.0.0/16"
}
resource "aws_vpc" "bar" {
cidr_block = "10.0.1.0/16"
}
resource "aws_vpc_peering_connection" "foo" {
peer_owner_id = "12345"
vpc_id = "${aws_vpc.foo.id}"
peer_vpc_id = "${aws_vpc.bar.id}"
}
`

View File

@ -39,8 +39,9 @@ Each route supports the following:
* `cidr_block` - (Required) The CIDR block of the route. * `cidr_block` - (Required) The CIDR block of the route.
* `gateway_id` - (Optional) The Internet Gateway ID. * `gateway_id` - (Optional) The Internet Gateway ID.
* `instance_id` - (Optional) The EC2 instance ID. * `instance_id` - (Optional) The EC2 instance ID.
* `vpc_peering_connection_id` - (Optional) The VPC Peering ID.
Each route must contain either a `gateway_id` or an `instance_id`. Note that the Each route must contain either a `gateway_id`, an `instance_id` or a `vpc_peering_connection_id`. Note that the
default route, mapping the VPC's CIDR block to "local", is created implicitly and default route, mapping the VPC's CIDR block to "local", is created implicitly and
cannot be specified. cannot be specified.

View File

@ -0,0 +1,59 @@
---
layout: "aws"
page_title: "AWS: aws_vpc_peering_connection"
sidebar_current: "docs-aws-resource-vpc-peering-connection"
description: |-
Provides an VPC Peering Connection resource.
---
# aws\_vpc\_peering\_connection
Provides an VPC Peering Connection resource.
## Example Usage
Basic usage:
```
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
```
Basic usage with tags:
```
resource "aws_vpc_peering_connection" "foo" {
peer_owner_id = "${var.peer_owner_id}"
peer_vpc_id = "${aws_vpc.bar.id}"
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
}
resource "aws_vpc" "bar" {
cidr_block = "10.2.0.0/16"
}
```
## Argument Reference
The following arguments are supported:
* `peer_owner_id` - (Required) The AWS account ID of the owner of the peer VPC.
* `peer_vpc_id` - (Required) The ID of the VPC with which you are creating the VPC peering connection.
* `vpc_id` - (Required) The ID of the requester VPC.
* `tags` - (Optional) A mapping of tags to assign to the resource.
## Attributes Reference
The following attributes are exported:
* `id` - The ID of the VPC Peering Connectiona
## Notes
You still have to accept the peering with the aws console, aws-cli or goamz