Merge pull request #12411 from drebes/cloud_router
provider/google: Cloud router resource
This commit is contained in:
commit
63ce0dae98
|
@ -0,0 +1,28 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccComputeRouterInterface_import(t *testing.T) {
|
||||
resourceName := "google_compute_router_interface.foobar"
|
||||
testId := acctest.RandString(10)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterInterfaceBasic(testId),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccComputeRouterPeer_import(t *testing.T) {
|
||||
resourceName := "google_compute_router_peer.foobar"
|
||||
testId := acctest.RandString(10)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterPeerBasic(testId),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccComputeRouter_import(t *testing.T) {
|
||||
resourceName := "google_compute_router.foobar"
|
||||
resourceRegion := "europe-west1"
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeRouterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterBasic(resourceRegion),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -6,12 +6,16 @@ import (
|
|||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/mutexkv"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
// Global MutexKV
|
||||
var mutexKV = mutexkv.NewMutexKV()
|
||||
|
||||
// Provider returns a terraform.ResourceProvider.
|
||||
func Provider() terraform.ResourceProvider {
|
||||
return &schema.Provider{
|
||||
|
@ -82,6 +86,9 @@ func Provider() terraform.ResourceProvider {
|
|||
"google_compute_project_metadata": resourceComputeProjectMetadata(),
|
||||
"google_compute_region_backend_service": resourceComputeRegionBackendService(),
|
||||
"google_compute_route": resourceComputeRoute(),
|
||||
"google_compute_router": resourceComputeRouter(),
|
||||
"google_compute_router_interface": resourceComputeRouterInterface(),
|
||||
"google_compute_router_peer": resourceComputeRouterPeer(),
|
||||
"google_compute_ssl_certificate": resourceComputeSslCertificate(),
|
||||
"google_compute_subnetwork": resourceComputeSubnetwork(),
|
||||
"google_compute_target_http_proxy": resourceComputeTargetHttpProxy(),
|
||||
|
@ -256,6 +263,10 @@ func getNetworkNameFromSelfLink(network string) (string, error) {
|
|||
return network, nil
|
||||
}
|
||||
|
||||
func getRouterLockName(region string, router string) string {
|
||||
return fmt.Sprintf("router/%s/%s", region, router)
|
||||
}
|
||||
|
||||
func handleNotFoundError(err error, d *schema.ResourceData, resource string) error {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing %s because it's gone", resource)
|
||||
|
@ -267,3 +278,11 @@ func handleNotFoundError(err error, d *schema.ResourceData, resource string) err
|
|||
|
||||
return fmt.Errorf("Error reading %s: %s", resource, err)
|
||||
}
|
||||
|
||||
func linkDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
|
||||
parts := strings.Split(old, "/")
|
||||
if parts[len(parts)-1] == new {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -87,3 +88,25 @@ func TestProvider_getRegionFromZone(t *testing.T) {
|
|||
t.Fatalf("Region (%s) did not match expected value: %s", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
// getTestRegion has the same logic as the provider's getRegion, to be used in tests.
|
||||
func getTestRegion(is *terraform.InstanceState, config *Config) (string, error) {
|
||||
if res, ok := is.Attributes["region"]; ok {
|
||||
return res, nil
|
||||
}
|
||||
if config.Region != "" {
|
||||
return config.Region, nil
|
||||
}
|
||||
return "", fmt.Errorf("%q: required field is not set", "region")
|
||||
}
|
||||
|
||||
// getTestProject has the same logic as the provider's getProject, to be used in tests.
|
||||
func getTestProject(is *terraform.InstanceState, config *Config) (string, error) {
|
||||
if res, ok := is.Attributes["project"]; ok {
|
||||
return res, nil
|
||||
}
|
||||
if config.Project != "" {
|
||||
return config.Project, nil
|
||||
}
|
||||
return "", fmt.Errorf("%q: required field is not set", "project")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
func resourceComputeRouter() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeRouterCreate,
|
||||
Read: resourceComputeRouterRead,
|
||||
Delete: resourceComputeRouterDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: resourceComputeRouterImportState,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"network": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"project": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"region": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"bgp": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
MaxItems: 1,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
|
||||
"asn": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceComputeRouterCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
routerLock := getRouterLockName(region, name)
|
||||
mutexKV.Lock(routerLock)
|
||||
defer mutexKV.Unlock(routerLock)
|
||||
|
||||
network, err := getNetworkLink(d, config, "network")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
routersService := config.clientCompute.Routers
|
||||
|
||||
router := &compute.Router{
|
||||
Name: name,
|
||||
Network: network,
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("description"); ok {
|
||||
router.Description = v.(string)
|
||||
}
|
||||
|
||||
if _, ok := d.GetOk("bgp"); ok {
|
||||
prefix := "bgp.0"
|
||||
if v, ok := d.GetOk(prefix + ".asn"); ok {
|
||||
asn := v.(int)
|
||||
bgp := &compute.RouterBgp{
|
||||
Asn: int64(asn),
|
||||
}
|
||||
router.Bgp = bgp
|
||||
}
|
||||
}
|
||||
|
||||
op, err := routersService.Insert(project, region, router).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Inserting Router %s into network %s: %s", name, network, err)
|
||||
}
|
||||
d.SetId(fmt.Sprintf("%s/%s", region, name))
|
||||
err = computeOperationWaitRegion(config, op, project, region, "Inserting Router")
|
||||
if err != nil {
|
||||
d.SetId("")
|
||||
return fmt.Errorf("Error Waiting to Insert Router %s into network %s: %s", name, network, err)
|
||||
}
|
||||
|
||||
return resourceComputeRouterRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceComputeRouterRead(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, name).Do()
|
||||
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing router %s/%s because it is gone", region, name)
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error Reading Router %s: %s", name, err)
|
||||
}
|
||||
|
||||
d.Set("self_link", router.SelfLink)
|
||||
d.Set("network", router.Network)
|
||||
|
||||
d.Set("name", router.Name)
|
||||
d.Set("description", router.Description)
|
||||
d.Set("region", region)
|
||||
d.Set("project", project)
|
||||
d.Set("bgp", flattenAsn(router.Bgp.Asn))
|
||||
d.SetId(fmt.Sprintf("%s/%s", region, name))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeRouterDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
routerLock := getRouterLockName(region, name)
|
||||
mutexKV.Lock(routerLock)
|
||||
defer mutexKV.Unlock(routerLock)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
|
||||
op, err := routersService.Delete(project, region, name).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Reading Router %s: %s", name, err)
|
||||
}
|
||||
|
||||
err = computeOperationWaitRegion(config, op, project, region, "Deleting Router")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Waiting to Delete Router %s: %s", name, err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeRouterImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
parts := strings.Split(d.Id(), "/")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("Invalid router specifier. Expecting {region}/{name}")
|
||||
}
|
||||
|
||||
d.Set("region", parts[0])
|
||||
d.Set("name", parts[1])
|
||||
|
||||
return []*schema.ResourceData{d}, nil
|
||||
}
|
||||
|
||||
func getRouterLink(config *Config, project string, region string, router string) (string, error) {
|
||||
|
||||
if !strings.HasPrefix(router, "https://www.googleapis.com/compute/") {
|
||||
// Router value provided is just the name, lookup the router SelfLink
|
||||
routerData, err := config.clientCompute.Routers.Get(
|
||||
project, region, router).Do()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error reading router: %s", err)
|
||||
}
|
||||
router = routerData.SelfLink
|
||||
}
|
||||
|
||||
return router, nil
|
||||
|
||||
}
|
||||
|
||||
func flattenAsn(asn int64) []map[string]interface{} {
|
||||
result := make([]map[string]interface{}, 0, 1)
|
||||
r := make(map[string]interface{})
|
||||
r["asn"] = asn
|
||||
result = append(result, r)
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
func resourceComputeRouterInterface() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeRouterInterfaceCreate,
|
||||
Read: resourceComputeRouterInterfaceRead,
|
||||
Delete: resourceComputeRouterInterfaceDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: resourceComputeRouterInterfaceImportState,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"router": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"vpn_tunnel": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
DiffSuppressFunc: linkDiffSuppress,
|
||||
},
|
||||
|
||||
"ip_range": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"project": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"region": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceComputeRouterInterfaceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routerName := d.Get("router").(string)
|
||||
ifaceName := d.Get("name").(string)
|
||||
|
||||
routerLock := getRouterLockName(region, routerName)
|
||||
mutexKV.Lock(routerLock)
|
||||
defer mutexKV.Unlock(routerLock)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing router interface %s because its router %s/%s is gone", ifaceName, region, routerName)
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
ifaces := router.Interfaces
|
||||
for _, iface := range ifaces {
|
||||
if iface.Name == ifaceName {
|
||||
d.SetId("")
|
||||
return fmt.Errorf("Router %s has interface %s already", routerName, ifaceName)
|
||||
}
|
||||
}
|
||||
|
||||
vpnTunnel, err := getVpnTunnelLink(config, project, region, d.Get("vpn_tunnel").(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iface := &compute.RouterInterface{Name: ifaceName,
|
||||
LinkedVpnTunnel: vpnTunnel}
|
||||
|
||||
if v, ok := d.GetOk("ip_range"); ok {
|
||||
iface.IpRange = v.(string)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Adding interface %s", ifaceName)
|
||||
ifaces = append(ifaces, iface)
|
||||
patchRouter := &compute.Router{
|
||||
Interfaces: ifaces,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Updating router %s/%s with interfaces: %+v", region, routerName, ifaces)
|
||||
op, err := routersService.Patch(project, region, router.Name, patchRouter).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error patching router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, ifaceName))
|
||||
err = computeOperationWaitRegion(config, op, project, region, "Patching router")
|
||||
if err != nil {
|
||||
d.SetId("")
|
||||
return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
return resourceComputeRouterInterfaceRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceComputeRouterInterfaceRead(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routerName := d.Get("router").(string)
|
||||
ifaceName := d.Get("name").(string)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing router interface %s because its router %s/%s is gone", ifaceName, region, routerName)
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
for _, iface := range router.Interfaces {
|
||||
|
||||
if iface.Name == ifaceName {
|
||||
d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, ifaceName))
|
||||
d.Set("vpn_tunnel", iface.LinkedVpnTunnel)
|
||||
d.Set("ip_range", iface.IpRange)
|
||||
d.Set("region", region)
|
||||
d.Set("project", project)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[WARN] Removing router interface %s/%s/%s because it is gone", region, routerName, ifaceName)
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeRouterInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routerName := d.Get("router").(string)
|
||||
ifaceName := d.Get("name").(string)
|
||||
|
||||
routerLock := getRouterLockName(region, routerName)
|
||||
mutexKV.Lock(routerLock)
|
||||
defer mutexKV.Unlock(routerLock)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing router interface %s because its router %s/%s is gone", ifaceName, region, routerName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error Reading Router %s: %s", routerName, err)
|
||||
}
|
||||
|
||||
var ifaceFound bool
|
||||
|
||||
newIfaces := make([]*compute.RouterInterface, 0, len(router.Interfaces))
|
||||
for _, iface := range router.Interfaces {
|
||||
|
||||
if iface.Name == ifaceName {
|
||||
ifaceFound = true
|
||||
continue
|
||||
} else {
|
||||
newIfaces = append(newIfaces, iface)
|
||||
}
|
||||
}
|
||||
|
||||
if !ifaceFound {
|
||||
log.Printf("[DEBUG] Router %s/%s had no interface %s already", region, routerName, ifaceName)
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"[INFO] Removing interface %s from router %s/%s", ifaceName, region, routerName)
|
||||
patchRouter := &compute.Router{
|
||||
Interfaces: newIfaces,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Updating router %s/%s with interfaces: %+v", region, routerName, newIfaces)
|
||||
op, err := routersService.Patch(project, region, router.Name, patchRouter).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error patching router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
err = computeOperationWaitRegion(config, op, project, region, "Patching router")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeRouterInterfaceImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
parts := strings.Split(d.Id(), "/")
|
||||
if len(parts) != 3 {
|
||||
return nil, fmt.Errorf("Invalid router interface specifier. Expecting {region}/{router}/{interface}")
|
||||
}
|
||||
|
||||
d.Set("region", parts[0])
|
||||
d.Set("router", parts[1])
|
||||
d.Set("name", parts[2])
|
||||
|
||||
return []*schema.ResourceData{d}, nil
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccComputeRouterInterface_basic(t *testing.T) {
|
||||
testId := acctest.RandString(10)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeRouterInterfaceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterInterfaceBasic(testId),
|
||||
Check: testAccCheckComputeRouterInterfaceExists(
|
||||
"google_compute_router_interface.foobar"),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterInterfaceKeepRouter(testId),
|
||||
Check: testAccCheckComputeRouterInterfaceDelete(
|
||||
"google_compute_router_interface.foobar"),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckComputeRouterInterfaceDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_compute_router" {
|
||||
continue
|
||||
}
|
||||
|
||||
project, err := getTestProject(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region, err := getTestRegion(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routerName := rs.Primary.Attributes["router"]
|
||||
|
||||
_, err = routersService.Get(project, region, routerName).Do()
|
||||
|
||||
if err == nil {
|
||||
return fmt.Errorf("Error, Router %s in region %s still exists",
|
||||
routerName, region)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckComputeRouterInterfaceDelete(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_compute_router_interface" {
|
||||
continue
|
||||
}
|
||||
|
||||
project, err := getTestProject(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region, err := getTestRegion(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := rs.Primary.Attributes["name"]
|
||||
routerName := rs.Primary.Attributes["router"]
|
||||
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Reading Router %s: %s", routerName, err)
|
||||
}
|
||||
|
||||
ifaces := router.Interfaces
|
||||
for _, iface := range ifaces {
|
||||
|
||||
if iface.Name == name {
|
||||
return fmt.Errorf("Interface %s still exists on router %s/%s", name, region, router.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckComputeRouterInterfaceExists(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)
|
||||
|
||||
project, err := getTestProject(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region, err := getTestRegion(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := rs.Primary.Attributes["name"]
|
||||
routerName := rs.Primary.Attributes["router"]
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Reading Router %s: %s", routerName, err)
|
||||
}
|
||||
|
||||
for _, iface := range router.Interfaces {
|
||||
|
||||
if iface.Name == name {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("Interface %s not found for router %s", name, router.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func testAccComputeRouterInterfaceBasic(testId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
}
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "us-central1"
|
||||
}
|
||||
resource "google_compute_address" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_vpn_gateway" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_esp" {
|
||||
name = "router-interface-test-%s-1"
|
||||
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 = "router-interface-test-%s-2"
|
||||
region = "${google_compute_forwarding_rule.foobar_esp.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "500-500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_udp4500" {
|
||||
name = "router-interface-test-%s-3"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "4500-4500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_router" "foobar"{
|
||||
name = "router-interface-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
bgp {
|
||||
asn = 64514
|
||||
}
|
||||
}
|
||||
resource "google_compute_vpn_tunnel" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp4500.region}"
|
||||
target_vpn_gateway = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
shared_secret = "unguessable"
|
||||
peer_ip = "8.8.8.8"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
}
|
||||
resource "google_compute_router_interface" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
region = "${google_compute_router.foobar.region}"
|
||||
ip_range = "169.254.3.1/30"
|
||||
vpn_tunnel = "${google_compute_vpn_tunnel.foobar.name}"
|
||||
}
|
||||
`, testId, testId, testId, testId, testId, testId, testId, testId, testId, testId)
|
||||
}
|
||||
|
||||
func testAccComputeRouterInterfaceKeepRouter(testId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
}
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "us-central1"
|
||||
}
|
||||
resource "google_compute_address" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_vpn_gateway" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_esp" {
|
||||
name = "router-interface-test-%s-1"
|
||||
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 = "router-interface-test-%s-2"
|
||||
region = "${google_compute_forwarding_rule.foobar_esp.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "500-500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_udp4500" {
|
||||
name = "router-interface-test-%s-3"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "4500-4500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_router" "foobar"{
|
||||
name = "router-interface-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
bgp {
|
||||
asn = 64514
|
||||
}
|
||||
}
|
||||
resource "google_compute_vpn_tunnel" "foobar" {
|
||||
name = "router-interface-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp4500.region}"
|
||||
target_vpn_gateway = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
shared_secret = "unguessable"
|
||||
peer_ip = "8.8.8.8"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
}
|
||||
`, testId, testId, testId, testId, testId, testId, testId, testId, testId)
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
func resourceComputeRouterPeer() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeRouterPeerCreate,
|
||||
Read: resourceComputeRouterPeerRead,
|
||||
Delete: resourceComputeRouterPeerDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: resourceComputeRouterPeerImportState,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"router": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"interface": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"peer_ip_address": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"peer_asn": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"advertised_route_priority": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"ip_address": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"project": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"region": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceComputeRouterPeerCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routerName := d.Get("router").(string)
|
||||
peerName := d.Get("name").(string)
|
||||
|
||||
routerLock := getRouterLockName(region, routerName)
|
||||
mutexKV.Lock(routerLock)
|
||||
defer mutexKV.Unlock(routerLock)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing router peer %s because its router %s/%s is gone", peerName, region, routerName)
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
peers := router.BgpPeers
|
||||
for _, peer := range peers {
|
||||
if peer.Name == peerName {
|
||||
d.SetId("")
|
||||
return fmt.Errorf("Router %s has peer %s already", routerName, peerName)
|
||||
}
|
||||
}
|
||||
|
||||
ifaceName := d.Get("interface").(string)
|
||||
|
||||
peer := &compute.RouterBgpPeer{Name: peerName,
|
||||
InterfaceName: ifaceName}
|
||||
|
||||
if v, ok := d.GetOk("peer_ip_address"); ok {
|
||||
peer.PeerIpAddress = v.(string)
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("peer_asn"); ok {
|
||||
peer.PeerAsn = int64(v.(int))
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("advertised_route_priority"); ok {
|
||||
peer.AdvertisedRoutePriority = int64(v.(int))
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Adding peer %s", peerName)
|
||||
peers = append(peers, peer)
|
||||
patchRouter := &compute.Router{
|
||||
BgpPeers: peers,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Updating router %s/%s with peers: %+v", region, routerName, peers)
|
||||
op, err := routersService.Patch(project, region, router.Name, patchRouter).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error patching router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, peerName))
|
||||
err = computeOperationWaitRegion(config, op, project, region, "Patching router")
|
||||
if err != nil {
|
||||
d.SetId("")
|
||||
return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
return resourceComputeRouterPeerRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceComputeRouterPeerRead(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routerName := d.Get("router").(string)
|
||||
peerName := d.Get("name").(string)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing router peer %s because its router %s/%s is gone", peerName, region, routerName)
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
for _, peer := range router.BgpPeers {
|
||||
|
||||
if peer.Name == peerName {
|
||||
d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, peerName))
|
||||
d.Set("interface", peer.InterfaceName)
|
||||
d.Set("peer_ip_address", peer.PeerIpAddress)
|
||||
d.Set("peer_asn", peer.PeerAsn)
|
||||
d.Set("advertised_route_priority", peer.AdvertisedRoutePriority)
|
||||
d.Set("ip_address", peer.IpAddress)
|
||||
d.Set("region", region)
|
||||
d.Set("project", project)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[WARN] Removing router peer %s/%s/%s because it is gone", region, routerName, peerName)
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeRouterPeerDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
|
||||
config := meta.(*Config)
|
||||
|
||||
region, err := getRegion(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routerName := d.Get("router").(string)
|
||||
peerName := d.Get("name").(string)
|
||||
|
||||
routerLock := getRouterLockName(region, routerName)
|
||||
mutexKV.Lock(routerLock)
|
||||
defer mutexKV.Unlock(routerLock)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing router peer %s because its router %s/%s is gone", peerName, region, routerName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error Reading Router %s: %s", routerName, err)
|
||||
}
|
||||
|
||||
var newPeers []*compute.RouterBgpPeer = make([]*compute.RouterBgpPeer, 0, len(router.BgpPeers))
|
||||
for _, peer := range router.BgpPeers {
|
||||
if peer.Name == peerName {
|
||||
continue
|
||||
} else {
|
||||
newPeers = append(newPeers, peer)
|
||||
}
|
||||
}
|
||||
|
||||
if len(newPeers) == len(router.BgpPeers) {
|
||||
log.Printf("[DEBUG] Router %s/%s had no peer %s already", region, routerName, peerName)
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"[INFO] Removing peer %s from router %s/%s", peerName, region, routerName)
|
||||
patchRouter := &compute.Router{
|
||||
BgpPeers: newPeers,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Updating router %s/%s with peers: %+v", region, routerName, newPeers)
|
||||
op, err := routersService.Patch(project, region, router.Name, patchRouter).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error patching router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
err = computeOperationWaitRegion(config, op, project, region, "Patching router")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeRouterPeerImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
parts := strings.Split(d.Id(), "/")
|
||||
if len(parts) != 3 {
|
||||
return nil, fmt.Errorf("Invalid router peer specifier. Expecting {region}/{router}/{peer}")
|
||||
}
|
||||
|
||||
d.Set("region", parts[0])
|
||||
d.Set("router", parts[1])
|
||||
d.Set("name", parts[2])
|
||||
|
||||
return []*schema.ResourceData{d}, nil
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccComputeRouterPeer_basic(t *testing.T) {
|
||||
testId := acctest.RandString(10)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeRouterPeerDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterPeerBasic(testId),
|
||||
Check: testAccCheckComputeRouterPeerExists(
|
||||
"google_compute_router_peer.foobar"),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterPeerKeepRouter(testId),
|
||||
Check: testAccCheckComputeRouterPeerDelete(
|
||||
"google_compute_router_peer.foobar"),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckComputeRouterPeerDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_compute_router" {
|
||||
continue
|
||||
}
|
||||
|
||||
project, err := getTestProject(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region, err := getTestRegion(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routerName := rs.Primary.Attributes["router"]
|
||||
|
||||
_, err = routersService.Get(project, region, routerName).Do()
|
||||
|
||||
if err == nil {
|
||||
return fmt.Errorf("Error, Router %s in region %s still exists",
|
||||
routerName, region)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckComputeRouterPeerDelete(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_compute_router_peer" {
|
||||
continue
|
||||
}
|
||||
|
||||
project, err := getTestProject(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region, err := getTestRegion(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := rs.Primary.Attributes["name"]
|
||||
routerName := rs.Primary.Attributes["router"]
|
||||
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Reading Router %s: %s", routerName, err)
|
||||
}
|
||||
|
||||
peers := router.BgpPeers
|
||||
for _, peer := range peers {
|
||||
|
||||
if peer.Name == name {
|
||||
return fmt.Errorf("Peer %s still exists on router %s/%s", name, region, router.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckComputeRouterPeerExists(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)
|
||||
|
||||
project, err := getTestProject(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region, err := getTestRegion(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := rs.Primary.Attributes["name"]
|
||||
routerName := rs.Primary.Attributes["router"]
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
router, err := routersService.Get(project, region, routerName).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Reading Router %s: %s", routerName, err)
|
||||
}
|
||||
|
||||
for _, peer := range router.BgpPeers {
|
||||
|
||||
if peer.Name == name {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("Peer %s not found for router %s", name, router.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func testAccComputeRouterPeerBasic(testId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
}
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "us-central1"
|
||||
}
|
||||
resource "google_compute_address" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_vpn_gateway" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_esp" {
|
||||
name = "router-peer-test-%s-1"
|
||||
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 = "router-peer-test-%s-2"
|
||||
region = "${google_compute_forwarding_rule.foobar_esp.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "500-500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_udp4500" {
|
||||
name = "router-peer-test-%s-3"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "4500-4500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_router" "foobar"{
|
||||
name = "router-peer-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
bgp {
|
||||
asn = 64514
|
||||
}
|
||||
}
|
||||
resource "google_compute_vpn_tunnel" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp4500.region}"
|
||||
target_vpn_gateway = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
shared_secret = "unguessable"
|
||||
peer_ip = "8.8.8.8"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
}
|
||||
resource "google_compute_router_interface" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
region = "${google_compute_router.foobar.region}"
|
||||
ip_range = "169.254.3.1/30"
|
||||
vpn_tunnel = "${google_compute_vpn_tunnel.foobar.name}"
|
||||
}
|
||||
resource "google_compute_router_peer" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
region = "${google_compute_router.foobar.region}"
|
||||
peer_ip_address = "169.254.3.2"
|
||||
peer_asn = 65515
|
||||
advertised_route_priority = 100
|
||||
interface = "${google_compute_router_interface.foobar.name}"
|
||||
}
|
||||
`, testId, testId, testId, testId, testId, testId, testId, testId, testId, testId, testId)
|
||||
}
|
||||
|
||||
func testAccComputeRouterPeerKeepRouter(testId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
}
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "us-central1"
|
||||
}
|
||||
resource "google_compute_address" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_vpn_gateway" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_esp" {
|
||||
name = "router-peer-test-%s-1"
|
||||
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 = "router-peer-test-%s-2"
|
||||
region = "${google_compute_forwarding_rule.foobar_esp.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "500-500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_udp4500" {
|
||||
name = "router-peer-test-%s-3"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "4500-4500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_router" "foobar"{
|
||||
name = "router-peer-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
bgp {
|
||||
asn = 64514
|
||||
}
|
||||
}
|
||||
resource "google_compute_vpn_tunnel" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp4500.region}"
|
||||
target_vpn_gateway = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
shared_secret = "unguessable"
|
||||
peer_ip = "8.8.8.8"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
}
|
||||
resource "google_compute_router_interface" "foobar" {
|
||||
name = "router-peer-test-%s"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
region = "${google_compute_router.foobar.region}"
|
||||
ip_range = "169.254.3.1/30"
|
||||
vpn_tunnel = "${google_compute_vpn_tunnel.foobar.name}"
|
||||
}
|
||||
`, testId, testId, testId, testId, testId, testId, testId, testId, testId, testId)
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccComputeRouter_basic(t *testing.T) {
|
||||
resourceRegion := "europe-west1"
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeRouterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterBasic(resourceRegion),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeRouterExists(
|
||||
"google_compute_router.foobar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"google_compute_router.foobar", "region", resourceRegion),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccComputeRouter_noRegion(t *testing.T) {
|
||||
providerRegion := "us-central1"
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeRouterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterNoRegion(providerRegion),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeRouterExists(
|
||||
"google_compute_router.foobar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"google_compute_router.foobar", "region", providerRegion),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccComputeRouter_networkLink(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeRouterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeRouterNetworkLink(),
|
||||
Check: testAccCheckComputeRouterExists(
|
||||
"google_compute_router.foobar"),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckComputeRouterDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_compute_router" {
|
||||
continue
|
||||
}
|
||||
|
||||
project, err := getTestProject(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region, err := getTestRegion(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := rs.Primary.Attributes["name"]
|
||||
|
||||
_, err = routersService.Get(project, region, name).Do()
|
||||
|
||||
if err == nil {
|
||||
return fmt.Errorf("Error, Router %s in region %s still exists",
|
||||
name, region)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckComputeRouterExists(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)
|
||||
|
||||
project, err := getTestProject(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
region, err := getTestRegion(rs.Primary, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := rs.Primary.Attributes["name"]
|
||||
|
||||
routersService := config.clientCompute.Routers
|
||||
_, err = routersService.Get(project, region, name).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Reading Router %s: %s", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccComputeRouterBasic(resourceRegion string) string {
|
||||
testId := acctest.RandString(10)
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "router-test-%s"
|
||||
}
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "router-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "%s"
|
||||
}
|
||||
resource "google_compute_router" "foobar" {
|
||||
name = "router-test-%s"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
network = "${google_compute_network.foobar.name}"
|
||||
bgp {
|
||||
asn = 64514
|
||||
}
|
||||
}
|
||||
`, testId, testId, resourceRegion, testId)
|
||||
}
|
||||
|
||||
func testAccComputeRouterNoRegion(providerRegion string) string {
|
||||
testId := acctest.RandString(10)
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "router-test-%s"
|
||||
}
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "router-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "%s"
|
||||
}
|
||||
resource "google_compute_router" "foobar" {
|
||||
name = "router-test-%s"
|
||||
network = "${google_compute_network.foobar.name}"
|
||||
bgp {
|
||||
asn = 64514
|
||||
}
|
||||
}
|
||||
`, testId, testId, providerRegion, testId)
|
||||
}
|
||||
|
||||
func testAccComputeRouterNetworkLink() string {
|
||||
testId := acctest.RandString(10)
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "router-test-%s"
|
||||
}
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "router-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "europe-west1"
|
||||
}
|
||||
resource "google_compute_router" "foobar" {
|
||||
name = "router-test-%s"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
bgp {
|
||||
asn = 64514
|
||||
}
|
||||
}
|
||||
`, testId, testId, testId)
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
|
||||
|
@ -75,6 +76,7 @@ func resourceComputeVpnTunnel() *schema.Resource {
|
|||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: schema.HashString,
|
||||
},
|
||||
|
@ -91,6 +93,12 @@ func resourceComputeVpnTunnel() *schema.Resource {
|
|||
ForceNew: true,
|
||||
},
|
||||
|
||||
"router": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
|
@ -155,6 +163,14 @@ func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) er
|
|||
vpnTunnel.Description = v.(string)
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("router"); ok {
|
||||
routerLink, err := getRouterLink(config, project, region, v.(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vpnTunnel.Router = routerLink
|
||||
}
|
||||
|
||||
op, err := vpnTunnelsService.Insert(project, region, vpnTunnel).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error Inserting VPN Tunnel %s : %s", name, err)
|
||||
|
@ -325,3 +341,33 @@ var invalidPeerAddrs = []struct {
|
|||
to: net.ParseIP("255.255.255.255"),
|
||||
},
|
||||
}
|
||||
|
||||
func getVpnTunnelLink(config *Config, project string, region string, tunnel string) (string, error) {
|
||||
|
||||
if !strings.HasPrefix(tunnel, "https://www.googleapis.com/compute/") {
|
||||
// Tunnel value provided is just the name, lookup the tunnel SelfLink
|
||||
tunnelData, err := config.clientCompute.VpnTunnels.Get(
|
||||
project, region, tunnel).Do()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error reading tunnel: %s", err)
|
||||
}
|
||||
tunnel = tunnelData.SelfLink
|
||||
}
|
||||
|
||||
return tunnel, nil
|
||||
|
||||
}
|
||||
|
||||
func getVpnTunnelName(vpntunnel string) (string, error) {
|
||||
|
||||
if strings.HasPrefix(vpntunnel, "https://www.googleapis.com/compute/") {
|
||||
// extract the VPN tunnel name from SelfLink URL
|
||||
vpntunnelName := vpntunnel[strings.LastIndex(vpntunnel, "/")+1:]
|
||||
if vpntunnelName == "" {
|
||||
return "", fmt.Errorf("VPN tunnel url not valid")
|
||||
}
|
||||
return vpntunnelName, nil
|
||||
}
|
||||
|
||||
return vpntunnel, nil
|
||||
}
|
||||
|
|
|
@ -32,6 +32,26 @@ func TestAccComputeVpnTunnel_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccComputeVpnTunnel_router(t *testing.T) {
|
||||
router := fmt.Sprintf("tunnel-test-router-%s", acctest.RandString(10))
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeVpnTunnelDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeVpnTunnelRouter(router),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeVpnTunnelExists(
|
||||
"google_compute_vpn_tunnel.foobar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"google_compute_vpn_tunnel.foobar", "router", router),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccComputeVpnTunnel_defaultTrafficSelectors(t *testing.T) {
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
|
@ -154,6 +174,69 @@ resource "google_compute_vpn_tunnel" "foobar" {
|
|||
acctest.RandString(10), acctest.RandString(10), acctest.RandString(10),
|
||||
acctest.RandString(10), acctest.RandString(10))
|
||||
|
||||
func testAccComputeVpnTunnelRouter(router string) string {
|
||||
testId := acctest.RandString(10)
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "tunnel-test-%s"
|
||||
}
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "tunnel-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "us-central1"
|
||||
}
|
||||
resource "google_compute_address" "foobar" {
|
||||
name = "tunnel-test-%s"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_vpn_gateway" "foobar" {
|
||||
name = "tunnel-test-%s"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_esp" {
|
||||
name = "tunnel-test-%s-1"
|
||||
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 = "tunnel-test-%s-2"
|
||||
region = "${google_compute_forwarding_rule.foobar_esp.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "500-500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_forwarding_rule" "foobar_udp4500" {
|
||||
name = "tunnel-test-%s-3"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "4500-4500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
resource "google_compute_router" "foobar"{
|
||||
name = "%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
bgp {
|
||||
asn = 64514
|
||||
}
|
||||
}
|
||||
resource "google_compute_vpn_tunnel" "foobar" {
|
||||
name = "tunnel-test-%s"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp4500.region}"
|
||||
target_vpn_gateway = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
shared_secret = "unguessable"
|
||||
peer_ip = "8.8.8.8"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
}
|
||||
`, testId, testId, testId, testId, testId, testId, testId, router, testId)
|
||||
}
|
||||
|
||||
var testAccComputeVpnTunnelDefaultTrafficSelectors = fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "tunnel-test-%s"
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_compute_router"
|
||||
sidebar_current: "docs-google-compute-router"
|
||||
description: |-
|
||||
Manages a Cloud Router resource.
|
||||
---
|
||||
|
||||
# google\_compute\_router
|
||||
|
||||
Manages a Cloud Router resource. For more info, read the
|
||||
[documentation](https://cloud.google.com/compute/docs/cloudrouter).
|
||||
|
||||
## Example Usage
|
||||
|
||||
```hcl
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "network-1"
|
||||
}
|
||||
|
||||
resource "google_compute_subnetwork" "foobar" {
|
||||
name = "subnet-1"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
ip_cidr_range = "10.0.0.0/16"
|
||||
region = "us-central1"
|
||||
}
|
||||
|
||||
resource "google_compute_address" "foobar" {
|
||||
name = "vpn-gateway-1-address"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
|
||||
resource "google_compute_vpn_gateway" "foobar" {
|
||||
name = "vpn-gateway-1"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
region = "${google_compute_subnetwork.foobar.region}"
|
||||
}
|
||||
|
||||
resource "google_compute_forwarding_rule" "foobar_esp" {
|
||||
name = "vpn-gw-1-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 = "vpn-gw-1-udp-500"
|
||||
region = "${google_compute_forwarding_rule.foobar_esp.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "500-500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
|
||||
resource "google_compute_forwarding_rule" "foobar_udp4500" {
|
||||
name = "vpn-gw-1-udp-4500"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
ip_protocol = "UDP"
|
||||
port_range = "4500-4500"
|
||||
ip_address = "${google_compute_address.foobar.address}"
|
||||
target = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
}
|
||||
|
||||
resource "google_compute_router" "foobar" {
|
||||
name = "router-1"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
|
||||
network = "${google_compute_network.foobar.self_link}"
|
||||
|
||||
bgp {
|
||||
asn = 64512
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_vpn_tunnel" "foobar" {
|
||||
name = "vpn-tunnel-1"
|
||||
region = "${google_compute_forwarding_rule.foobar_udp4500.region}"
|
||||
target_vpn_gateway = "${google_compute_vpn_gateway.foobar.self_link}"
|
||||
shared_secret = "unguessable"
|
||||
peer_ip = "8.8.8.8"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
}
|
||||
|
||||
resource "google_compute_router_interface" "foobar" {
|
||||
name = "interface-1"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
region = "${google_compute_router.foobar.region}"
|
||||
ip_range = "169.254.1.1/30"
|
||||
vpn_tunnel = "${google_compute_vpn_tunnel.foobar.name}"
|
||||
}
|
||||
|
||||
resource "google_compute_router_peer" "foobar" {
|
||||
name = "peer-1"
|
||||
router = "${google_compute_router.foobar.name}"
|
||||
region = "${google_compute_router.foobar.region}"
|
||||
peer_ip_address = "169.254.1.2"
|
||||
peer_asn = 65513
|
||||
advertised_route_priority = 100
|
||||
interface = "${google_compute_router_interface.foobar.name}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) A unique name for the router, required by GCE. Changing
|
||||
this forces a new router to be created.
|
||||
|
||||
* `network` - (Required) The name or resource link to the network this Cloud Router
|
||||
will use to learn and announce routes. Changing this forces a new router to be created.
|
||||
|
||||
* `bgp` - (Required) BGP information specific to this router.
|
||||
Changing this forces a new router to be created.
|
||||
Structure is documented below.
|
||||
|
||||
- - -
|
||||
|
||||
* `description` - (Optional) A description of the resource.
|
||||
Changing this forces a new router to be created.
|
||||
|
||||
* `project` - (Optional) The project in which the resource belongs. If it
|
||||
is not provided, the provider project is used.
|
||||
Changing this forces a new router to be created.
|
||||
|
||||
* `region` - (Optional) The region this router should sit in. If not specified,
|
||||
the project region will be used. Changing this forces a new router to be
|
||||
created.
|
||||
|
||||
- - -
|
||||
|
||||
The `bgp` block supports:
|
||||
|
||||
* `asn` - (Required) Local BGP Autonomous System Number (ASN). Must be an
|
||||
RFC6996 private ASN.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
In addition to the arguments listed above, the following computed attributes are
|
||||
exported:
|
||||
|
||||
* `self_link` - The URI of the created resource.
|
||||
|
||||
## Import
|
||||
|
||||
Routers can be imported using the `region` and `name`, e.g.
|
||||
|
||||
```
|
||||
$ terraform import google_compute_router.router-1 us-central1/router-1
|
||||
```
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_compute_router_interface"
|
||||
sidebar_current: "docs-google-compute-router-interface"
|
||||
description: |-
|
||||
Manages a Cloud Router interface.
|
||||
---
|
||||
|
||||
# google\_compute\_router_interface
|
||||
|
||||
Manages a Cloud Router interface. For more info, read the
|
||||
[documentation](https://cloud.google.com/compute/docs/cloudrouter).
|
||||
|
||||
## Example Usage
|
||||
|
||||
```hcl
|
||||
resource "google_compute_router_interface" "foobar" {
|
||||
name = "interface-1"
|
||||
router = "router-1"
|
||||
region = "us-central1"
|
||||
ip_range = "169.254.1.1/30"
|
||||
vpn_tunnel = "tunnel-1"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) A unique name for the interface, required by GCE. Changing
|
||||
this forces a new interface to be created.
|
||||
|
||||
* `router` - (Required) The name of the router this interface will be attached to.
|
||||
Changing this forces a new interface to be created.
|
||||
|
||||
* `vpn_tunnel` - (Required) The name or resource link to the VPN tunnel this
|
||||
interface will be linked to. Changing this forces a new interface to be created.
|
||||
|
||||
- - -
|
||||
|
||||
* `ip_range` - (Optional) IP address and range of the interface. The IP range must be
|
||||
in the RFC3927 link-local IP space. Changing this forces a new interface to be created.
|
||||
|
||||
* `project` - (Optional) The project in which this interface's router belongs. If it
|
||||
is not provided, the provider project is used. Changing this forces a new interface to be created.
|
||||
|
||||
* `region` - (Optional) The region this interface's router sits in. If not specified,
|
||||
the project region will be used. Changing this forces a new interface to be
|
||||
created.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
Only the arguments listed above are exposed as attributes.
|
||||
|
||||
## Import
|
||||
|
||||
Router interfaces can be imported using the `region`, `router` and `name`, e.g.
|
||||
|
||||
```
|
||||
$ terraform import google_compute_router_interface.interface-1 us-central1/router-1/interface-1
|
||||
```
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_compute_router_peer"
|
||||
sidebar_current: "docs-google-compute-router-peer"
|
||||
description: |-
|
||||
Manages a Cloud Router BGP peer.
|
||||
---
|
||||
|
||||
# google\_compute\_router
|
||||
|
||||
Manages a Cloud Router BGP peer. For more info, read the
|
||||
[documentation](https://cloud.google.com/compute/docs/cloudrouter).
|
||||
|
||||
## Example Usage
|
||||
|
||||
```hcl
|
||||
resource "google_compute_router_peer" "foobar" {
|
||||
name = "peer-1"
|
||||
router = "router-1"
|
||||
region = "us-central1"
|
||||
peer_ip_address = "169.254.1.2"
|
||||
peer_asn = 65513
|
||||
advertised_route_priority = 100
|
||||
interface = "interface-1"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) A unique name for BGP peer, required by GCE. Changing
|
||||
this forces a new peer to be created.
|
||||
|
||||
* `router` - (Required) The name of the router in which this BGP peer will be configured.
|
||||
Changing this forces a new peer to be created.
|
||||
|
||||
* `interface` - (Required) The name of the interface the BGP peer is associated with.
|
||||
Changing this forces a new peer to be created.
|
||||
|
||||
* `peer_ip_address` - (Required) IP address of the BGP interface outside Google Cloud.
|
||||
Changing this forces a new peer to be created.
|
||||
|
||||
* `peer_asn` - (Required) Peer BGP Autonomous System Number (ASN).
|
||||
Changing this forces a new peer to be created.
|
||||
|
||||
- - -
|
||||
|
||||
* `advertised_route_priority` - (Optional) The priority of routes advertised to this BGP peer.
|
||||
Changing this forces a new peer to be created.
|
||||
|
||||
* `project` - (Optional) The project in which this peer's router belongs. If it
|
||||
is not provided, the provider project is used. Changing this forces a new peer to be created.
|
||||
|
||||
* `region` - (Optional) The region this peer's router sits in. If not specified,
|
||||
the project region will be used. Changing this forces a new peer to be
|
||||
created.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
In addition to the arguments listed above, the following computed attributes are
|
||||
exported:
|
||||
|
||||
* `ip_address` - IP address of the interface inside Google Cloud Platform.
|
||||
|
||||
## Import
|
||||
|
||||
Router BGP peers can be imported using the `region`, `router` and `name`, e.g.
|
||||
|
||||
```
|
||||
$ terraform import google_compute_router_peer.peer-1 us-central1/router-1/peer-1
|
||||
```
|
|
@ -120,6 +120,10 @@ The following arguments are supported:
|
|||
custom subnetted network. Refer to Google documentation for more
|
||||
information.
|
||||
|
||||
* `router` - (Optional) Name of a Cloud Router in the same region
|
||||
to be used for dynamic routing. Refer to Google documentation for more
|
||||
information.
|
||||
|
||||
* `project` - (Optional) The project in which the resource belongs. If it
|
||||
is not provided, the provider project is used.
|
||||
|
||||
|
|
|
@ -150,10 +150,22 @@
|
|||
<a href="/docs/providers/google/r/compute_route.html">google_compute_route</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-compute-router") %>>
|
||||
<a href="/docs/providers/google/r/compute_router.html">google_compute_router</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-compute-router-interface") %>>
|
||||
<a href="/docs/providers/google/r/compute_router_interface.html">google_compute_router_interface</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-compute-router-peer") %>>
|
||||
<a href="/docs/providers/google/r/compute_router_peer.html">google_compute_router_peer</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-compute-snapshot") %>>
|
||||
<a href="/docs/providers/google/r/compute_snapshot.html">google_compute_snapshot</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li<%= sidebar_current("docs-google-compute-ssl-certificate") %>>
|
||||
<a href="/docs/providers/google/r/compute_ssl_certificate.html">google_compute_ssl_certificate</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue