Documentation and tests written for GCE VPN config

This commit is contained in:
Lars Wander 2015-09-04 16:54:18 -04:00
parent b91df72371
commit 6850786422
17 changed files with 1011 additions and 23 deletions

View File

@ -7,6 +7,7 @@ FEATURES:
* **New resource: `google_compute_project_metadata`** [GH-3065] * **New resource: `google_compute_project_metadata`** [GH-3065]
* **New resources: `aws_ami`, `aws_ami_copy`, `aws_ami_from_instance`** [GH-2874] * **New resources: `aws_ami`, `aws_ami_copy`, `aws_ami_from_instance`** [GH-2874]
* **New resource: `google_storage_bucket_object`** [GH-3192] * **New resource: `google_storage_bucket_object`** [GH-3192]
* **New resources: `google_compute_vpn_gateway`, `google_compute_vpn_tunnel`** [GH-3213]
IMPROVEMENTS: IMPROVEMENTS:

View File

@ -47,6 +47,8 @@ func Provider() terraform.ResourceProvider {
"google_compute_project_metadata": resourceComputeProjectMetadata(), "google_compute_project_metadata": resourceComputeProjectMetadata(),
"google_compute_route": resourceComputeRoute(), "google_compute_route": resourceComputeRoute(),
"google_compute_target_pool": resourceComputeTargetPool(), "google_compute_target_pool": resourceComputeTargetPool(),
"google_compute_vpn_gateway": resourceComputeVpnGateway(),
"google_compute_vpn_tunnel": resourceComputeVpnTunnel(),
"google_container_cluster": resourceContainerCluster(), "google_container_cluster": resourceContainerCluster(),
"google_dns_managed_zone": resourceDnsManagedZone(), "google_dns_managed_zone": resourceDnsManagedZone(),
"google_dns_record_set": resourceDnsRecordSet(), "google_dns_record_set": resourceDnsRecordSet(),

View File

@ -32,18 +32,32 @@ func resourceComputeAddress() *schema.Resource {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
"region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
}, },
} }
} }
func getOptionalRegion(d *schema.ResourceData, config *Config) string {
if res, ok := d.GetOk("region"); !ok {
return config.Region
} else {
return res.(string)
}
}
func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) error { func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config) config := meta.(*Config)
region := getOptionalRegion(d, config)
// Build the address parameter // Build the address parameter
addr := &compute.Address{Name: d.Get("name").(string)} addr := &compute.Address{Name: d.Get("name").(string)}
log.Printf("[DEBUG] Address insert request: %#v", addr)
op, err := config.clientCompute.Addresses.Insert( op, err := config.clientCompute.Addresses.Insert(
config.Project, config.Region, addr).Do() config.Project, region, addr).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error creating address: %s", err) return fmt.Errorf("Error creating address: %s", err)
} }
@ -56,7 +70,7 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro
Service: config.clientCompute, Service: config.clientCompute,
Op: op, Op: op,
Project: config.Project, Project: config.Project,
Region: config.Region, Region: region,
Type: OperationWaitRegion, Type: OperationWaitRegion,
} }
state := w.Conf() state := w.Conf()
@ -81,8 +95,10 @@ func resourceComputeAddressCreate(d *schema.ResourceData, meta interface{}) erro
func resourceComputeAddressRead(d *schema.ResourceData, meta interface{}) error { func resourceComputeAddressRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config) config := meta.(*Config)
region := getOptionalRegion(d, config)
addr, err := config.clientCompute.Addresses.Get( addr, err := config.clientCompute.Addresses.Get(
config.Project, config.Region, d.Id()).Do() config.Project, region, d.Id()).Do()
if err != nil { if err != nil {
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
// The resource doesn't exist anymore // The resource doesn't exist anymore
@ -103,10 +119,11 @@ func resourceComputeAddressRead(d *schema.ResourceData, meta interface{}) error
func resourceComputeAddressDelete(d *schema.ResourceData, meta interface{}) error { func resourceComputeAddressDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config) config := meta.(*Config)
region := getOptionalRegion(d, config)
// Delete the address // Delete the address
log.Printf("[DEBUG] address delete request") log.Printf("[DEBUG] address delete request")
op, err := config.clientCompute.Addresses.Delete( op, err := config.clientCompute.Addresses.Delete(
config.Project, config.Region, d.Id()).Do() config.Project, region, d.Id()).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error deleting address: %s", err) return fmt.Errorf("Error deleting address: %s", err)
} }
@ -116,7 +133,7 @@ func resourceComputeAddressDelete(d *schema.ResourceData, meta interface{}) erro
Service: config.clientCompute, Service: config.clientCompute,
Op: op, Op: op,
Project: config.Project, Project: config.Project,
Region: config.Region, Region: region,
Type: OperationWaitRegion, Type: OperationWaitRegion,
} }
state := w.Conf() state := w.Conf()

