diff --git a/google-beta/provider.go b/google-beta/provider.go index 7733987c175..21b9276681e 100644 --- a/google-beta/provider.go +++ b/google-beta/provider.go @@ -152,6 +152,7 @@ func Provider() terraform.ResourceProvider { "google_compute_route": resourceComputeRoute(), "google_compute_router": resourceComputeRouter(), "google_compute_router_interface": resourceComputeRouterInterface(), + "google_compute_router_nat": resourceComputeRouterNat(), "google_compute_router_peer": resourceComputeRouterPeer(), "google_compute_security_policy": resourceComputeSecurityPolicy(), "google_compute_shared_vpc_host_project": resourceComputeSharedVpcHostProject(), diff --git a/google-beta/resource_compute_router_nat.go b/google-beta/resource_compute_router_nat.go new file mode 100644 index 00000000000..0da513197ac --- /dev/null +++ b/google-beta/resource_compute_router_nat.go @@ -0,0 +1,360 @@ +package google + +import ( + "fmt" + "log" + + "strings" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + computeBeta "google.golang.org/api/compute/v0.beta" + + "google.golang.org/api/googleapi" +) + +var ( + routerNatSubnetworkConfig = &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "source_ip_ranges_to_nat": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "secondary_ip_range_names": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +) + +func resourceComputeRouterNat() *schema.Resource { + return &schema.Resource{ + // TODO(https://github.com/GoogleCloudPlatform/magic-modules/issues/963): Implement Update + Create: resourceComputeRouterNatCreate, + Read: resourceComputeRouterNatRead, + Delete: resourceComputeRouterNatDelete, + Importer: &schema.ResourceImporter{ + State: resourceComputeRouterNatImportState, + }, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateRFC1035Name(2, 63), + }, + "router": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "nat_ip_allocate_option": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"MANUAL_ONLY", "AUTO_ONLY"}, false), + }, + "nat_ips": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "source_subnetwork_ip_ranges_to_nat": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"ALL_SUBNETWORKS_ALL_IP_RANGES", "ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES", "LIST_OF_SUBNETWORKS"}, false), + }, + "subnetwork": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: routerNatSubnetworkConfig, + }, + "min_ports_per_vm": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + "udp_idle_timeout_sec": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + "icmp_idle_timeout_sec": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + "tcp_established_idle_timeout_sec": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + "tcp_transitory_idle_timeout_sec": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + "project": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceComputeRouterNatCreate(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + + region, err := getRegion(d, config) + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + + routerName := d.Get("router").(string) + natName := d.Get("name").(string) + + routerLock := getRouterLockName(region, routerName) + mutexKV.Lock(routerLock) + defer mutexKV.Unlock(routerLock) + + routersService := config.clientComputeBeta.Routers + router, err := routersService.Get(project, region, routerName).Do() + if err != nil { + if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { + return fmt.Errorf("Router %s/%s not found", region, routerName) + } + + return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err) + } + + nats := router.Nats + for _, nat := range nats { + if nat.Name == natName { + return fmt.Errorf("Router %s has nat %s already", routerName, natName) + } + } + + nat := &computeBeta.RouterNat{ + Name: natName, + NatIpAllocateOption: d.Get("nat_ip_allocate_option").(string), + NatIps: convertStringArr(d.Get("nat_ips").(*schema.Set).List()), + SourceSubnetworkIpRangesToNat: d.Get("source_subnetwork_ip_ranges_to_nat").(string), + MinPortsPerVm: int64(d.Get("min_ports_per_vm").(int)), + UdpIdleTimeoutSec: int64(d.Get("udp_idle_timeout_sec").(int)), + IcmpIdleTimeoutSec: int64(d.Get("icmp_idle_timeout_sec").(int)), + TcpEstablishedIdleTimeoutSec: int64(d.Get("tcp_established_idle_timeout_sec").(int)), + TcpTransitoryIdleTimeoutSec: int64(d.Get("tcp_transitory_idle_timeout_sec").(int)), + } + + if v, ok := d.GetOk("subnetwork"); ok { + nat.Subnetworks = expandSubnetworks(v.([]map[string]interface{})) + } + + log.Printf("[INFO] Adding nat %s", natName) + nats = append(nats, nat) + patchRouter := &computeBeta.Router{ + Nats: nats, + } + + log.Printf("[DEBUG] Updating router %s/%s with nats: %+v", region, routerName, nats) + op, err := routersService.Patch(project, region, router.Name, patchRouter).Do() + if err != nil { + return fmt.Errorf("Error patching router %s/%s: %s", region, routerName, err) + } + d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, natName)) + err = computeBetaOperationWaitTime(config.clientCompute, op, project, "Patching router", 4) + if err != nil { + d.SetId("") + return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err) + } + + return resourceComputeRouterNatRead(d, meta) +} + +func resourceComputeRouterNatRead(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + + region, err := getRegion(d, config) + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + + routerName := d.Get("router").(string) + natName := d.Get("name").(string) + + routersService := config.clientComputeBeta.Routers + router, err := routersService.Get(project, region, routerName).Do() + if err != nil { + if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { + log.Printf("[WARN] Removing router nat %s because its router %s/%s is gone", natName, region, routerName) + d.SetId("") + + return nil + } + + return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err) + } + + for _, nat := range router.Nats { + + if nat.Name == natName { + d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, natName)) + d.Set("nat_ip_allocate_option", nat.NatIpAllocateOption) + d.Set("nat_ips", schema.NewSet(schema.HashString, convertStringArrToInterface(nat.NatIps))) + d.Set("source_subnetwork_ip_ranges_to_nat", nat.SourceSubnetworkIpRangesToNat) + d.Set("min_ports_per_vm", nat.MinPortsPerVm) + d.Set("udp_idle_timeout_sec", nat.UdpIdleTimeoutSec) + d.Set("icmp_idle_timeout_sec", nat.IcmpIdleTimeoutSec) + d.Set("tcp_established_idle_timeout_sec", nat.TcpEstablishedIdleTimeoutSec) + d.Set("tcp_transitory_idle_timeout_sec", nat.TcpTransitoryIdleTimeoutSec) + d.Set("region", region) + d.Set("project", project) + + if err := d.Set("subnetwork", nat.Subnetworks); err != nil { + return fmt.Errorf("Error reading router nat: %s", err) + } + + return nil + } + } + + log.Printf("[WARN] Removing router nat %s/%s/%s because it is gone", region, routerName, natName) + d.SetId("") + return nil +} + +func resourceComputeRouterNatDelete(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + + region, err := getRegion(d, config) + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + + routerName := d.Get("router").(string) + natName := d.Get("name").(string) + + routerLock := getRouterLockName(region, routerName) + mutexKV.Lock(routerLock) + defer mutexKV.Unlock(routerLock) + + routersService := config.clientComputeBeta.Routers + router, err := routersService.Get(project, region, routerName).Do() + if err != nil { + if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { + log.Printf("[WARN] Removing router nat %s because its router %s/%s is gone", natName, region, routerName) + + return nil + } + + return fmt.Errorf("Error Reading Router %s: %s", routerName, err) + } + + var newNats []*computeBeta.RouterNat = make([]*computeBeta.RouterNat, 0, len(router.Nats)) + for _, nat := range router.Nats { + if nat.Name == natName { + continue + } else { + newNats = append(newNats, nat) + } + } + + if len(newNats) == len(router.Nats) { + log.Printf("[DEBUG] Router %s/%s had no nat %s already", region, routerName, natName) + d.SetId("") + return nil + } + + log.Printf("[INFO] Removing nat %s from router %s/%s", natName, region, routerName) + patchRouter := &computeBeta.Router{ + Nats: newNats, + } + + if len(newNats) == 0 { + patchRouter.ForceSendFields = append(patchRouter.ForceSendFields, "Nats") + } + + log.Printf("[DEBUG] Updating router %s/%s with nats: %+v", region, routerName, newNats) + op, err := routersService.Patch(project, region, router.Name, patchRouter).Do() + if err != nil { + return fmt.Errorf("Error patching router %s/%s: %s", region, routerName, err) + } + + err = computeBetaOperationWaitTime(config.clientCompute, op, project, "Patching router", 4) + if err != nil { + return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err) + } + + d.SetId("") + return nil +} + +func resourceComputeRouterNatImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 3 { + return nil, fmt.Errorf("Invalid router nat specifier. Expecting {region}/{router}/{nat}") + } + + d.Set("region", parts[0]) + d.Set("router", parts[1]) + d.Set("name", parts[2]) + + return []*schema.ResourceData{d}, nil +} + +func expandSubnetworks(subnetworks []map[string]interface{}) []*computeBeta.RouterNatSubnetworkToNat { + result := make([]*computeBeta.RouterNatSubnetworkToNat, 0, len(subnetworks)) + + for _, subnetwork := range subnetworks { + subnetworkToNat := computeBeta.RouterNatSubnetworkToNat{ + Name: subnetwork["name"].(string), + SourceIpRangesToNat: convertStringSet(subnetwork["source_ip_ranges_to_nat"].(*schema.Set)), + } + if v, ok := subnetwork["secondary_ip_range_names"]; ok { + subnetworkToNat.SecondaryIpRangeNames = convertStringSet(v.(*schema.Set)) + } + result = append(result, &subnetworkToNat) + } + + return result +} diff --git a/google-beta/resource_compute_router_nat_test.go b/google-beta/resource_compute_router_nat_test.go new file mode 100644 index 00000000000..4846c0a05e8 --- /dev/null +++ b/google-beta/resource_compute_router_nat_test.go @@ -0,0 +1,221 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccComputeRouterNat_basic(t *testing.T) { + t.Parallel() + + testId := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeRouterNatDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeRouterNatBasic(testId), + }, + resource.TestStep{ + ResourceName: "google_compute_router_nat.foobar", + ImportState: true, + ImportStateVerify: true, + }, + resource.TestStep{ + Config: testAccComputeRouterNatKeepRouter(testId), + Check: testAccCheckComputeRouterNatDelete( + "google_compute_router_nat.foobar"), + }, + }, + }) +} + +func TestAccComputeRouterNat_withManualIpAndSubnetConfiguration(t *testing.T) { + t.Parallel() + + testId := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeRouterNatDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeRouterNatWithManualIpAndSubnetConfiguration(testId), + }, + resource.TestStep{ + ResourceName: "google_compute_router_nat.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckComputeRouterNatDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + routersService := config.clientCompute.Routers + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_router" { + continue + } + + project, err := getTestProject(rs.Primary, config) + if err != nil { + return err + } + + region, err := getTestRegion(rs.Primary, config) + if err != nil { + return err + } + + routerName := rs.Primary.Attributes["router"] + + _, err = routersService.Get(project, region, routerName).Do() + + if err == nil { + return fmt.Errorf("Error, Router %s in region %s still exists", + routerName, region) + } + } + + return nil +} + +func testAccCheckComputeRouterNatDelete(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + routersService := config.clientComputeBeta.Routers + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_router_nat" { + continue + } + + project, err := getTestProject(rs.Primary, config) + if err != nil { + return err + } + + region, err := getTestRegion(rs.Primary, config) + if err != nil { + return err + } + + name := rs.Primary.Attributes["name"] + routerName := rs.Primary.Attributes["router"] + + router, err := routersService.Get(project, region, routerName).Do() + + if err != nil { + return fmt.Errorf("Error Reading Router %s: %s", routerName, err) + } + + nats := router.Nats + for _, nat := range nats { + + if nat.Name == name { + return fmt.Errorf("Nat %s still exists on router %s/%s", name, region, router.Name) + } + } + } + + return nil + } +} + +func testAccComputeRouterNatBasic(testId string) string { + return fmt.Sprintf(` + resource "google_compute_network" "foobar" { + name = "router-nat-test-%s" + } + resource "google_compute_subnetwork" "foobar" { + name = "router-nat-test-subnetwork-%s" + network = "${google_compute_network.foobar.self_link}" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + } + resource "google_compute_router" "foobar"{ + name = "router-nat-test-%s" + region = "${google_compute_subnetwork.foobar.region}" + network = "${google_compute_network.foobar.self_link}" + bgp { + asn = 64514 + } + } + resource "google_compute_router_nat" "foobar" { + name = "router-nat-test-%s" + router = "${google_compute_router.foobar.name}" + region = "${google_compute_router.foobar.region}" + nat_ip_allocate_option = "AUTO_ONLY" + source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES" + } + `, testId, testId, testId, testId) +} + +func testAccComputeRouterNatWithManualIpAndSubnetConfiguration(testId string) string { + return fmt.Sprintf(` + resource "google_compute_network" "foobar" { + name = "router-nat-test-%s" + } + resource "google_compute_subnetwork" "foobar" { + name = "router-nat-test-subnetwork-%s" + network = "${google_compute_network.foobar.self_link}" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + } + resource "google_compute_address" "foobar" { + name = "router-peer-test-%s" + region = "${google_compute_subnetwork.foobar.region}" + } + resource "google_compute_router" "foobar"{ + name = "router-nat-test-%s" + region = "${google_compute_subnetwork.foobar.region}" + network = "${google_compute_network.foobar.self_link}" + bgp { + asn = 64514 + } + } + resource "google_compute_router_nat" "foobar" { + name = "router-nat-test-%s" + router = "${google_compute_router.foobar.name}" + region = "${google_compute_router.foobar.region}" + nat_ip_allocate_option = "MANUAL_ONLY" + nat_ips = ["${google_compute_address.foobar.self_link}"] + source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS" + subnetwork { + name = "${google_compute_subnetwork.foobar.self_link}" + } + } + `, testId, testId, testId, testId, testId) +} + +func testAccComputeRouterNatKeepRouter(testId string) string { + return fmt.Sprintf(` + resource "google_compute_network" "foobar" { + name = "router-nat-test-%s" + } + resource "google_compute_subnetwork" "foobar" { + name = "router-nat-test-subnetwork-%s" + network = "${google_compute_network.foobar.self_link}" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + } + resource "google_compute_router" "foobar"{ + name = "router-nat-test-%s" + region = "${google_compute_subnetwork.foobar.region}" + network = "${google_compute_network.foobar.self_link}" + bgp { + asn = 64514 + } + } + `, testId, testId, testId) +} diff --git a/website/docs/r/compute_router_nat.html.markdown b/website/docs/r/compute_router_nat.html.markdown new file mode 100644 index 00000000000..680c1482491 --- /dev/null +++ b/website/docs/r/compute_router_nat.html.markdown @@ -0,0 +1,166 @@ +--- +layout: "google" +page_title: "Google: google_compute_router_nat" +sidebar_current: "docs-google-compute-router-nat" +description: |- + Manages a Cloud NAT. +--- + +# google\_compute\_router\_nat + +Manages a Cloud NAT. For more information see +[the official documentation](https://cloud.google.com/nat/docs/overview) +and +[API](https://cloud.google.com/compute/docs/reference/rest/beta/routers). + +## Example Usage + +A simple NAT configuration: enable NAT for all Subnetworks associated with +the Network associated with the given Router. + +```hcl +resource "google_compute_network" "network" { + name = "my-network" +} + +resource "google_compute_subnetwork" "subnetwork" { + name = "my-subnet" + network = "${google_compute_network.network.self_link}" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" +} + +resource "google_compute_router" "router" { + name = "router" + region = "${google_compute_subnetwork.foobar.region}" + network = "${google_compute_network.foobar.self_link}" + bgp { + asn = 64514 + } +} + +resource "google_compute_router_nat" "simple-nat" { + name = "nat-1" + router = "${google_compute_router.router.name}" + region = "us-central1" + nat_ip_allocate_option = "AUTO_ONLY" + source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES" +} +``` + +A production-like configuration: enable NAT for one Subnetwork and use a list of +static external IP address. + +```hcl +resource "google_compute_network" "network" { + name = "my-network" +} + +resource "google_compute_subnetwork" "subnetwork" { + name = "my-subnet" + network = "${google_compute_network.network.self_link}" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" +} + +resource "google_compute_router" "router" { + name = "router" + region = "${google_compute_subnetwork.foobar.region}" + network = "${google_compute_network.foobar.self_link}" + bgp { + asn = 64514 + } +} + +resource "google_compute_address" "address" { + count = 2 + name = "nat-external-address-${var.count}" + region = "us-central1" +} + +resource "google_compute_router_nat" "advanced-nat" { + name = "nat-1" + router = "${google_compute_router.router.name}" + region = "us-central1" + nat_ip_allocate_option = "MANUAL_ONLY" + nat_ips = ["${google_compute_address.*.address.self_link}"] + source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS" + subnetwork { + name = "${google_compute_subnetwork.subnetwork.self_link}" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) A unique name for Cloud NAT, required by GCE. Changing + this forces a new NAT to be created. + +* `router` - (Required) The name of the router in which this NAT will be configured. + Changing this forces a new NAT to be created. + +* `nat_ip_allocate_option` - (Required) How external IPs should be allocated for + this NAT. Valid values are `AUTO_ONLY` or `MANUAL_ONLY`. Changing this forces + a new NAT to be created. + +* `source_subnetwork_ip_ranges_to_nat` - (Required) How NAT should be configured + per Subnetwork. Valid values include: `ALL_SUBNETWORKS_ALL_IP_RANGES`, + `ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES`, `LIST_OF_SUBNETWORKS`. Changing + this forces a new NAT to be created. + +- - - + +* `nat_ips` - (Optional) List of `self_link`s of external IPs. Only valid if + `nat_ip_allocate_option` is set to `MANUAL_ONLY`. Changing this forces a + new NAT to be created. + +* `subnetwork` - (Optional) One or more subnetwork NAT configurations. Only used + if `source_subnetwork_ip_ranges_to_nat` is set to `LIST_OF_SUBNETWORKS`. See + the section below for details on configuration. + +* `min_ports_per_vm` - (Optional) Minimum number of ports allocated to a VM + from this NAT config. If not set, a default number of ports is allocated to a VM. + Changing this forces a new NAT to be created. + +* `udp_idle_timeout_sec` - (Optional) Timeout (in seconds) for UDP connections. + Defaults to 30s if not set. Changing this forces a new NAT to be created. + +* `icmp_idle_timeout_sec` - (Optional) Timeout (in seconds) for ICMP connections. + Defaults to 30s if not set. Changing this forces a new NAT to be created. + +* `tcp_established_idle_timeout_sec` - (Optional) Timeout (in seconds) for TCP + established connections. Defaults to 1200s if not set. Changing this forces + a new NAT to be created. + +* `tcp_transitory_idle_timeout_sec` - (Optional) Timeout (in seconds) for TCP + transitory connections. Defaults to 30s if not set. Changing this forces a + new NAT to be created. + +* `project` - (Optional) The ID of the project in which this NAT's router belongs. If it + is not provided, the provider project is used. Changing this forces a new NAT to be created. + +* `region` - (Optional) The region this NAT's router sits in. If not specified, + the project region will be used. Changing this forces a new NAT to be + created. + +The `subnetwork` block supports: + +* `name` - (Required) The `self_link` of the subnetwork to NAT. + +* `source_ip_ranges_to_nat` - (Optional) List of options for which source IPs in the subnetwork + should have NAT enabled. Supported values include: `ALL_IP_RANGES`, + `LIST_OF_SECONDARY_IP_RANGES`, `PRIMARY_IP_RANGE` + +* `secondary_ip_range_names` - (Optional) List of the secondary ranges of the subnetwork + that are allowed to use NAT. This can be populated only if + `LIST_OF_SECONDARY_IP_RANGES` is one of the values in `source_ip_ranges_to_nat`. + +## Import + +Router NATs can be imported using the `region`, `router`, and `name`, e.g. + +``` +$ terraform import google_compute_router_nat.my-nat us-central1/router-1/nat-1 +``` diff --git a/website/google.erb b/website/google.erb index 6cd10b02fe1..3e48319ed49 100644 --- a/website/google.erb +++ b/website/google.erb @@ -430,6 +430,10 @@ google_compute_router_interface +