From e4720b37ebd43dbb3cb81fc8102cb15ac4b57362 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Wed, 22 Jun 2022 00:11:24 +0000 Subject: [PATCH] compute: support maxPortsPerVm field related to Cloud NAT's enableDynamicPortAllocation (#6155) Support for the Dynamic Port Allocation feature (tracked in terraform-google-modules/terraform-google-cloud-nat#64 and hashicorp/terraform-provider-google#11052) was initially implemented in #6022, but it lacked support for the maxPortsPerVm field. This field is crucial to allow the full configuration to work. Signed-off-by: Modular Magician --- .changelog/6155.txt | 3 + google-beta/resource_compute_router_nat.go | 46 +++++++++++++++- .../resource_compute_router_nat_test.go | 55 +++++++++++++++++++ .../docs/r/compute_router_nat.html.markdown | 9 ++- 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 .changelog/6155.txt diff --git a/.changelog/6155.txt b/.changelog/6155.txt new file mode 100644 index 0000000000..ccbd2de4c0 --- /dev/null +++ b/.changelog/6155.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +compute: add maxPortsPerVm field to `google_compute_router_nat` resource +``` diff --git a/google-beta/resource_compute_router_nat.go b/google-beta/resource_compute_router_nat.go index e4f6ba23a6..e94f6bacc6 100644 --- a/google-beta/resource_compute_router_nat.go +++ b/google-beta/resource_compute_router_nat.go @@ -185,8 +185,10 @@ valid static external IPs that have been assigned to the NAT.`, Computed: true, Optional: true, Description: `Enable Dynamic Port Allocation. -If minPorts is set, minPortsPerVm must be set to a power of two greater than or equal to 32. +If minPortsPerVm is set, minPortsPerVm must be set to a power of two greater than or equal to 32. If minPortsPerVm is not set, a minimum of 32 ports will be allocated to a VM from this NAT config. +If maxPortsPerVm is set, maxPortsPerVm must be set to a power of two greater than minPortsPerVm. +If maxPortsPerVm is not set, a maximum of 65536 ports will be allocated to a VM from this NAT config. Mutually exclusive with enableEndpointIndependentMapping.`, }, @@ -224,6 +226,12 @@ see the [official documentation](https://cloud.google.com/nat/docs/overview#spec }, }, }, + "max_ports_per_vm": { + Type: schema.TypeInt, + Optional: true, + Description: `Maximum number of ports allocated to a VM from this NAT. +This field can only be set when enableDynamicPortAllocation is enabled.`, + }, "min_ports_per_vm": { Type: schema.TypeInt, Optional: true, @@ -375,6 +383,12 @@ func resourceComputeRouterNatCreate(d *schema.ResourceData, meta interface{}) er } else if v, ok := d.GetOkExists("min_ports_per_vm"); !isEmptyValue(reflect.ValueOf(minPortsPerVmProp)) && (ok || !reflect.DeepEqual(v, minPortsPerVmProp)) { obj["minPortsPerVm"] = minPortsPerVmProp } + maxPortsPerVmProp, err := expandNestedComputeRouterNatMaxPortsPerVm(d.Get("max_ports_per_vm"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("max_ports_per_vm"); !isEmptyValue(reflect.ValueOf(maxPortsPerVmProp)) && (ok || !reflect.DeepEqual(v, maxPortsPerVmProp)) { + obj["maxPortsPerVm"] = maxPortsPerVmProp + } enableDynamicPortAllocationProp, err := expandNestedComputeRouterNatEnableDynamicPortAllocation(d.Get("enable_dynamic_port_allocation"), d, config) if err != nil { return err @@ -543,6 +557,9 @@ func resourceComputeRouterNatRead(d *schema.ResourceData, meta interface{}) erro if err := d.Set("min_ports_per_vm", flattenNestedComputeRouterNatMinPortsPerVm(res["minPortsPerVm"], d, config)); err != nil { return fmt.Errorf("Error reading RouterNat: %s", err) } + if err := d.Set("max_ports_per_vm", flattenNestedComputeRouterNatMaxPortsPerVm(res["maxPortsPerVm"], d, config)); err != nil { + return fmt.Errorf("Error reading RouterNat: %s", err) + } if err := d.Set("enable_dynamic_port_allocation", flattenNestedComputeRouterNatEnableDynamicPortAllocation(res["enableDynamicPortAllocation"], d, config)); err != nil { return fmt.Errorf("Error reading RouterNat: %s", err) } @@ -620,6 +637,12 @@ func resourceComputeRouterNatUpdate(d *schema.ResourceData, meta interface{}) er } else if v, ok := d.GetOkExists("min_ports_per_vm"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, minPortsPerVmProp)) { obj["minPortsPerVm"] = minPortsPerVmProp } + maxPortsPerVmProp, err := expandNestedComputeRouterNatMaxPortsPerVm(d.Get("max_ports_per_vm"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("max_ports_per_vm"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, maxPortsPerVmProp)) { + obj["maxPortsPerVm"] = maxPortsPerVmProp + } enableDynamicPortAllocationProp, err := expandNestedComputeRouterNatEnableDynamicPortAllocation(d.Get("enable_dynamic_port_allocation"), d, config) if err != nil { return err @@ -868,6 +891,23 @@ func flattenNestedComputeRouterNatMinPortsPerVm(v interface{}, d *schema.Resourc return v // let terraform core handle it otherwise } +func flattenNestedComputeRouterNatMaxPortsPerVm(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := stringToFixed64(strVal); 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 flattenNestedComputeRouterNatEnableDynamicPortAllocation(v interface{}, d *schema.ResourceData, config *Config) interface{} { return v } @@ -1060,6 +1100,10 @@ func expandNestedComputeRouterNatMinPortsPerVm(v interface{}, d TerraformResourc return v, nil } +func expandNestedComputeRouterNatMaxPortsPerVm(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandNestedComputeRouterNatEnableDynamicPortAllocation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } diff --git a/google-beta/resource_compute_router_nat_test.go b/google-beta/resource_compute_router_nat_test.go index 737cfc52d3..f5152d6eac 100644 --- a/google-beta/resource_compute_router_nat_test.go +++ b/google-beta/resource_compute_router_nat_test.go @@ -211,6 +211,14 @@ func TestAccComputeRouterNat_withPortAllocationMethods(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccComputeRouterNatWithAllocationMethodWithParameters(routerName, false, true, 256, 8192), + }, + { + ResourceName: "google_compute_router_nat.foobar", + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -654,6 +662,53 @@ resource "google_compute_router_nat" "foobar" { `, routerName, routerName, routerName, routerName, routerName, enableEndpointIndependentMapping, enableDynamicPortAllocation) } +func testAccComputeRouterNatWithAllocationMethodWithParameters(routerName string, enableEndpointIndependentMapping, enableDynamicPortAllocation bool, minPortsPerVm, maxPortsPerVm uint32) string { + return fmt.Sprintf(` +resource "google_compute_network" "foobar" { + name = "%s-net" + auto_create_subnetworks = "false" +} + +resource "google_compute_subnetwork" "foobar" { + name = "%s-subnet" + 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-nat-%s-addr" + region = google_compute_subnetwork.foobar.region +} + +resource "google_compute_router" "foobar" { + name = "%s" + region = google_compute_subnetwork.foobar.region + network = google_compute_network.foobar.self_link + bgp { + asn = 64514 + } +} + +resource "google_compute_router_nat" "foobar" { + name = "%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.name + source_ip_ranges_to_nat = ["ALL_IP_RANGES"] + } + enable_endpoint_independent_mapping = %t + enable_dynamic_port_allocation = %t + min_ports_per_vm = %d + max_ports_per_vm = %d +} +`, routerName, routerName, routerName, routerName, routerName, enableEndpointIndependentMapping, enableDynamicPortAllocation, minPortsPerVm, maxPortsPerVm) +} + func testAccComputeRouterNatBaseResourcesWithNatIps(routerName string) string { return fmt.Sprintf(` resource "google_compute_network" "foobar" { diff --git a/website/docs/r/compute_router_nat.html.markdown b/website/docs/r/compute_router_nat.html.markdown index e84181c950..fe4bea39ba 100644 --- a/website/docs/r/compute_router_nat.html.markdown +++ b/website/docs/r/compute_router_nat.html.markdown @@ -171,11 +171,18 @@ The following arguments are supported: (Optional) Minimum number of ports allocated to a VM from this NAT. +* `max_ports_per_vm` - + (Optional) + Maximum number of ports allocated to a VM from this NAT. + This field can only be set when enableDynamicPortAllocation is enabled. + * `enable_dynamic_port_allocation` - (Optional) Enable Dynamic Port Allocation. - If minPorts is set, minPortsPerVm must be set to a power of two greater than or equal to 32. + If minPortsPerVm is set, minPortsPerVm must be set to a power of two greater than or equal to 32. If minPortsPerVm is not set, a minimum of 32 ports will be allocated to a VM from this NAT config. + If maxPortsPerVm is set, maxPortsPerVm must be set to a power of two greater than minPortsPerVm. + If maxPortsPerVm is not set, a maximum of 65536 ports will be allocated to a VM from this NAT config. Mutually exclusive with enableEndpointIndependentMapping. * `udp_idle_timeout_sec` -