View File

@ -50,6 +50,12 @@ func resourceComputeForwardingRule() *schema.Resource {
ForceNew: true, ForceNew: true,
}, },
"region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"self_link": &schema.Schema{ "self_link": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
@ -67,6 +73,8 @@ func resourceComputeForwardingRule() *schema.Resource {
func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{}) error { func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config) config := meta.(*Config)
region := getOptionalRegion(d, config)
frule := &compute.ForwardingRule{ frule := &compute.ForwardingRule{
IPAddress: d.Get("ip_address").(string), IPAddress: d.Get("ip_address").(string),
IPProtocol: d.Get("ip_protocol").(string), IPProtocol: d.Get("ip_protocol").(string),
@ -78,7 +86,7 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{
log.Printf("[DEBUG] ForwardingRule insert request: %#v", frule) log.Printf("[DEBUG] ForwardingRule insert request: %#v", frule)
op, err := config.clientCompute.ForwardingRules.Insert( op, err := config.clientCompute.ForwardingRules.Insert(
config.Project, config.Region, frule).Do() config.Project, region, frule).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error creating ForwardingRule: %s", err) return fmt.Errorf("Error creating ForwardingRule: %s", err)
} }
@ -90,7 +98,7 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{
w := &OperationWaiter{ w := &OperationWaiter{
Service: config.clientCompute, Service: config.clientCompute,
Op: op, Op: op,
Region: config.Region, Region: region,
Project: config.Project, Project: config.Project,
Type: OperationWaitRegion, Type: OperationWaitRegion,
} }
@ -116,13 +124,15 @@ func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{
func resourceComputeForwardingRuleUpdate(d *schema.ResourceData, meta interface{}) error { func resourceComputeForwardingRuleUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config) config := meta.(*Config)
region := getOptionalRegion(d, config)
d.Partial(true) d.Partial(true)
if d.HasChange("target") { if d.HasChange("target") {
target_name := d.Get("target").(string) target_name := d.Get("target").(string)
target_ref := &compute.TargetReference{Target: target_name} target_ref := &compute.TargetReference{Target: target_name}
op, err := config.clientCompute.ForwardingRules.SetTarget( op, err := config.clientCompute.ForwardingRules.SetTarget(
config.Project, config.Region, d.Id(), target_ref).Do() config.Project, region, d.Id(), target_ref).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error updating target: %s", err) return fmt.Errorf("Error updating target: %s", err)
} }
@ -131,7 +141,7 @@ func resourceComputeForwardingRuleUpdate(d *schema.ResourceData, meta interface{
w := &OperationWaiter{ w := &OperationWaiter{
Service: config.clientCompute, Service: config.clientCompute,
Op: op, Op: op,
Region: config.Region, Region: region,
Project: config.Project, Project: config.Project,
Type: OperationWaitRegion, Type: OperationWaitRegion,
} }
@ -161,8 +171,10 @@ func resourceComputeForwardingRuleUpdate(d *schema.ResourceData, meta interface{
func resourceComputeForwardingRuleRead(d *schema.ResourceData, meta interface{}) error { func resourceComputeForwardingRuleRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config) config := meta.(*Config)
region := getOptionalRegion(d, config)
frule, err := config.clientCompute.ForwardingRules.Get( frule, err := config.clientCompute.ForwardingRules.Get(
config.Project, config.Region, d.Id()).Do() config.Project, region, d.Id()).Do()
if err != nil { if err != nil {
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
// The resource doesn't exist anymore // The resource doesn't exist anymore
@ -184,10 +196,12 @@ func resourceComputeForwardingRuleRead(d *schema.ResourceData, meta interface{})
func resourceComputeForwardingRuleDelete(d *schema.ResourceData, meta interface{}) error { func resourceComputeForwardingRuleDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config) config := meta.(*Config)
region := getOptionalRegion(d, config)
// Delete the ForwardingRule // Delete the ForwardingRule
log.Printf("[DEBUG] ForwardingRule delete request") log.Printf("[DEBUG] ForwardingRule delete request")
op, err := config.clientCompute.ForwardingRules.Delete( op, err := config.clientCompute.ForwardingRules.Delete(
config.Project, config.Region, d.Id()).Do() config.Project, region, d.Id()).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error deleting ForwardingRule: %s", err) return fmt.Errorf("Error deleting ForwardingRule: %s", err)
} }
@ -196,7 +210,7 @@ func resourceComputeForwardingRuleDelete(d *schema.ResourceData, meta interface{
w := &OperationWaiter{ w := &OperationWaiter{
Service: config.clientCompute, Service: config.clientCompute,
Op: op, Op: op,
Region: config.Region, Region: region,
Project: config.Project, Project: config.Project,
Type: OperationWaitRegion, Type: OperationWaitRegion,
} }

View File

@ -66,6 +66,12 @@ func resourceComputeRoute() *schema.Resource {
ForceNew: true, ForceNew: true,
}, },
"next_hop_vpn_tunnel": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"priority": &schema.Schema{ "priority": &schema.Schema{
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
@ -101,13 +107,17 @@ func resourceComputeRouteCreate(d *schema.ResourceData, meta interface{}) error
} }
// Next hop data // Next hop data
var nextHopInstance, nextHopIp, nextHopNetwork, nextHopGateway string var nextHopInstance, nextHopIp, nextHopNetwork, nextHopGateway,
nextHopVpnTunnel string
if v, ok := d.GetOk("next_hop_ip"); ok { if v, ok := d.GetOk("next_hop_ip"); ok {
nextHopIp = v.(string) nextHopIp = v.(string)
} }
if v, ok := d.GetOk("next_hop_gateway"); ok { if v, ok := d.GetOk("next_hop_gateway"); ok {
nextHopGateway = v.(string) nextHopGateway = v.(string)
} }
if v, ok := d.GetOk("next_hop_vpn_tunnel"); ok {
nextHopVpnTunnel = v.(string)
}
if v, ok := d.GetOk("next_hop_instance"); ok { if v, ok := d.GetOk("next_hop_instance"); ok {
nextInstance, err := config.clientCompute.Instances.Get( nextInstance, err := config.clientCompute.Instances.Get(
config.Project, config.Project,
@ -140,15 +150,16 @@ func resourceComputeRouteCreate(d *schema.ResourceData, meta interface{}) error
// Build the route parameter // Build the route parameter
route := &compute.Route{ route := &compute.Route{
Name: d.Get("name").(string), Name: d.Get("name").(string),
DestRange: d.Get("dest_range").(string), DestRange: d.Get("dest_range").(string),
Network: network.SelfLink, Network: network.SelfLink,
NextHopInstance: nextHopInstance, NextHopInstance: nextHopInstance,
NextHopIp: nextHopIp, NextHopVpnTunnel: nextHopVpnTunnel,
NextHopNetwork: nextHopNetwork, NextHopIp: nextHopIp,
NextHopGateway: nextHopGateway, NextHopNetwork: nextHopNetwork,
Priority: int64(d.Get("priority").(int)), NextHopGateway: nextHopGateway,
Tags: tags, Priority: int64(d.Get("priority").(int)),
Tags: tags,
} }
log.Printf("[DEBUG] Route insert request: %#v", route) log.Printf("[DEBUG] Route insert request: %#v", route)
op, err := config.clientCompute.Routes.Insert( op, err := config.clientCompute.Routes.Insert(

View File

@ -0,0 +1,120 @@
package google
import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/compute/v1"
)
func resourceComputeVpnGateway() *schema.Resource {
return &schema.Resource{
// Unfortunately, the VPNGatewayService does not support update
// operations. This is why everything is marked forcenew
Create: resourceComputeVpnGatewayCreate,
Read: resourceComputeVpnGatewayRead,
Delete: resourceComputeVpnGatewayDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"network": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"self_link": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceComputeVpnGatewayCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
name := d.Get("name").(string)
network := d.Get("network").(string)
region := getOptionalRegion(d, config)
project := config.Project
vpnGatewaysService := compute.NewTargetVpnGatewaysService(config.clientCompute)
vpnGateway := &compute.TargetVpnGateway{
Name: name,
Network: network,
}
if v, ok := d.GetOk("description"); ok {
vpnGateway.Description = v.(string)
}
op, err := vpnGatewaysService.Insert(project, region, vpnGateway).Do()
if err != nil {
return fmt.Errorf("Error Inserting VPN Gateway %s into network %s: %s", name, network, err)
}
err = resourceOperationWaitRegion(config, op, region, "Inserting VPN Gateway")
if err != nil {
return fmt.Errorf("Error Waiting to Insert VPN Gateway %s into network %s: %s", name, network, err)
}
return resourceComputeVpnGatewayRead(d, meta)
}
func resourceComputeVpnGatewayRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
name := d.Get("name").(string)
region := d.Get("region").(string)
project := config.Project
vpnGatewaysService := compute.NewTargetVpnGatewaysService(config.clientCompute)
vpnGateway, err := vpnGatewaysService.Get(project, region, name).Do()
if err != nil {
return fmt.Errorf("Error Reading VPN Gateway %s: %s", name, err)
}
d.Set("self_link", vpnGateway.SelfLink)
d.SetId(name)
return nil
}
func resourceComputeVpnGatewayDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
name := d.Get("name").(string)
region := d.Get("region").(string)
project := config.Project
vpnGatewaysService := compute.NewTargetVpnGatewaysService(config.clientCompute)
op, err := vpnGatewaysService.Delete(project, region, name).Do()
if err != nil {
return fmt.Errorf("Error Reading VPN Gateway %s: %s", name, err)
}
err = resourceOperationWaitRegion(config, op, region, "Deleting VPN Gateway")
if err != nil {
return fmt.Errorf("Error Waiting to Delete VPN Gateway %s: %s", name, err)
}
return nil
}

View File

@ -0,0 +1,91 @@
package google
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"google.golang.org/api/compute/v1"
)
func TestAccComputeVpnGateway_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeVpnGatewayDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeVpnGateway_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeVpnGatewayExists(
"google_compute_vpn_gateway.foobar"),
),
},
},
})
}
func testAccCheckComputeVpnGatewayDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
project := config.Project
vpnGatewaysService := compute.NewTargetVpnGatewaysService(config.clientCompute)
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_compute_network" {
continue
}
region := rs.Primary.Attributes["region"]
name := rs.Primary.Attributes["name"]
_, err := vpnGatewaysService.Get(project, region, name).Do()
if err == nil {
return fmt.Errorf("Error, VPN Gateway %s in region %s still exists",
name, region)
}
}
return nil
}
func testAccCheckComputeVpnGatewayExists(n string) 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 ID is set")
}
config := testAccProvider.Meta().(*Config)
name := rs.Primary.Attributes["name"]
region := rs.Primary.Attributes["region"]
project := config.Project
vpnGatewaysService := compute.NewTargetVpnGatewaysService(config.clientCompute)
_, err := vpnGatewaysService.Get(project, region, name).Do()
if err != nil {
return fmt.Errorf("Error Reading VPN Gateway %s: %s", name, err)
}
return nil
}
}
const testAccComputeVpnGateway_basic = `
resource "google_compute_network" "foobar" {
name = "tf-test-network"
ipv4_range = "10.0.0.0/16"
}
resource "google_compute_vpn_gateway" "foobar" {
name = "tf-test-vpn-gateway"
network = "${google_compute_network.foobar.self_link}"
region = "us-central1"
} `

