From 89f76788d4369e1cec9e764062885defc0489cfb Mon Sep 17 00:00:00 2001 From: emily Date: Tue, 18 Jun 2019 02:13:46 +0000 Subject: [PATCH] Add max_connection/rate_per_endpoint to backend services Signed-off-by: Modular Magician --- google/resource_compute_backend_service.go | 71 +++++- .../resource_compute_backend_service_test.go | 230 ++++++++++++++++++ ...resource_compute_network_endpoint_group.go | 7 + .../r/compute_backend_service.html.markdown | 16 ++ ...mpute_network_endpoint_group.html.markdown | 1 + 5 files changed, 321 insertions(+), 4 deletions(-) diff --git a/google/resource_compute_backend_service.go b/google/resource_compute_backend_service.go index 9204064475e..dc6947ebfb9 100644 --- a/google/resource_compute_backend_service.go +++ b/google/resource_compute_backend_service.go @@ -111,6 +111,23 @@ func resourceGoogleComputeBackendServiceBackendHash(v interface{}) int { // the hash function doesn't return something else. buf.WriteString(fmt.Sprintf("%f-", v.(float64))) } + if v, ok := m["max_connections_per_endpoint"]; ok { + if v == nil { + v = 0 + } + + buf.WriteString(fmt.Sprintf("%v-", v)) + } + if v, ok := m["max_rate_per_endpoint"]; ok { + if v == nil { + v = 0.0 + } + + // floats can't be added to the hash with %v as the other values are because + // %v and %f are not equivalent strings so this must remain as a float so that + // the hash function doesn't return something else. + buf.WriteString(fmt.Sprintf("%f-", v.(float64))) + } log.Printf("[DEBUG] computed hash value of %v from %v", hashcode.String(buf.String()), buf.String()) return hashcode.String(buf.String()) @@ -333,6 +350,10 @@ func computeBackendServiceBackendSchema() *schema.Resource { Type: schema.TypeInt, Optional: true, }, + "max_connections_per_endpoint": { + Type: schema.TypeInt, + Optional: true, + }, "max_connections_per_instance": { Type: schema.TypeInt, Optional: true, @@ -341,6 +362,10 @@ func computeBackendServiceBackendSchema() *schema.Resource { Type: schema.TypeInt, Optional: true, }, + "max_rate_per_endpoint": { + Type: schema.TypeFloat, + Optional: true, + }, "max_rate_per_instance": { Type: schema.TypeFloat, Optional: true, @@ -852,8 +877,10 @@ func flattenComputeBackendServiceBackend(v interface{}, d *schema.ResourceData) "group": flattenComputeBackendServiceBackendGroup(original["group"], d), "max_connections": flattenComputeBackendServiceBackendMaxConnections(original["maxConnections"], d), "max_connections_per_instance": flattenComputeBackendServiceBackendMaxConnectionsPerInstance(original["maxConnectionsPerInstance"], d), + "max_connections_per_endpoint": flattenComputeBackendServiceBackendMaxConnectionsPerEndpoint(original["maxConnectionsPerEndpoint"], d), "max_rate": flattenComputeBackendServiceBackendMaxRate(original["maxRate"], d), "max_rate_per_instance": flattenComputeBackendServiceBackendMaxRatePerInstance(original["maxRatePerInstance"], d), + "max_rate_per_endpoint": flattenComputeBackendServiceBackendMaxRatePerEndpoint(original["maxRatePerEndpoint"], d), "max_utilization": flattenComputeBackendServiceBackendMaxUtilization(original["maxUtilization"], d), }) } @@ -898,6 +925,16 @@ func flattenComputeBackendServiceBackendMaxConnectionsPerInstance(v interface{}, return v } +func flattenComputeBackendServiceBackendMaxConnectionsPerEndpoint(v interface{}, d *schema.ResourceData) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + func flattenComputeBackendServiceBackendMaxRate(v interface{}, d *schema.ResourceData) interface{} { // Handles the string fixed64 format if strVal, ok := v.(string); ok { @@ -912,6 +949,10 @@ func flattenComputeBackendServiceBackendMaxRatePerInstance(v interface{}, d *sch return v } +func flattenComputeBackendServiceBackendMaxRatePerEndpoint(v interface{}, d *schema.ResourceData) interface{} { + return v +} + func flattenComputeBackendServiceBackendMaxUtilization(v interface{}, d *schema.ResourceData) interface{} { return v } @@ -1143,31 +1184,45 @@ func expandComputeBackendServiceBackend(v interface{}, d TerraformResourceData, transformedMaxConnections, err := expandComputeBackendServiceBackendMaxConnections(original["max_connections"], d, config) if err != nil { return nil, err - } else if val := reflect.ValueOf(transformedMaxConnections); val.IsValid() && !isEmptyValue(val) { + } else { transformed["maxConnections"] = transformedMaxConnections } transformedMaxConnectionsPerInstance, err := expandComputeBackendServiceBackendMaxConnectionsPerInstance(original["max_connections_per_instance"], d, config) if err != nil { return nil, err - } else if val := reflect.ValueOf(transformedMaxConnectionsPerInstance); val.IsValid() && !isEmptyValue(val) { + } else { transformed["maxConnectionsPerInstance"] = transformedMaxConnectionsPerInstance } + transformedMaxConnectionsPerEndpoint, err := expandComputeBackendServiceBackendMaxConnectionsPerEndpoint(original["max_connections_per_endpoint"], d, config) + if err != nil { + return nil, err + } else { + transformed["maxConnectionsPerEndpoint"] = transformedMaxConnectionsPerEndpoint + } + transformedMaxRate, err := expandComputeBackendServiceBackendMaxRate(original["max_rate"], d, config) if err != nil { return nil, err - } else if val := reflect.ValueOf(transformedMaxRate); val.IsValid() && !isEmptyValue(val) { + } else { transformed["maxRate"] = transformedMaxRate } transformedMaxRatePerInstance, err := expandComputeBackendServiceBackendMaxRatePerInstance(original["max_rate_per_instance"], d, config) if err != nil { return nil, err - } else if val := reflect.ValueOf(transformedMaxRatePerInstance); val.IsValid() && !isEmptyValue(val) { + } else { transformed["maxRatePerInstance"] = transformedMaxRatePerInstance } + transformedMaxRatePerEndpoint, err := expandComputeBackendServiceBackendMaxRatePerEndpoint(original["max_rate_per_endpoint"], d, config) + if err != nil { + return nil, err + } else { + transformed["maxRatePerEndpoint"] = transformedMaxRatePerEndpoint + } + transformedMaxUtilization, err := expandComputeBackendServiceBackendMaxUtilization(original["max_utilization"], d, config) if err != nil { return nil, err @@ -1204,6 +1259,10 @@ func expandComputeBackendServiceBackendMaxConnectionsPerInstance(v interface{}, return v, nil } +func expandComputeBackendServiceBackendMaxConnectionsPerEndpoint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandComputeBackendServiceBackendMaxRate(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -1212,6 +1271,10 @@ func expandComputeBackendServiceBackendMaxRatePerInstance(v interface{}, d Terra return v, nil } +func expandComputeBackendServiceBackendMaxRatePerEndpoint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandComputeBackendServiceBackendMaxUtilization(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } diff --git a/google/resource_compute_backend_service_test.go b/google/resource_compute_backend_service_test.go index 117084e9099..597f01b7590 100644 --- a/google/resource_compute_backend_service_test.go +++ b/google/resource_compute_backend_service_test.go @@ -603,6 +603,80 @@ func TestAccComputeBackendService_withMaxConnectionsPerInstance(t *testing.T) { } } +func TestAccComputeBackendService_withMaxRatePerEndpoint(t *testing.T) { + t.Parallel() + + randSuffix := acctest.RandString(10) + service := fmt.Sprintf("tf-test-%s", randSuffix) + instance := fmt.Sprintf("tf-test-%s", randSuffix) + neg := fmt.Sprintf("tf-test-%s", randSuffix) + network := fmt.Sprintf("tf-test-%s", randSuffix) + check := fmt.Sprintf("tf-test-%s", randSuffix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeBackendServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeBackendService_withMaxRatePerEndpoint( + service, instance, neg, network, check, 0.2), + }, + { + ResourceName: "google_compute_backend_service.lipsum", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeBackendService_withMaxRatePerEndpoint( + service, instance, neg, network, check, 0.4), + }, + { + ResourceName: "google_compute_backend_service.lipsum", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeBackendService_withMaxConnectionsPerEndpoint(t *testing.T) { + t.Parallel() + + randSuffix := acctest.RandString(10) + service := fmt.Sprintf("tf-test-%s", randSuffix) + instance := fmt.Sprintf("tf-test-%s", randSuffix) + neg := fmt.Sprintf("tf-test-%s", randSuffix) + network := fmt.Sprintf("tf-test-%s", randSuffix) + check := fmt.Sprintf("tf-test-%s", randSuffix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeBackendServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeBackendService_withMaxConnectionsPerEndpoint( + service, instance, neg, network, check, 5), + }, + { + ResourceName: "google_compute_backend_service.lipsum", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeBackendService_withMaxConnectionsPerEndpoint( + service, instance, neg, network, check, 10), + }, + { + ResourceName: "google_compute_backend_service.lipsum", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccComputeBackendService_basic(serviceName, checkName string) string { return fmt.Sprintf(` resource "google_compute_backend_service" "foobar" { @@ -996,3 +1070,159 @@ resource "google_compute_health_check" "default" { } `, serviceName, maxConnectionsPerInstance, igName, itName, checkName) } + +func testAccComputeBackendService_withMaxConnectionsPerEndpoint( + service, instance, neg, network, check string, maxConnections int64) string { + return fmt.Sprintf(` +resource "google_compute_backend_service" "lipsum" { + name = "%s" + description = "Hello World 1234" + port_name = "http" + protocol = "TCP" + + backend { + group = "${google_compute_network_endpoint_group.lb-neg.self_link}" + balancing_mode = "CONNECTION" + max_connections_per_endpoint = %v + } + + health_checks = ["${google_compute_health_check.default.self_link}"] +} + +data "google_compute_image" "my_image" { + family = "debian-9" + project = "debian-cloud" +} + +resource "google_compute_instance" "endpoint-instance" { + name = "%s" + machine_type = "n1-standard-1" + + boot_disk { + initialize_params{ + image = "${data.google_compute_image.my_image.self_link}" + } + } + + network_interface { + subnetwork = "${google_compute_subnetwork.default.self_link}" + access_config { } + } +} + +resource "google_compute_network_endpoint_group" "lb-neg" { + name = "%s" + network = "${google_compute_network.default.self_link}" + subnetwork = "${google_compute_subnetwork.default.self_link}" + default_port = "90" + zone = "us-central1-a" +} + +resource "google_compute_network_endpoint" "lb-endpoint" { + network_endpoint_group = "${google_compute_network_endpoint_group.lb-neg.name}" + + instance = "${google_compute_instance.endpoint-instance.name}" + port = "${google_compute_network_endpoint_group.lb-neg.default_port}" + ip_address = "${google_compute_instance.endpoint-instance.network_interface.0.network_ip}" +} + +resource "google_compute_network" "default" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "default" { + name = "%s" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = "${google_compute_network.default.self_link}" +} + +resource "google_compute_health_check" "default" { + name = "%s" + tcp_health_check { + port = "110" + } +} +`, service, maxConnections, instance, neg, network, network, check) +} + +func testAccComputeBackendService_withMaxRatePerEndpoint( + service, instance, neg, network, check string, maxRate float64) string { + return fmt.Sprintf(` +resource "google_compute_backend_service" "lipsum" { + name = "%s" + description = "Hello World 1234" + port_name = "https" + protocol = "HTTPS" + + backend { + group = "${google_compute_network_endpoint_group.lb-neg.self_link}" + balancing_mode = "RATE" + max_rate_per_endpoint = %v + } + + health_checks = ["${google_compute_health_check.default.self_link}"] +} + +data "google_compute_image" "my_image" { + family = "debian-9" + project = "debian-cloud" +} + +resource "google_compute_instance" "endpoint-instance" { + name = "%s" + machine_type = "n1-standard-1" + + boot_disk { + initialize_params{ + image = "${data.google_compute_image.my_image.self_link}" + } + } + + network_interface { + subnetwork = "${google_compute_subnetwork.default.self_link}" + access_config { } + } +} + +resource "google_compute_network_endpoint_group" "lb-neg" { + name = "%s" + network = "${google_compute_network.default.self_link}" + subnetwork = "${google_compute_subnetwork.default.self_link}" + default_port = "90" + zone = "us-central1-a" +} + +resource "google_compute_network_endpoint" "lb-endpoint" { + network_endpoint_group = "${google_compute_network_endpoint_group.lb-neg.name}" + + instance = "${google_compute_instance.endpoint-instance.name}" + port = "${google_compute_network_endpoint_group.lb-neg.default_port}" + ip_address = "${google_compute_instance.endpoint-instance.network_interface.0.network_ip}" +} + +resource "google_compute_network" "default" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "default" { + name = "%s" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = "${google_compute_network.default.self_link}" +} + +resource "google_compute_health_check" "default" { + name = "%s" + check_interval_sec = 3 + healthy_threshold = 3 + timeout_sec = 2 + unhealthy_threshold = 3 + https_health_check { + port = "443" + } +} +`, service, maxRate, instance, neg, network, network, check) +} diff --git a/google/resource_compute_network_endpoint_group.go b/google/resource_compute_network_endpoint_group.go index 69d42eb6006..9e8115d0712 100644 --- a/google/resource_compute_network_endpoint_group.go +++ b/google/resource_compute_network_endpoint_group.go @@ -94,6 +94,10 @@ func resourceComputeNetworkEndpointGroup() *schema.Resource { Computed: true, ForceNew: true, }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -233,6 +237,9 @@ func resourceComputeNetworkEndpointGroupRead(d *schema.ResourceData, meta interf if err := d.Set("zone", flattenComputeNetworkEndpointGroupZone(res["zone"], d)); err != nil { return fmt.Errorf("Error reading NetworkEndpointGroup: %s", err) } + if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading NetworkEndpointGroup: %s", err) + } return nil } diff --git a/website/docs/r/compute_backend_service.html.markdown b/website/docs/r/compute_backend_service.html.markdown index 0fc369d346d..f095eb2e121 100644 --- a/website/docs/r/compute_backend_service.html.markdown +++ b/website/docs/r/compute_backend_service.html.markdown @@ -213,6 +213,15 @@ The `backend` block supports: For CONNECTION mode, either maxConnections or maxConnectionsPerInstance must be set. +* `max_connections_per_endpoint` - + (Optional) + The max number of simultaneous connections that a single backend + network endpoint can handle. This is used to calculate the + capacity of the group. Can be used in either CONNECTION or + UTILIZATION balancing modes. + For CONNECTION mode, either + maxConnections or maxConnectionsPerEndpoint must be set. + * `max_rate` - (Optional) The max requests per second (RPS) of the group. @@ -227,6 +236,13 @@ The `backend` block supports: the group. Can be used in either balancing mode. For RATE mode, either maxRate or maxRatePerInstance must be set. +* `max_rate_per_endpoint` - + (Optional) + The max requests per second (RPS) that a single backend network + endpoint can handle. This is used to calculate the capacity of + the group. Can be used in either balancing mode. For RATE mode, + either maxRate or maxRatePerEndpoint must be set. + * `max_utilization` - (Optional) Used when balancingMode is UTILIZATION. This ratio defines the diff --git a/website/docs/r/compute_network_endpoint_group.html.markdown b/website/docs/r/compute_network_endpoint_group.html.markdown index fb33505dcfe..917b3dd1284 100644 --- a/website/docs/r/compute_network_endpoint_group.html.markdown +++ b/website/docs/r/compute_network_endpoint_group.html.markdown @@ -129,6 +129,7 @@ In addition to the arguments listed above, the following computed attributes are * `size` - Number of network endpoints in the network endpoint group. +* `self_link` - The URI of the created resource. ## Timeouts