From 0ed4068cfbdeef40bd065f853233aa6b0b4f90b4 Mon Sep 17 00:00:00 2001 From: The Magician Date: Tue, 5 Nov 2019 13:50:56 -0800 Subject: [PATCH] Add L7 ILB fields to RegionBackendService (#1311) Signed-off-by: Modular Magician --- .../resource_compute_forwarding_rule.go | 2 +- ...resource_compute_global_forwarding_rule.go | 2 +- ...resource_compute_region_backend_service.go | 1699 +++++++++++++++-- ...e_region_backend_service_generated_test.go | 102 + ...rce_compute_region_backend_service_test.go | 262 +++ .../r/compute_backend_service.html.markdown | 2 +- .../r/compute_forwarding_rule.html.markdown | 12 +- ...mpute_region_backend_service.html.markdown | 496 ++++- 8 files changed, 2390 insertions(+), 187 deletions(-) diff --git a/google-beta/resource_compute_forwarding_rule.go b/google-beta/resource_compute_forwarding_rule.go index c995168d5e..53ffa03b85 100644 --- a/google-beta/resource_compute_forwarding_rule.go +++ b/google-beta/resource_compute_forwarding_rule.go @@ -95,7 +95,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-beta/resource_compute_global_forwarding_rule.go b/google-beta/resource_compute_global_forwarding_rule.go index 89ff33a043..04d70b9a8b 100644 --- a/google-beta/resource_compute_global_forwarding_rule.go +++ b/google-beta/resource_compute_global_forwarding_rule.go @@ -87,7 +87,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-beta/resource_compute_region_backend_service.go b/google-beta/resource_compute_region_backend_service.go index acd35082a6..f58ca1ae9f 100644 --- a/google-beta/resource_compute_region_backend_service.go +++ b/google-beta/resource_compute_region_backend_service.go @@ -67,18 +67,124 @@ func resourceComputeRegionBackendService() *schema.Resource { Required: true, ForceNew: true, }, + "affinity_cookie_ttl_sec": { + Type: schema.TypeInt, + Optional: true, + }, "backend": { Type: schema.TypeSet, Optional: true, Elem: computeRegionBackendServiceBackendSchema(), Set: resourceGoogleComputeBackendServiceBackendHash, }, + "circuit_breakers": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_timeout": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "seconds": { + Type: schema.TypeInt, + Required: true, + }, + "nanos": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "max_connections": { + Type: schema.TypeInt, + Optional: true, + Default: 1024, + }, + "max_pending_requests": { + Type: schema.TypeInt, + Optional: true, + Default: 1024, + }, + "max_requests": { + Type: schema.TypeInt, + Optional: true, + Default: 1024, + }, + "max_requests_per_connection": { + Type: schema.TypeInt, + Optional: true, + }, + "max_retries": { + Type: schema.TypeInt, + Optional: true, + Default: 3, + }, + }, + }, + }, "connection_draining_timeout_sec": { Type: schema.TypeInt, Optional: true, Default: 0, }, + "consistent_hash": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_cookie": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + }, + "path": { + Type: schema.TypeString, + Optional: true, + }, + "ttl": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "seconds": { + Type: schema.TypeInt, + Required: true, + }, + "nanos": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "http_header_name": { + Type: schema.TypeString, + Optional: true, + }, + "minimum_ring_size": { + Type: schema.TypeInt, + Optional: true, + Default: 1024, + }, + }, + }, + }, "description": { Type: schema.TypeString, Optional: true, @@ -107,9 +213,121 @@ 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", }, + "locality_lb_policy": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"ROUND_ROBIN", "LEAST_REQUEST", "RING_HASH", "RANDOM", "ORIGINAL_DESTINATION", "MAGLEV", ""}, false), + }, + "log_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable": { + Type: schema.TypeBool, + Optional: true, + }, + "sample_rate": { + Type: schema.TypeFloat, + Optional: true, + }, + }, + }, + }, + "outlier_detection": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "base_ejection_time": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "seconds": { + Type: schema.TypeInt, + Required: true, + }, + "nanos": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "consecutive_errors": { + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + "consecutive_gateway_failure": { + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + "enforcing_consecutive_errors": { + Type: schema.TypeInt, + Optional: true, + Default: 100, + }, + "enforcing_consecutive_gateway_failure": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + }, + "enforcing_success_rate": { + Type: schema.TypeInt, + Optional: true, + Default: 100, + }, + "interval": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "seconds": { + Type: schema.TypeInt, + Required: true, + }, + "nanos": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "max_ejection_percent": { + Type: schema.TypeInt, + Optional: true, + Default: 10, + }, + "success_rate_minimum_hosts": { + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + "success_rate_request_volume": { + Type: schema.TypeInt, + Optional: true, + Default: 100, + }, + "success_rate_stdev_factor": { + Type: schema.TypeInt, + Optional: true, + Default: 1900, + }, + }, + }, + }, "protocol": { Type: schema.TypeString, Computed: true, @@ -120,20 +338,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, @@ -155,6 +376,22 @@ func resourceComputeRegionBackendService() *schema.Resource { func computeRegionBackendServiceBackendSchema() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ + "group": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkRelativePaths, + }, + "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, @@ -163,10 +400,33 @@ func computeRegionBackendServiceBackendSchema() *schema.Resource { Type: schema.TypeBool, Optional: true, }, - "group": { - Type: schema.TypeString, - 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, }, }, } @@ -176,17 +436,11 @@ func resourceComputeRegionBackendServiceCreate(d *schema.ResourceData, meta inte config := meta.(*Config) 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(nameProp)) && (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(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 { @@ -194,6 +448,24 @@ 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 } + circuitBreakersProp, err := expandComputeRegionBackendServiceCircuitBreakers(d.Get("circuit_breakers"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("circuit_breakers"); !isEmptyValue(reflect.ValueOf(circuitBreakersProp)) && (ok || !reflect.DeepEqual(v, circuitBreakersProp)) { + obj["circuitBreakers"] = circuitBreakersProp + } + consistentHashProp, err := expandComputeRegionBackendServiceConsistentHash(d.Get("consistent_hash"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("consistent_hash"); !isEmptyValue(reflect.ValueOf(consistentHashProp)) && (ok || !reflect.DeepEqual(v, consistentHashProp)) { + obj["consistentHash"] = consistentHashProp + } + 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 @@ -212,6 +484,36 @@ 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 + } + localityLbPolicyProp, err := expandComputeRegionBackendServiceLocalityLbPolicy(d.Get("locality_lb_policy"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("locality_lb_policy"); !isEmptyValue(reflect.ValueOf(localityLbPolicyProp)) && (ok || !reflect.DeepEqual(v, localityLbPolicyProp)) { + obj["localityLbPolicy"] = localityLbPolicyProp + } + 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 + } + outlierDetectionProp, err := expandComputeRegionBackendServiceOutlierDetection(d.Get("outlier_detection"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("outlier_detection"); !isEmptyValue(reflect.ValueOf(outlierDetectionProp)) && (ok || !reflect.DeepEqual(v, outlierDetectionProp)) { + obj["outlierDetection"] = outlierDetectionProp + } protocolProp, err := expandComputeRegionBackendServiceProtocol(d.Get("protocol"), d, config) if err != nil { return err @@ -224,29 +526,23 @@ 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) + logConfigProp, err := expandComputeRegionBackendServiceLogConfig(d.Get("log_config"), d, config) if err != nil { return err - } else if !isEmptyValue(reflect.ValueOf(connectionDrainingProp)) { - obj["connectionDraining"] = connectionDrainingProp + } else if v, ok := d.GetOkExists("log_config"); !isEmptyValue(reflect.ValueOf(logConfigProp)) && (ok || !reflect.DeepEqual(v, logConfigProp)) { + obj["logConfig"] = logConfigProp } - 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") @@ -313,13 +609,29 @@ 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 { + if err := d.Set("circuit_breakers", flattenComputeRegionBackendServiceCircuitBreakers(res["circuitBreakers"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("consistent_hash", flattenComputeRegionBackendServiceConsistentHash(res["consistentHash"], 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("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 { @@ -331,29 +643,34 @@ 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("locality_lb_policy", flattenComputeRegionBackendServiceLocalityLbPolicy(res["localityLbPolicy"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("name", flattenComputeRegionBackendServiceName(res["name"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("outlier_detection", flattenComputeRegionBackendServiceOutlierDetection(res["outlierDetection"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + if err := d.Set("protocol", flattenComputeRegionBackendServiceProtocol(res["protocol"], d)); err != nil { + return fmt.Errorf("Error reading RegionBackendService: %s", err) + } + 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) } - // 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("log_config", flattenComputeRegionBackendServiceLogConfig(res["logConfig"], 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("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 { @@ -372,17 +689,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 { @@ -390,6 +701,24 @@ 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 } + circuitBreakersProp, err := expandComputeRegionBackendServiceCircuitBreakers(d.Get("circuit_breakers"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("circuit_breakers"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, circuitBreakersProp)) { + obj["circuitBreakers"] = circuitBreakersProp + } + consistentHashProp, err := expandComputeRegionBackendServiceConsistentHash(d.Get("consistent_hash"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("consistent_hash"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, consistentHashProp)) { + obj["consistentHash"] = consistentHashProp + } + 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 @@ -408,23 +737,47 @@ 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 } - protocolProp, err := expandComputeRegionBackendServiceProtocol(d.Get("protocol"), d, config) + healthChecksProp, err := expandComputeRegionBackendServiceHealthChecks(d.Get("health_checks"), d, config) if err != nil { return err - } else if v, ok := d.GetOkExists("protocol"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, protocolProp)) { - obj["protocol"] = protocolProp + } else if v, ok := d.GetOkExists("health_checks"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, healthChecksProp)) { + obj["healthChecks"] = healthChecksProp } - sessionAffinityProp, err := expandComputeRegionBackendServiceSessionAffinity(d.Get("session_affinity"), d, config) + loadBalancingSchemeProp, err := expandComputeRegionBackendServiceLoadBalancingScheme(d.Get("load_balancing_scheme"), d, config) if err != nil { return err - } 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) + } else if v, ok := d.GetOkExists("load_balancing_scheme"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, loadBalancingSchemeProp)) { + obj["loadBalancingScheme"] = loadBalancingSchemeProp + } + localityLbPolicyProp, err := expandComputeRegionBackendServiceLocalityLbPolicy(d.Get("locality_lb_policy"), 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 + } else if v, ok := d.GetOkExists("locality_lb_policy"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, localityLbPolicyProp)) { + obj["localityLbPolicy"] = localityLbPolicyProp + } + 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 + } + outlierDetectionProp, err := expandComputeRegionBackendServiceOutlierDetection(d.Get("outlier_detection"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("outlier_detection"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, outlierDetectionProp)) { + obj["outlierDetection"] = outlierDetectionProp + } + protocolProp, err := expandComputeRegionBackendServiceProtocol(d.Get("protocol"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("protocol"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, protocolProp)) { + obj["protocol"] = protocolProp + } + sessionAffinityProp, err := expandComputeRegionBackendServiceSessionAffinity(d.Get("session_affinity"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("session_affinity"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sessionAffinityProp)) { + obj["sessionAffinity"] = sessionAffinityProp } timeoutSecProp, err := expandComputeRegionBackendServiceTimeoutSec(d.Get("timeout_sec"), d, config) if err != nil { @@ -432,17 +785,17 @@ func resourceComputeRegionBackendServiceUpdate(d *schema.ResourceData, meta inte } 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) + logConfigProp, err := expandComputeRegionBackendServiceLogConfig(d.Get("log_config"), 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 + } else if v, ok := d.GetOkExists("log_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, logConfigProp)) { + obj["logConfig"] = logConfigProp } - 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}}") @@ -534,15 +887,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{} { @@ -558,17 +910,38 @@ func flattenComputeRegionBackendServiceBackend(v interface{}, d *schema.Resource continue } transformed.Add(map[string]interface{}{ - "description": flattenComputeRegionBackendServiceBackendDescription(original["description"], d), - "group": flattenComputeRegionBackendServiceBackendGroup(original["group"], d), - "failover": flattenComputeRegionBackendServiceBackendFailover(original["failover"], d), + "balancing_mode": flattenComputeRegionBackendServiceBackendBalancingMode(original["balancingMode"], d), + "capacity_scaler": flattenComputeRegionBackendServiceBackendCapacityScaler(original["capacityScaler"], d), + "description": flattenComputeRegionBackendServiceBackendDescription(original["description"], d), + "failover": flattenComputeRegionBackendServiceBackendFailover(original["failover"], 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 } +func flattenComputeRegionBackendServiceBackendFailover(v interface{}, d *schema.ResourceData) interface{} { + return v +} + func flattenComputeRegionBackendServiceBackendGroup(v interface{}, d *schema.ResourceData) interface{} { if v == nil { return v @@ -576,15 +949,59 @@ func flattenComputeRegionBackendServiceBackendGroup(v interface{}, d *schema.Res return ConvertSelfLinkToV1(v.(string)) } -func flattenComputeRegionBackendServiceBackendFailover(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 flattenComputeRegionBackendServiceDescription(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 flattenComputeRegionBackendServiceFailoverPolicy(v interface{}, d *schema.ResourceData) interface{} { +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 v +} + +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 { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + 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 flattenComputeRegionBackendServiceCircuitBreakers(v interface{}, d *schema.ResourceData) interface{} { if v == nil { return nil } @@ -593,46 +1010,187 @@ func flattenComputeRegionBackendServiceFailoverPolicy(v interface{}, d *schema.R return nil } transformed := make(map[string]interface{}) - transformed["disable_connection_drain_on_failover"] = - flattenComputeRegionBackendServiceFailoverPolicyDisableConnectionDrainOnFailover(original["disableConnectionDrainOnFailover"], d) - transformed["drop_traffic_if_unhealthy"] = - flattenComputeRegionBackendServiceFailoverPolicyDropTrafficIfUnhealthy(original["dropTrafficIfUnhealthy"], d) - transformed["failover_ratio"] = - flattenComputeRegionBackendServiceFailoverPolicyFailoverRatio(original["failoverRatio"], d) + transformed["connect_timeout"] = + flattenComputeRegionBackendServiceCircuitBreakersConnectTimeout(original["connectTimeout"], d) + transformed["max_requests_per_connection"] = + flattenComputeRegionBackendServiceCircuitBreakersMaxRequestsPerConnection(original["maxRequestsPerConnection"], d) + transformed["max_connections"] = + flattenComputeRegionBackendServiceCircuitBreakersMaxConnections(original["maxConnections"], d) + transformed["max_pending_requests"] = + flattenComputeRegionBackendServiceCircuitBreakersMaxPendingRequests(original["maxPendingRequests"], d) + transformed["max_requests"] = + flattenComputeRegionBackendServiceCircuitBreakersMaxRequests(original["maxRequests"], d) + transformed["max_retries"] = + flattenComputeRegionBackendServiceCircuitBreakersMaxRetries(original["maxRetries"], d) return []interface{}{transformed} } -func flattenComputeRegionBackendServiceFailoverPolicyDisableConnectionDrainOnFailover(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceCircuitBreakersConnectTimeout(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["seconds"] = + flattenComputeRegionBackendServiceCircuitBreakersConnectTimeoutSeconds(original["seconds"], d) + transformed["nanos"] = + flattenComputeRegionBackendServiceCircuitBreakersConnectTimeoutNanos(original["nanos"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceCircuitBreakersConnectTimeoutSeconds(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 flattenComputeRegionBackendServiceFailoverPolicyDropTrafficIfUnhealthy(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceCircuitBreakersConnectTimeoutNanos(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 flattenComputeRegionBackendServiceFailoverPolicyFailoverRatio(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceCircuitBreakersMaxRequestsPerConnection(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 flattenComputeRegionBackendServiceFingerprint(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceCircuitBreakersMaxConnections(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 flattenComputeRegionBackendServiceProtocol(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceCircuitBreakersMaxPendingRequests(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 flattenComputeRegionBackendServiceCircuitBreakersMaxRequests(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{} { +func flattenComputeRegionBackendServiceCircuitBreakersMaxRetries(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 flattenComputeRegionBackendServiceConsistentHash(v interface{}, d *schema.ResourceData) interface{} { if v == nil { - return v + return nil } - return NameFromSelfLinkStateFunc(v) + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["http_cookie"] = + flattenComputeRegionBackendServiceConsistentHashHttpCookie(original["httpCookie"], d) + transformed["http_header_name"] = + flattenComputeRegionBackendServiceConsistentHashHttpHeaderName(original["httpHeaderName"], d) + transformed["minimum_ring_size"] = + flattenComputeRegionBackendServiceConsistentHashMinimumRingSize(original["minimumRingSize"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceConsistentHashHttpCookie(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["ttl"] = + flattenComputeRegionBackendServiceConsistentHashHttpCookieTtl(original["ttl"], d) + transformed["name"] = + flattenComputeRegionBackendServiceConsistentHashHttpCookieName(original["name"], d) + transformed["path"] = + flattenComputeRegionBackendServiceConsistentHashHttpCookiePath(original["path"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceConsistentHashHttpCookieTtl(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["seconds"] = + flattenComputeRegionBackendServiceConsistentHashHttpCookieTtlSeconds(original["seconds"], d) + transformed["nanos"] = + flattenComputeRegionBackendServiceConsistentHashHttpCookieTtlNanos(original["nanos"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceConsistentHashHttpCookieTtlSeconds(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 flattenComputeRegionBackendServiceTimeoutSec(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceConsistentHashHttpCookieTtlNanos(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 flattenComputeRegionBackendServiceConsistentHashHttpCookieName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceConsistentHashHttpCookiePath(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceConsistentHashHttpHeaderName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceConsistentHashMinimumRingSize(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 { @@ -665,22 +1223,314 @@ func flattenComputeRegionBackendServiceConnectionDrainingConnectionDrainingTimeo return v } -func flattenComputeRegionBackendServiceLoadBalancingScheme(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionBackendServiceCreationTimestamp(v interface{}, d *schema.ResourceData) interface{} { return v } -func expandComputeRegionBackendServiceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - return v, nil +func flattenComputeRegionBackendServiceDescription(v interface{}, d *schema.ResourceData) interface{} { + return v } -func expandComputeRegionBackendServiceHealthChecks(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - v = v.(*schema.Set).List() - return v, nil +func flattenComputeRegionBackendServiceFailoverPolicy(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["disable_connection_drain_on_failover"] = + flattenComputeRegionBackendServiceFailoverPolicyDisableConnectionDrainOnFailover(original["disableConnectionDrainOnFailover"], d) + transformed["drop_traffic_if_unhealthy"] = + flattenComputeRegionBackendServiceFailoverPolicyDropTrafficIfUnhealthy(original["dropTrafficIfUnhealthy"], d) + transformed["failover_ratio"] = + flattenComputeRegionBackendServiceFailoverPolicyFailoverRatio(original["failoverRatio"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceFailoverPolicyDisableConnectionDrainOnFailover(v interface{}, d *schema.ResourceData) interface{} { + return v } -func expandComputeRegionBackendServiceBackend(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - v = v.(*schema.Set).List() - l := v.([]interface{}) +func flattenComputeRegionBackendServiceFailoverPolicyDropTrafficIfUnhealthy(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceFailoverPolicyFailoverRatio(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 flattenComputeRegionBackendServiceLocalityLbPolicy(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceOutlierDetection(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["base_ejection_time"] = + flattenComputeRegionBackendServiceOutlierDetectionBaseEjectionTime(original["baseEjectionTime"], d) + transformed["consecutive_errors"] = + flattenComputeRegionBackendServiceOutlierDetectionConsecutiveErrors(original["consecutiveErrors"], d) + transformed["consecutive_gateway_failure"] = + flattenComputeRegionBackendServiceOutlierDetectionConsecutiveGatewayFailure(original["consecutiveGatewayFailure"], d) + transformed["enforcing_consecutive_errors"] = + flattenComputeRegionBackendServiceOutlierDetectionEnforcingConsecutiveErrors(original["enforcingConsecutiveErrors"], d) + transformed["enforcing_consecutive_gateway_failure"] = + flattenComputeRegionBackendServiceOutlierDetectionEnforcingConsecutiveGatewayFailure(original["enforcingConsecutiveGatewayFailure"], d) + transformed["enforcing_success_rate"] = + flattenComputeRegionBackendServiceOutlierDetectionEnforcingSuccessRate(original["enforcingSuccessRate"], d) + transformed["interval"] = + flattenComputeRegionBackendServiceOutlierDetectionInterval(original["interval"], d) + transformed["max_ejection_percent"] = + flattenComputeRegionBackendServiceOutlierDetectionMaxEjectionPercent(original["maxEjectionPercent"], d) + transformed["success_rate_minimum_hosts"] = + flattenComputeRegionBackendServiceOutlierDetectionSuccessRateMinimumHosts(original["successRateMinimumHosts"], d) + transformed["success_rate_request_volume"] = + flattenComputeRegionBackendServiceOutlierDetectionSuccessRateRequestVolume(original["successRateRequestVolume"], d) + transformed["success_rate_stdev_factor"] = + flattenComputeRegionBackendServiceOutlierDetectionSuccessRateStdevFactor(original["successRateStdevFactor"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceOutlierDetectionBaseEjectionTime(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["seconds"] = + flattenComputeRegionBackendServiceOutlierDetectionBaseEjectionTimeSeconds(original["seconds"], d) + transformed["nanos"] = + flattenComputeRegionBackendServiceOutlierDetectionBaseEjectionTimeNanos(original["nanos"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceOutlierDetectionBaseEjectionTimeSeconds(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 flattenComputeRegionBackendServiceOutlierDetectionBaseEjectionTimeNanos(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 flattenComputeRegionBackendServiceOutlierDetectionConsecutiveErrors(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 flattenComputeRegionBackendServiceOutlierDetectionConsecutiveGatewayFailure(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 flattenComputeRegionBackendServiceOutlierDetectionEnforcingConsecutiveErrors(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 flattenComputeRegionBackendServiceOutlierDetectionEnforcingConsecutiveGatewayFailure(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 flattenComputeRegionBackendServiceOutlierDetectionEnforcingSuccessRate(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 flattenComputeRegionBackendServiceOutlierDetectionInterval(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["seconds"] = + flattenComputeRegionBackendServiceOutlierDetectionIntervalSeconds(original["seconds"], d) + transformed["nanos"] = + flattenComputeRegionBackendServiceOutlierDetectionIntervalNanos(original["nanos"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceOutlierDetectionIntervalSeconds(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 flattenComputeRegionBackendServiceOutlierDetectionIntervalNanos(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 flattenComputeRegionBackendServiceOutlierDetectionMaxEjectionPercent(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 flattenComputeRegionBackendServiceOutlierDetectionSuccessRateMinimumHosts(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 flattenComputeRegionBackendServiceOutlierDetectionSuccessRateRequestVolume(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 flattenComputeRegionBackendServiceOutlierDetectionSuccessRateStdevFactor(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 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 flattenComputeRegionBackendServiceLogConfig(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["enable"] = + flattenComputeRegionBackendServiceLogConfigEnable(original["enable"], d) + transformed["sample_rate"] = + flattenComputeRegionBackendServiceLogConfigSampleRate(original["sampleRate"], d) + return []interface{}{transformed} +} +func flattenComputeRegionBackendServiceLogConfigEnable(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionBackendServiceLogConfigSampleRate(v interface{}, d *schema.ResourceData) interface{} { + 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 +} + +func expandComputeRegionBackendServiceBackend(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + l := v.([]interface{}) req := make([]interface{}, 0, len(l)) for _, raw := range l { if raw == nil { @@ -689,41 +1539,380 @@ func expandComputeRegionBackendServiceBackend(v interface{}, d TerraformResource original := raw.(map[string]interface{}) transformed := make(map[string]interface{}) - transformedDescription, err := expandComputeRegionBackendServiceBackendDescription(original["description"], d, config) - if err != nil { - return nil, err - } else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) { - transformed["description"] = transformedDescription - } + 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 + } else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) { + transformed["description"] = transformedDescription + } + + transformedFailover, err := expandComputeRegionBackendServiceBackendFailover(original["failover"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedFailover); val.IsValid() && !isEmptyValue(val) { + transformed["failover"] = transformedFailover + } + + transformedGroup, err := expandComputeRegionBackendServiceBackendGroup(original["group"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedGroup); val.IsValid() && !isEmptyValue(val) { + 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 +} + +func expandComputeRegionBackendServiceBackendFailover(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendGroup(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendMaxConnections(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendMaxConnectionsPerInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendMaxConnectionsPerEndpoint(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendMaxRate(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceBackendMaxRatePerInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +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 +} + +func expandComputeRegionBackendServiceCircuitBreakers(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedConnectTimeout, err := expandComputeRegionBackendServiceCircuitBreakersConnectTimeout(original["connect_timeout"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedConnectTimeout); val.IsValid() && !isEmptyValue(val) { + transformed["connectTimeout"] = transformedConnectTimeout + } + + transformedMaxRequestsPerConnection, err := expandComputeRegionBackendServiceCircuitBreakersMaxRequestsPerConnection(original["max_requests_per_connection"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxRequestsPerConnection); val.IsValid() && !isEmptyValue(val) { + transformed["maxRequestsPerConnection"] = transformedMaxRequestsPerConnection + } + + transformedMaxConnections, err := expandComputeRegionBackendServiceCircuitBreakersMaxConnections(original["max_connections"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxConnections); val.IsValid() && !isEmptyValue(val) { + transformed["maxConnections"] = transformedMaxConnections + } + + transformedMaxPendingRequests, err := expandComputeRegionBackendServiceCircuitBreakersMaxPendingRequests(original["max_pending_requests"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxPendingRequests); val.IsValid() && !isEmptyValue(val) { + transformed["maxPendingRequests"] = transformedMaxPendingRequests + } + + transformedMaxRequests, err := expandComputeRegionBackendServiceCircuitBreakersMaxRequests(original["max_requests"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxRequests); val.IsValid() && !isEmptyValue(val) { + transformed["maxRequests"] = transformedMaxRequests + } + + transformedMaxRetries, err := expandComputeRegionBackendServiceCircuitBreakersMaxRetries(original["max_retries"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxRetries); val.IsValid() && !isEmptyValue(val) { + transformed["maxRetries"] = transformedMaxRetries + } + + return transformed, nil +} + +func expandComputeRegionBackendServiceCircuitBreakersConnectTimeout(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSeconds, err := expandComputeRegionBackendServiceCircuitBreakersConnectTimeoutSeconds(original["seconds"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !isEmptyValue(val) { + transformed["seconds"] = transformedSeconds + } + + transformedNanos, err := expandComputeRegionBackendServiceCircuitBreakersConnectTimeoutNanos(original["nanos"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !isEmptyValue(val) { + transformed["nanos"] = transformedNanos + } + + return transformed, nil +} + +func expandComputeRegionBackendServiceCircuitBreakersConnectTimeoutSeconds(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceCircuitBreakersConnectTimeoutNanos(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceCircuitBreakersMaxRequestsPerConnection(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceCircuitBreakersMaxConnections(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceCircuitBreakersMaxPendingRequests(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceCircuitBreakersMaxRequests(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceCircuitBreakersMaxRetries(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceConsistentHash(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedHttpCookie, err := expandComputeRegionBackendServiceConsistentHashHttpCookie(original["http_cookie"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHttpCookie); val.IsValid() && !isEmptyValue(val) { + transformed["httpCookie"] = transformedHttpCookie + } + + transformedHttpHeaderName, err := expandComputeRegionBackendServiceConsistentHashHttpHeaderName(original["http_header_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHttpHeaderName); val.IsValid() && !isEmptyValue(val) { + transformed["httpHeaderName"] = transformedHttpHeaderName + } + + transformedMinimumRingSize, err := expandComputeRegionBackendServiceConsistentHashMinimumRingSize(original["minimum_ring_size"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMinimumRingSize); val.IsValid() && !isEmptyValue(val) { + transformed["minimumRingSize"] = transformedMinimumRingSize + } + + return transformed, nil +} + +func expandComputeRegionBackendServiceConsistentHashHttpCookie(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedTtl, err := expandComputeRegionBackendServiceConsistentHashHttpCookieTtl(original["ttl"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTtl); val.IsValid() && !isEmptyValue(val) { + transformed["ttl"] = transformedTtl + } - transformedGroup, err := expandComputeRegionBackendServiceBackendGroup(original["group"], d, config) - if err != nil { - return nil, err - } else if val := reflect.ValueOf(transformedGroup); val.IsValid() && !isEmptyValue(val) { - transformed["group"] = transformedGroup - } + transformedName, err := expandComputeRegionBackendServiceConsistentHashHttpCookieName(original["name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) { + transformed["name"] = transformedName + } - transformedFailover, err := expandComputeRegionBackendServiceBackendFailover(original["failover"], d, config) - if err != nil { - return nil, err - } else if val := reflect.ValueOf(transformedFailover); val.IsValid() && !isEmptyValue(val) { - transformed["failover"] = transformedFailover - } + transformedPath, err := expandComputeRegionBackendServiceConsistentHashHttpCookiePath(original["path"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPath); val.IsValid() && !isEmptyValue(val) { + transformed["path"] = transformedPath + } - req = append(req, transformed) + return transformed, nil +} + +func expandComputeRegionBackendServiceConsistentHashHttpCookieTtl(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil } - return req, nil + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSeconds, err := expandComputeRegionBackendServiceConsistentHashHttpCookieTtlSeconds(original["seconds"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !isEmptyValue(val) { + transformed["seconds"] = transformedSeconds + } + + transformedNanos, err := expandComputeRegionBackendServiceConsistentHashHttpCookieTtlNanos(original["nanos"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !isEmptyValue(val) { + transformed["nanos"] = transformedNanos + } + + return transformed, nil } -func expandComputeRegionBackendServiceBackendDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceConsistentHashHttpCookieTtlSeconds(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } -func expandComputeRegionBackendServiceBackendGroup(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceConsistentHashHttpCookieTtlNanos(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } -func expandComputeRegionBackendServiceBackendFailover(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceConsistentHashHttpCookieName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceConsistentHashHttpCookiePath(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceConsistentHashHttpHeaderName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceConsistentHashMinimumRingSize(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceConnectionDraining(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + transformed := make(map[string]interface{}) + transformedConnectionDrainingTimeoutSec, err := expandComputeRegionBackendServiceConnectionDrainingConnectionDrainingTimeoutSec(d.Get("connection_draining_timeout_sec"), d, config) + if err != nil { + return nil, err + } else { + transformed["drainingTimeoutSec"] = transformedConnectionDrainingTimeoutSec + } + + return transformed, nil +} + +func expandComputeRegionBackendServiceConnectionDrainingConnectionDrainingTimeoutSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -780,42 +1969,266 @@ func expandComputeRegionBackendServiceFingerprint(v interface{}, d TerraformReso return v, nil } -func expandComputeRegionBackendServiceProtocol(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceHealthChecks(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() return v, nil } -func expandComputeRegionBackendServiceSessionAffinity(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceLoadBalancingScheme(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) +func expandComputeRegionBackendServiceLocalityLbPolicy(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 expandComputeRegionBackendServiceOutlierDetection(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedBaseEjectionTime, err := expandComputeRegionBackendServiceOutlierDetectionBaseEjectionTime(original["base_ejection_time"], d, config) if err != nil { - return nil, fmt.Errorf("Invalid value for region: %s", err) + return nil, err + } else if val := reflect.ValueOf(transformedBaseEjectionTime); val.IsValid() && !isEmptyValue(val) { + transformed["baseEjectionTime"] = transformedBaseEjectionTime } - return f.RelativeLink(), nil + + transformedConsecutiveErrors, err := expandComputeRegionBackendServiceOutlierDetectionConsecutiveErrors(original["consecutive_errors"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedConsecutiveErrors); val.IsValid() && !isEmptyValue(val) { + transformed["consecutiveErrors"] = transformedConsecutiveErrors + } + + transformedConsecutiveGatewayFailure, err := expandComputeRegionBackendServiceOutlierDetectionConsecutiveGatewayFailure(original["consecutive_gateway_failure"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedConsecutiveGatewayFailure); val.IsValid() && !isEmptyValue(val) { + transformed["consecutiveGatewayFailure"] = transformedConsecutiveGatewayFailure + } + + transformedEnforcingConsecutiveErrors, err := expandComputeRegionBackendServiceOutlierDetectionEnforcingConsecutiveErrors(original["enforcing_consecutive_errors"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEnforcingConsecutiveErrors); val.IsValid() && !isEmptyValue(val) { + transformed["enforcingConsecutiveErrors"] = transformedEnforcingConsecutiveErrors + } + + transformedEnforcingConsecutiveGatewayFailure, err := expandComputeRegionBackendServiceOutlierDetectionEnforcingConsecutiveGatewayFailure(original["enforcing_consecutive_gateway_failure"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEnforcingConsecutiveGatewayFailure); val.IsValid() && !isEmptyValue(val) { + transformed["enforcingConsecutiveGatewayFailure"] = transformedEnforcingConsecutiveGatewayFailure + } + + transformedEnforcingSuccessRate, err := expandComputeRegionBackendServiceOutlierDetectionEnforcingSuccessRate(original["enforcing_success_rate"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEnforcingSuccessRate); val.IsValid() && !isEmptyValue(val) { + transformed["enforcingSuccessRate"] = transformedEnforcingSuccessRate + } + + transformedInterval, err := expandComputeRegionBackendServiceOutlierDetectionInterval(original["interval"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedInterval); val.IsValid() && !isEmptyValue(val) { + transformed["interval"] = transformedInterval + } + + transformedMaxEjectionPercent, err := expandComputeRegionBackendServiceOutlierDetectionMaxEjectionPercent(original["max_ejection_percent"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxEjectionPercent); val.IsValid() && !isEmptyValue(val) { + transformed["maxEjectionPercent"] = transformedMaxEjectionPercent + } + + transformedSuccessRateMinimumHosts, err := expandComputeRegionBackendServiceOutlierDetectionSuccessRateMinimumHosts(original["success_rate_minimum_hosts"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSuccessRateMinimumHosts); val.IsValid() && !isEmptyValue(val) { + transformed["successRateMinimumHosts"] = transformedSuccessRateMinimumHosts + } + + transformedSuccessRateRequestVolume, err := expandComputeRegionBackendServiceOutlierDetectionSuccessRateRequestVolume(original["success_rate_request_volume"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSuccessRateRequestVolume); val.IsValid() && !isEmptyValue(val) { + transformed["successRateRequestVolume"] = transformedSuccessRateRequestVolume + } + + transformedSuccessRateStdevFactor, err := expandComputeRegionBackendServiceOutlierDetectionSuccessRateStdevFactor(original["success_rate_stdev_factor"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSuccessRateStdevFactor); val.IsValid() && !isEmptyValue(val) { + transformed["successRateStdevFactor"] = transformedSuccessRateStdevFactor + } + + return transformed, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionBaseEjectionTime(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSeconds, err := expandComputeRegionBackendServiceOutlierDetectionBaseEjectionTimeSeconds(original["seconds"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !isEmptyValue(val) { + transformed["seconds"] = transformedSeconds + } + + transformedNanos, err := expandComputeRegionBackendServiceOutlierDetectionBaseEjectionTimeNanos(original["nanos"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !isEmptyValue(val) { + transformed["nanos"] = transformedNanos + } + + return transformed, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionBaseEjectionTimeSeconds(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionBaseEjectionTimeNanos(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionConsecutiveErrors(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionConsecutiveGatewayFailure(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionEnforcingConsecutiveErrors(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionEnforcingConsecutiveGatewayFailure(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionEnforcingSuccessRate(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionInterval(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSeconds, err := expandComputeRegionBackendServiceOutlierDetectionIntervalSeconds(original["seconds"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !isEmptyValue(val) { + transformed["seconds"] = transformedSeconds + } + + transformedNanos, err := expandComputeRegionBackendServiceOutlierDetectionIntervalNanos(original["nanos"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !isEmptyValue(val) { + transformed["nanos"] = transformedNanos + } + + return transformed, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionIntervalSeconds(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionIntervalNanos(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionMaxEjectionPercent(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionSuccessRateMinimumHosts(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionSuccessRateRequestVolume(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionBackendServiceOutlierDetectionSuccessRateStdevFactor(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 expandComputeRegionBackendServiceConnectionDraining(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceLogConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) transformed := make(map[string]interface{}) - transformedConnectionDrainingTimeoutSec, err := expandComputeRegionBackendServiceConnectionDrainingConnectionDrainingTimeoutSec(d.Get("connection_draining_timeout_sec"), d, config) + + transformedEnable, err := expandComputeRegionBackendServiceLogConfigEnable(original["enable"], d, config) if err != nil { return nil, err - } else { - transformed["drainingTimeoutSec"] = transformedConnectionDrainingTimeoutSec + } else if val := reflect.ValueOf(transformedEnable); val.IsValid() && !isEmptyValue(val) { + transformed["enable"] = transformedEnable + } + + transformedSampleRate, err := expandComputeRegionBackendServiceLogConfigSampleRate(original["sample_rate"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSampleRate); val.IsValid() && !isEmptyValue(val) { + transformed["sampleRate"] = transformedSampleRate } return transformed, nil } -func expandComputeRegionBackendServiceConnectionDrainingConnectionDrainingTimeoutSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceLogConfigEnable(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } -func expandComputeRegionBackendServiceLoadBalancingScheme(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionBackendServiceLogConfigSampleRate(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/google-beta/resource_compute_region_backend_service_generated_test.go b/google-beta/resource_compute_region_backend_service_generated_test.go index 011a9117a9..5889c36ecf 100644 --- a/google-beta/resource_compute_region_backend_service_generated_test.go +++ b/google-beta/resource_compute_region_backend_service_generated_test.go @@ -70,6 +70,108 @@ resource "google_compute_health_check" "default" { `, context) } +func TestAccComputeRegionBackendService_regionBackendServiceIlbRoundRobinExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckComputeRegionBackendServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionBackendService_regionBackendServiceIlbRoundRobinExample(context), + }, + }, + }) +} + +func testAccComputeRegionBackendService_regionBackendServiceIlbRoundRobinExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_region_backend_service" "default" { + provider = "google-beta" + + region = "us-central1" + name = "region-backend-service%{random_suffix}" + 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%{random_suffix}" + http_health_check { + + } +} +`, context) +} + +func TestAccComputeRegionBackendService_regionBackendServiceIlbRingHashExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + CheckDestroy: testAccCheckComputeRegionBackendServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionBackendService_regionBackendServiceIlbRingHashExample(context), + }, + }, + }) +} + +func testAccComputeRegionBackendService_regionBackendServiceIlbRingHashExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_region_backend_service" "default" { + provider = "google-beta" + + region = "us-central1" + name = "region-backend-service%{random_suffix}" + 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%{random_suffix}" + http_health_check { + + } +} +`, context) +} + func testAccCheckComputeRegionBackendServiceDestroy(s *terraform.State) error { for name, rs := range s.RootModule().Resources { if rs.Type != "google_compute_region_backend_service" { diff --git a/google-beta/resource_compute_region_backend_service_test.go b/google-beta/resource_compute_region_backend_service_test.go index 4ee7d6dd70..d9e459c5b5 100644 --- a/google-beta/resource_compute_region_backend_service_test.go +++ b/google-beta/resource_compute_region_backend_service_test.go @@ -131,6 +131,268 @@ func TestAccComputeRegionBackendService_withConnectionDrainingAndUpdate(t *testi }) } +func TestAccComputeRegionBackendService_ilbUpdateBasic(t *testing.T) { + t.Parallel() + + backendName := fmt.Sprintf("foo-%s", acctest.RandString(10)) + checkName := fmt.Sprintf("bar-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeRegionBackendServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionBackendService_ilbBasic(backendName, checkName), + }, + { + ResourceName: "google_compute_region_backend_service.foobar", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeRegionBackendService_ilbUpdateBasic(backendName, checkName), + }, + { + ResourceName: "google_compute_region_backend_service.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeRegionBackendService_ilbUpdateFull(t *testing.T) { + t.Parallel() + + randString := acctest.RandString(10) + + backendName := fmt.Sprintf("foo-%s", randString) + checkName := fmt.Sprintf("bar-%s", randString) + igName := fmt.Sprintf("baz-%s", randString) + instanceName := fmt.Sprintf("boz-%s", randString) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeRegionBackendServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionBackendService_ilbFull(backendName, checkName), + }, + { + ResourceName: "google_compute_region_backend_service.foobar", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeRegionBackendService_ilbUpdateFull(backendName, igName, instanceName, checkName), + }, + { + ResourceName: "google_compute_region_backend_service.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccComputeRegionBackendService_ilbBasic(serviceName, checkName string) string { + return fmt.Sprintf(` +resource "google_compute_region_backend_service" "foobar" { + + name = "%s" + health_checks = ["${google_compute_health_check.health_check.self_link}"] + protocol = "HTTP" + load_balancing_scheme = "INTERNAL_MANAGED" + locality_lb_policy = "RING_HASH" + circuit_breakers { + max_connections = 10 + } + consistent_hash { + http_cookie { + ttl { + seconds = 11 + nanos = 1234 + } + name = "mycookie" + } + } + outlier_detection { + consecutive_errors = 2 + } +} + +resource "google_compute_health_check" "health_check" { + + name = "%s" + http_health_check { + + } +} +`, serviceName, checkName) +} + +func testAccComputeRegionBackendService_ilbUpdateBasic(serviceName, checkName string) string { + return fmt.Sprintf(` +resource "google_compute_region_backend_service" "foobar" { + + name = "%s" + health_checks = ["${google_compute_health_check.health_check.self_link}"] + protocol = "HTTP" + load_balancing_scheme = "INTERNAL_MANAGED" + locality_lb_policy = "RANDOM" + circuit_breakers { + max_connections = 10 + } + outlier_detection { + consecutive_errors = 2 + } +} + +resource "google_compute_health_check" "health_check" { + + name = "%s" + http_health_check { + + } +} +`, serviceName, checkName) +} + +func testAccComputeRegionBackendService_ilbFull(serviceName, checkName string) string { + return fmt.Sprintf(` +resource "google_compute_region_backend_service" "foobar" { + + name = "%s" + health_checks = ["${google_compute_health_check.health_check.self_link}"] + protocol = "HTTP" + load_balancing_scheme = "INTERNAL_MANAGED" + locality_lb_policy = "MAGLEV" + circuit_breakers { + max_connections = 10 + } + consistent_hash { + http_cookie { + ttl { + seconds = 11 + nanos = 1234 + } + name = "mycookie" + } + } + outlier_detection { + consecutive_errors = 2 + } +} + +resource "google_compute_health_check" "health_check" { + + name = "%s" + http_health_check { + + } +} +`, serviceName, checkName) +} + +func testAccComputeRegionBackendService_ilbUpdateFull(serviceName, igName, instanceName, checkName string) string { + return fmt.Sprintf(` +resource "google_compute_region_backend_service" "foobar" { + + name = "%s" + health_checks = ["${google_compute_health_check.health_check.self_link}"] + protocol = "HTTP" + load_balancing_scheme = "INTERNAL_MANAGED" + locality_lb_policy = "MAGLEV" + backend { + balancing_mode = "UTILIZATION" + capacity_scaler = 0.5 + description = "The backend" + group = google_compute_instance_group.group.self_link + max_rate = 6 + max_utilization = 0.5 + } + circuit_breakers { + connect_timeout { + seconds = 3 + nanos = 4 + } + max_connections = 11 + max_requests_per_connection = 12 + max_pending_requests = 13 + max_requests = 14 + max_retries = 15 + } + consistent_hash { + http_cookie { + ttl { + seconds = 12 + } + name = "mycookie2" + path = "mycookie2/path" + } + minimum_ring_size = 16 + } + log_config { + enable = true + sample_rate = 0.5 + } + outlier_detection { + base_ejection_time { + seconds = 0 + nanos = 5 + } + consecutive_errors = 1 + consecutive_gateway_failure = 3 + enforcing_consecutive_errors = 4 + enforcing_consecutive_gateway_failure = 5 + enforcing_success_rate = 6 + interval { + seconds = 7 + } + max_ejection_percent = 99 + success_rate_minimum_hosts = 98 + success_rate_request_volume = 97 + success_rate_stdev_factor = 1800 + } +} + +resource "google_compute_instance_group" "group" { + name = "%s" + instances = [ "${google_compute_instance.ig_instance.self_link}" ] +} + +data "google_compute_image" "my_image" { + family = "debian-9" + project = "debian-cloud" +} + +resource "google_compute_instance" "ig_instance" { + name = "%s" + machine_type = "n1-standard-1" + + boot_disk { + initialize_params { + image = "${data.google_compute_image.my_image.self_link}" + } + } + + network_interface { + network = "default" + } +} + +resource "google_compute_health_check" "health_check" { + + name = "%s" + http_health_check { + + } +} +`, serviceName, igName, instanceName, checkName) +} + func testAccComputeRegionBackendService_basic(serviceName, checkName string) string { return fmt.Sprintf(` resource "google_compute_region_backend_service" "foobar" { diff --git a/website/docs/r/compute_backend_service.html.markdown b/website/docs/r/compute_backend_service.html.markdown index ed101219a2..029a4b2214 100644 --- a/website/docs/r/compute_backend_service.html.markdown +++ b/website/docs/r/compute_backend_service.html.markdown @@ -316,7 +316,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 1b2679f662..07941e8ab6 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 b021f03cbe..559f67b068 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,19 +155,45 @@ 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, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + 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. + +* `circuit_breakers` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + Settings controlling the volume of connections to a backend service. This field + is applicable only when the `load_balancing_scheme` is set to INTERNAL_MANAGED + and the `protocol` is set to HTTP, HTTPS, or HTTP2. Structure is documented below. + +* `consistent_hash` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + Consistent Hash-based load balancing can be used to provide soft session + affinity based on HTTP headers, cookies or other properties. This load balancing + policy is applicable only for HTTP connections. The affinity to a particular + destination host will be lost when one or more hosts are added/removed from the + destination service. This field specifies parameters that control consistent + hashing. + This field only applies when all of the following are true - + * `load_balancing_scheme` is set to INTERNAL_MANAGED + * `protocol` is set to HTTP, HTTPS, or HTTP2 + * `locality_lb_policy` is set to MAGLEV or RING_HASH 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) @@ -100,36 +203,70 @@ The following arguments are supported: (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) Policy for failovers. Structure is documented below. -* `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 what kind of load balancing this regional backend service + will be used for. A backend service created for one type of load + balancing cannot be used with the other(s). Must be `INTERNAL` or + `INTERNAL_MANAGED`. Defaults to `INTERNAL`. -* `session_affinity` - +* `locality_lb_policy` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + The load balancing algorithm used within the scope of the locality. + The possible values are - + ROUND_ROBIN - This is a simple policy in which each healthy backend + is selected in round robin order. + LEAST_REQUEST - An O(1) algorithm which selects two random healthy + hosts and picks the host which has fewer active requests. + RING_HASH - The ring/modulo hash load balancer implements consistent + hashing to backends. The algorithm has the property that the + addition/removal of a host from a set of N hosts only affects + 1/N of the requests. + RANDOM - The load balancer selects a random healthy host. + ORIGINAL_DESTINATION - Backend host is selected based on the client + connection metadata, i.e., connections are opened + to the same address as the destination address of + the incoming connection before the connection + was redirected to the load balancer. + MAGLEV - used as a drop in replacement for the ring hash load balancer. + Maglev is not as stable as ring hash but has faster table lookup + build times and host selection times. For more information about + Maglev, refer to https://ai.google/research/pubs/pub44824 + This field is applicable only when the `load_balancing_scheme` is set to + INTERNAL_MANAGED and the `protocol` is set to HTTP, HTTPS, or HTTP2. + +* `outlier_detection` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + Settings controlling eviction of unhealthy hosts from the load balancing pool. + This field is applicable only when the `load_balancing_scheme` is set + to INTERNAL_MANAGED and the `protocol` is set to HTTP, HTTPS, or HTTP2. Structure is documented below. + +* `protocol` - (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. + 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. -* `region` - +* `session_affinity` - (Optional) - The Region in which the created backend service should reside. - If it is not provided, the provider region is used. + 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). +* `log_config` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + This field denotes the logging options for the load balancer traffic served by this backend service. + If logging is enabled, logs will be exported to Stackdriver. Structure is documented below. -* `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. @@ -137,27 +274,199 @@ 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. Provide this property when you create the resource. +* `failover` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + This field designates whether this is a failover backend. More + than one failover backend can be configured for a given RegionBackendService. + * `group` - - (Optional) - The fully-qualified URL of an Instance Group. This defines the list + (Required) + 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. -* `failover` - - (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) - This field designates whether this is a failover backend. More - than one failover backend can be configured for a given 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. 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]. + +The `circuit_breakers` block supports: + +* `connect_timeout` - + (Optional) + The timeout for new network connections to hosts. Structure is documented below. + +* `max_requests_per_connection` - + (Optional) + Maximum requests for a single backend connection. This parameter + is respected by both the HTTP/1.1 and HTTP/2 implementations. If + not specified, there is no limit. Setting this parameter to 1 + will effectively disable keep alive. + +* `max_connections` - + (Optional) + The maximum number of connections to the backend cluster. + Defaults to 1024. + +* `max_pending_requests` - + (Optional) + The maximum number of pending requests to the backend cluster. + Defaults to 1024. + +* `max_requests` - + (Optional) + The maximum number of parallel requests to the backend cluster. + Defaults to 1024. + +* `max_retries` - + (Optional) + The maximum number of parallel retries to the backend cluster. + Defaults to 3. + + +The `connect_timeout` block supports: + +* `seconds` - + (Required) + Span of time at a resolution of a second. + Must be from 0 to 315,576,000,000 inclusive. + +* `nanos` - + (Optional) + Span of time that's a fraction of a second at nanosecond + resolution. Durations less than one second are represented + with a 0 seconds field and a positive nanos field. Must + be from 0 to 999,999,999 inclusive. + +The `consistent_hash` block supports: + +* `http_cookie` - + (Optional) + Hash is based on HTTP Cookie. This field describes a HTTP cookie + that will be used as the hash key for the consistent hash load + balancer. If the cookie is not present, it will be generated. + This field is applicable if the sessionAffinity is set to HTTP_COOKIE. Structure is documented below. + +* `http_header_name` - + (Optional) + The hash based on the value of the specified header field. + This field is applicable if the sessionAffinity is set to HEADER_FIELD. + +* `minimum_ring_size` - + (Optional) + The minimum number of virtual nodes to use for the hash ring. + Larger ring sizes result in more granular load + distributions. If the number of hosts in the load balancing pool + is larger than the ring size, each host will be assigned a single + virtual node. + Defaults to 1024. + + +The `http_cookie` block supports: + +* `ttl` - + (Optional) + Liftime of the cookie. Structure is documented below. + +* `name` - + (Optional) + Name of the cookie. + +* `path` - + (Optional) + Path to set for the cookie. + + +The `ttl` block supports: + +* `seconds` - + (Required) + Span of time at a resolution of a second. + Must be from 0 to 315,576,000,000 inclusive. + +* `nanos` - + (Optional) + Span of time that's a fraction of a second at nanosecond + resolution. Durations less than one second are represented + with a 0 seconds field and a positive nanos field. Must + be from 0 to 999,999,999 inclusive. The `failover_policy` block supports: @@ -190,11 +499,126 @@ The `failover_policy` block supports: VMs with the best effort, or to all VMs when no VM is healthy. This field is only used with l4 load balancing. +The `outlier_detection` block supports: + +* `base_ejection_time` - + (Optional) + The base time that a host is ejected for. The real time is equal to the base + time multiplied by the number of times the host has been ejected. Defaults to + 30000ms or 30s. Structure is documented below. + +* `consecutive_errors` - + (Optional) + Number of errors before a host is ejected from the connection pool. When the + backend host is accessed over HTTP, a 5xx return code qualifies as an error. + Defaults to 5. + +* `consecutive_gateway_failure` - + (Optional) + The number of consecutive gateway failures (502, 503, 504 status or connection + errors that are mapped to one of those status codes) before a consecutive + gateway failure ejection occurs. Defaults to 5. + +* `enforcing_consecutive_errors` - + (Optional) + The percentage chance that a host will be actually ejected when an outlier + status is detected through consecutive 5xx. This setting can be used to disable + ejection or to ramp it up slowly. Defaults to 100. + +* `enforcing_consecutive_gateway_failure` - + (Optional) + The percentage chance that a host will be actually ejected when an outlier + status is detected through consecutive gateway failures. This setting can be + used to disable ejection or to ramp it up slowly. Defaults to 0. + +* `enforcing_success_rate` - + (Optional) + The percentage chance that a host will be actually ejected when an outlier + status is detected through success rate statistics. This setting can be used to + disable ejection or to ramp it up slowly. Defaults to 100. + +* `interval` - + (Optional) + Time interval between ejection sweep analysis. This can result in both new + ejections as well as hosts being returned to service. Defaults to 10 seconds. Structure is documented below. + +* `max_ejection_percent` - + (Optional) + Maximum percentage of hosts in the load balancing pool for the backend service + that can be ejected. Defaults to 10%. + +* `success_rate_minimum_hosts` - + (Optional) + The number of hosts in a cluster that must have enough request volume to detect + success rate outliers. If the number of hosts is less than this setting, outlier + detection via success rate statistics is not performed for any host in the + cluster. Defaults to 5. + +* `success_rate_request_volume` - + (Optional) + The minimum number of total requests that must be collected in one interval (as + defined by the interval duration above) to include this host in success rate + based outlier detection. If the volume is lower than this setting, outlier + detection via success rate statistics is not performed for that host. Defaults + to 100. + +* `success_rate_stdev_factor` - + (Optional) + This factor is used to determine the ejection threshold for success rate outlier + ejection. The ejection threshold is the difference between the mean success + rate, and the product of this factor and the standard deviation of the mean + success rate: mean - (stdev * success_rate_stdev_factor). This factor is divided + by a thousand to get a double. That is, if the desired factor is 1.9, the + runtime value should be 1900. Defaults to 1900. + + +The `base_ejection_time` block supports: + +* `seconds` - + (Required) + Span of time at a resolution of a second. Must be from 0 to 315,576,000,000 + inclusive. + +* `nanos` - + (Optional) + Span of time that's a fraction of a second at nanosecond resolution. Durations + less than one second are represented with a 0 `seconds` field and a positive + `nanos` field. Must be from 0 to 999,999,999 inclusive. + +The `interval` block supports: + +* `seconds` - + (Required) + Span of time at a resolution of a second. Must be from 0 to 315,576,000,000 + inclusive. + +* `nanos` - + (Optional) + Span of time that's a fraction of a second at nanosecond resolution. Durations + less than one second are represented with a 0 `seconds` field and a positive + `nanos` field. Must be from 0 to 999,999,999 inclusive. + +The `log_config` block supports: + +* `enable` - + (Optional) + Whether to enable logging for the load balancer traffic served by this backend service. + +* `sample_rate` - + (Optional) + This field can only be specified if logging is enabled for this backend service. The value of + the field must be in [0, 1]. This configures the sampling rate of requests to the load balancer + where 1.0 means all logged requests are reported and 0.0 means no logged requests are reported. + The default value is 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.