From e0ce967dab22e2be3273fe2c9a96630661044d5d Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Fri, 16 Oct 2020 00:36:03 +0000 Subject: [PATCH] Promote HA VPN to GA (#4115) Signed-off-by: Modular Magician --- .changelog/4115.txt | 12 + google/provider.go | 6 +- .../resource_compute_external_vpn_gateway.go | 409 ++++++++++++++++++ ...ute_external_vpn_gateway_generated_test.go | 185 ++++++++ ...mpute_external_vpn_gateway_sweeper_test.go | 124 ++++++ google/resource_compute_ha_vpn_gateway.go | 396 +++++++++++++++++ ...e_compute_ha_vpn_gateway_generated_test.go | 307 +++++++++++++ ...rce_compute_ha_vpn_gateway_sweeper_test.go | 124 ++++++ google/resource_compute_vpn_tunnel.go | 172 ++++++++ ...ource_compute_vpn_tunnel_generated_test.go | 2 +- ...compute_external_vpn_gateway.html.markdown | 16 +- .../r/compute_ha_vpn_gateway.html.markdown | 28 +- .../docs/r/compute_vpn_gateway.html.markdown | 3 + .../docs/r/compute_vpn_tunnel.html.markdown | 10 +- 14 files changed, 1744 insertions(+), 50 deletions(-) create mode 100644 .changelog/4115.txt create mode 100644 google/resource_compute_external_vpn_gateway.go create mode 100644 google/resource_compute_external_vpn_gateway_generated_test.go create mode 100644 google/resource_compute_external_vpn_gateway_sweeper_test.go create mode 100644 google/resource_compute_ha_vpn_gateway.go create mode 100644 google/resource_compute_ha_vpn_gateway_generated_test.go create mode 100644 google/resource_compute_ha_vpn_gateway_sweeper_test.go diff --git a/.changelog/4115.txt b/.changelog/4115.txt new file mode 100644 index 00000000000..983aef71055 --- /dev/null +++ b/.changelog/4115.txt @@ -0,0 +1,12 @@ +```release-note:note +compute: added a deprecation warning to `google_compute_vpn_gateway` +``` +```release-note:enhancement +compute: promoted `google_compute_ha_vpn_gateway` to GA +``` +```release-note:enhancement +compute: promoted `google_compute_external_vpn_gateway` to GA +``` +```release-note:enhancement +compute: promoted HA VPN fields in `google_compute_vpn_tunnel` to GA +``` diff --git a/google/provider.go b/google/provider.go index 4be060b8272..aa21b050e9f 100644 --- a/google/provider.go +++ b/google/provider.go @@ -656,9 +656,9 @@ func Provider() *schema.Provider { return provider } -// Generated resources: 163 +// Generated resources: 165 // Generated IAM resources: 69 -// Total generated resources: 232 +// Total generated resources: 234 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -782,6 +782,8 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "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_external_vpn_gateway": resourceComputeExternalVpnGateway(), "google_compute_url_map": resourceComputeUrlMap(), "google_compute_vpn_tunnel": resourceComputeVpnTunnel(), "google_compute_target_grpc_proxy": resourceComputeTargetGrpcProxy(), diff --git a/google/resource_compute_external_vpn_gateway.go b/google/resource_compute_external_vpn_gateway.go new file mode 100644 index 00000000000..9f1072f6ecb --- /dev/null +++ b/google/resource_compute_external_vpn_gateway.go @@ -0,0 +1,409 @@ +// ---------------------------------------------------------------------------- +// +// *** 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-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceComputeExternalVpnGateway() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeExternalVpnGatewayCreate, + Read: resourceComputeExternalVpnGatewayRead, + Delete: resourceComputeExternalVpnGatewayDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeExternalVpnGatewayImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `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.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `An optional description of this resource.`, + }, + "interface": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `A list of interfaces on this external VPN gateway.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: `The numberic ID for this interface. Allowed values are based on the redundancy type +of this external VPN gateway +* '0 - SINGLE_IP_INTERNALLY_REDUNDANT' +* '0, 1 - TWO_IPS_REDUNDANCY' +* '0, 1, 2, 3 - FOUR_IPS_REDUNDANCY'`, + }, + "ip_address": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `IP address of the interface in the external VPN gateway. +Only IPv4 is supported. This IP address can be either from +your on-premise gateway or another Cloud provider's VPN gateway, +it cannot be an IP address from Google Compute Engine.`, + }, + }, + }, + }, + "redundancy_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"FOUR_IPS_REDUNDANCY", "SINGLE_IP_INTERNALLY_REDUNDANT", "TWO_IPS_REDUNDANCY", ""}, false), + Description: `Indicates the redundancy type of this external VPN gateway Possible values: ["FOUR_IPS_REDUNDANCY", "SINGLE_IP_INTERNALLY_REDUNDANT", "TWO_IPS_REDUNDANCY"]`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceComputeExternalVpnGatewayCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + descriptionProp, err := expandComputeExternalVpnGatewayDescription(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 := expandComputeExternalVpnGatewayName(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 + } + redundancyTypeProp, err := expandComputeExternalVpnGatewayRedundancyType(d.Get("redundancy_type"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("redundancy_type"); !isEmptyValue(reflect.ValueOf(redundancyTypeProp)) && (ok || !reflect.DeepEqual(v, redundancyTypeProp)) { + obj["redundancyType"] = redundancyTypeProp + } + interfacesProp, err := expandComputeExternalVpnGatewayInterface(d.Get("interface"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("interface"); !isEmptyValue(reflect.ValueOf(interfacesProp)) && (ok || !reflect.DeepEqual(v, interfacesProp)) { + obj["interfaces"] = interfacesProp + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/externalVpnGateways") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new ExternalVpnGateway: %#v", obj) + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return err + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "POST", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating ExternalVpnGateway: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "projects/{{project}}/global/externalVpnGateways/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = computeOperationWaitTime( + config, res, project, "Creating ExternalVpnGateway", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create ExternalVpnGateway: %s", err) + } + + log.Printf("[DEBUG] Finished creating ExternalVpnGateway %q: %#v", d.Id(), res) + + return resourceComputeExternalVpnGatewayRead(d, meta) +} + +func resourceComputeExternalVpnGatewayRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/externalVpnGateways/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return err + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequest(config, "GET", billingProject, url, userAgent, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeExternalVpnGateway %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading ExternalVpnGateway: %s", err) + } + + if err := d.Set("description", flattenComputeExternalVpnGatewayDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading ExternalVpnGateway: %s", err) + } + if err := d.Set("name", flattenComputeExternalVpnGatewayName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading ExternalVpnGateway: %s", err) + } + if err := d.Set("redundancy_type", flattenComputeExternalVpnGatewayRedundancyType(res["redundancyType"], d, config)); err != nil { + return fmt.Errorf("Error reading ExternalVpnGateway: %s", err) + } + if err := d.Set("interface", flattenComputeExternalVpnGatewayInterface(res["interfaces"], d, config)); err != nil { + return fmt.Errorf("Error reading ExternalVpnGateway: %s", err) + } + if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading ExternalVpnGateway: %s", err) + } + + return nil +} + +func resourceComputeExternalVpnGatewayDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + config.userAgent = userAgent + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return err + } + billingProject = project + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/global/externalVpnGateways/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting ExternalVpnGateway %q", d.Id()) + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "DELETE", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "ExternalVpnGateway") + } + + err = computeOperationWaitTime( + config, res, project, "Deleting ExternalVpnGateway", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting ExternalVpnGateway %q: %#v", d.Id(), res) + return nil +} + +func resourceComputeExternalVpnGatewayImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/global/externalVpnGateways/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "projects/{{project}}/global/externalVpnGateways/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeExternalVpnGatewayDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeExternalVpnGatewayName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeExternalVpnGatewayRedundancyType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeExternalVpnGatewayInterface(v interface{}, d *schema.ResourceData, config *Config) 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": flattenComputeExternalVpnGatewayInterfaceId(original["id"], d, config), + "ip_address": flattenComputeExternalVpnGatewayInterfaceIpAddress(original["ipAddress"], d, config), + }) + } + return transformed +} +func flattenComputeExternalVpnGatewayInterfaceId(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenComputeExternalVpnGatewayInterfaceIpAddress(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func expandComputeExternalVpnGatewayDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeExternalVpnGatewayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeExternalVpnGatewayRedundancyType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeExternalVpnGatewayInterface(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedId, err := expandComputeExternalVpnGatewayInterfaceId(original["id"], d, config) + if err != nil { + return nil, err + } else { + transformed["id"] = transformedId + } + + transformedIpAddress, err := expandComputeExternalVpnGatewayInterfaceIpAddress(original["ip_address"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIpAddress); val.IsValid() && !isEmptyValue(val) { + transformed["ipAddress"] = transformedIpAddress + } + + req = append(req, transformed) + } + return req, nil +} + +func expandComputeExternalVpnGatewayInterfaceId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeExternalVpnGatewayInterfaceIpAddress(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_compute_external_vpn_gateway_generated_test.go b/google/resource_compute_external_vpn_gateway_generated_test.go new file mode 100644 index 00000000000..3f0c461bc40 --- /dev/null +++ b/google/resource_compute_external_vpn_gateway_generated_test.go @@ -0,0 +1,185 @@ +// ---------------------------------------------------------------------------- +// +// *** 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-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccComputeExternalVpnGateway_externalVpnGatewayExample(t *testing.T) { + skipIfVcr(t) + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckComputeExternalVpnGatewayDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeExternalVpnGateway_externalVpnGatewayExample(context), + }, + { + ResourceName: "google_compute_external_vpn_gateway.external_gateway", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccComputeExternalVpnGateway_externalVpnGatewayExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_ha_vpn_gateway" "ha_gateway" { + region = "us-central1" + name = "tf-test-ha-vpn%{random_suffix}" + network = google_compute_network.network.id +} + +resource "google_compute_external_vpn_gateway" "external_gateway" { + name = "tf-test-external-gateway%{random_suffix}" + redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT" + description = "An externally managed VPN gateway" + interface { + id = 0 + ip_address = "8.8.8.8" + } +} + +resource "google_compute_network" "network" { + name = "network%{random_suffix}" + routing_mode = "GLOBAL" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "network_subnet1" { + name = "ha-vpn-subnet-1" + ip_cidr_range = "10.0.1.0/24" + region = "us-central1" + network = google_compute_network.network.id +} + +resource "google_compute_subnetwork" "network_subnet2" { + name = "ha-vpn-subnet-2" + ip_cidr_range = "10.0.2.0/24" + region = "us-west1" + network = google_compute_network.network.id +} + +resource "google_compute_router" "router1" { + name = "ha-vpn-router1" + network = google_compute_network.network.name + bgp { + asn = 64514 + } +} + +resource "google_compute_vpn_tunnel" "tunnel1" { + name = "ha-vpn-tunnel1" + region = "us-central1" + vpn_gateway = google_compute_ha_vpn_gateway.ha_gateway.id + peer_external_gateway = google_compute_external_vpn_gateway.external_gateway.id + peer_external_gateway_interface = 0 + shared_secret = "a secret message" + router = google_compute_router.router1.id + vpn_gateway_interface = 0 +} + +resource "google_compute_vpn_tunnel" "tunnel2" { + name = "ha-vpn-tunnel2" + region = "us-central1" + vpn_gateway = google_compute_ha_vpn_gateway.ha_gateway.id + peer_external_gateway = google_compute_external_vpn_gateway.external_gateway.id + peer_external_gateway_interface = 0 + shared_secret = "a secret message" + router = " ${google_compute_router.router1.id}" + vpn_gateway_interface = 1 +} + +resource "google_compute_router_interface" "router1_interface1" { + 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" { + 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" { + 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" { + 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 +} +`, context) +} + +func testAccCheckComputeExternalVpnGatewayDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_external_vpn_gateway" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{ComputeBasePath}}projects/{{project}}/global/externalVpnGateways/{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", "", url, config.userAgent, nil) + if err == nil { + return fmt.Errorf("ComputeExternalVpnGateway still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/resource_compute_external_vpn_gateway_sweeper_test.go b/google/resource_compute_external_vpn_gateway_sweeper_test.go new file mode 100644 index 00000000000..fe2813c1f6a --- /dev/null +++ b/google/resource_compute_external_vpn_gateway_sweeper_test.go @@ -0,0 +1,124 @@ +// ---------------------------------------------------------------------------- +// +// *** 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 ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func init() { + resource.AddTestSweepers("ComputeExternalVpnGateway", &resource.Sweeper{ + Name: "ComputeExternalVpnGateway", + F: testSweepComputeExternalVpnGateway, + }) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepComputeExternalVpnGateway(region string) error { + resourceName := "ComputeExternalVpnGateway" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := getTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://compute.googleapis.com/compute/v1/projects/{{project}}/global/externalVpnGateways", "?")[0] + listUrl, err := replaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := sendRequest(config, "GET", config.Project, listUrl, config.userAgent, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["items"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + if obj["name"] == nil { + log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) + return nil + } + + name := GetResourceNameFromSelfLink(obj["name"].(string)) + // Skip resources that shouldn't be sweeped + if !isSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://compute.googleapis.com/compute/v1/projects/{{project}}/global/externalVpnGateways/{{name}}" + deleteUrl, err := replaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = sendRequest(config, "DELETE", config.Project, deleteUrl, config.userAgent, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/google/resource_compute_ha_vpn_gateway.go b/google/resource_compute_ha_vpn_gateway.go new file mode 100644 index 00000000000..508461d3bbb --- /dev/null +++ b/google/resource_compute_ha_vpn_gateway.go @@ -0,0 +1,396 @@ +// ---------------------------------------------------------------------------- +// +// *** 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-plugin-sdk/v2/helper/schema" +) + +func resourceComputeHaVpnGateway() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeHaVpnGatewayCreate, + Read: resourceComputeHaVpnGatewayRead, + Delete: resourceComputeHaVpnGatewayDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeHaVpnGatewayImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateGCPName, + Description: `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": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: `The network this VPN gateway is accepting traffic for.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `An optional description of this resource.`, + }, + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: `The region this gateway should sit in.`, + }, + "vpn_interfaces": { + Type: schema.TypeList, + Computed: true, + Description: `A list of interfaces on this VPN gateway.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeInt, + Optional: true, + Description: `The numeric ID of this VPN gateway interface.`, + }, + "ip_address": { + Type: schema.TypeString, + Optional: true, + Description: `The external IP address for this VPN gateway interface.`, + }, + }, + }, + }, + "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) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + 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, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/vpnGateways") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new HaVpnGateway: %#v", obj) + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return err + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "POST", billingProject, url, userAgent, 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, "projects/{{project}}/regions/{{region}}/vpnGateways/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = computeOperationWaitTime( + config, res, project, "Creating HaVpnGateway", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create HaVpnGateway: %s", err) + } + + 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) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/vpnGateways/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return err + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequest(config, "GET", billingProject, url, userAgent, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeHaVpnGateway %q", d.Id())) + } + + 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, config)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("name", flattenComputeHaVpnGatewayName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("network", flattenComputeHaVpnGatewayNetwork(res["network"], d, config)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("vpn_interfaces", flattenComputeHaVpnGatewayVpnInterfaces(res["vpnInterfaces"], d, config)); err != nil { + return fmt.Errorf("Error reading HaVpnGateway: %s", err) + } + if err := d.Set("region", flattenComputeHaVpnGatewayRegion(res["region"], d, config)); 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) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + config.userAgent = userAgent + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return err + } + billingProject = project + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/vpnGateways/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting HaVpnGateway %q", d.Id()) + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "DELETE", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "HaVpnGateway") + } + + err = computeOperationWaitTime( + config, res, project, "Deleting HaVpnGateway", userAgent, + d.Timeout(schema.TimeoutDelete)) + + 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[^/]+)/(?P[^/]+)", + "(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "projects/{{project}}/regions/{{region}}/vpnGateways/{{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, config *Config) interface{} { + return v +} + +func flattenComputeHaVpnGatewayName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeHaVpnGatewayNetwork(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func flattenComputeHaVpnGatewayVpnInterfaces(v interface{}, d *schema.ResourceData, config *Config) 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, config), + "ip_address": flattenComputeHaVpnGatewayVpnInterfacesIpAddress(original["ipAddress"], d, config), + }) + } + return transformed +} +func flattenComputeHaVpnGatewayVpnInterfacesId(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenComputeHaVpnGatewayVpnInterfacesIpAddress(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeHaVpnGatewayRegion(v interface{}, d *schema.ResourceData, config *Config) 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/resource_compute_ha_vpn_gateway_generated_test.go b/google/resource_compute_ha_vpn_gateway_generated_test.go new file mode 100644 index 00000000000..deae41416e1 --- /dev/null +++ b/google/resource_compute_ha_vpn_gateway_generated_test.go @@ -0,0 +1,307 @@ +// ---------------------------------------------------------------------------- +// +// *** 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-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccComputeHaVpnGateway_haVpnGatewayBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckComputeHaVpnGatewayDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeHaVpnGateway_haVpnGatewayBasicExample(context), + }, + { + ResourceName: "google_compute_ha_vpn_gateway.ha_gateway1", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"network", "region"}, + }, + }, + }) +} + +func testAccComputeHaVpnGateway_haVpnGatewayBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_ha_vpn_gateway" "ha_gateway1" { + region = "us-central1" + name = "tf-test-ha-vpn-1%{random_suffix}" + network = google_compute_network.network1.id +} + +resource "google_compute_network" "network1" { + name = "network1%{random_suffix}" + auto_create_subnetworks = false +} +`, context) +} + +func TestAccComputeHaVpnGateway_haVpnGatewayGcpToGcpExample(t *testing.T) { + skipIfVcr(t) + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckComputeHaVpnGatewayDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeHaVpnGateway_haVpnGatewayGcpToGcpExample(context), + }, + { + ResourceName: "google_compute_ha_vpn_gateway.ha_gateway1", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"network", "region"}, + }, + }, + }) +} + +func testAccComputeHaVpnGateway_haVpnGatewayGcpToGcpExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_ha_vpn_gateway" "ha_gateway1" { + region = "us-central1" + name = "tf-test-ha-vpn-1%{random_suffix}" + network = google_compute_network.network1.id +} + +resource "google_compute_ha_vpn_gateway" "ha_gateway2" { + region = "us-central1" + name = "tf-test-ha-vpn-2%{random_suffix}" + network = google_compute_network.network2.id +} + +resource "google_compute_network" "network1" { + name = "network1%{random_suffix}" + routing_mode = "GLOBAL" + auto_create_subnetworks = false +} + +resource "google_compute_network" "network2" { + name = "network2%{random_suffix}" + routing_mode = "GLOBAL" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "network1_subnet1" { + name = "ha-vpn-subnet-1" + ip_cidr_range = "10.0.1.0/24" + region = "us-central1" + network = google_compute_network.network1.id +} + +resource "google_compute_subnetwork" "network1_subnet2" { + name = "ha-vpn-subnet-2" + ip_cidr_range = "10.0.2.0/24" + region = "us-west1" + network = google_compute_network.network1.id +} + +resource "google_compute_subnetwork" "network2_subnet1" { + name = "ha-vpn-subnet-3" + ip_cidr_range = "192.168.1.0/24" + region = "us-central1" + network = google_compute_network.network2.id +} + +resource "google_compute_subnetwork" "network2_subnet2" { + name = "ha-vpn-subnet-4" + ip_cidr_range = "192.168.2.0/24" + region = "us-east1" + network = google_compute_network.network2.id +} + +resource "google_compute_router" "router1" { + name = "ha-vpn-router1" + network = google_compute_network.network1.name + bgp { + asn = 64514 + } +} + +resource "google_compute_router" "router2" { + name = "ha-vpn-router2" + network = google_compute_network.network2.name + bgp { + asn = 64515 + } +} + +resource "google_compute_vpn_tunnel" "tunnel1" { + name = "ha-vpn-tunnel1" + region = "us-central1" + vpn_gateway = google_compute_ha_vpn_gateway.ha_gateway1.id + peer_gcp_gateway = google_compute_ha_vpn_gateway.ha_gateway2.id + shared_secret = "a secret message" + router = google_compute_router.router1.id + vpn_gateway_interface = 0 +} + +resource "google_compute_vpn_tunnel" "tunnel2" { + name = "ha-vpn-tunnel2" + region = "us-central1" + vpn_gateway = google_compute_ha_vpn_gateway.ha_gateway1.id + peer_gcp_gateway = google_compute_ha_vpn_gateway.ha_gateway2.id + shared_secret = "a secret message" + router = google_compute_router.router1.id + vpn_gateway_interface = 1 +} + +resource "google_compute_vpn_tunnel" "tunnel3" { + name = "ha-vpn-tunnel3" + region = "us-central1" + vpn_gateway = google_compute_ha_vpn_gateway.ha_gateway2.id + peer_gcp_gateway = google_compute_ha_vpn_gateway.ha_gateway1.id + shared_secret = "a secret message" + router = google_compute_router.router2.id + vpn_gateway_interface = 0 +} + +resource "google_compute_vpn_tunnel" "tunnel4" { + name = "ha-vpn-tunnel4" + region = "us-central1" + vpn_gateway = google_compute_ha_vpn_gateway.ha_gateway2.id + peer_gcp_gateway = google_compute_ha_vpn_gateway.ha_gateway1.id + shared_secret = "a secret message" + router = google_compute_router.router2.id + vpn_gateway_interface = 1 +} + +resource "google_compute_router_interface" "router1_interface1" { + 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" { + 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" { + 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" { + 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" { + 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" { + 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" { + 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" { + 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 testAccCheckComputeHaVpnGatewayDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(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 := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/vpnGateways/{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", "", url, config.userAgent, nil) + if err == nil { + return fmt.Errorf("ComputeHaVpnGateway still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/resource_compute_ha_vpn_gateway_sweeper_test.go b/google/resource_compute_ha_vpn_gateway_sweeper_test.go new file mode 100644 index 00000000000..e385894d1ab --- /dev/null +++ b/google/resource_compute_ha_vpn_gateway_sweeper_test.go @@ -0,0 +1,124 @@ +// ---------------------------------------------------------------------------- +// +// *** 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 ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func init() { + resource.AddTestSweepers("ComputeHaVpnGateway", &resource.Sweeper{ + Name: "ComputeHaVpnGateway", + F: testSweepComputeHaVpnGateway, + }) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepComputeHaVpnGateway(region string) error { + resourceName := "ComputeHaVpnGateway" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := getTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://compute.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/vpnGateways", "?")[0] + listUrl, err := replaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := sendRequest(config, "GET", config.Project, listUrl, config.userAgent, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["items"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + if obj["name"] == nil { + log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) + return nil + } + + name := GetResourceNameFromSelfLink(obj["name"].(string)) + // Skip resources that shouldn't be sweeped + if !isSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://compute.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/vpnGateways/{{name}}" + deleteUrl, err := replaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = sendRequest(config, "DELETE", config.Project, deleteUrl, config.userAgent, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/google/resource_compute_vpn_tunnel.go b/google/resource_compute_vpn_tunnel.go index e48e24003f1..8cd605b9ffd 100644 --- a/google/resource_compute_vpn_tunnel.go +++ b/google/resource_compute_vpn_tunnel.go @@ -193,6 +193,31 @@ Only IPv4 is supported.`, }, Set: schema.HashString, }, + "peer_external_gateway": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: `URL of the peer side external VPN gateway to which this VPN tunnel is connected.`, + ExactlyOneOf: []string{"peer_external_gateway", "peer_gcp_gateway"}, + }, + "peer_external_gateway_interface": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: `The interface ID of the external VPN gateway to which this VPN tunnel is connected.`, + }, + "peer_gcp_gateway": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: `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.`, + ExactlyOneOf: []string{"peer_external_gateway", "peer_gcp_gateway"}, + }, "peer_ip": { Type: schema.TypeString, Computed: true, @@ -238,6 +263,21 @@ Only IPv4 is supported.`, Description: `URL of the Target VPN gateway with which this VPN tunnel is associated.`, }, + "vpn_gateway": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: `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": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: `The interface ID of the VPN gateway with which this VPN tunnel is associated.`, + }, "creation_timestamp": { Type: schema.TypeString, Computed: true, @@ -298,6 +338,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"); 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 @@ -441,6 +511,21 @@ func resourceComputeVpnTunnelRead(d *schema.ResourceData, meta interface{}) erro if err := d.Set("target_vpn_gateway", flattenComputeVpnTunnelTargetVpnGateway(res["targetVpnGateway"], d, config)); err != nil { return fmt.Errorf("Error reading VpnTunnel: %s", err) } + if err := d.Set("vpn_gateway", flattenComputeVpnTunnelVpnGateway(res["vpnGateway"], d, config)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("vpn_gateway_interface", flattenComputeVpnTunnelVpnGatewayInterface(res["vpnGatewayInterface"], d, config)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("peer_external_gateway", flattenComputeVpnTunnelPeerExternalGateway(res["peerExternalGateway"], d, config)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("peer_external_gateway_interface", flattenComputeVpnTunnelPeerExternalGatewayInterface(res["peerExternalGatewayInterface"], d, config)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } + if err := d.Set("peer_gcp_gateway", flattenComputeVpnTunnelPeerGcpGateway(res["peerGcpGateway"], d, config)); err != nil { + return fmt.Errorf("Error reading VpnTunnel: %s", err) + } if err := d.Set("router", flattenComputeVpnTunnelRouter(res["router"], d, config)); err != nil { return fmt.Errorf("Error reading VpnTunnel: %s", err) } @@ -562,6 +647,61 @@ func flattenComputeVpnTunnelTargetVpnGateway(v interface{}, d *schema.ResourceDa return ConvertSelfLinkToV1(v.(string)) } +func flattenComputeVpnTunnelVpnGateway(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func flattenComputeVpnTunnelVpnGatewayInterface(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenComputeVpnTunnelPeerExternalGateway(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func flattenComputeVpnTunnelPeerExternalGatewayInterface(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenComputeVpnTunnelPeerGcpGateway(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + func flattenComputeVpnTunnelRouter(v interface{}, d *schema.ResourceData, config *Config) interface{} { if v == nil { return v @@ -635,6 +775,38 @@ 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) { + f, err := parseGlobalFieldValue("externalVpnGateways", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for peer_external_gateway: %s", err) + } + return f.RelativeLink(), 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/google/resource_compute_vpn_tunnel_generated_test.go b/google/resource_compute_vpn_tunnel_generated_test.go index e9703d2685a..dd5c35d1b7c 100644 --- a/google/resource_compute_vpn_tunnel_generated_test.go +++ b/google/resource_compute_vpn_tunnel_generated_test.go @@ -45,7 +45,7 @@ func TestAccComputeVpnTunnel_vpnTunnelBasicExample(t *testing.T) { ResourceName: "google_compute_vpn_tunnel.tunnel1", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"target_vpn_gateway", "router", "shared_secret", "region"}, + ImportStateVerifyIgnore: []string{"target_vpn_gateway", "vpn_gateway", "peer_external_gateway", "peer_gcp_gateway", "router", "shared_secret", "region"}, }, }, }) diff --git a/website/docs/r/compute_external_vpn_gateway.html.markdown b/website/docs/r/compute_external_vpn_gateway.html.markdown index b1b629ef7ff..9b40a182f50 100644 --- a/website/docs/r/compute_external_vpn_gateway.html.markdown +++ b/website/docs/r/compute_external_vpn_gateway.html.markdown @@ -24,12 +24,10 @@ description: |- Represents a VPN gateway managed outside of GCP. -~> **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/guides/provider_versions.html) for more details on beta resources. To get more information about ExternalVpnGateway, see: -* [API documentation](https://cloud.google.com/compute/docs/reference/rest/beta/externalVpnGateways) +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/externalVpnGateways)
@@ -41,14 +39,12 @@ To get more information about ExternalVpnGateway, see: ```hcl resource "google_compute_ha_vpn_gateway" "ha_gateway" { - provider = google-beta region = "us-central1" name = "ha-vpn" network = google_compute_network.network.id } resource "google_compute_external_vpn_gateway" "external_gateway" { - provider = google-beta name = "external-gateway" redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT" description = "An externally managed VPN gateway" @@ -59,14 +55,12 @@ resource "google_compute_external_vpn_gateway" "external_gateway" { } resource "google_compute_network" "network" { - provider = google-beta name = "network" routing_mode = "GLOBAL" auto_create_subnetworks = false } resource "google_compute_subnetwork" "network_subnet1" { - provider = google-beta name = "ha-vpn-subnet-1" ip_cidr_range = "10.0.1.0/24" region = "us-central1" @@ -74,7 +68,6 @@ resource "google_compute_subnetwork" "network_subnet1" { } resource "google_compute_subnetwork" "network_subnet2" { - provider = google-beta name = "ha-vpn-subnet-2" ip_cidr_range = "10.0.2.0/24" region = "us-west1" @@ -82,7 +75,6 @@ resource "google_compute_subnetwork" "network_subnet2" { } resource "google_compute_router" "router1" { - provider = google-beta name = "ha-vpn-router1" network = google_compute_network.network.name bgp { @@ -91,7 +83,6 @@ resource "google_compute_router" "router1" { } resource "google_compute_vpn_tunnel" "tunnel1" { - provider = google-beta name = "ha-vpn-tunnel1" region = "us-central1" vpn_gateway = google_compute_ha_vpn_gateway.ha_gateway.id @@ -103,7 +94,6 @@ resource "google_compute_vpn_tunnel" "tunnel1" { } resource "google_compute_vpn_tunnel" "tunnel2" { - provider = google-beta name = "ha-vpn-tunnel2" region = "us-central1" vpn_gateway = google_compute_ha_vpn_gateway.ha_gateway.id @@ -115,7 +105,6 @@ resource "google_compute_vpn_tunnel" "tunnel2" { } resource "google_compute_router_interface" "router1_interface1" { - provider = google-beta name = "router1-interface1" router = google_compute_router.router1.name region = "us-central1" @@ -124,7 +113,6 @@ resource "google_compute_router_interface" "router1_interface1" { } resource "google_compute_router_peer" "router1_peer1" { - provider = google-beta name = "router1-peer1" router = google_compute_router.router1.name region = "us-central1" @@ -135,7 +123,6 @@ resource "google_compute_router_peer" "router1_peer1" { } resource "google_compute_router_interface" "router1_interface2" { - provider = google-beta name = "router1-interface2" router = google_compute_router.router1.name region = "us-central1" @@ -144,7 +131,6 @@ resource "google_compute_router_interface" "router1_interface2" { } resource "google_compute_router_peer" "router1_peer2" { - provider = google-beta name = "router1-peer2" router = google_compute_router.router1.name region = "us-central1" diff --git a/website/docs/r/compute_ha_vpn_gateway.html.markdown b/website/docs/r/compute_ha_vpn_gateway.html.markdown index 77840fc64a8..c1afa4e39a0 100644 --- a/website/docs/r/compute_ha_vpn_gateway.html.markdown +++ b/website/docs/r/compute_ha_vpn_gateway.html.markdown @@ -26,12 +26,10 @@ 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/guides/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) +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/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) @@ -46,14 +44,12 @@ To get more information about HaVpnGateway, see: ```hcl resource "google_compute_ha_vpn_gateway" "ha_gateway1" { - provider = google-beta region = "us-central1" name = "ha-vpn-1" network = google_compute_network.network1.id } resource "google_compute_network" "network1" { - provider = google-beta name = "network1" auto_create_subnetworks = false } @@ -68,35 +64,30 @@ resource "google_compute_network" "network1" { ```hcl resource "google_compute_ha_vpn_gateway" "ha_gateway1" { - provider = google-beta region = "us-central1" name = "ha-vpn-1" network = google_compute_network.network1.id } resource "google_compute_ha_vpn_gateway" "ha_gateway2" { - provider = google-beta region = "us-central1" name = "ha-vpn-2" network = google_compute_network.network2.id } 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" @@ -104,7 +95,6 @@ resource "google_compute_subnetwork" "network1_subnet1" { } 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" @@ -112,7 +102,6 @@ resource "google_compute_subnetwork" "network1_subnet2" { } 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" @@ -120,7 +109,6 @@ resource "google_compute_subnetwork" "network2_subnet1" { } 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" @@ -128,7 +116,6 @@ resource "google_compute_subnetwork" "network2_subnet2" { } resource "google_compute_router" "router1" { - provider = google-beta name = "ha-vpn-router1" network = google_compute_network.network1.name bgp { @@ -137,7 +124,6 @@ resource "google_compute_router" "router1" { } resource "google_compute_router" "router2" { - provider = google-beta name = "ha-vpn-router2" network = google_compute_network.network2.name bgp { @@ -146,7 +132,6 @@ resource "google_compute_router" "router2" { } 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.id @@ -157,7 +142,6 @@ resource "google_compute_vpn_tunnel" "tunnel1" { } 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.id @@ -168,7 +152,6 @@ resource "google_compute_vpn_tunnel" "tunnel2" { } 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.id @@ -179,7 +162,6 @@ resource "google_compute_vpn_tunnel" "tunnel3" { } 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.id @@ -190,7 +172,6 @@ resource "google_compute_vpn_tunnel" "tunnel4" { } resource "google_compute_router_interface" "router1_interface1" { - provider = google-beta name = "router1-interface1" router = google_compute_router.router1.name region = "us-central1" @@ -199,7 +180,6 @@ resource "google_compute_router_interface" "router1_interface1" { } resource "google_compute_router_peer" "router1_peer1" { - provider = google-beta name = "router1-peer1" router = google_compute_router.router1.name region = "us-central1" @@ -210,7 +190,6 @@ resource "google_compute_router_peer" "router1_peer1" { } resource "google_compute_router_interface" "router1_interface2" { - provider = google-beta name = "router1-interface2" router = google_compute_router.router1.name region = "us-central1" @@ -219,7 +198,6 @@ resource "google_compute_router_interface" "router1_interface2" { } resource "google_compute_router_peer" "router1_peer2" { - provider = google-beta name = "router1-peer2" router = google_compute_router.router1.name region = "us-central1" @@ -230,7 +208,6 @@ resource "google_compute_router_peer" "router1_peer2" { } resource "google_compute_router_interface" "router2_interface1" { - provider = google-beta name = "router2-interface1" router = google_compute_router.router2.name region = "us-central1" @@ -239,7 +216,6 @@ resource "google_compute_router_interface" "router2_interface1" { } resource "google_compute_router_peer" "router2_peer1" { - provider = google-beta name = "router2-peer1" router = google_compute_router.router2.name region = "us-central1" @@ -250,7 +226,6 @@ resource "google_compute_router_peer" "router2_peer1" { } resource "google_compute_router_interface" "router2_interface2" { - provider = google-beta name = "router2-interface2" router = google_compute_router.router2.name region = "us-central1" @@ -259,7 +234,6 @@ resource "google_compute_router_interface" "router2_interface2" { } resource "google_compute_router_peer" "router2_peer2" { - provider = google-beta name = "router2-peer2" router = google_compute_router.router2.name region = "us-central1" diff --git a/website/docs/r/compute_vpn_gateway.html.markdown b/website/docs/r/compute_vpn_gateway.html.markdown index 18a7dea3d36..9c2acabb406 100644 --- a/website/docs/r/compute_vpn_gateway.html.markdown +++ b/website/docs/r/compute_vpn_gateway.html.markdown @@ -30,6 +30,9 @@ To get more information about VpnGateway, see: * [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/targetVpnGateways) +~> **Warning:** Classic VPN is deprecating certain functionality on October 31, 2021. For more information, +see the [Classic VPN partial deprecation page](https://cloud.google.com/network-connectivity/docs/vpn/deprecations/classic-vpn-deprecation). +
Open in Cloud Shell diff --git a/website/docs/r/compute_vpn_tunnel.html.markdown b/website/docs/r/compute_vpn_tunnel.html.markdown index 6c62845aef8..1bf94394876 100644 --- a/website/docs/r/compute_vpn_tunnel.html.markdown +++ b/website/docs/r/compute_vpn_tunnel.html.markdown @@ -224,25 +224,25 @@ The following arguments are supported: associated. * `vpn_gateway` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + (Optional) 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/guides/provider_versions.html)) + (Optional) 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/guides/provider_versions.html)) + (Optional) 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/guides/provider_versions.html)) + (Optional) 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/guides/provider_versions.html)) + (Optional) 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.