diff --git a/google-beta/provider_compute_gen.go b/google-beta/provider_compute_gen.go index 6bb78f7c52..f95fd6a5e6 100644 --- a/google-beta/provider_compute_gen.go +++ b/google-beta/provider_compute_gen.go @@ -53,6 +53,7 @@ var GeneratedComputeResourcesMap = map[string]*schema.Resource{ "google_compute_target_ssl_proxy": resourceComputeTargetSslProxy(), "google_compute_target_tcp_proxy": resourceComputeTargetTcpProxy(), "google_compute_vpn_gateway": resourceComputeVpnGateway(), + "google_compute_ha_vpn_gateway": resourceComputeHaVpnGateway(), "google_compute_url_map": resourceComputeUrlMap(), "google_compute_vpn_tunnel": resourceComputeVpnTunnel(), } diff --git a/google-beta/resource_compute_ha_vpn_gateway.go b/google-beta/resource_compute_ha_vpn_gateway.go new file mode 100644 index 0000000000..4419337485 --- /dev/null +++ b/google-beta/resource_compute_ha_vpn_gateway.go @@ -0,0 +1,343 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "strconv" + "time" + + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/compute/v1" +) + +func resourceComputeHaVpnGateway() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeHaVpnGatewayCreate, + Read: resourceComputeHaVpnGatewayRead, + Delete: resourceComputeHaVpnGatewayDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeHaVpnGatewayImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateGCPName, + }, + "network": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "vpn_interfaces": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeInt, + Optional: true, + }, + "ip_address": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceComputeHaVpnGatewayCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + descriptionProp, err := expandComputeHaVpnGatewayDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + nameProp, err := expandComputeHaVpnGatewayName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + networkProp, err := expandComputeHaVpnGatewayNetwork(d.Get("network"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("network"); !isEmptyValue(reflect.ValueOf(networkProp)) && (ok || !reflect.DeepEqual(v, networkProp)) { + obj["network"] = networkProp + } + regionProp, err := expandComputeHaVpnGatewayRegion(d.Get("region"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("region"); !isEmptyValue(reflect.ValueOf(regionProp)) && (ok || !reflect.DeepEqual(v, regionProp)) { + obj["region"] = regionProp + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/regions/{{region}}/vpnGateways") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new HaVpnGateway: %#v", obj) + res, err := sendRequestWithTimeout(config, "POST", url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating HaVpnGateway: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + project, err := getProject(d, config) + if err != nil { + return err + } + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating HaVpnGateway", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create HaVpnGateway: %s", waitErr) + } + + log.Printf("[DEBUG] Finished creating HaVpnGateway %q: %#v", d.Id(), res) + + return resourceComputeHaVpnGatewayRead(d, meta) +} + +func resourceComputeHaVpnGatewayRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/regions/{{region}}/vpnGateways/{{name}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeHaVpnGateway %q", d.Id())) + } + + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + + if err := d.Set("description", flattenComputeHaVpnGatewayDescription(res["description"], d)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("name", flattenComputeHaVpnGatewayName(res["name"], d)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("network", flattenComputeHaVpnGatewayNetwork(res["network"], d)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("vpn_interfaces", flattenComputeHaVpnGatewayVpnInterfaces(res["vpnInterfaces"], d)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("region", flattenComputeHaVpnGatewayRegion(res["region"], d)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + + return nil +} + +func resourceComputeHaVpnGatewayDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/regions/{{region}}/vpnGateways/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting HaVpnGateway %q", d.Id()) + res, err := sendRequestWithTimeout(config, "DELETE", url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "HaVpnGateway") + } + + project, err := getProject(d, config) + if err != nil { + return err + } + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting HaVpnGateway", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting HaVpnGateway %q: %#v", d.Id(), res) + return nil +} + +func resourceComputeHaVpnGatewayImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{"projects/(?P[^/]+)/regions/(?P[^/]+)/vpnGateways/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeHaVpnGatewayDescription(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeHaVpnGatewayName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeHaVpnGatewayNetwork(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func flattenComputeHaVpnGatewayVpnInterfaces(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "id": flattenComputeHaVpnGatewayVpnInterfacesId(original["id"], d), + "ip_address": flattenComputeHaVpnGatewayVpnInterfacesIpAddress(original["ipAddress"], d), + }) + } + return transformed +} +func flattenComputeHaVpnGatewayVpnInterfacesId(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenComputeHaVpnGatewayVpnInterfacesIpAddress(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeHaVpnGatewayRegion(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +func expandComputeHaVpnGatewayDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeHaVpnGatewayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeHaVpnGatewayNetwork(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("networks", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for network: %s", err) + } + return f.RelativeLink(), nil +} + +func expandComputeHaVpnGatewayRegion(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("regions", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for region: %s", err) + } + return f.RelativeLink(), nil +} diff --git a/google-beta/resource_compute_ha_vpn_gateway_generated_test.go b/google-beta/resource_compute_ha_vpn_gateway_generated_test.go new file mode 100644 index 0000000000..d742c25e6b --- /dev/null +++ b/google-beta/resource_compute_ha_vpn_gateway_generated_test.go @@ -0,0 +1,311 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccComputeHaVpnGateway_haVpnGatewayBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckComputeHaVpnGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeHaVpnGateway_haVpnGatewayBasicExample(context), + }, + }, + }) +} + +func testAccComputeHaVpnGateway_haVpnGatewayBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_ha_vpn_gateway" "ha_gateway1" { + provider = "google-beta" + region = "us-central1" + name = "ha-vpn-1-%{random_suffix}" + network = "${google_compute_network.network1.self_link}" +} + +resource "google_compute_network" "network1" { + provider = "google-beta" + name = "network1-%{random_suffix}" + auto_create_subnetworks = false +} +`, context) +} + +func TestAccComputeHaVpnGateway_haVpnGatewayGcpToGcpExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckComputeHaVpnGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeHaVpnGateway_haVpnGatewayGcpToGcpExample(context), + }, + }, + }) +} + +func testAccComputeHaVpnGateway_haVpnGatewayGcpToGcpExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_ha_vpn_gateway" "ha_gateway1" { + provider = "google-beta" + region = "us-central1" + name = "ha-vpn-1-%{random_suffix}" + network = "${google_compute_network.network1.self_link}" +} + +resource "google_compute_ha_vpn_gateway" "ha_gateway2" { + provider = "google-beta" + region = "us-central1" + name = "ha-vpn-2-%{random_suffix}" + network = "${google_compute_network.network2.self_link}" +} + +resource "google_compute_network" "network1" { + provider = "google-beta" + name = "network1-%{random_suffix}" + routing_mode = "GLOBAL" + auto_create_subnetworks = false +} + +resource "google_compute_network" "network2" { + provider = "google-beta" + name = "network2-%{random_suffix}" + routing_mode = "GLOBAL" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "network1_subnet1" { + provider = "google-beta" + name = "ha-vpn-subnet-1" + ip_cidr_range = "10.0.1.0/24" + region = "us-central1" + network = "${google_compute_network.network1.self_link}" +} + +resource "google_compute_subnetwork" "network1_subnet2" { + provider = "google-beta" + name = "ha-vpn-subnet-2" + ip_cidr_range = "10.0.2.0/24" + region = "us-west1" + network = "${google_compute_network.network1.self_link}" +} + +resource "google_compute_subnetwork" "network2_subnet1" { + provider = "google-beta" + name = "ha-vpn-subnet-3" + ip_cidr_range = "192.168.1.0/24" + region = "us-central1" + network = "${google_compute_network.network2.self_link}" +} + +resource "google_compute_subnetwork" "network2_subnet2" { + provider = "google-beta" + name = "ha-vpn-subnet-4" + ip_cidr_range = "192.168.2.0/24" + region = "us-east1" + network = "${google_compute_network.network2.self_link}" +} + +resource "google_compute_router" "router1" { + provider = "google-beta" + name = "ha-vpn-router1" + network = "${google_compute_network.network1.name}" + bgp { + asn = 64514 + } +} + +resource "google_compute_router" "router2" { + provider = "google-beta" + name = "ha-vpn-router2" + network = "${google_compute_network.network2.name}" + bgp { + asn = 64515 + } +} + +resource "google_compute_vpn_tunnel" "tunnel1" { + provider = "google-beta" + name = "ha-vpn-tunnel1" + region = "us-central1" + vpn_gateway = "${google_compute_ha_vpn_gateway.ha_gateway1.self_link}" + peer_gcp_gateway = "${google_compute_ha_vpn_gateway.ha_gateway2.self_link}" + shared_secret = "a secret message" + router = "${google_compute_router.router1.self_link}" + vpn_gateway_interface = 0 +} + +resource "google_compute_vpn_tunnel" "tunnel2" { + provider = "google-beta" + name = "ha-vpn-tunnel2" + region = "us-central1" + vpn_gateway = "${google_compute_ha_vpn_gateway.ha_gateway1.self_link}" + peer_gcp_gateway = "${google_compute_ha_vpn_gateway.ha_gateway2.self_link}" + shared_secret = "a secret message" + router = " ${google_compute_router.router1.self_link}" + vpn_gateway_interface = 1 +} + +resource "google_compute_vpn_tunnel" "tunnel3" { + provider = "google-beta" + name = "ha-vpn-tunnel3" + region = "us-central1" + vpn_gateway = "${google_compute_ha_vpn_gateway.ha_gateway2.self_link}" + peer_gcp_gateway = "${google_compute_ha_vpn_gateway.ha_gateway1.self_link}" + shared_secret = "a secret message" + router = "${google_compute_router.router2.self_link}" + vpn_gateway_interface = 0 +} + +resource "google_compute_vpn_tunnel" "tunnel4" { + provider = "google-beta" + name = "ha-vpn-tunnel4" + region = "us-central1" + vpn_gateway = "${google_compute_ha_vpn_gateway.ha_gateway2.self_link}" + peer_gcp_gateway = "${google_compute_ha_vpn_gateway.ha_gateway1.self_link}" + shared_secret = "a secret message" + router = "${google_compute_router.router2.self_link}" + vpn_gateway_interface = 1 +} + +resource "google_compute_router_interface" "router1_interface1" { + provider = "google-beta" + name = "router1-interface1" + router = "${google_compute_router.router1.name}" + region = "us-central1" + ip_range = "169.254.0.1/30" + vpn_tunnel = "${google_compute_vpn_tunnel.tunnel1.name}" +} + +resource "google_compute_router_peer" "router1_peer1" { + provider = "google-beta" + name = "router1-peer1" + router = "${google_compute_router.router1.name}" + region = "us-central1" + peer_ip_address = "169.254.0.2" + peer_asn = 64515 + advertised_route_priority = 100 + interface = "${google_compute_router_interface.router1_interface1.name}" +} + +resource "google_compute_router_interface" "router1_interface2" { + provider = "google-beta" + name = "router1-interface2" + router = "${google_compute_router.router1.name}" + region = "us-central1" + ip_range = "169.254.1.1/30" + vpn_tunnel = "${google_compute_vpn_tunnel.tunnel2.name}" +} + +resource "google_compute_router_peer" "router1_peer2" { + provider = "google-beta" + name = "router1-peer2" + router = "${google_compute_router.router1.name}" + region = "us-central1" + peer_ip_address = "169.254.1.2" + peer_asn = 64515 + advertised_route_priority = 100 + interface = "${google_compute_router_interface.router1_interface2.name}" +} + +resource "google_compute_router_interface" "router2_interface1" { + provider = "google-beta" + name = "router2-interface1" + router = "${google_compute_router.router2.name}" + region = "us-central1" + ip_range = "169.254.0.1/30" + vpn_tunnel = "${google_compute_vpn_tunnel.tunnel3.name}" +} + +resource "google_compute_router_peer" "router2_peer1" { + provider = "google-beta" + name = "router2-peer1" + router = "${google_compute_router.router2.name}" + region = "us-central1" + peer_ip_address = "169.254.0.2" + peer_asn = 64514 + advertised_route_priority = 100 + interface = "${google_compute_router_interface.router2_interface1.name}" +} + +resource "google_compute_router_interface" "router2_interface2" { + provider = "google-beta" + name = "router2-interface2" + router = "${google_compute_router.router2.name}" + region = "us-central1" + ip_range = "169.254.1.1/30" + vpn_tunnel = "${google_compute_vpn_tunnel.tunnel4.name}" +} + +resource "google_compute_router_peer" "router2_peer2" { + provider = "google-beta" + name = "router2-peer2" + router = "${google_compute_router.router2.name}" + region = "us-central1" + peer_ip_address = "169.254.1.2" + peer_asn = 64514 + advertised_route_priority = 100 + interface = "${google_compute_router_interface.router2_interface2.name}" +} +`, context) +} + +func testAccCheckComputeHaVpnGatewayDestroy(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_ha_vpn_gateway" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := testAccProvider.Meta().(*Config) + + url, err := replaceVarsForTest(rs, "https://www.googleapis.com/compute/beta/projects/{{project}}/regions/{{region}}/vpnGateways/{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", url, nil) + if err == nil { + return fmt.Errorf("ComputeHaVpnGateway still exists at %s", url) + } + } + + return nil +} diff --git a/google-beta/resource_compute_vpn_tunnel.go b/google-beta/resource_compute_vpn_tunnel.go index 7a68f0d933..9581d39100 100644 --- a/google-beta/resource_compute_vpn_tunnel.go +++ b/google-beta/resource_compute_vpn_tunnel.go @@ -152,24 +152,12 @@ func resourceComputeVpnTunnel() *schema.Resource { Required: true, ForceNew: true, }, - "peer_ip": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validatePeerAddr, - }, "shared_secret": { Type: schema.TypeString, Required: true, ForceNew: true, Sensitive: true, }, - "target_vpn_gateway": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - DiffSuppressFunc: compareSelfLinkOrResourceName, - }, "description": { Type: schema.TypeString, Optional: true, @@ -196,6 +184,29 @@ func resourceComputeVpnTunnel() *schema.Resource { }, Set: schema.HashString, }, + "peer_external_gateway": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "peer_external_gateway_interface": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + "peer_gcp_gateway": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "peer_ip": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + ValidateFunc: validatePeerAddr, + }, "region": { Type: schema.TypeString, Computed: true, @@ -219,6 +230,23 @@ func resourceComputeVpnTunnel() *schema.Resource { ForceNew: true, DiffSuppressFunc: compareSelfLinkOrResourceName, }, + "target_vpn_gateway": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "vpn_gateway": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "vpn_gateway_interface": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, "creation_timestamp": { Type: schema.TypeString, Computed: true, @@ -271,6 +299,36 @@ func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) er } else if v, ok := d.GetOkExists("target_vpn_gateway"); !isEmptyValue(reflect.ValueOf(targetVpnGatewayProp)) && (ok || !reflect.DeepEqual(v, targetVpnGatewayProp)) { obj["targetVpnGateway"] = targetVpnGatewayProp } + vpnGatewayProp, err := expandComputeVpnTunnelVpnGateway(d.Get("vpn_gateway"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("vpn_gateway"); !isEmptyValue(reflect.ValueOf(vpnGatewayProp)) && (ok || !reflect.DeepEqual(v, vpnGatewayProp)) { + obj["vpnGateway"] = vpnGatewayProp + } + vpnGatewayInterfaceProp, err := expandComputeVpnTunnelVpnGatewayInterface(d.Get("vpn_gateway_interface"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("vpn_gateway_interface"); ok || !reflect.DeepEqual(v, vpnGatewayInterfaceProp) { + obj["vpnGatewayInterface"] = vpnGatewayInterfaceProp + } + peerExternalGatewayProp, err := expandComputeVpnTunnelPeerExternalGateway(d.Get("peer_external_gateway"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("peer_external_gateway"); !isEmptyValue(reflect.ValueOf(peerExternalGatewayProp)) && (ok || !reflect.DeepEqual(v, peerExternalGatewayProp)) { + obj["peerExternalGateway"] = peerExternalGatewayProp + } + peerExternalGatewayInterfaceProp, err := expandComputeVpnTunnelPeerExternalGatewayInterface(d.Get("peer_external_gateway_interface"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("peer_external_gateway_interface"); !isEmptyValue(reflect.ValueOf(peerExternalGatewayInterfaceProp)) && (ok || !reflect.DeepEqual(v, peerExternalGatewayInterfaceProp)) { + obj["peerExternalGatewayInterface"] = peerExternalGatewayInterfaceProp + } + peerGcpGatewayProp, err := expandComputeVpnTunnelPeerGcpGateway(d.Get("peer_gcp_gateway"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("peer_gcp_gateway"); !isEmptyValue(reflect.ValueOf(peerGcpGatewayProp)) && (ok || !reflect.DeepEqual(v, peerGcpGatewayProp)) { + obj["peerGcpGateway"] = peerGcpGatewayProp + } routerProp, err := expandComputeVpnTunnelRouter(d.Get("router"), d, config) if err != nil { return err @@ -448,6 +506,21 @@ func resourceComputeVpnTunnelRead(d *schema.ResourceData, meta interface{}) erro if err := d.Set("target_vpn_gateway", flattenComputeVpnTunnelTargetVpnGateway(res["targetVpnGateway"], d)); err != nil { return fmt.Errorf("Error reading VpnTunnel: %s", err) } + if err := d.Set("vpn_gateway", flattenComputeVpnTunnelVpnGateway(res["vpnGateway"], d)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("vpn_gateway_interface", flattenComputeVpnTunnelVpnGatewayInterface(res["vpnGatewayInterface"], d)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("peer_external_gateway", flattenComputeVpnTunnelPeerExternalGateway(res["peerExternalGateway"], d)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("peer_external_gateway_interface", flattenComputeVpnTunnelPeerExternalGatewayInterface(res["peerExternalGatewayInterface"], d)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("peer_gcp_gateway", flattenComputeVpnTunnelPeerGcpGateway(res["peerGcpGateway"], d)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } if err := d.Set("router", flattenComputeVpnTunnelRouter(res["router"], d)); err != nil { return fmt.Errorf("Error reading VpnTunnel: %s", err) } @@ -613,6 +686,44 @@ func flattenComputeVpnTunnelTargetVpnGateway(v interface{}, d *schema.ResourceDa return ConvertSelfLinkToV1(v.(string)) } +func flattenComputeVpnTunnelVpnGateway(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func flattenComputeVpnTunnelVpnGatewayInterface(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenComputeVpnTunnelPeerExternalGateway(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeVpnTunnelPeerExternalGatewayInterface(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenComputeVpnTunnelPeerGcpGateway(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + func flattenComputeVpnTunnelRouter(v interface{}, d *schema.ResourceData) interface{} { if v == nil { return v @@ -687,6 +798,34 @@ func expandComputeVpnTunnelTargetVpnGateway(v interface{}, d TerraformResourceDa return f.RelativeLink(), nil } +func expandComputeVpnTunnelVpnGateway(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseRegionalFieldValue("vpnGateways", v.(string), "project", "region", "zone", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for vpn_gateway: %s", err) + } + return f.RelativeLink(), nil +} + +func expandComputeVpnTunnelVpnGatewayInterface(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeVpnTunnelPeerExternalGateway(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeVpnTunnelPeerExternalGatewayInterface(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeVpnTunnelPeerGcpGateway(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseRegionalFieldValue("vpnGateways", v.(string), "project", "region", "zone", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for peer_gcp_gateway: %s", err) + } + return f.RelativeLink(), nil +} + func expandComputeVpnTunnelRouter(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { if v == nil || v.(string) == "" { return "", nil diff --git a/website/docs/r/compute_ha_vpn_gateway.html.markdown b/website/docs/r/compute_ha_vpn_gateway.html.markdown new file mode 100644 index 0000000000..917430c4ca --- /dev/null +++ b/website/docs/r/compute_ha_vpn_gateway.html.markdown @@ -0,0 +1,346 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +layout: "google" +page_title: "Google: google_compute_ha_vpn_gateway" +sidebar_current: "docs-google-compute-ha-vpn-gateway" +description: |- + Represents a VPN gateway running in GCP. +--- + +# google\_compute\_ha\_vpn\_gateway + +Represents a VPN gateway running in GCP. This virtual device is managed +by Google, but used only by you. This type of VPN Gateway allows for the creation +of VPN solutions with higher availability than classic Target VPN Gateways. + +~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider. +See [Provider Versions](https://terraform.io/docs/providers/google/provider_versions.html) for more details on beta resources. + +To get more information about HaVpnGateway, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/beta/vpnGateways) +* How-to Guides + * [Choosing a VPN](https://cloud.google.com/vpn/docs/how-to/choosing-a-vpn) + * [Cloud VPN Overview](https://cloud.google.com/vpn/docs/concepts/overview) + + +## Example Usage - Ha Vpn Gateway Basic + + +```hcl +resource "google_compute_ha_vpn_gateway" "ha_gateway1" { + provider = "google-beta" + region = "us-central1" + name = "ha-vpn-1" + network = "${google_compute_network.network1.self_link}" +} + +resource "google_compute_network" "network1" { + provider = "google-beta" + name = "network1" + auto_create_subnetworks = false +} +``` + +## Example Usage - Ha Vpn Gateway Gcp To Gcp + + +```hcl +resource "google_compute_ha_vpn_gateway" "ha_gateway1" { + provider = "google-beta" + region = "us-central1" + name = "ha-vpn-1" + network = "${google_compute_network.network1.self_link}" +} + +resource "google_compute_ha_vpn_gateway" "ha_gateway2" { + provider = "google-beta" + region = "us-central1" + name = "ha-vpn-2" + network = "${google_compute_network.network2.self_link}" +} + +resource "google_compute_network" "network1" { + provider = "google-beta" + name = "network1" + routing_mode = "GLOBAL" + auto_create_subnetworks = false +} + +resource "google_compute_network" "network2" { + provider = "google-beta" + name = "network2" + routing_mode = "GLOBAL" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "network1_subnet1" { + provider = "google-beta" + name = "ha-vpn-subnet-1" + ip_cidr_range = "10.0.1.0/24" + region = "us-central1" + network = "${google_compute_network.network1.self_link}" +} + +resource "google_compute_subnetwork" "network1_subnet2" { + provider = "google-beta" + name = "ha-vpn-subnet-2" + ip_cidr_range = "10.0.2.0/24" + region = "us-west1" + network = "${google_compute_network.network1.self_link}" +} + +resource "google_compute_subnetwork" "network2_subnet1" { + provider = "google-beta" + name = "ha-vpn-subnet-3" + ip_cidr_range = "192.168.1.0/24" + region = "us-central1" + network = "${google_compute_network.network2.self_link}" +} + +resource "google_compute_subnetwork" "network2_subnet2" { + provider = "google-beta" + name = "ha-vpn-subnet-4" + ip_cidr_range = "192.168.2.0/24" + region = "us-east1" + network = "${google_compute_network.network2.self_link}" +} + +resource "google_compute_router" "router1" { + provider = "google-beta" + name = "ha-vpn-router1" + network = "${google_compute_network.network1.name}" + bgp { + asn = 64514 + } +} + +resource "google_compute_router" "router2" { + provider = "google-beta" + name = "ha-vpn-router2" + network = "${google_compute_network.network2.name}" + bgp { + asn = 64515 + } +} + +resource "google_compute_vpn_tunnel" "tunnel1" { + provider = "google-beta" + name = "ha-vpn-tunnel1" + region = "us-central1" + vpn_gateway = "${google_compute_ha_vpn_gateway.ha_gateway1.self_link}" + peer_gcp_gateway = "${google_compute_ha_vpn_gateway.ha_gateway2.self_link}" + shared_secret = "a secret message" + router = "${google_compute_router.router1.self_link}" + vpn_gateway_interface = 0 +} + +resource "google_compute_vpn_tunnel" "tunnel2" { + provider = "google-beta" + name = "ha-vpn-tunnel2" + region = "us-central1" + vpn_gateway = "${google_compute_ha_vpn_gateway.ha_gateway1.self_link}" + peer_gcp_gateway = "${google_compute_ha_vpn_gateway.ha_gateway2.self_link}" + shared_secret = "a secret message" + router = " ${google_compute_router.router1.self_link}" + vpn_gateway_interface = 1 +} + +resource "google_compute_vpn_tunnel" "tunnel3" { + provider = "google-beta" + name = "ha-vpn-tunnel3" + region = "us-central1" + vpn_gateway = "${google_compute_ha_vpn_gateway.ha_gateway2.self_link}" + peer_gcp_gateway = "${google_compute_ha_vpn_gateway.ha_gateway1.self_link}" + shared_secret = "a secret message" + router = "${google_compute_router.router2.self_link}" + vpn_gateway_interface = 0 +} + +resource "google_compute_vpn_tunnel" "tunnel4" { + provider = "google-beta" + name = "ha-vpn-tunnel4" + region = "us-central1" + vpn_gateway = "${google_compute_ha_vpn_gateway.ha_gateway2.self_link}" + peer_gcp_gateway = "${google_compute_ha_vpn_gateway.ha_gateway1.self_link}" + shared_secret = "a secret message" + router = "${google_compute_router.router2.self_link}" + vpn_gateway_interface = 1 +} + +resource "google_compute_router_interface" "router1_interface1" { + provider = "google-beta" + name = "router1-interface1" + router = "${google_compute_router.router1.name}" + region = "us-central1" + ip_range = "169.254.0.1/30" + vpn_tunnel = "${google_compute_vpn_tunnel.tunnel1.name}" +} + +resource "google_compute_router_peer" "router1_peer1" { + provider = "google-beta" + name = "router1-peer1" + router = "${google_compute_router.router1.name}" + region = "us-central1" + peer_ip_address = "169.254.0.2" + peer_asn = 64515 + advertised_route_priority = 100 + interface = "${google_compute_router_interface.router1_interface1.name}" +} + +resource "google_compute_router_interface" "router1_interface2" { + provider = "google-beta" + name = "router1-interface2" + router = "${google_compute_router.router1.name}" + region = "us-central1" + ip_range = "169.254.1.1/30" + vpn_tunnel = "${google_compute_vpn_tunnel.tunnel2.name}" +} + +resource "google_compute_router_peer" "router1_peer2" { + provider = "google-beta" + name = "router1-peer2" + router = "${google_compute_router.router1.name}" + region = "us-central1" + peer_ip_address = "169.254.1.2" + peer_asn = 64515 + advertised_route_priority = 100 + interface = "${google_compute_router_interface.router1_interface2.name}" +} + +resource "google_compute_router_interface" "router2_interface1" { + provider = "google-beta" + name = "router2-interface1" + router = "${google_compute_router.router2.name}" + region = "us-central1" + ip_range = "169.254.0.1/30" + vpn_tunnel = "${google_compute_vpn_tunnel.tunnel3.name}" +} + +resource "google_compute_router_peer" "router2_peer1" { + provider = "google-beta" + name = "router2-peer1" + router = "${google_compute_router.router2.name}" + region = "us-central1" + peer_ip_address = "169.254.0.2" + peer_asn = 64514 + advertised_route_priority = 100 + interface = "${google_compute_router_interface.router2_interface1.name}" +} + +resource "google_compute_router_interface" "router2_interface2" { + provider = "google-beta" + name = "router2-interface2" + router = "${google_compute_router.router2.name}" + region = "us-central1" + ip_range = "169.254.1.1/30" + vpn_tunnel = "${google_compute_vpn_tunnel.tunnel4.name}" +} + +resource "google_compute_router_peer" "router2_peer2" { + provider = "google-beta" + name = "router2-peer2" + router = "${google_compute_router.router2.name}" + region = "us-central1" + peer_ip_address = "169.254.1.2" + peer_asn = 64514 + advertised_route_priority = 100 + interface = "${google_compute_router_interface.router2_interface2.name}" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `name` - + (Required) + Name of the resource. Provided by the client when the resource is + created. The name must be 1-63 characters long, and comply with + RFC1035. Specifically, the name must be 1-63 characters long and + match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means + the first character must be a lowercase letter, and all following + characters must be a dash, lowercase letter, or digit, except the last + character, which cannot be a dash. + +* `network` - + (Required) + The network this VPN gateway is accepting traffic for. + + +- - - + + +* `description` - + (Optional) + An optional description of this resource. + +* `region` - + (Optional) + The region this gateway should sit in. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + + +* `vpn_interfaces` - + A list of interfaces on this VPN gateway. Structure is documented below. +* `self_link` - The URI of the created resource. + + +The `vpn_interfaces` block contains: + +* `id` - + (Optional) + The numeric ID of this VPN gateway interface. + +* `ip_address` - + (Optional) + The external IP address for this VPN gateway interface. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +HaVpnGateway can be imported using any of these accepted formats: + +``` +$ terraform import -provider=google-beta google_compute_ha_vpn_gateway.default projects/{{project}}/regions/{{region}}/vpnGateways/{{name}} +$ terraform import -provider=google-beta google_compute_ha_vpn_gateway.default {{project}}/{{region}}/{{name}} +$ terraform import -provider=google-beta google_compute_ha_vpn_gateway.default {{name}} +``` + +-> If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource. diff --git a/website/docs/r/compute_vpn_tunnel.html.markdown b/website/docs/r/compute_vpn_tunnel.html.markdown index 2e27f94341..c7f291d1f1 100644 --- a/website/docs/r/compute_vpn_tunnel.html.markdown +++ b/website/docs/r/compute_vpn_tunnel.html.markdown @@ -204,15 +204,6 @@ The following arguments are supported: be a dash, lowercase letter, or digit, except the last character, which cannot be a dash. -* `target_vpn_gateway` - - (Required) - URL of the Target VPN gateway with which this VPN tunnel is - associated. - -* `peer_ip` - - (Required) - IP address of the peer VPN gateway. Only IPv4 is supported. - * `shared_secret` - (Required) Shared secret used to set the secure session between the Cloud VPN @@ -226,10 +217,44 @@ The following arguments are supported: (Optional) An optional description of this resource. +* `target_vpn_gateway` - + (Optional) + URL of the Target VPN gateway with which this VPN tunnel is + associated. + +* `vpn_gateway` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + URL of the VPN gateway with which this VPN tunnel is associated. + This must be used if a High Availability VPN gateway resource is created. + This field must reference a `google_compute_ha_vpn_gateway` resource. + +* `vpn_gateway_interface` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + The interface ID of the VPN gateway with which this VPN tunnel is associated. + +* `peer_external_gateway` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + URL of the peer side external VPN gateway to which this VPN tunnel is connected. + +* `peer_external_gateway_interface` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + The interface ID of the external VPN gateway to which this VPN tunnel is connected. + +* `peer_gcp_gateway` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + URL of the peer side HA GCP VPN gateway to which this VPN tunnel is connected. + If provided, the VPN tunnel will automatically use the same vpn_gateway_interface + ID in the peer GCP VPN gateway. + This field must reference a `google_compute_ha_vpn_gateway` resource. + * `router` - (Optional) URL of router resource to be used for dynamic routing. +* `peer_ip` - + (Optional) + IP address of the peer VPN gateway. Only IPv4 is supported. + * `ike_version` - (Optional) IKE protocol version to use when establishing the VPN tunnel with