View File

@ -0,0 +1,178 @@
package google
import (
"fmt"
"time"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/compute/v1"
)
func resourceComputeVpnTunnel() *schema.Resource {
return &schema.Resource{
// Unfortunately, the VPNTunnelService does not support update
// operations. This is why everything is marked forcenew
Create: resourceComputeVpnTunnelCreate,
Read: resourceComputeVpnTunnelRead,
Delete: resourceComputeVpnTunnelDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"peer_ip": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"shared_secret": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"target_vpn_gateway": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"ike_version": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: 2,
ForceNew: true,
},
"detailed_status": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"self_link": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceOperationWaitRegion(config *Config, op *compute.Operation, region, activity string) error {
w := &OperationWaiter{
Service: config.clientCompute,
Op: op,
Project: config.Project,
Type: OperationWaitRegion,
Region: region,
}
state := w.Conf()
state.Timeout = 2 * time.Minute
state.MinTimeout = 1 * time.Second
opRaw, err := state.WaitForState()
if err != nil {
return fmt.Errorf("Error waiting for %s: %s", activity, err)
}
op = opRaw.(*compute.Operation)
if op.Error != nil {
return OperationError(*op.Error)
}
return nil
}
func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
name := d.Get("name").(string)
region := getOptionalRegion(d, config)
peerIp := d.Get("peer_ip").(string)
sharedSecret := d.Get("shared_secret").(string)
targetVpnGateway := d.Get("target_vpn_gateway").(string)
ikeVersion := d.Get("ike_version").(int)
project := config.Project
if ikeVersion < 1 || ikeVersion > 2 {
return fmt.Errorf("Only IKE version 1 or 2 supported, not %d", ikeVersion)
}
vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute)
vpnTunnel := &compute.VpnTunnel{
Name: name,
PeerIp: peerIp,
SharedSecret: sharedSecret,
TargetVpnGateway: targetVpnGateway,
IkeVersion: int64(ikeVersion),
}
if v, ok := d.GetOk("description"); ok {
vpnTunnel.Description = v.(string)
}
op, err := vpnTunnelsService.Insert(project, region, vpnTunnel).Do()
if err != nil {
return fmt.Errorf("Error Inserting VPN Tunnel %s : %s", name, err)
}
err = resourceOperationWaitRegion(config, op, region, "Inserting VPN Tunnel")
if err != nil {
return fmt.Errorf("Error Waiting to Insert VPN Tunnel %s: %s", name, err)
}
return resourceComputeVpnTunnelRead(d, meta)
}
func resourceComputeVpnTunnelRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
name := d.Get("name").(string)
region := d.Get("region").(string)
project := config.Project
vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute)
vpnTunnel, err := vpnTunnelsService.Get(project, region, name).Do()
if err != nil {
return fmt.Errorf("Error Reading VPN Tunnel %s: %s", name, err)
}
d.Set("detailed_status", vpnTunnel.DetailedStatus)
d.Set("self_link", vpnTunnel.SelfLink)
d.SetId(name)
return nil
}
func resourceComputeVpnTunnelDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
name := d.Get("name").(string)
region := d.Get("region").(string)
project := config.Project
vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute)
op, err := vpnTunnelsService.Delete(project, region, name).Do()
if err != nil {
return fmt.Errorf("Error Reading VPN Tunnel %s: %s", name, err)
}
err = resourceOperationWaitRegion(config, op, region, "Deleting VPN Tunnel")
if err != nil {
return fmt.Errorf("Error Waiting to Delete VPN Tunnel %s: %s", name, err)
}
return nil
}

View File

@ -0,0 +1,125 @@
package google
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"google.golang.org/api/compute/v1"
)
func TestAccComputeVpnTunnel_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeVpnTunnelDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeVpnTunnel_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeVpnTunnelExists(
"google_compute_vpn_tunnel.foobar"),
),
},
},
})
}
func testAccCheckComputeVpnTunnelDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
project := config.Project
vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute)
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_compute_network" {
continue
}
region := rs.Primary.Attributes["region"]
name := rs.Primary.Attributes["name"]
_, err := vpnTunnelsService.Get(project, region, name).Do()
if err == nil {
return fmt.Errorf("Error, VPN Tunnel %s in region %s still exists",
name, region)
}
}
return nil
}
func testAccCheckComputeVpnTunnelExists(n string) 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 ID is set")
}
config := testAccProvider.Meta().(*Config)
name := rs.Primary.Attributes["name"]
region := rs.Primary.Attributes["region"]
project := config.Project
vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute)
_, err := vpnTunnelsService.Get(project, region, name).Do()
if err != nil {
return fmt.Errorf("Error Reading VPN Tunnel %s: %s", name, err)
}
return nil
}
}
const testAccComputeVpnTunnel_basic = `
resource "google_compute_network" "foobar" {
name = "tf-test-network"
ipv4_range = "10.0.0.0/16"
}
resource "google_compute_address" "foobar" {
name = "tf-test-static-ip"
region = "us-central1"
}
resource "google_compute_vpn_gateway" "foobar" {
name = "tf-test-vpn-gateway"
network = "${google_compute_network.foobar.self_link}"
region = "${google_compute_address.foobar.region}"
}
resource "google_compute_forwarding_rule" "foobar_esp" {
name = "tf-test-fr-esp"
region = "${google_compute_vpn_gateway.foobar.region}"
ip_protocol = "ESP"
ip_address = "${google_compute_address.foobar.address}"
target = "${google_compute_vpn_gateway.foobar.self_link}"
}
resource "google_compute_forwarding_rule" "foobar_udp500" {
name = "tf-test-fr-udp500"
region = "${google_compute_forwarding_rule.foobar_esp.region}"
ip_protocol = "UDP"
port_range = "500"
ip_address = "${google_compute_address.foobar.address}"
target = "${google_compute_vpn_gateway.foobar.self_link}"
}
resource "google_compute_forwarding_rule" "foobar_udp4500" {
name = "tf-test-fr-udp4500"
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
ip_protocol = "UDP"
port_range = "4500"
ip_address = "${google_compute_address.foobar.address}"
target = "${google_compute_vpn_gateway.foobar.self_link}"
}
resource "google_compute_vpn_tunnel" "foobar" {
name = "tf-test-vpn-tunnel"
region = "${google_compute_forwarding_rule.foobar_udp4500.region}"
target_vpn_gateway = "${google_compute_vpn_gateway.foobar.self_link}"
shared_secret = "unguessable"
peer_ip = "0.0.0.0"
}`

