From 53d0d44cda5833795afb884278284ee97b9f3cdb Mon Sep 17 00:00:00 2001 From: Ty Larrabee Date: Tue, 29 Oct 2019 20:28:24 +0000 Subject: [PATCH] Add L7 ILB fields to RegionBackendService Signed-off-by: Modular Magician --- google/resource_compute_forwarding_rule.go | 2 +- ...resource_compute_global_forwarding_rule.go | 2 +- ...resource_compute_region_backend_service.go | 495 ++++++++++++++---- .../r/compute_backend_service.html.markdown | 2 +- .../r/compute_forwarding_rule.html.markdown | 12 +- ...mpute_region_backend_service.html.markdown | 226 ++++++-- 6 files changed, 591 insertions(+), 148 deletions(-) diff --git a/google/resource_compute_forwarding_rule.go b/google/resource_compute_forwarding_rule.go index 001836dc0d9..c2830ab8e50 100644 --- a/google/resource_compute_forwarding_rule.go +++ b/google/resource_compute_forwarding_rule.go @@ -90,7 +90,7 @@ func resourceComputeForwardingRule() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{"INTERNAL", "EXTERNAL", ""}, false), + ValidateFunc: validation.StringInSlice([]string{"EXTERNAL", "INTERNAL", "INTERNAL_MANAGED", ""}, false), Default: "EXTERNAL", }, "network": { diff --git a/google/resource_compute_global_forwarding_rule.go b/google/resource_compute_global_forwarding_rule.go index f2318ffef2d..264f7e1cbc5 100644 --- a/google/resource_compute_global_forwarding_rule.go +++ b/google/resource_compute_global_forwarding_rule.go @@ -82,7 +82,7 @@ func resourceComputeGlobalForwardingRule() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{"INTERNAL_SELF_MANAGED", "EXTERNAL", ""}, false), + ValidateFunc: validation.StringInSlice([]string{"EXTERNAL", "INTERNAL_SELF_MANAGED", ""}, false), Default: "EXTERNAL", }, "metadata_filters": { diff --git a/google/resource_compute_region_backend_service.go b/google/resource_compute_region_backend_service.go index 5e204959201..e0fb8f7ef9a 100644 --- a/google/resource_compute_region_backend_service.go +++ b/google/resource_compute_region_backend_service.go @@ -67,6 +67,10 @@ func resourceComputeRegionBackendService() *schema.Resource { Required: true, ForceNew: true, }, + "affinity_cookie_ttl_sec": { + Type: schema.TypeInt, + Optional: true, + }, "backend": { Type: schema.TypeSet, Optional: true, @@ -86,9 +90,15 @@ func resourceComputeRegionBackendService() *schema.Resource { "load_balancing_scheme": { Type: schema.TypeString, Optional: true, - ValidateFunc: validation.StringInSlice([]string{"INTERNAL", ""}, false), + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"INTERNAL", "INTERNAL_MANAGED", ""}, false), Default: "INTERNAL", }, + "port_name": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, "protocol": { Type: schema.TypeString, Computed: true, @@ -99,20 +109,23 @@ func resourceComputeRegionBackendService() *schema.Resource { Type: schema.TypeString, Computed: true, Optional: true, - ForceNew: true, DiffSuppressFunc: compareSelfLinkOrResourceName, }, "session_affinity": { Type: schema.TypeString, Computed: true, Optional: true, - ValidateFunc: validation.StringInSlice([]string{"NONE", "CLIENT_IP", "CLIENT_IP_PROTO", "CLIENT_IP_PORT_PROTO", ""}, false), + ValidateFunc: validation.StringInSlice([]string{"NONE", "CLIENT_IP", "CLIENT_IP_PORT_PROTO", "CLIENT_IP_PROTO", "GENERATED_COOKIE", "HEADER_FIELD", "HTTP_COOKIE", ""}, false), }, "timeout_sec": { Type: schema.TypeInt, Computed: true, Optional: true, }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, "fingerprint": { Type: schema.TypeString, Computed: true, @@ -134,6 +147,17 @@ func resourceComputeRegionBackendService() *schema.Resource { func computeRegionBackendServiceBackendSchema() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ + "balancing_mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"UTILIZATION", "RATE", "CONNECTION", ""}, false), + Default: "CONNECTION", + }, + "capacity_scaler": { + Type: schema.TypeFloat, + Computed: true, + Optional: true, + }, "description": { Type: schema.TypeString, Optional: true, @@ -143,6 +167,34 @@ func computeRegionBackendServiceBackendSchema() *schema.Resource { Optional: true, DiffSuppressFunc: compareSelfLinkRelativePaths, }, + "max_connections": { + Type: schema.TypeInt, + Optional: true, + }, + "max_connections_per_endpoint": { + Type: schema.TypeInt, + Optional: true, + }, + "max_connections_per_instance": { + Type: schema.TypeInt, + Optional: true, + }, + "max_rate": { + Type: schema.TypeInt, + Optional: true, + }, + "max_rate_per_endpoint": { + Type: schema.TypeFloat, + Optional: true, + }, + "max_rate_per_instance": { + Type: schema.TypeFloat, + Optional: true, + }, + "max_utilization": { + Type: schema.TypeFloat, + Optional: true, + }, }, } } @@ -151,17 +203,11 @@ func resourceComputeRegionBackendServiceCreate(d *schema.ResourceData, meta inte config := meta.(*Config) obj := make(map[string]interface{}) - nameProp, err := expandComputeRegionBackendServiceName(d.Get("name"), d, config) + affinityCookieTtlSecProp, err := expandComputeRegionBackendServiceAffinityCookieTtlSec(d.Get("affinity_cookie_ttl_sec"), 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 - } - healthChecksProp, err := expandComputeRegionBackendServiceHealthChecks(d.Get("health_checks"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(healthChecksProp)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) { - obj["healthChecks"] = healthChecksProp + } else if v, ok := d.GetOkExists("affinity_cookie_ttl_sec"); !isEmptyValue(reflect.ValueOf(affinityCookieTtlSecProp)) && (ok || !reflect.DeepEqual(v, affinityCookieTtlSecProp)) { + obj["affinityCookieTtlSec"] = affinityCookieTtlSecProp } backendsProp, err := expandComputeRegionBackendServiceBackend(d.Get("backend"), d, config) if err != nil { @@ -169,6 +215,12 @@ func resourceComputeRegionBackendServiceCreate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("backend"); !isEmptyValue(reflect.ValueOf(backendsProp)) && (ok || !reflect.DeepEqual(v, backendsProp)) { obj["backends"] = backendsProp } + connectionDrainingProp, err := expandComputeRegionBackendServiceConnectionDraining(nil, d, config) + if err != nil { + return err + } else if !isEmptyValue(reflect.ValueOf(connectionDrainingProp)) { + obj["connectionDraining"] = connectionDrainingProp + } descriptionProp, err := expandComputeRegionBackendServiceDescription(d.Get("description"), d, config) if err != nil { return err @@ -181,6 +233,30 @@ func resourceComputeRegionBackendServiceCreate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("fingerprint"); !isEmptyValue(reflect.ValueOf(fingerprintProp)) && (ok || !reflect.DeepEqual(v, fingerprintProp)) { obj["fingerprint"] = fingerprintProp } + healthChecksProp, err := expandComputeRegionBackendServiceHealthChecks(d.Get("health_checks"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(healthChecksProp)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) { + obj["healthChecks"] = healthChecksProp + } + loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(loadBalancingSchemeProp)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) { + obj["loadBalancingScheme"] = loadBalancingSchemeProp + } + nameProp, err := expandComputeRegionBackendServiceName(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 + } + portNameProp, err := expandComputeRegionBackendServicePortName(d.Get("port_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("port_name"); !isEmptyValue(reflect.ValueOf(portNameProp)) && (ok || !reflect.DeepEqual(v, portNameProp)) { + obj["portName"] = portNameProp + } protocolProp, err := expandComputeRegionBackendServiceProtocol(d.Get("protocol"), d, config) if err != nil { return err @@ -193,29 +269,17 @@ func resourceComputeRegionBackendServiceCreate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("session_affinity"); !isEmptyValue(reflect.ValueOf(sessionAffinityProp)) && (ok || !reflect.DeepEqual(v, sessionAffinityProp)) { obj["sessionAffinity"] = sessionAffinityProp } - regionProp, err := expandComputeRegionBackendServiceRegion(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 - } timeoutSecProp, err := expandComputeRegionBackendServiceTimeoutSec(d.Get("timeout_sec"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("timeout_sec"); !isEmptyValue(reflect.ValueOf(timeoutSecProp)) && (ok || !reflect.DeepEqual(v, timeoutSecProp)) { obj["timeoutSec"] = timeoutSecProp } - connectionDrainingProp, err := expandComputeRegionBackendServiceConnectionDraining(nil, d, config) - if err != nil { - return err - } else if !isEmptyValue(reflect.ValueOf(connectionDrainingProp)) { - obj["connectionDraining"] = connectionDrainingProp - } - loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config) + regionProp, err := expandComputeRegionBackendServiceRegion(d.Get("region"), d, config) if err != nil { return err - } else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(loadBalancingSchemeProp)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) { - obj["loadBalancingScheme"] = loadBalancingSchemeProp + } 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}}/backendServices") @@ -282,13 +346,23 @@ func resourceComputeRegionBackendServiceRead(d *schema.ResourceData, meta interf return fmt.Errorf("Error reading RegionBackendService: %s", err) } - if err := d.Set("name", flattenComputeRegionBackendServiceName(res["name"], d)); err != nil { + if err := d.Set("affinity_cookie_ttl_sec", flattenComputeRegionBackendServiceAffinityCookieTtlSec(res["affinityCookieTtlSec"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } - if err := d.Set("health_checks", flattenComputeRegionBackendServiceHealthChecks(res["healthChecks"], d)); err != nil { + if err := d.Set("backend", flattenComputeRegionBackendServiceBackend(res["backends"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } - if err := d.Set("backend", flattenComputeRegionBackendServiceBackend(res["backends"], d)); err != nil { + // Terraform must set the top level schema field, but since this object contains collapsed properties + // it's difficult to know what the top level should be. Instead we just loop over the map returned from flatten. + if flattenedProp := flattenComputeRegionBackendServiceConnectionDraining(res["connectionDraining"], d); flattenedProp != nil { + casted := flattenedProp.([]interface{})[0] + if casted != nil { + for k, v := range casted.(map[string]interface{}) { + d.Set(k, v) + } + } + } + if err := d.Set("creation_timestamp", flattenComputeRegionBackendServiceCreationTimestamp(res["creationTimestamp"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } if err := d.Set("description", flattenComputeRegionBackendServiceDescription(res["description"], d)); err != nil { @@ -297,29 +371,28 @@ func resourceComputeRegionBackendServiceRead(d *schema.ResourceData, meta interf if err := d.Set("fingerprint", flattenComputeRegionBackendServiceFingerprint(res["fingerprint"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } - if err := d.Set("protocol", flattenComputeRegionBackendServiceProtocol(res["protocol"], d)); err != nil { + if err := d.Set("health_checks", flattenComputeRegionBackendServiceHealthChecks(res["healthChecks"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } - if err := d.Set("session_affinity", flattenComputeRegionBackendServiceSessionAffinity(res["sessionAffinity"], d)); err != nil { + if err := d.Set("load_balancing_scheme", flattenComputeRegionBackendServiceLoadBalancingScheme(res["loadBalancingScheme"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } - if err := d.Set("region", flattenComputeRegionBackendServiceRegion(res["region"], d)); err != nil { + if err := d.Set("name", flattenComputeRegionBackendServiceName(res["name"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } - if err := d.Set("timeout_sec", flattenComputeRegionBackendServiceTimeoutSec(res["timeoutSec"], d)); err != nil { + if err := d.Set("port_name", flattenComputeRegionBackendServicePortName(res["portName"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } - // Terraform must set the top level schema field, but since this object contains collapsed properties - // it's difficult to know what the top level should be. Instead we just loop over the map returned from flatten. - if flattenedProp := flattenComputeRegionBackendServiceConnectionDraining(res["connectionDraining"], d); flattenedProp != nil { - casted := flattenedProp.([]interface{})[0] - if casted != nil { - for k, v := range casted.(map[string]interface{}) { - d.Set(k, v) - } - } + if err := d.Set("protocol", flattenComputeRegionBackendServiceProtocol(res["protocol"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) } - if err := d.Set("load_balancing_scheme", flattenComputeRegionBackendServiceLoadBalancingScheme(res["loadBalancingScheme"], d)); err != nil { + if err := d.Set("session_affinity", flattenComputeRegionBackendServiceSessionAffinity(res["sessionAffinity"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("timeout_sec", flattenComputeRegionBackendServiceTimeoutSec(res["timeoutSec"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("region", flattenComputeRegionBackendServiceRegion(res["region"], d)); err != nil { return fmt.Errorf("Error reading RegionBackendService: %s", err) } if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { @@ -338,17 +411,11 @@ func resourceComputeRegionBackendServiceUpdate(d *schema.ResourceData, meta inte } obj := make(map[string]interface{}) - nameProp, err := expandComputeRegionBackendServiceName(d.Get("name"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { - obj["name"] = nameProp - } - healthChecksProp, err := expandComputeRegionBackendServiceHealthChecks(d.Get("health_checks"), d, config) + affinityCookieTtlSecProp, err := expandComputeRegionBackendServiceAffinityCookieTtlSec(d.Get("affinity_cookie_ttl_sec"), d, config) if err != nil { return err - } else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) { - obj["healthChecks"] = healthChecksProp + } else if v, ok := d.GetOkExists("affinity_cookie_ttl_sec"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, affinityCookieTtlSecProp)) { + obj["affinityCookieTtlSec"] = affinityCookieTtlSecProp } backendsProp, err := expandComputeRegionBackendServiceBackend(d.Get("backend"), d, config) if err != nil { @@ -356,6 +423,12 @@ func resourceComputeRegionBackendServiceUpdate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("backend"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, backendsProp)) { obj["backends"] = backendsProp } + connectionDrainingProp, err := expandComputeRegionBackendServiceConnectionDraining(nil, d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("connection_draining"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, connectionDrainingProp)) { + obj["connectionDraining"] = connectionDrainingProp + } descriptionProp, err := expandComputeRegionBackendServiceDescription(d.Get("description"), d, config) if err != nil { return err @@ -368,6 +441,30 @@ func resourceComputeRegionBackendServiceUpdate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("fingerprint"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, fingerprintProp)) { obj["fingerprint"] = fingerprintProp } + healthChecksProp, err := expandComputeRegionBackendServiceHealthChecks(d.Get("health_checks"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) { + obj["healthChecks"] = healthChecksProp + } + loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) { + obj["loadBalancingScheme"] = loadBalancingSchemeProp + } + nameProp, err := expandComputeRegionBackendServiceName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + portNameProp, err := expandComputeRegionBackendServicePortName(d.Get("port_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("port_name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, portNameProp)) { + obj["portName"] = portNameProp + } protocolProp, err := expandComputeRegionBackendServiceProtocol(d.Get("protocol"), d, config) if err != nil { return err @@ -380,29 +477,17 @@ func resourceComputeRegionBackendServiceUpdate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("session_affinity"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sessionAffinityProp)) { obj["sessionAffinity"] = sessionAffinityProp } - regionProp, err := expandComputeRegionBackendServiceRegion(d.Get("region"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("region"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, regionProp)) { - obj["region"] = regionProp - } timeoutSecProp, err := expandComputeRegionBackendServiceTimeoutSec(d.Get("timeout_sec"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("timeout_sec"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, timeoutSecProp)) { obj["timeoutSec"] = timeoutSecProp } - connectionDrainingProp, err := expandComputeRegionBackendServiceConnectionDraining(nil, d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("connection_draining"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, connectionDrainingProp)) { - obj["connectionDraining"] = connectionDrainingProp - } - loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config) + regionProp, err := expandComputeRegionBackendServiceRegion(d.Get("region"), d, config) if err != nil { return err - } else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) { - obj["loadBalancingScheme"] = loadBalancingSchemeProp + } else if v, ok := d.GetOkExists("region"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, regionProp)) { + obj["region"] = regionProp } url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/backendServices/{{name}}") @@ -494,15 +579,14 @@ func resourceComputeRegionBackendServiceImport(d *schema.ResourceData, meta inte return []*schema.ResourceData{d}, nil } -func flattenComputeRegionBackendServiceName(v interface{}, d *schema.ResourceData) interface{} { - return v -} - -func flattenComputeRegionBackendServiceHealthChecks(v interface{}, d *schema.ResourceData) interface{} { - if v == nil { - return v +func flattenComputeRegionBackendServiceAffinityCookieTtlSec(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 convertAndMapStringArr(v.([]interface{}), ConvertSelfLinkToV1) + return v } func flattenComputeRegionBackendServiceBackend(v interface{}, d *schema.ResourceData) interface{} { @@ -518,12 +602,29 @@ func flattenComputeRegionBackendServiceBackend(v interface{}, d *schema.Resource continue } transformed.Add(map[string]interface{}{ - "description": flattenComputeRegionBackendServiceBackendDescription(original["description"], d), - "group": flattenComputeRegionBackendServiceBackendGroup(original["group"], d), + "balancing_mode": flattenComputeRegionBackendServiceBackendBalancingMode(original["balancingMode"], d), + "capacity_scaler": flattenComputeRegionBackendServiceBackendCapacityScaler(original["capacityScaler"], d), + "description": flattenComputeRegionBackendServiceBackendDescription(original["description"], d), + "group": flattenComputeRegionBackendServiceBackendGroup(original["group"], d), + "max_connections": flattenComputeRegionBackendServiceBackendMaxConnections(original["maxConnections"], d), + "max_connections_per_instance": flattenComputeRegionBackendServiceBackendMaxConnectionsPerInstance(original["maxConnectionsPerInstance"], d), + "max_connections_per_endpoint": flattenComputeRegionBackendServiceBackendMaxConnectionsPerEndpoint(original["maxConnectionsPerEndpoint"], d), + "max_rate": flattenComputeRegionBackendServiceBackendMaxRate(original["maxRate"], d), + "max_rate_per_instance": flattenComputeRegionBackendServiceBackendMaxRatePerInstance(original["maxRatePerInstance"], d), + "max_rate_per_endpoint": flattenComputeRegionBackendServiceBackendMaxRatePerEndpoint(original["maxRatePerEndpoint"], d), + "max_utilization": flattenComputeRegionBackendServiceBackendMaxUtilization(original["maxUtilization"], d), }) } return transformed } +func flattenComputeRegionBackendServiceBackendBalancingMode(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceBackendCapacityScaler(v interface{}, d *schema.ResourceData) interface{} { + return v +} + func flattenComputeRegionBackendServiceBackendDescription(v interface{}, d *schema.ResourceData) interface{} { return v } @@ -535,30 +636,37 @@ func flattenComputeRegionBackendServiceBackendGroup(v interface{}, d *schema.Res return ConvertSelfLinkToV1(v.(string)) } -func flattenComputeRegionBackendServiceDescription(v interface{}, d *schema.ResourceData) interface{} { - return v -} - -func flattenComputeRegionBackendServiceFingerprint(v interface{}, d *schema.ResourceData) interface{} { - return v -} - -func flattenComputeRegionBackendServiceProtocol(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceBackendMaxConnections(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 flattenComputeRegionBackendServiceSessionAffinity(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceBackendMaxConnectionsPerInstance(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 flattenComputeRegionBackendServiceRegion(v interface{}, d *schema.ResourceData) interface{} { - if v == nil { - return v +func flattenComputeRegionBackendServiceBackendMaxConnectionsPerEndpoint(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 NameFromSelfLinkStateFunc(v) + return v } -func flattenComputeRegionBackendServiceTimeoutSec(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceBackendMaxRate(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 { @@ -568,6 +676,18 @@ func flattenComputeRegionBackendServiceTimeoutSec(v interface{}, d *schema.Resou return v } +func flattenComputeRegionBackendServiceBackendMaxRatePerInstance(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceBackendMaxRatePerEndpoint(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceBackendMaxUtilization(v interface{}, d *schema.ResourceData) interface{} { + return v +} + func flattenComputeRegionBackendServiceConnectionDraining(v interface{}, d *schema.ResourceData) interface{} { if v == nil { return nil @@ -591,16 +711,63 @@ func flattenComputeRegionBackendServiceConnectionDrainingConnectionDrainingTimeo return v } +func flattenComputeRegionBackendServiceCreationTimestamp(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceDescription(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceFingerprint(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceHealthChecks(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return convertAndMapStringArr(v.([]interface{}), ConvertSelfLinkToV1) +} + func flattenComputeRegionBackendServiceLoadBalancingScheme(v interface{}, d *schema.ResourceData) interface{} { return v } -func expandComputeRegionBackendServiceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - return v, nil +func flattenComputeRegionBackendServiceName(v interface{}, d *schema.ResourceData) interface{} { + return v } -func expandComputeRegionBackendServiceHealthChecks(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - v = v.(*schema.Set).List() +func flattenComputeRegionBackendServicePortName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceProtocol(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceSessionAffinity(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceTimeoutSec(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 flattenComputeRegionBackendServiceRegion(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +func expandComputeRegionBackendServiceAffinityCookieTtlSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -615,6 +782,20 @@ func expandComputeRegionBackendServiceBackend(v interface{}, d TerraformResource original := raw.(map[string]interface{}) transformed := make(map[string]interface{}) + transformedBalancingMode, err := expandComputeRegionBackendServiceBackendBalancingMode(original["balancing_mode"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedBalancingMode); val.IsValid() && !isEmptyValue(val) { + transformed["balancingMode"] = transformedBalancingMode + } + + transformedCapacityScaler, err := expandComputeRegionBackendServiceBackendCapacityScaler(original["capacity_scaler"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCapacityScaler); val.IsValid() && !isEmptyValue(val) { + transformed["capacityScaler"] = transformedCapacityScaler + } + transformedDescription, err := expandComputeRegionBackendServiceBackendDescription(original["description"], d, config) if err != nil { return nil, err @@ -629,11 +810,68 @@ func expandComputeRegionBackendServiceBackend(v interface{}, d TerraformResource transformed["group"] = transformedGroup } + transformedMaxConnections, err := expandComputeRegionBackendServiceBackendMaxConnections(original["max_connections"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxConnections); val.IsValid() && !isEmptyValue(val) { + transformed["maxConnections"] = transformedMaxConnections + } + + transformedMaxConnectionsPerInstance, err := expandComputeRegionBackendServiceBackendMaxConnectionsPerInstance(original["max_connections_per_instance"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxConnectionsPerInstance); val.IsValid() && !isEmptyValue(val) { + transformed["maxConnectionsPerInstance"] = transformedMaxConnectionsPerInstance + } + + transformedMaxConnectionsPerEndpoint, err := expandComputeRegionBackendServiceBackendMaxConnectionsPerEndpoint(original["max_connections_per_endpoint"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxConnectionsPerEndpoint); val.IsValid() && !isEmptyValue(val) { + transformed["maxConnectionsPerEndpoint"] = transformedMaxConnectionsPerEndpoint + } + + transformedMaxRate, err := expandComputeRegionBackendServiceBackendMaxRate(original["max_rate"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxRate); val.IsValid() && !isEmptyValue(val) { + transformed["maxRate"] = transformedMaxRate + } + + transformedMaxRatePerInstance, err := expandComputeRegionBackendServiceBackendMaxRatePerInstance(original["max_rate_per_instance"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxRatePerInstance); val.IsValid() && !isEmptyValue(val) { + transformed["maxRatePerInstance"] = transformedMaxRatePerInstance + } + + transformedMaxRatePerEndpoint, err := expandComputeRegionBackendServiceBackendMaxRatePerEndpoint(original["max_rate_per_endpoint"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxRatePerEndpoint); val.IsValid() && !isEmptyValue(val) { + transformed["maxRatePerEndpoint"] = transformedMaxRatePerEndpoint + } + + transformedMaxUtilization, err := expandComputeRegionBackendServiceBackendMaxUtilization(original["max_utilization"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxUtilization); val.IsValid() && !isEmptyValue(val) { + transformed["maxUtilization"] = transformedMaxUtilization + } + req = append(req, transformed) } return req, nil } +func expandComputeRegionBackendServiceBackendBalancingMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendCapacityScaler(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandComputeRegionBackendServiceBackendDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -642,31 +880,31 @@ func expandComputeRegionBackendServiceBackendGroup(v interface{}, d TerraformRes return v, nil } -func expandComputeRegionBackendServiceDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceBackendMaxConnections(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } -func expandComputeRegionBackendServiceFingerprint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceBackendMaxConnectionsPerInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } -func expandComputeRegionBackendServiceProtocol(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceBackendMaxConnectionsPerEndpoint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } -func expandComputeRegionBackendServiceSessionAffinity(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceBackendMaxRate(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } -func expandComputeRegionBackendServiceRegion(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 +func expandComputeRegionBackendServiceBackendMaxRatePerInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil } -func expandComputeRegionBackendServiceTimeoutSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceBackendMaxRatePerEndpoint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendMaxUtilization(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -686,6 +924,47 @@ func expandComputeRegionBackendServiceConnectionDrainingConnectionDrainingTimeou return v, nil } +func expandComputeRegionBackendServiceDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceFingerprint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceHealthChecks(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + func expandComputeRegionBackendServiceLoadBalancingScheme(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } + +func expandComputeRegionBackendServiceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServicePortName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceProtocol(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceSessionAffinity(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceTimeoutSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceRegion(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/website/docs/r/compute_backend_service.html.markdown b/website/docs/r/compute_backend_service.html.markdown index d2c3c8c97af..7c4455991a1 100644 --- a/website/docs/r/compute_backend_service.html.markdown +++ b/website/docs/r/compute_backend_service.html.markdown @@ -259,7 +259,7 @@ The `backend` block supports: For Network Endpoint Groups this defines list of endpoints. All endpoints of Network Endpoint Group must be hosted on instances located in the same zone as the Network Endpoint Group. - Backend service can not contain mix of Instance Group and + Backend services cannot mix Instance Group and Network Endpoint Group backends. Note that you must specify an Instance Group or Network Endpoint Group resource using the fully-qualified URL, rather than a diff --git a/website/docs/r/compute_forwarding_rule.html.markdown b/website/docs/r/compute_forwarding_rule.html.markdown index 64398fa942e..24a313ed85c 100644 --- a/website/docs/r/compute_forwarding_rule.html.markdown +++ b/website/docs/r/compute_forwarding_rule.html.markdown @@ -169,11 +169,13 @@ The following arguments are supported: * `load_balancing_scheme` - (Optional) - This signifies what the ForwardingRule will be used for and can only - take the following values: INTERNAL, EXTERNAL The value of INTERNAL - means that this will be used for Internal Network Load Balancing (TCP, - UDP). The value of EXTERNAL means that this will be used for External - Load Balancing (HTTP(S) LB, External TCP/UDP LB, SSL Proxy) + This signifies what the ForwardingRule will be used for and can be + EXTERNAL, INTERNAL, or INTERNAL_MANAGED. EXTERNAL is used for Classic + Cloud VPN gateways, protocol forwarding to VMs from an external IP address, + and HTTP(S), SSL Proxy, TCP Proxy, and Network TCP/UDP load balancers. + INTERNAL is used for protocol forwarding to VMs from an internal IP address, + and internal TCP/UDP load balancers. + INTERNAL_MANAGED is used for internal HTTP(S) load balancers. * `network` - (Optional) diff --git a/website/docs/r/compute_region_backend_service.html.markdown b/website/docs/r/compute_region_backend_service.html.markdown index 514cbee9b4d..668c445349f 100644 --- a/website/docs/r/compute_region_backend_service.html.markdown +++ b/website/docs/r/compute_region_backend_service.html.markdown @@ -25,9 +25,6 @@ description: |- A Region Backend Service defines a regionally-scoped group of virtual machines that will serve traffic for load balancing. -Region backend services can only be used when using internal load balancing. -For external load balancing, use a global backend service instead. - To get more information about RegionBackendService, see: @@ -62,12 +59,92 @@ resource "google_compute_health_check" "default" { } } ``` + +## Example Usage - Region Backend Service Ilb Round Robin + + +```hcl +resource "google_compute_region_backend_service" "default" { + provider = "google-beta" + + region = "us-central1" + name = "region-backend-service" + health_checks = ["${google_compute_health_check.health_check.self_link}"] + protocol = "HTTP" + load_balancing_scheme = "INTERNAL_MANAGED" + locality_lb_policy = "ROUND_ROBIN" +} + +resource "google_compute_health_check" "health_check" { + provider = "google-beta" + + name = "health-check" + http_health_check { + + } +} +``` + +## Example Usage - Region Backend Service Ilb Ring Hash + + +```hcl +resource "google_compute_region_backend_service" "default" { + provider = "google-beta" + + region = "us-central1" + name = "region-backend-service" + health_checks = ["${google_compute_health_check.health_check.self_link}"] + load_balancing_scheme = "INTERNAL_MANAGED" + locality_lb_policy = "RING_HASH" + session_affinity = "HTTP_COOKIE" + protocol = "HTTP" + circuit_breakers { + max_connections = 10 + } + consistent_hash { + http_cookie { + ttl { + seconds = 11 + nanos = 1111 + } + name = "mycookie" + } + } + outlier_detection { + consecutive_errors = 2 + } +} + +resource "google_compute_health_check" "health_check" { + provider = "google-beta" + + name = "health-check" + http_health_check { + + } +} +``` ## Argument Reference The following arguments are supported: +* `health_checks` - + (Required) + The set of URLs to HealthCheck resources for health checking + this RegionBackendService. Currently at most one health + check can be specified, and a health check is required. + * `name` - (Required) Name of the resource. Provided by the client when the resource is @@ -78,54 +155,65 @@ The following arguments are supported: characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash. -* `health_checks` - - (Required) - The list of HealthChecks for checking the health of the backend service. - Currently at most one health check can be specified, and a health check - is required. - - - - +* `affinity_cookie_ttl_sec` - + (Optional) + Lifetime of cookies in seconds if session_affinity is + GENERATED_COOKIE. If set to 0, the cookie is non-persistent and lasts + only until the end of the browser session (or equivalent). The + maximum allowed value for TTL is one day. + When the load balancing scheme is INTERNAL, this field is not used. + * `backend` - (Optional) - The list of backends that serve this RegionBackendService. Structure is documented below. + The set of backends that serve this RegionBackendService. Structure is documented below. + +* `connection_draining_timeout_sec` - + (Optional) + Time for which instance will be drained (not accept new + connections, but still work to finish started). * `description` - (Optional) An optional description of this resource. -* `protocol` - +* `load_balancing_scheme` - (Optional) - The protocol this BackendService uses to communicate with backends. - The possible values are TCP and UDP, and the default is TCP. + Indicates whether the backend service will be used with internal or + external load balancing. A backend service created for one type of + load balancing cannot be used with the other. Must be `INTERNAL` + or `INTERNAL_MANAGED` for a regional backend service. Defaults to `INTERNAL`. -* `session_affinity` - +* `port_name` - (Optional) - Type of session affinity to use. The default is NONE. - Can be NONE, CLIENT_IP, CLIENT_IP_PROTO, or CLIENT_IP_PORT_PROTO. - When the protocol is UDP, this field is not used. + Name of backend port. The same name should appear in the instance + groups referenced by this service. Required when the load balancing + scheme is EXTERNAL. Must be omitted otherwise. -* `region` - +* `protocol` - (Optional) - The Region in which the created backend service should reside. - If it is not provided, the provider region is used. + The protocol this RegionBackendService uses to communicate with backends. + Possible values are HTTP, HTTPS, HTTP2, SSL, TCP, and UDP. The default is + HTTP. **NOTE**: HTTP2 is only valid for beta HTTP/2 load balancer + types and may result in errors if used with the GA API. + +* `session_affinity` - + (Optional) + Type of session affinity to use. The default is NONE. Session affinity is + not applicable if the protocol is UDP. * `timeout_sec` - (Optional) How many seconds to wait for the backend before considering it a failed request. Default is 30 seconds. Valid range is [1, 86400]. -* `connection_draining_timeout_sec` - - (Optional) - Time for which instance will be drained (not accept new - connections, but still work to finish started). - -* `load_balancing_scheme` - +* `region` - (Optional) - This signifies what the ForwardingRule will be used for and can only - be INTERNAL for RegionBackendServices + The Region in which the created backend service should reside. + If it is not provided, the provider region is used. * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. @@ -133,6 +221,17 @@ The following arguments are supported: The `backend` block supports: +* `balancing_mode` - + (Optional) + Specifies the balancing mode for this backend. Defaults to CONNECTION. + +* `capacity_scaler` - + (Optional) + A multiplier applied to the group's maximum servicing capacity + (based on UTILIZATION, RATE or CONNECTION). + A setting of 0 means the group is completely drained, offering + 0% of its available Capacity. Valid range is [0.0,1.0]. + * `description` - (Optional) An optional description of this resource. @@ -140,21 +239,84 @@ The `backend` block supports: * `group` - (Optional) - The fully-qualified URL of an Instance Group. This defines the list + The fully-qualified URL of an Instance Group or Network Endpoint + Group resource. In case of instance group this defines the list of instances that serve traffic. Member virtual machine instances from each instance group must live in the same zone as the instance group itself. No two backends in a backend service are allowed to use same Instance Group resource. - Note that you must specify an Instance Group - resource using the fully-qualified URL, rather than a + For Network Endpoint Groups this defines list of endpoints. All + endpoints of Network Endpoint Group must be hosted on instances + located in the same zone as the Network Endpoint Group. + Backend services cannot mix Instance Group and + Network Endpoint Group backends. + When the `load_balancing_scheme` is INTERNAL, only instance groups + are supported. + Note that you must specify an Instance Group or Network Endpoint + Group resource using the fully-qualified URL, rather than a partial URL. - The instance group must be within the same region as the BackendService. + +* `max_connections` - + (Optional) + The max number of simultaneous connections for the group. Can + be used with either CONNECTION or UTILIZATION balancing modes. + For CONNECTION mode, either maxConnections or one + of maxConnectionsPerInstance or maxConnectionsPerEndpoint, + as appropriate for group type, must be set. + +* `max_connections_per_instance` - + (Optional) + The max number of simultaneous connections that a single + backend instance 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 + 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. + Can be used with either RATE or UTILIZATION balancing modes, + but required if RATE mode. For RATE mode, either maxRate or one + of maxRatePerInstance or maxRatePerEndpoint, as appropriate for + group type, must be set. + +* `max_rate_per_instance` - + (Optional) + The max requests per second (RPS) that a single backend + instance 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 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 + CPU utilization target for the group. Valid range is [0.0, 1.0]. ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: +* `creation_timestamp` - + Creation timestamp in RFC3339 text format. + * `fingerprint` - Fingerprint of this resource. A hash of the contents stored in this object. This field is used in optimistic locking.