View File

@ -0,0 +1,17 @@
# Google Compute Engine VPN Example
This example joins two GCE networks via VPN. The firewall rules have been set up
so that you can create an instance in each network and have them communicate
using their internal IP addresses.
See this [example](https://cloud.google.com/compute/docs/vpn) for more
information.
Run this example using
```
terraform apply \
-var="region1=us-central1" \
-var="region2=europe-west1" \
-var="project=my-project-id-123"
```

View File

@ -0,0 +1,11 @@
variable "project" {
description = "Your project name"
}
variable "region1" {
description = "The desired region for the first network & VPN and project"
}
variable "region2" {
description = "The desired region for the second network & VPN"
}

172
examples/gce-vpn/vpn.tf Normal file
View File

@ -0,0 +1,172 @@
# An example of how to connect two GCE networks with a VPN
provider "google" {
account_file = "${file("~/gce/account.json")}"
project = "${var.project}"
region = "${var.region1}"
}
# Create the two networks we want to join. They must have seperate, internal
# ranges.
resource "google_compute_network" "network1" {
name = "network1"
ipv4_range = "10.120.0.0/16"
}
resource "google_compute_network" "network2" {
name = "network2"
ipv4_range = "10.121.0.0/16"
}
# Attach a VPN gateway to each network.
resource "google_compute_vpn_gateway" "target_gateway1" {
name = "vpn1"
network = "${google_compute_network.network1.self_link}"
region = "${var.region1}"
}
resource "google_compute_vpn_gateway" "target_gateway2" {
name = "vpn2"
network = "${google_compute_network.network2.self_link}"
region = "${var.region2}"
}
# Create an outward facing static IP for each VPN that will be used by the
# other VPN to connect.
resource "google_compute_address" "vpn_static_ip1" {
name = "vpn-static-ip1"
region = "${var.region1}"
}
resource "google_compute_address" "vpn_static_ip2" {
name = "vpn-static-ip2"
region = "${var.region2}"
}
# Forward IPSec traffic coming into our static IP to our VPN gateway.
resource "google_compute_forwarding_rule" "fr1_esp" {
name = "fr1-esp"
region = "${var.region1}"
ip_protocol = "ESP"
ip_address = "${google_compute_address.vpn_static_ip1.address}"
target = "${google_compute_vpn_gateway.target_gateway1.self_link}"
}
resource "google_compute_forwarding_rule" "fr2_esp" {
name = "fr2-esp"
region = "${var.region2}"
ip_protocol = "ESP"
ip_address = "${google_compute_address.vpn_static_ip2.address}"
target = "${google_compute_vpn_gateway.target_gateway2.self_link}"
}
# The following two sets of forwarding rules are used as a part of the IPSec
# protocol
resource "google_compute_forwarding_rule" "fr1_udp500" {
name = "fr1-udp500"
region = "${var.region1}"
ip_protocol = "UDP"
port_range = "500"
ip_address = "${google_compute_address.vpn_static_ip1.address}"
target = "${google_compute_vpn_gateway.target_gateway1.self_link}"
}
resource "google_compute_forwarding_rule" "fr2_udp500" {
name = "fr2-udp500"
region = "${var.region2}"
ip_protocol = "UDP"
port_range = "500"
ip_address = "${google_compute_address.vpn_static_ip2.address}"
target = "${google_compute_vpn_gateway.target_gateway2.self_link}"
}
resource "google_compute_forwarding_rule" "fr1_udp4500" {
name = "fr1-udp4500"
region = "${var.region1}"
ip_protocol = "UDP"
port_range = "4500"
ip_address = "${google_compute_address.vpn_static_ip1.address}"
target = "${google_compute_vpn_gateway.target_gateway1.self_link}"
}
resource "google_compute_forwarding_rule" "fr2_udp4500" {
name = "fr2-udp4500"
region = "${var.region2}"
ip_protocol = "UDP"
port_range = "4500"
ip_address = "${google_compute_address.vpn_static_ip2.address}"
target = "${google_compute_vpn_gateway.target_gateway2.self_link}"
}
# Each tunnel is responsible for encrypting and decrypting traffic exiting
# and leaving it's associated gateway
resource "google_compute_vpn_tunnel" "tunnel1" {
name = "tunnel1"
region = "${var.region1}"
peer_ip = "${google_compute_address.vpn_static_ip2.address}"
shared_secret = "a secret message"
target_vpn_gateway = "${google_compute_vpn_gateway.target_gateway1.self_link}"
depends_on = ["google_compute_forwarding_rule.fr1_udp500",
"google_compute_forwarding_rule.fr1_udp4500",
"google_compute_forwarding_rule.fr1_esp"]
}
resource "google_compute_vpn_tunnel" "tunnel2" {
name = "tunnel2"
region = "${var.region2}"
peer_ip = "${google_compute_address.vpn_static_ip1.address}"
shared_secret = "a secret message"
target_vpn_gateway = "${google_compute_vpn_gateway.target_gateway2.self_link}"
depends_on = ["google_compute_forwarding_rule.fr2_udp500",
"google_compute_forwarding_rule.fr2_udp4500",
"google_compute_forwarding_rule.fr2_esp"]
}
# Each route tells the associated network to send all traffic in the dest_range
# through the VPN tunnel
resource "google_compute_route" "route1" {
name = "route1"
network = "${google_compute_network.network1.name}"
next_hop_vpn_tunnel = "${google_compute_vpn_tunnel.tunnel1.self_link}"
dest_range = "${google_compute_network.network2.ipv4_range}"
priority = 1000
}
resource "google_compute_route" "route2" {
name = "route2"
network = "${google_compute_network.network2.name}"
next_hop_vpn_tunnel = "${google_compute_vpn_tunnel.tunnel2.self_link}"
dest_range = "${google_compute_network.network1.ipv4_range}"
priority = 1000
}
# We want to allow the two networks to communicate, so we need to unblock
# them in the firewall
resource "google_compute_firewall" "network1-allow-network1" {
name = "network1-allow-network1"
network = "${google_compute_network.network1.name}"
source_ranges = ["${google_compute_network.network1.ipv4_range}"]
allow {
protocol = "tcp"
}
allow {
protocol = "udp"
}
allow {
protocol = "icmp"
}
}
resource "google_compute_firewall" "network1-allow-network2" {
name = "network1-allow-network2"
network = "${google_compute_network.network1.name}"
source_ranges = ["${google_compute_network.network2.ipv4_range}"]
allow {
protocol = "tcp"
}
allow {
protocol = "udp"
}
allow {
protocol = "icmp"
}
}

View File

@ -27,6 +27,8 @@ The following arguments are supported:
* `name` - (Required) A unique name for the resource, required by GCE. * `name` - (Required) A unique name for the resource, required by GCE.
Changing this forces a new resource to be created. Changing this forces a new resource to be created.
* `region` - (Optional) The Region in which the created address should reside.
If it is not provided, the provider region is used.
## Attributes Reference ## Attributes Reference
@ -35,3 +37,4 @@ The following attributes are exported:
* `name` - The name of the resource. * `name` - The name of the resource.
* `address` - The IP address that was allocated. * `address` - The IP address that was allocated.
* `self_link` - The URI of the created resource. * `self_link` - The URI of the created resource.
* `region` - The Region in which the created address does reside.

View File

@ -54,6 +54,9 @@ The following arguments are supported:
* `next_hop_network` - (Optional) The name of the network to route to if this * `next_hop_network` - (Optional) The name of the network to route to if this
route is matched. route is matched.
* `next_hop_vpn_gateway` - (Optional) The name of the VPN to route to if this
route is matched.
* `priority` - (Required) The priority of this route, used to break ties. * `priority` - (Required) The priority of this route, used to break ties.
* `tags` - (Optional) The tags that this route applies to. * `tags` - (Optional) The tags that this route applies to.

View File

@ -0,0 +1,103 @@
---
layout: "google"
page_title: "Google: google_compute_vpn_gateway"
sidebar_current: "docs-google-resource-vpn-gateway"
description: |-
Manages a VPN Gateway in the GCE network
---
# google\_compute\_vpn\_gateway
Manages a VPN Gateway in the GCE network. For more info, read the
[documentation](https://cloud.google.com/compute/docs/vpn).
## Example Usage
```
resource "google_compute_network" "network1" {
name = "network1"
ipv4_range = "10.120.0.0/16"
}
resource "google_compute_vpn_gateway" "target_gateway" {
name = "vpn1"
network = "${google_compute_network.network1.self_link}"
region = "${var.region}"
}
resource "google_compute_address" "vpn_static_ip" {
name = "vpn-static-ip"
region = "${var.region}"
}
resource "google_compute_forwarding_rule" "fr_esp" {
name = "fr-esp"
region = "${var.region}"
ip_protocol = "ESP"
ip_address = "${google_compute_address.vpn_static_ip.address}"
target = "${google_compute_vpn_gateway.target_gateway.self_link}"
}
resource "google_compute_forwarding_rule" "fr_udp500" {
name = "fr-udp500"
region = "${var.region}"
ip_protocol = "UDP"
port_range = "500"
ip_address = "${google_compute_address.vpn_static_ip.address}"
target = "${google_compute_vpn_gateway.target_gateway.self_link}"
}
resource "google_compute_forwarding_rule" "fr_udp4500" {
name = "fr-udp4500"
region = "${var.region}"
ip_protocol = "UDP"
port_range = "4500"
ip_address = "${google_compute_address.vpn_static_ip.address}"
target = "${google_compute_vpn_gateway.target_gateway.self_link}"
}
resource "google_compute_vpn_tunnel" "tunnel1" {
name = "tunnel1"
region = "${var.region}"
peer_ip = "15.0.0.120"
shared_secret = "a secret message"
target_vpn_gateway = "${google_compute_vpn_gateway.target_gateway.self_link}"
depends_on = ["google_compute_forwarding_rule.fr_esp",
"google_compute_forwarding_rule.fr_udp500",
"google_compute_forwarding_rule.fr_udp4500"]
}
resource "google_compute_route" "route1" {
name = "route1"
network = "${google_compute_network.network1.name}"
next_hop_vpn_tunnel = "${google_compute_vpn_tunnel.tunnel1.self_link}"
dest_range = "15.0.0.0/24"
priority = 1000
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) A unique name for the resource, required by GCE.
Changing this forces a new resource to be created.
* `description` - (Optional) A description of the resource.
Changing this forces a new resource to be created.
* `network` - (Required) A link to the network this VPN gateway is accepting
traffic for.
Changing this forces a new resource to be created.
* `region` - (Optional) The region this gateway should sit in. If not specified,
the project region will be used. Changing this forces a new resource to be
created.
## Attributes Reference
The following attributes are exported:
* `self_link` - A GCE server assigned link to this resource.

View File

@ -0,0 +1,112 @@
---
layout: "google"
page_title: "Google: google_compute_vpn_tunnel"
sidebar_current: "docs-google-resource-vpn-tunnel"
description: |-
Manages a VPN Tunnel to the GCE network
---
# google\_compute\_vpn\_tunnel
Manages a VPN Tunnel to the GCE network. For more info, read the
[documentation](https://cloud.google.com/compute/docs/vpn).
## Example Usage
```
resource "google_compute_network" "network1" {
name = "network1"
ipv4_range = "10.120.0.0/16"
}
resource "google_compute_vpn_gateway" "target_gateway" {
name = "vpn1"
network = "${google_compute_network.network1.self_link}"
region = "${var.region}"
}
resource "google_compute_address" "vpn_static_ip" {
name = "vpn-static-ip"
region = "${var.region}"
}
resource "google_compute_forwarding_rule" "fr_esp" {
name = "fr-esp"
region = "${var.region}"
ip_protocol = "ESP"
ip_address = "${google_compute_address.vpn_static_ip.address}"
target = "${google_compute_vpn_gateway.target_gateway.self_link}"
}
resource "google_compute_forwarding_rule" "fr_udp500" {
name = "fr-udp500"
region = "${var.region}"
ip_protocol = "UDP"
port_range = "500"
ip_address = "${google_compute_address.vpn_static_ip.address}"
target = "${google_compute_vpn_gateway.target_gateway.self_link}"
}
resource "google_compute_forwarding_rule" "fr_udp4500" {
name = "fr-udp4500"
region = "${var.region}"
ip_protocol = "UDP"
port_range = "4500"
ip_address = "${google_compute_address.vpn_static_ip.address}"
target = "${google_compute_vpn_gateway.target_gateway.self_link}"
}
resource "google_compute_vpn_tunnel" "tunnel1" {
name = "tunnel1"
region = "${var.region}"
peer_ip = "15.0.0.120"
shared_secret = "a secret message"
target_vpn_gateway = "${google_compute_vpn_gateway.target_gateway.self_link}"
depends_on = ["google_compute_forwarding_rule.fr_esp",
"google_compute_forwarding_rule.fr_udp500",
"google_compute_forwarding_rule.fr_udp4500"]
}
resource "google_compute_route" "route1" {
name = "route1"
network = "${google_compute_network.network1.name}"
next_hop_vpn_tunnel = "${google_compute_vpn_tunnel.tunnel1.self_link}"
dest_range = "15.0.0.0/24"
priority = 1000
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) A unique name for the resource, required by GCE.
Changing this forces a new resource to be created.
* `description` - (Optional) A description of the resource.
Changing this forces a new resource to be created.
* `peer_ip` - (Required) The VPN gateway sitting outside of GCE.
Changing this forces a new resource to be created.
* `region` - (Optional) The region this tunnel should sit in. If not specified,
the project region will be used. Changing this forces a new resource to be
created.
* `shared_secret` - (Required) A passphrase shared between the two VPN gateways.
Changing this forces a new resource to be created.
* `target_vpn_gateway` - (Required) A link to the VPN gateway sitting inside GCE.
Changing this forces a new resource to be created.
* `ike_version` - (Optional) Either version 1 or 2. Default is 2.
Changing this forces a new resource to be created.
## Attributes Reference
The following attributes are exported:
* `self_link` - A GCE server assigned link to this resource.
* `detailed_status` - Information about the status of the VPN tunnel.

View File

@ -69,6 +69,14 @@
<a href="/docs/providers/google/r/compute_target_pool.html">google_compute_target_pool</a> <a href="/docs/providers/google/r/compute_target_pool.html">google_compute_target_pool</a>
</li> </li>
<li<%= sidebar_current("docs-google-resource-vpn-gateway") %>>
<a href="/docs/providers/google/r/compute_vpn_gateway.html">google_compute_vpn_gateway</a>
</li>
<li<%= sidebar_current("docs-google-resource-vpn-tunnel") %>>
<a href="/docs/providers/google/r/compute_vpn_tunnel.html">google_compute_vpn_tunnel</a>
</li>
<li<%= sidebar_current("docs-google-resource-container-cluster") %>> <li<%= sidebar_current("docs-google-resource-container-cluster") %>>
<a href="/docs/providers/google/r/container_cluster.html">google_container_cluster</a> <a href="/docs/providers/google/r/container_cluster.html">google_container_cluster</a>
</li> </li>