diff --git a/google-beta/resource_compute_region_url_map.go b/google-beta/resource_compute_region_url_map.go index 4560458fdd..1d499a6935 100644 --- a/google-beta/resource_compute_region_url_map.go +++ b/google-beta/resource_compute_region_url_map.go @@ -22,6 +22,7 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceComputeRegionUrlMap() *schema.Resource { @@ -98,30 +99,521 @@ the URL's path portion.`, Description: `An optional description of this resource.`, }, "path_rule": { - Type: schema.TypeList, - Optional: true, - Description: `The list of path rules.`, + Type: schema.TypeList, + Optional: true, + Description: `The list of path rules. Use this list instead of routeRules when routing based +on simple path matching is all that's required. The order by which path rules +are specified does not matter. Matches are always done on the longest-path-first +basis. For example: a pathRule with a path /a/b/c/* will match before /a/b/* +irrespective of the order in which those paths appear in this list. Within a +given pathMatcher, only one of pathRules or routeRules must be set.`, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "paths": { Type: schema.TypeSet, Required: true, - Description: `The list of path patterns to match. Each must start with / -and the only place a * is allowed is at the end following -a /. The string fed to the path matcher does not include -any text after the first ? or #, and those chars are not + Description: `The list of path patterns to match. Each must start with / and the only place a +* is allowed is at the end following a /. The string fed to the path matcher +does not include any text after the first ? or #, and those chars are not allowed here.`, Elem: &schema.Schema{ Type: schema.TypeString, }, Set: schema.HashString, }, + "route_action": { + Type: schema.TypeList, + Optional: true, + Description: `In response to a matching path, the load balancer performs advanced routing +actions like URL rewrites, header transformations, etc. prior to forwarding the +request to the selected backend. If routeAction specifies any +weightedBackendServices, service must not be set. Conversely if service is set, +routeAction cannot contain any weightedBackendServices. Only one of routeAction +or urlRedirect must be set.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cors_policy": { + Type: schema.TypeList, + Optional: true, + Description: `The specification for allowing client side cross-origin requests. Please see W3C +Recommendation for Cross Origin Resource Sharing`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "disabled": { + Type: schema.TypeBool, + Required: true, + Description: `If true, specifies the CORS policy is disabled.`, + }, + "allow_credentials": { + Type: schema.TypeBool, + Optional: true, + Description: `In response to a preflight request, setting this to true indicates that the +actual request can include user credentials. This translates to the Access- +Control-Allow-Credentials header. Defaults to false.`, + Default: false, + }, + "allow_headers": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies the content for the Access-Control-Allow-Headers header.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "allow_methods": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies the content for the Access-Control-Allow-Methods header.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "allow_origin_regexes": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies the regualar expression patterns that match allowed origins. For +regular expression grammar please see en.cppreference.com/w/cpp/regex/ecmascript +An origin is allowed if it matches either allow_origins or allow_origin_regex.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "allow_origins": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies the list of origins that will be allowed to do CORS requests. An +origin is allowed if it matches either allow_origins or allow_origin_regex.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "expose_headers": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies the content for the Access-Control-Expose-Headers header.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "max_age": { + Type: schema.TypeInt, + Optional: true, + Description: `Specifies how long the results of a preflight request can be cached. This +translates to the content for the Access-Control-Max-Age header.`, + }, + }, + }, + }, + "fault_injection_policy": { + Type: schema.TypeList, + Optional: true, + Description: `The specification for fault injection introduced into traffic to test the +resiliency of clients to backend service failure. As part of fault injection, +when clients send requests to a backend service, delays can be introduced by +Loadbalancer on a percentage of requests before sending those request to the +backend service. Similarly requests from clients can be aborted by the +Loadbalancer for a percentage of requests. timeout and retry_policy will be +ignored by clients that are configured with a fault_injection_policy.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "abort": { + Type: schema.TypeList, + Optional: true, + Description: `The specification for how client requests are aborted as part of fault +injection.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_status": { + Type: schema.TypeInt, + Required: true, + Description: `The HTTP status code used to abort the request. The value must be between 200 +and 599 inclusive.`, + }, + "percentage": { + Type: schema.TypeFloat, + Required: true, + Description: `The percentage of traffic (connections/operations/requests) which will be +aborted as part of fault injection. The value must be between 0.0 and 100.0 +inclusive.`, + }, + }, + }, + }, + "delay": { + Type: schema.TypeList, + Optional: true, + Description: `The specification for how client requests are delayed as part of fault +injection, before being sent to a backend service.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "fixed_delay": { + Type: schema.TypeList, + Required: true, + Description: `Specifies the value of the fixed delay interval.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "seconds": { + Type: schema.TypeString, + Required: true, + Description: `Span of time at a resolution of a second. Must be from 0 to 315,576,000,000 +inclusive.`, + }, + "nanos": { + Type: schema.TypeInt, + Optional: true, + Description: `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.`, + }, + }, + }, + }, + "percentage": { + Type: schema.TypeFloat, + Required: true, + Description: `The percentage of traffic (connections/operations/requests) on which delay will +be introduced as part of fault injection. The value must be between 0.0 and +100.0 inclusive.`, + }, + }, + }, + }, + }, + }, + }, + "request_mirror_policy": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies the policy on how requests intended for the route's backends are +shadowed to a separate mirrored backend service. Loadbalancer does not wait for +responses from the shadow service. Prior to sending traffic to the shadow +service, the host / authority header is suffixed with -shadow.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "backend_service": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: `The RegionBackendService resource being mirrored to.`, + }, + }, + }, + }, + "retry_policy": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies the retry policy associated with this route.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "num_retries": { + Type: schema.TypeInt, + Optional: true, + Description: `Specifies the allowed number retries. This number must be > 0.`, + }, + "per_try_timeout": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies a non-zero timeout per retry attempt.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "seconds": { + Type: schema.TypeString, + Required: true, + Description: `Span of time at a resolution of a second. Must be from 0 to 315,576,000,000 +inclusive.`, + }, + "nanos": { + Type: schema.TypeInt, + Optional: true, + Description: `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.`, + }, + }, + }, + }, + "retry_conditions": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies one or more conditions when this retry rule applies. Valid values are: +- 5xx: Loadbalancer will attempt a retry if the backend service responds with +any 5xx response code, or if the backend service does not respond at all, +example: disconnects, reset, read timeout, connection failure, and refused +streams. +- gateway-error: Similar to 5xx, but only applies to response codes +502, 503 or 504. +- connect-failure: Loadbalancer will retry on failures +connecting to backend services, for example due to connection timeouts. +- retriable-4xx: Loadbalancer will retry for retriable 4xx response codes. +Currently the only retriable error supported is 409. +- refused-stream: Loadbalancer will retry if the backend service resets the stream with a +REFUSED_STREAM error code. This reset type indicates that it is safe to retry. +- cancelled: Loadbalancer will retry if the gRPC status code in the response +header is set to cancelled +- deadline-exceeded: Loadbalancer will retry if the +gRPC status code in the response header is set to deadline-exceeded +- resource-exhausted: Loadbalancer will retry if the gRPC status code in the response +header is set to resource-exhausted +- unavailable: Loadbalancer will retry if +the gRPC status code in the response header is set to unavailable`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "timeout": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies the timeout for the selected route. Timeout is computed from the time +the request is has been fully processed (i.e. end-of-stream) up until the +response has been completely processed. Timeout includes all retries. If not +specified, the default value is 15 seconds.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "seconds": { + Type: schema.TypeString, + Required: true, + Description: `Span of time at a resolution of a second. Must be from 0 to 315,576,000,000 +inclusive.`, + }, + "nanos": { + Type: schema.TypeInt, + Optional: true, + Description: `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.`, + }, + }, + }, + }, + "url_rewrite": { + Type: schema.TypeList, + Optional: true, + Description: `The spec to modify the URL of the request, prior to forwarding the request to +the matched service`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "host_rewrite": { + Type: schema.TypeString, + Optional: true, + Description: `Prior to forwarding the request to the selected service, the request's host +header is replaced with contents of hostRewrite. The value must be between 1 and +255 characters.`, + }, + "path_prefix_rewrite": { + Type: schema.TypeString, + Optional: true, + Description: `Prior to forwarding the request to the selected backend service, the matching +portion of the request's path is replaced by pathPrefixRewrite. The value must +be between 1 and 1024 characters.`, + }, + }, + }, + }, + "weighted_backend_services": { + Type: schema.TypeList, + Optional: true, + Description: `A list of weighted backend services to send traffic to when a route match +occurs. The weights determine the fraction of traffic that flows to their +corresponding backend service. If all traffic needs to go to a single backend +service, there must be one weightedBackendService with weight set to a non 0 +number. Once a backendService is identified and before forwarding the request to +the backend service, advanced routing actions like Url rewrites and header +transformations are applied depending on additional settings specified in this +HttpRouteAction.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "backend_service": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: `The default RegionBackendService resource. Before +forwarding the request to backendService, the loadbalancer applies any relevant +headerActions specified as part of this backendServiceWeight.`, + }, + "weight": { + Type: schema.TypeInt, + Required: true, + Description: `Specifies the fraction of traffic sent to backendService, computed as weight / +(sum of all weightedBackendService weights in routeAction) . The selection of a +backend service is determined only for new traffic. Once a user's request has +been directed to a backendService, subsequent requests will be sent to the same +backendService as determined by the BackendService's session affinity policy. +The value must be between 0 and 1000`, + }, + "header_action": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies changes to request and response headers that need to take effect for +the selected backendService. headerAction specified here take effect before +headerAction in the enclosing HttpRouteRule, PathMatcher and UrlMap.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "request_headers_to_add": { + Type: schema.TypeList, + Optional: true, + Description: `Headers to add to a matching request prior to forwarding the request to the +backendService.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "header_name": { + Type: schema.TypeString, + Required: true, + Description: `The name of the header.`, + }, + "header_value": { + Type: schema.TypeString, + Required: true, + Description: `The value of the header to add.`, + }, + "replace": { + Type: schema.TypeBool, + Required: true, + Description: `If false, headerValue is appended to any values that already exist for the +header. If true, headerValue is set for the header, discarding any values that +were set for that header.`, + }, + }, + }, + }, + "request_headers_to_remove": { + Type: schema.TypeList, + Optional: true, + Description: `A list of header names for headers that need to be removed from the request +prior to forwarding the request to the backendService.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "response_headers_to_add": { + Type: schema.TypeList, + Optional: true, + Description: `Headers to add the response prior to sending the response back to the client.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "header_name": { + Type: schema.TypeString, + Required: true, + Description: `The name of the header.`, + }, + "header_value": { + Type: schema.TypeString, + Required: true, + Description: `The value of the header to add.`, + }, + "replace": { + Type: schema.TypeBool, + Required: true, + Description: `If false, headerValue is appended to any values that already exist for the +header. If true, headerValue is set for the header, discarding any values that +were set for that header.`, + }, + }, + }, + }, + "response_headers_to_remove": { + Type: schema.TypeList, + Optional: true, + Description: `A list of header names for headers that need to be removed from the response +prior to sending the response back to the client.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, "service": { Type: schema.TypeString, - Required: true, + Optional: true, DiffSuppressFunc: compareSelfLinkOrResourceName, - Description: `A reference to the RegionBackendService resource if this rule is -matched.`, + Description: `The region backend service resource to which traffic is +directed if this rule is matched. If routeAction is additionally specified, +advanced routing actions like URL Rewrites, etc. take effect prior to sending +the request to the backend. However, if service is specified, routeAction cannot +contain any weightedBackendService s. Conversely, if routeAction specifies any +weightedBackendServices, service must not be specified. Only one of urlRedirect, +service or routeAction.weightedBackendService must be set.`, + }, + "url_redirect": { + Type: schema.TypeList, + Optional: true, + Description: `When a path pattern is matched, the request is redirected to a URL specified by +urlRedirect. If urlRedirect is specified, service or routeAction must not be +set.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "strip_query": { + Type: schema.TypeBool, + Required: true, + Description: `If set to true, any accompanying query portion of the original URL is removed +prior to redirecting the request. If set to false, the query portion of the +original URL is retained.`, + }, + "host_redirect": { + Type: schema.TypeString, + Optional: true, + Description: `The host that will be used in the redirect response instead of the one that was +supplied in the request. The value must be between 1 and 255 characters.`, + }, + "https_redirect": { + Type: schema.TypeBool, + Optional: true, + Description: `If set to true, the URL scheme in the redirected request is set to https. If set +to false, the URL scheme of the redirected request will remain the same as that +of the request. This must only be set for UrlMaps used in TargetHttpProxys. +Setting this true for TargetHttpsProxy is not permitted. Defaults to false.`, + Default: false, + }, + "path_redirect": { + Type: schema.TypeString, + Optional: true, + Description: `The path that will be used in the redirect response instead of the one that was +supplied in the request. Only one of pathRedirect or prefixRedirect must be +specified. The value must be between 1 and 1024 characters.`, + }, + "prefix_redirect": { + Type: schema.TypeString, + Optional: true, + Description: `The prefix that replaces the prefixMatch specified in the HttpRouteRuleMatch, +retaining the remaining portion of the URL before redirecting the request.`, + }, + "redirect_response_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"FOUND", "MOVED_PERMANENTLY_DEFAULT", "PERMANENT_REDIRECT", "SEE_OTHER", "TEMPORARY_REDIRECT", ""}, false), + Description: `The HTTP Status code to use for this RedirectAction. Supported values are: +- MOVED_PERMANENTLY_DEFAULT, which is the default value and corresponds to 301. +- FOUND, which corresponds to 302. +- SEE_OTHER which corresponds to 303. +- TEMPORARY_REDIRECT, which corresponds to 307. In this case, the request method +will be retained. +- PERMANENT_REDIRECT, which corresponds to 308. In this case, +the request method will be retained.`, + }, + }, + }, }, }, }, @@ -629,12 +1121,21 @@ func flattenComputeRegionUrlMapPathMatcherPathRule(v interface{}, d *schema.Reso continue } transformed = append(transformed, map[string]interface{}{ - "paths": flattenComputeRegionUrlMapPathMatcherPathRulePaths(original["paths"], d), - "service": flattenComputeRegionUrlMapPathMatcherPathRuleService(original["service"], d), + "service": flattenComputeRegionUrlMapPathMatcherPathRuleService(original["service"], d), + "paths": flattenComputeRegionUrlMapPathMatcherPathRulePaths(original["paths"], d), + "route_action": flattenComputeRegionUrlMapPathMatcherPathRuleRouteAction(original["routeAction"], d), + "url_redirect": flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirect(original["urlRedirect"], d), }) } return transformed } +func flattenComputeRegionUrlMapPathMatcherPathRuleService(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + func flattenComputeRegionUrlMapPathMatcherPathRulePaths(v interface{}, d *schema.ResourceData) interface{} { if v == nil { return v @@ -642,13 +1143,495 @@ func flattenComputeRegionUrlMapPathMatcherPathRulePaths(v interface{}, d *schema return schema.NewSet(schema.HashString, v.([]interface{})) } -func flattenComputeRegionUrlMapPathMatcherPathRuleService(v interface{}, d *schema.ResourceData) interface{} { +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteAction(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["cors_policy"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicy(original["corsPolicy"], d) + transformed["fault_injection_policy"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicy(original["faultInjectionPolicy"], d) + transformed["request_mirror_policy"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRequestMirrorPolicy(original["requestMirrorPolicy"], d) + transformed["retry_policy"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicy(original["retryPolicy"], d) + transformed["timeout"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeout(original["timeout"], d) + transformed["url_rewrite"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewrite(original["urlRewrite"], d) + transformed["weighted_backend_services"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServices(original["weightedBackendServices"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicy(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["allow_credentials"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowCredentials(original["allowCredentials"], d) + transformed["allow_headers"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowHeaders(original["allowHeaders"], d) + transformed["allow_methods"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowMethods(original["allowMethods"], d) + transformed["allow_origin_regexes"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowOriginRegexes(original["allowOriginRegexes"], d) + transformed["allow_origins"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowOrigins(original["allowOrigins"], d) + transformed["disabled"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyDisabled(original["disabled"], d) + transformed["expose_headers"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyExposeHeaders(original["exposeHeaders"], d) + transformed["max_age"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyMaxAge(original["maxAge"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowCredentials(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowHeaders(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowMethods(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowOriginRegexes(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowOrigins(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyDisabled(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyExposeHeaders(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyMaxAge(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 flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicy(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["abort"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbort(original["abort"], d) + transformed["delay"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelay(original["delay"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbort(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["http_status"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortHttpStatus(original["httpStatus"], d) + transformed["percentage"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortPercentage(original["percentage"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortHttpStatus(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 flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortPercentage(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelay(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["fixed_delay"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelay(original["fixedDelay"], d) + transformed["percentage"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayPercentage(original["percentage"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelay(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["nanos"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayNanos(original["nanos"], d) + transformed["seconds"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelaySeconds(original["seconds"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayNanos(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 flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelaySeconds(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayPercentage(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRequestMirrorPolicy(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["backend_service"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRequestMirrorPolicyBackendService(original["backendService"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRequestMirrorPolicyBackendService(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicy(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["num_retries"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyNumRetries(original["numRetries"], d) + transformed["per_try_timeout"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeout(original["perTryTimeout"], d) + transformed["retry_conditions"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyRetryConditions(original["retryConditions"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyNumRetries(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 flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeout(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["nanos"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutNanos(original["nanos"], d) + transformed["seconds"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutSeconds(original["seconds"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutNanos(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 flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutSeconds(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyRetryConditions(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeout(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["nanos"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeoutNanos(original["nanos"], d) + transformed["seconds"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeoutSeconds(original["seconds"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeoutNanos(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 flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeoutSeconds(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewrite(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["host_rewrite"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewriteHostRewrite(original["hostRewrite"], d) + transformed["path_prefix_rewrite"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewritePathPrefixRewrite(original["pathPrefixRewrite"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewriteHostRewrite(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewritePathPrefixRewrite(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServices(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "backend_service": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesBackendService(original["backendService"], d), + "header_action": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderAction(original["headerAction"], d), + "weight": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesWeight(original["weight"], d), + }) + } + return transformed +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesBackendService(v interface{}, d *schema.ResourceData) interface{} { if v == nil { return v } return ConvertSelfLinkToV1(v.(string)) } +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderAction(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["request_headers_to_add"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAdd(original["requestHeadersToAdd"], d) + transformed["request_headers_to_remove"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToRemove(original["requestHeadersToRemove"], d) + transformed["response_headers_to_add"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAdd(original["responseHeadersToAdd"], d) + transformed["response_headers_to_remove"] = + flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToRemove(original["responseHeadersToRemove"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAdd(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "header_name": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddHeaderName(original["headerName"], d), + "header_value": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddHeaderValue(original["headerValue"], d), + "replace": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddReplace(original["replace"], d), + }) + } + return transformed +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddHeaderName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddHeaderValue(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddReplace(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToRemove(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAdd(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "header_name": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddHeaderName(original["headerName"], d), + "header_value": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddHeaderValue(original["headerValue"], d), + "replace": flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddReplace(original["replace"], d), + }) + } + return transformed +} +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddHeaderName(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddHeaderValue(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddReplace(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToRemove(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesWeight(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 flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirect(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["host_redirect"] = + flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectHostRedirect(original["hostRedirect"], d) + transformed["https_redirect"] = + flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectHttpsRedirect(original["httpsRedirect"], d) + transformed["path_redirect"] = + flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectPathRedirect(original["pathRedirect"], d) + transformed["prefix_redirect"] = + flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectPrefixRedirect(original["prefixRedirect"], d) + transformed["redirect_response_code"] = + flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectRedirectResponseCode(original["redirectResponseCode"], d) + transformed["strip_query"] = + flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectStripQuery(original["stripQuery"], d) + return []interface{}{transformed} +} +func flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectHostRedirect(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectHttpsRedirect(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectPathRedirect(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectPrefixRedirect(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectRedirectResponseCode(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenComputeRegionUrlMapPathMatcherPathRuleUrlRedirectStripQuery(v interface{}, d *schema.ResourceData) interface{} { + return v +} + func flattenComputeRegionUrlMapTest(v interface{}, d *schema.ResourceData) interface{} { if v == nil { return v @@ -835,6 +1818,13 @@ func expandComputeRegionUrlMapPathMatcherPathRule(v interface{}, d TerraformReso original := raw.(map[string]interface{}) transformed := make(map[string]interface{}) + transformedService, err := expandComputeRegionUrlMapPathMatcherPathRuleService(original["service"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedService); val.IsValid() && !isEmptyValue(val) { + transformed["service"] = transformedService + } + transformedPaths, err := expandComputeRegionUrlMapPathMatcherPathRulePaths(original["paths"], d, config) if err != nil { return nil, err @@ -842,31 +1832,763 @@ func expandComputeRegionUrlMapPathMatcherPathRule(v interface{}, d TerraformReso transformed["paths"] = transformedPaths } - transformedService, err := expandComputeRegionUrlMapPathMatcherPathRuleService(original["service"], d, config) + transformedRouteAction, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteAction(original["route_action"], d, config) if err != nil { return nil, err - } else if val := reflect.ValueOf(transformedService); val.IsValid() && !isEmptyValue(val) { - transformed["service"] = transformedService + } else if val := reflect.ValueOf(transformedRouteAction); val.IsValid() && !isEmptyValue(val) { + transformed["routeAction"] = transformedRouteAction } - req = append(req, transformed) + transformedUrlRedirect, err := expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirect(original["url_redirect"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedUrlRedirect); val.IsValid() && !isEmptyValue(val) { + transformed["urlRedirect"] = transformedUrlRedirect + } + + req = append(req, transformed) } return req, nil } +func expandComputeRegionUrlMapPathMatcherPathRuleService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseRegionalFieldValue("backendServices", v.(string), "project", "region", "zone", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for service: %s", err) + } + return f.RelativeLink(), nil +} + func expandComputeRegionUrlMapPathMatcherPathRulePaths(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { v = v.(*schema.Set).List() return v, nil } -func expandComputeRegionUrlMapPathMatcherPathRuleService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { +func expandComputeRegionUrlMapPathMatcherPathRuleRouteAction(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{}) + + transformedCorsPolicy, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicy(original["cors_policy"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCorsPolicy); val.IsValid() && !isEmptyValue(val) { + transformed["corsPolicy"] = transformedCorsPolicy + } + + transformedFaultInjectionPolicy, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicy(original["fault_injection_policy"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedFaultInjectionPolicy); val.IsValid() && !isEmptyValue(val) { + transformed["faultInjectionPolicy"] = transformedFaultInjectionPolicy + } + + transformedRequestMirrorPolicy, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRequestMirrorPolicy(original["request_mirror_policy"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRequestMirrorPolicy); val.IsValid() && !isEmptyValue(val) { + transformed["requestMirrorPolicy"] = transformedRequestMirrorPolicy + } + + transformedRetryPolicy, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicy(original["retry_policy"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRetryPolicy); val.IsValid() && !isEmptyValue(val) { + transformed["retryPolicy"] = transformedRetryPolicy + } + + transformedTimeout, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeout(original["timeout"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTimeout); val.IsValid() && !isEmptyValue(val) { + transformed["timeout"] = transformedTimeout + } + + transformedUrlRewrite, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewrite(original["url_rewrite"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedUrlRewrite); val.IsValid() && !isEmptyValue(val) { + transformed["urlRewrite"] = transformedUrlRewrite + } + + transformedWeightedBackendServices, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServices(original["weighted_backend_services"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedWeightedBackendServices); val.IsValid() && !isEmptyValue(val) { + transformed["weightedBackendServices"] = transformedWeightedBackendServices + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicy(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{}) + + transformedAllowCredentials, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowCredentials(original["allow_credentials"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAllowCredentials); val.IsValid() && !isEmptyValue(val) { + transformed["allowCredentials"] = transformedAllowCredentials + } + + transformedAllowHeaders, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowHeaders(original["allow_headers"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAllowHeaders); val.IsValid() && !isEmptyValue(val) { + transformed["allowHeaders"] = transformedAllowHeaders + } + + transformedAllowMethods, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowMethods(original["allow_methods"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAllowMethods); val.IsValid() && !isEmptyValue(val) { + transformed["allowMethods"] = transformedAllowMethods + } + + transformedAllowOriginRegexes, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowOriginRegexes(original["allow_origin_regexes"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAllowOriginRegexes); val.IsValid() && !isEmptyValue(val) { + transformed["allowOriginRegexes"] = transformedAllowOriginRegexes + } + + transformedAllowOrigins, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowOrigins(original["allow_origins"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAllowOrigins); val.IsValid() && !isEmptyValue(val) { + transformed["allowOrigins"] = transformedAllowOrigins + } + + transformedDisabled, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyDisabled(original["disabled"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDisabled); val.IsValid() && !isEmptyValue(val) { + transformed["disabled"] = transformedDisabled + } + + transformedExposeHeaders, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyExposeHeaders(original["expose_headers"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedExposeHeaders); val.IsValid() && !isEmptyValue(val) { + transformed["exposeHeaders"] = transformedExposeHeaders + } + + transformedMaxAge, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyMaxAge(original["max_age"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMaxAge); val.IsValid() && !isEmptyValue(val) { + transformed["maxAge"] = transformedMaxAge + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowCredentials(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowHeaders(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowMethods(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowOriginRegexes(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyAllowOrigins(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyDisabled(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyExposeHeaders(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionCorsPolicyMaxAge(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicy(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{}) + + transformedAbort, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbort(original["abort"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAbort); val.IsValid() && !isEmptyValue(val) { + transformed["abort"] = transformedAbort + } + + transformedDelay, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelay(original["delay"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDelay); val.IsValid() && !isEmptyValue(val) { + transformed["delay"] = transformedDelay + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbort(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{}) + + transformedHttpStatus, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortHttpStatus(original["http_status"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHttpStatus); val.IsValid() && !isEmptyValue(val) { + transformed["httpStatus"] = transformedHttpStatus + } + + transformedPercentage, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortPercentage(original["percentage"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPercentage); val.IsValid() && !isEmptyValue(val) { + transformed["percentage"] = transformedPercentage + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortHttpStatus(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortPercentage(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelay(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{}) + + transformedFixedDelay, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelay(original["fixed_delay"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedFixedDelay); val.IsValid() && !isEmptyValue(val) { + transformed["fixedDelay"] = transformedFixedDelay + } + + transformedPercentage, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayPercentage(original["percentage"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPercentage); val.IsValid() && !isEmptyValue(val) { + transformed["percentage"] = transformedPercentage + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelay(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{}) + + transformedNanos, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayNanos(original["nanos"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !isEmptyValue(val) { + transformed["nanos"] = transformedNanos + } + + transformedSeconds, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelaySeconds(original["seconds"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !isEmptyValue(val) { + transformed["seconds"] = transformedSeconds + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayNanos(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelaySeconds(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayPercentage(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRequestMirrorPolicy(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{}) + + transformedBackendService, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRequestMirrorPolicyBackendService(original["backend_service"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedBackendService); val.IsValid() && !isEmptyValue(val) { + transformed["backendService"] = transformedBackendService + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRequestMirrorPolicyBackendService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { f, err := parseRegionalFieldValue("backendServices", v.(string), "project", "region", "zone", d, config, true) if err != nil { - return nil, fmt.Errorf("Invalid value for service: %s", err) + return nil, fmt.Errorf("Invalid value for backend_service: %s", err) + } + return f.RelativeLink(), nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicy(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{}) + + transformedNumRetries, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyNumRetries(original["num_retries"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNumRetries); val.IsValid() && !isEmptyValue(val) { + transformed["numRetries"] = transformedNumRetries + } + + transformedPerTryTimeout, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeout(original["per_try_timeout"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPerTryTimeout); val.IsValid() && !isEmptyValue(val) { + transformed["perTryTimeout"] = transformedPerTryTimeout + } + + transformedRetryConditions, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyRetryConditions(original["retry_conditions"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRetryConditions); val.IsValid() && !isEmptyValue(val) { + transformed["retryConditions"] = transformedRetryConditions + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyNumRetries(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeout(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{}) + + transformedNanos, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutNanos(original["nanos"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !isEmptyValue(val) { + transformed["nanos"] = transformedNanos + } + + transformedSeconds, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutSeconds(original["seconds"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !isEmptyValue(val) { + transformed["seconds"] = transformedSeconds + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutNanos(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutSeconds(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionRetryPolicyRetryConditions(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeout(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{}) + + transformedNanos, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeoutNanos(original["nanos"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNanos); val.IsValid() && !isEmptyValue(val) { + transformed["nanos"] = transformedNanos + } + + transformedSeconds, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeoutSeconds(original["seconds"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSeconds); val.IsValid() && !isEmptyValue(val) { + transformed["seconds"] = transformedSeconds + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeoutNanos(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionTimeoutSeconds(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewrite(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{}) + + transformedHostRewrite, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewriteHostRewrite(original["host_rewrite"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHostRewrite); val.IsValid() && !isEmptyValue(val) { + transformed["hostRewrite"] = transformedHostRewrite + } + + transformedPathPrefixRewrite, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewritePathPrefixRewrite(original["path_prefix_rewrite"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPathPrefixRewrite); val.IsValid() && !isEmptyValue(val) { + transformed["pathPrefixRewrite"] = transformedPathPrefixRewrite + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewriteHostRewrite(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionUrlRewritePathPrefixRewrite(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedBackendService, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesBackendService(original["backend_service"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedBackendService); val.IsValid() && !isEmptyValue(val) { + transformed["backendService"] = transformedBackendService + } + + transformedHeaderAction, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderAction(original["header_action"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHeaderAction); val.IsValid() && !isEmptyValue(val) { + transformed["headerAction"] = transformedHeaderAction + } + + transformedWeight, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesWeight(original["weight"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedWeight); val.IsValid() && !isEmptyValue(val) { + transformed["weight"] = transformedWeight + } + + req = append(req, transformed) + } + return req, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesBackendService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + f, err := parseRegionalFieldValue("backendServices", v.(string), "project", "region", "zone", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for backend_service: %s", err) } return f.RelativeLink(), nil } +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderAction(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{}) + + transformedRequestHeadersToAdd, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAdd(original["request_headers_to_add"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRequestHeadersToAdd); val.IsValid() && !isEmptyValue(val) { + transformed["requestHeadersToAdd"] = transformedRequestHeadersToAdd + } + + transformedRequestHeadersToRemove, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToRemove(original["request_headers_to_remove"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRequestHeadersToRemove); val.IsValid() && !isEmptyValue(val) { + transformed["requestHeadersToRemove"] = transformedRequestHeadersToRemove + } + + transformedResponseHeadersToAdd, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAdd(original["response_headers_to_add"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedResponseHeadersToAdd); val.IsValid() && !isEmptyValue(val) { + transformed["responseHeadersToAdd"] = transformedResponseHeadersToAdd + } + + transformedResponseHeadersToRemove, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToRemove(original["response_headers_to_remove"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedResponseHeadersToRemove); val.IsValid() && !isEmptyValue(val) { + transformed["responseHeadersToRemove"] = transformedResponseHeadersToRemove + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAdd(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedHeaderName, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddHeaderName(original["header_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHeaderName); val.IsValid() && !isEmptyValue(val) { + transformed["headerName"] = transformedHeaderName + } + + transformedHeaderValue, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddHeaderValue(original["header_value"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHeaderValue); val.IsValid() && !isEmptyValue(val) { + transformed["headerValue"] = transformedHeaderValue + } + + transformedReplace, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddReplace(original["replace"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedReplace); val.IsValid() && !isEmptyValue(val) { + transformed["replace"] = transformedReplace + } + + req = append(req, transformed) + } + return req, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddHeaderName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddHeaderValue(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToAddReplace(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionRequestHeadersToRemove(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAdd(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedHeaderName, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddHeaderName(original["header_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHeaderName); val.IsValid() && !isEmptyValue(val) { + transformed["headerName"] = transformedHeaderName + } + + transformedHeaderValue, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddHeaderValue(original["header_value"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHeaderValue); val.IsValid() && !isEmptyValue(val) { + transformed["headerValue"] = transformedHeaderValue + } + + transformedReplace, err := expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddReplace(original["replace"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedReplace); val.IsValid() && !isEmptyValue(val) { + transformed["replace"] = transformedReplace + } + + req = append(req, transformed) + } + return req, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddHeaderName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddHeaderValue(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToAddReplace(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesHeaderActionResponseHeadersToRemove(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleRouteActionWeightedBackendServicesWeight(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirect(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{}) + + transformedHostRedirect, err := expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectHostRedirect(original["host_redirect"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHostRedirect); val.IsValid() && !isEmptyValue(val) { + transformed["hostRedirect"] = transformedHostRedirect + } + + transformedHttpsRedirect, err := expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectHttpsRedirect(original["https_redirect"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHttpsRedirect); val.IsValid() && !isEmptyValue(val) { + transformed["httpsRedirect"] = transformedHttpsRedirect + } + + transformedPathRedirect, err := expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectPathRedirect(original["path_redirect"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPathRedirect); val.IsValid() && !isEmptyValue(val) { + transformed["pathRedirect"] = transformedPathRedirect + } + + transformedPrefixRedirect, err := expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectPrefixRedirect(original["prefix_redirect"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPrefixRedirect); val.IsValid() && !isEmptyValue(val) { + transformed["prefixRedirect"] = transformedPrefixRedirect + } + + transformedRedirectResponseCode, err := expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectRedirectResponseCode(original["redirect_response_code"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRedirectResponseCode); val.IsValid() && !isEmptyValue(val) { + transformed["redirectResponseCode"] = transformedRedirectResponseCode + } + + transformedStripQuery, err := expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectStripQuery(original["strip_query"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStripQuery); val.IsValid() && !isEmptyValue(val) { + transformed["stripQuery"] = transformedStripQuery + } + + return transformed, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectHostRedirect(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectHttpsRedirect(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectPathRedirect(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectPrefixRedirect(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectRedirectResponseCode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionUrlMapPathMatcherPathRuleUrlRedirectStripQuery(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandComputeRegionUrlMapTest(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { l := v.([]interface{}) req := make([]interface{}, 0, len(l)) diff --git a/google-beta/resource_compute_region_url_map_generated_test.go b/google-beta/resource_compute_region_url_map_generated_test.go index 6341339ba8..fe7965b1ba 100644 --- a/google-beta/resource_compute_region_url_map_generated_test.go +++ b/google-beta/resource_compute_region_url_map_generated_test.go @@ -122,6 +122,230 @@ resource "google_compute_region_health_check" "default" { `, context) } +func TestAccComputeRegionUrlMap_regionUrlMapL7IlbPathExample(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: testAccCheckComputeRegionUrlMapDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionUrlMap_regionUrlMapL7IlbPathExample(context), + }, + }, + }) +} + +func testAccComputeRegionUrlMap_regionUrlMapL7IlbPathExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_region_url_map" "regionurlmap" { + provider = "google-beta" + name = "regionurlmap%{random_suffix}" + description = "a description" + default_service = google_compute_region_backend_service.home.self_link + + host_rule { + hosts = ["mysite.com"] + path_matcher = "allpaths" + } + + path_matcher { + name = "allpaths" + default_service = google_compute_region_backend_service.home.self_link + + path_rule { + paths = ["/home"] + route_action { + cors_policy { + allow_credentials = true + allow_headers = ["Allowed content"] + allow_methods = ["GET"] + allow_origins = ["Allowed origin"] + expose_headers = ["Exposed header"] + max_age = 30 + disabled = false + } + fault_injection_policy { + abort { + http_status = 234 + percentage = 5.6 + } + delay { + fixed_delay { + seconds = 0 + nanos = 50000 + } + percentage = 7.8 + } + } + request_mirror_policy { + backend_service = google_compute_region_backend_service.home.self_link + } + retry_policy { + num_retries = 4 + per_try_timeout { + seconds = 30 + } + retry_conditions = ["5xx", "deadline-exceeded"] + } + timeout { + seconds = 20 + nanos = 750000000 + } + url_rewrite { + host_rewrite = "A replacement header" + path_prefix_rewrite = "A replacement path" + } + weighted_backend_services { + backend_service = google_compute_region_backend_service.home.self_link + weight = 400 + header_action { + request_headers_to_remove = ["RemoveMe"] + request_headers_to_add { + header_name = "AddMe" + header_value = "MyValue" + replace = true + } + response_headers_to_remove = ["RemoveMe"] + response_headers_to_add { + header_name = "AddMe" + header_value = "MyValue" + replace = false + } + } + } + } + } + } + + test { + service = google_compute_region_backend_service.home.self_link + host = "hi.com" + path = "/home" + } +} + +resource "google_compute_region_backend_service" "home" { + provider = "google-beta" + name = "home%{random_suffix}" + protocol = "HTTP" + timeout_sec = 10 + + health_checks = [google_compute_region_health_check.default.self_link] + load_balancing_scheme = "INTERNAL_MANAGED" +} + +resource "google_compute_region_health_check" "default" { + provider = "google-beta" + name = "health-check%{random_suffix}" + http_health_check { + port = 80 + } +} +`, context) +} + +func TestAccComputeRegionUrlMap_regionUrlMapL7IlbPathPartialExample(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: testAccCheckComputeRegionUrlMapDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionUrlMap_regionUrlMapL7IlbPathPartialExample(context), + }, + }, + }) +} + +func testAccComputeRegionUrlMap_regionUrlMapL7IlbPathPartialExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_region_url_map" "regionurlmap" { + provider = "google-beta" + name = "regionurlmap%{random_suffix}" + description = "a description" + default_service = google_compute_region_backend_service.home.self_link + + host_rule { + hosts = ["mysite.com"] + path_matcher = "allpaths" + } + + path_matcher { + name = "allpaths" + default_service = google_compute_region_backend_service.home.self_link + + path_rule { + paths = ["/home"] + route_action { + retry_policy { + num_retries = 4 + per_try_timeout { + seconds = 30 + } + retry_conditions = ["5xx", "deadline-exceeded"] + } + timeout { + seconds = 20 + nanos = 750000000 + } + url_rewrite { + host_rewrite = "A replacement header" + path_prefix_rewrite = "A replacement path" + } + weighted_backend_services { + backend_service = google_compute_region_backend_service.home.self_link + weight = 400 + header_action { + response_headers_to_add { + header_name = "AddMe" + header_value = "MyValue" + replace = false + } + } + } + } + } + } + + test { + service = google_compute_region_backend_service.home.self_link + host = "hi.com" + path = "/home" + } +} + +resource "google_compute_region_backend_service" "home" { + provider = "google-beta" + name = "home%{random_suffix}" + protocol = "HTTP" + timeout_sec = 10 + + health_checks = [google_compute_region_health_check.default.self_link] + load_balancing_scheme = "INTERNAL_MANAGED" +} + +resource "google_compute_region_health_check" "default" { + provider = "google-beta" + name = "health-check%{random_suffix}" + http_health_check { + port = 80 + } +} +`, context) +} + func testAccCheckComputeRegionUrlMapDestroy(s *terraform.State) error { for name, rs := range s.RootModule().Resources { if rs.Type != "google_compute_region_url_map" { diff --git a/google-beta/resource_compute_region_url_map_test.go b/google-beta/resource_compute_region_url_map_test.go index 8a877f4fa8..ba43040d5f 100644 --- a/google-beta/resource_compute_region_url_map_test.go +++ b/google-beta/resource_compute_region_url_map_test.go @@ -98,6 +98,36 @@ func TestAccComputeRegionUrlMap_noPathRulesWithUpdate(t *testing.T) { }) } +func TestAccComputeRegionUrlMap_ilbPathUpdate(t *testing.T) { + t.Parallel() + + randomSuffix := acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeUrlMapDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionUrlMap_ilbPath(randomSuffix), + }, + { + ResourceName: "google_compute_region_url_map.foobar", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeRegionUrlMap_ilbPathUpdate(randomSuffix), + }, + { + ResourceName: "google_compute_region_url_map.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccComputeRegionUrlMap_basic1(randomSuffix string) string { return fmt.Sprintf(` resource "google_compute_region_backend_service" "foobar" { @@ -360,3 +390,224 @@ resource "google_compute_region_url_map" "foobar" { } `, randomSuffix, randomSuffix, randomSuffix) } + +func testAccComputeRegionUrlMap_ilbPath(randomSuffix string) string { + return fmt.Sprintf(` +resource "google_compute_region_url_map" "foobar" { + name = "regionurlmap-test-%s" + description = "a description" + default_service = google_compute_region_backend_service.home.self_link + + host_rule { + hosts = ["mysite.com"] + path_matcher = "allpaths" + } + + path_matcher { + name = "allpaths" + default_service = google_compute_region_backend_service.home.self_link + + path_rule { + paths = ["/home"] + route_action { + cors_policy { + allow_credentials = true + allow_headers = ["Allowed content"] + allow_methods = ["GET"] + allow_origins = ["Allowed origin"] + expose_headers = ["Exposed header"] + max_age = 30 + disabled = false + } + fault_injection_policy { + abort { + http_status = 234 + percentage = 5.6 + } + delay { + fixed_delay { + seconds = 0 + nanos = 50000 + } + percentage = 7.8 + } + } + request_mirror_policy { + backend_service = google_compute_region_backend_service.home.self_link + } + retry_policy { + num_retries = 4 + per_try_timeout { + seconds = 30 + } + retry_conditions = ["5xx", "deadline-exceeded"] + } + timeout { + seconds = 20 + nanos = 750000000 + } + url_rewrite { + host_rewrite = "A replacement header" + path_prefix_rewrite = "A replacement path" + } + weighted_backend_services { + backend_service = google_compute_region_backend_service.home.self_link + weight = 400 + header_action { + request_headers_to_remove = ["RemoveMe"] + request_headers_to_add { + header_name = "AddMe" + header_value = "MyValue" + replace = true + } + response_headers_to_remove = ["RemoveMe"] + response_headers_to_add { + header_name = "AddMe" + header_value = "MyValue" + replace = false + } + } + } + } + } + } + + test { + service = google_compute_region_backend_service.home.self_link + host = "hi.com" + path = "/home" + } +} + +resource "google_compute_region_backend_service" "home" { + name = "regionurlmap-test-%s" + protocol = "HTTP" + timeout_sec = 10 + + health_checks = [google_compute_region_health_check.default.self_link] + load_balancing_scheme = "INTERNAL_MANAGED" +} + +resource "google_compute_region_health_check" "default" { + name = "regionurlmap-test-%s" + http_health_check { + port = 80 + } +} +`, randomSuffix, randomSuffix, randomSuffix) +} + +func testAccComputeRegionUrlMap_ilbPathUpdate(randomSuffix string) string { + return fmt.Sprintf(` +resource "google_compute_region_url_map" "foobar" { + name = "regionurlmap-test-%s" + description = "a description" + default_service = google_compute_region_backend_service.home2.self_link + + host_rule { + hosts = ["mysite.com"] + path_matcher = "allpaths2" + } + + path_matcher { + name = "allpaths2" + default_service = google_compute_region_backend_service.home.self_link + + path_rule { + paths = ["/home2"] + route_action { + cors_policy { + allow_credentials = true + allow_headers = ["Allowed content again"] + allow_methods = ["PUT"] + allow_origins = ["Allowed origin again"] + expose_headers = ["Exposed header again"] + max_age = 31 + disabled = true + } + fault_injection_policy { + abort { + http_status = 345 + percentage = 6.7 + } + delay { + fixed_delay { + seconds = 1 + nanos = 51000 + } + percentage = 8.9 + } + } + request_mirror_policy { + backend_service = google_compute_region_backend_service.home.self_link + } + retry_policy { + num_retries = 6 + per_try_timeout { + seconds = 31 + } + retry_conditions = ["5xx"] + } + timeout { + seconds = 21 + nanos = 760000000 + } + url_rewrite { + host_rewrite = "A replacement header again" + path_prefix_rewrite = "A replacement path again" + } + weighted_backend_services { + backend_service = google_compute_region_backend_service.home.self_link + weight = 401 + header_action { + request_headers_to_remove = ["RemoveMe2"] + request_headers_to_add { + header_name = "AddMe2" + header_value = "MyValue2" + replace = false + } + response_headers_to_remove = ["RemoveMe2"] + response_headers_to_add { + header_name = "AddMe2" + header_value = "MyValue2" + replace = true + } + } + } + } + } + } + + test { + service = google_compute_region_backend_service.home.self_link + host = "hi.com" + path = "/home" + } +} + +resource "google_compute_region_backend_service" "home" { + name = "regionurlmap-test-%s" + protocol = "HTTP" + timeout_sec = 10 + + health_checks = [google_compute_region_health_check.default.self_link] + load_balancing_scheme = "INTERNAL_MANAGED" +} + +resource "google_compute_region_backend_service" "home2" { + name = "regionurlmap-test-%s-2" + protocol = "HTTP" + timeout_sec = 10 + + health_checks = [google_compute_region_health_check.default.self_link] + load_balancing_scheme = "INTERNAL_MANAGED" +} + +resource "google_compute_region_health_check" "default" { + name = "regionurlmap-test-%s" + http_health_check { + port = 80 + } +} +`, randomSuffix, randomSuffix, randomSuffix, randomSuffix) +} diff --git a/google-beta/resource_compute_url_map.go b/google-beta/resource_compute_url_map.go index 97409b37d1..90e7e6cc0e 100644 --- a/google-beta/resource_compute_url_map.go +++ b/google-beta/resource_compute_url_map.go @@ -512,7 +512,7 @@ less than one second are represented with a 0 'seconds' field and a positive "retry_conditions": { Type: schema.TypeList, Optional: true, - Description: `Specfies one or more conditions when this retry rule applies. Valid values are: + Description: `Specifies one or more conditions when this retry rule applies. Valid values are: - 5xx: Loadbalancer will attempt a retry if the backend service responds with any 5xx response code, or if the backend service does not respond at all, example: disconnects, reset, read timeout, connection failure, and refused @@ -611,6 +611,16 @@ HttpRouteAction.`, Description: `The default BackendService resource. Before forwarding the request to backendService, the loadbalancer applies any relevant headerActions specified as part of this backendServiceWeight.`, + }, + "weight": { + Type: schema.TypeInt, + Required: true, + Description: `Specifies the fraction of traffic sent to backendService, computed as weight / +(sum of all weightedBackendService weights in routeAction) . The selection of a +backend service is determined only for new traffic. Once a user's request has +been directed to a backendService, subsequent requests will be sent to the same +backendService as determined by the BackendService's session affinity policy. +The value must be between 0 and 1000`, }, "header_action": { Type: schema.TypeList, @@ -695,16 +705,6 @@ prior to sending the response back to the client.`, }, }, }, - "weight": { - Type: schema.TypeInt, - Optional: true, - Description: `Specifies the fraction of traffic sent to backendService, computed as weight / -(sum of all weightedBackendService weights in routeAction) . The selection of a -backend service is determined only for new traffic. Once a user's request has -been directed to a backendService, subsequent requests will be sent to the same -backendService as determined by the BackendService's session affinity policy. -The value must be between 0 and 1000`, - }, }, }, }, diff --git a/google-beta/resource_compute_url_map_generated_test.go b/google-beta/resource_compute_url_map_generated_test.go index f3074865a4..abf3be2900 100644 --- a/google-beta/resource_compute_url_map_generated_test.go +++ b/google-beta/resource_compute_url_map_generated_test.go @@ -155,7 +155,7 @@ func testAccComputeUrlMap_urlMapTrafficDirectorRouteExample(context map[string]i resource "google_compute_url_map" "urlmap" { name = "urlmap%{random_suffix}" description = "a description" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link host_rule { hosts = ["mysite.com"] @@ -164,7 +164,7 @@ resource "google_compute_url_map" "urlmap" { path_matcher { name = "allpaths" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link route_rules { priority = 1 @@ -213,7 +213,7 @@ resource "google_compute_url_map" "urlmap" { } test { - service = "${google_compute_backend_service.home.self_link}" + service = google_compute_backend_service.home.self_link host = "hi.com" path = "/home" } @@ -225,7 +225,7 @@ resource "google_compute_backend_service" "home" { protocol = "HTTP" timeout_sec = 10 - health_checks = ["${google_compute_health_check.default.self_link}"] + health_checks = [google_compute_health_check.default.self_link] load_balancing_scheme = "INTERNAL_SELF_MANAGED" } @@ -267,7 +267,7 @@ func testAccComputeUrlMap_urlMapTrafficDirectorRoutePartialExample(context map[s resource "google_compute_url_map" "urlmap" { name = "urlmap%{random_suffix}" description = "a description" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link host_rule { hosts = ["mysite.com"] @@ -276,7 +276,7 @@ resource "google_compute_url_map" "urlmap" { path_matcher { name = "allpaths" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link route_rules { priority = 1 @@ -296,7 +296,7 @@ resource "google_compute_url_map" "urlmap" { } test { - service = "${google_compute_backend_service.home.self_link}" + service = google_compute_backend_service.home.self_link host = "hi.com" path = "/home" } @@ -308,7 +308,7 @@ resource "google_compute_backend_service" "home" { protocol = "HTTP" timeout_sec = 10 - health_checks = ["${google_compute_health_check.default.self_link}"] + health_checks = [google_compute_health_check.default.self_link] load_balancing_scheme = "INTERNAL_SELF_MANAGED" } @@ -350,7 +350,7 @@ func testAccComputeUrlMap_urlMapTrafficDirectorPathExample(context map[string]in resource "google_compute_url_map" "urlmap" { name = "urlmap%{random_suffix}" description = "a description" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link host_rule { hosts = ["mysite.com"] @@ -359,7 +359,7 @@ resource "google_compute_url_map" "urlmap" { path_matcher { name = "allpaths" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link path_rule { paths = ["/home"] @@ -388,7 +388,7 @@ resource "google_compute_url_map" "urlmap" { } } request_mirror_policy { - backend_service = "${google_compute_backend_service.home.self_link}" + backend_service = google_compute_backend_service.home.self_link } retry_policy { num_retries = 4 @@ -406,7 +406,7 @@ resource "google_compute_url_map" "urlmap" { path_prefix_rewrite = "A replacement path" } weighted_backend_services { - backend_service = "${google_compute_backend_service.home.self_link}" + backend_service = google_compute_backend_service.home.self_link weight = 400 header_action { request_headers_to_remove = ["RemoveMe"] @@ -428,7 +428,7 @@ resource "google_compute_url_map" "urlmap" { } test { - service = "${google_compute_backend_service.home.self_link}" + service = google_compute_backend_service.home.self_link host = "hi.com" path = "/home" } @@ -440,7 +440,7 @@ resource "google_compute_backend_service" "home" { protocol = "HTTP" timeout_sec = 10 - health_checks = ["${google_compute_health_check.default.self_link}"] + health_checks = [google_compute_health_check.default.self_link] load_balancing_scheme = "INTERNAL_SELF_MANAGED" } @@ -482,7 +482,7 @@ func testAccComputeUrlMap_urlMapTrafficDirectorPathPartialExample(context map[st resource "google_compute_url_map" "urlmap" { name = "urlmap%{random_suffix}" description = "a description" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link host_rule { hosts = ["mysite.com"] @@ -491,7 +491,7 @@ resource "google_compute_url_map" "urlmap" { path_matcher { name = "allpaths" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link path_rule { paths = ["/home"] @@ -507,7 +507,7 @@ resource "google_compute_url_map" "urlmap" { disabled = false } weighted_backend_services { - backend_service = "${google_compute_backend_service.home.self_link}" + backend_service = google_compute_backend_service.home.self_link weight = 400 header_action { request_headers_to_remove = ["RemoveMe"] @@ -529,7 +529,7 @@ resource "google_compute_url_map" "urlmap" { } test { - service = "${google_compute_backend_service.home.self_link}" + service = google_compute_backend_service.home.self_link host = "hi.com" path = "/home" } @@ -541,7 +541,7 @@ resource "google_compute_backend_service" "home" { protocol = "HTTP" timeout_sec = 10 - health_checks = ["${google_compute_health_check.default.self_link}"] + health_checks = [google_compute_health_check.default.self_link] load_balancing_scheme = "INTERNAL_SELF_MANAGED" } diff --git a/google-beta/resource_sql_database_instance_test.go b/google-beta/resource_sql_database_instance_test.go index 37f554d23a..a2d60ce2bd 100644 --- a/google-beta/resource_sql_database_instance_test.go +++ b/google-beta/resource_sql_database_instance_test.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" - sqladmin "google.golang.org/api/sqladmin/v1beta4" ) diff --git a/website/docs/r/compute_region_url_map.html.markdown b/website/docs/r/compute_region_url_map.html.markdown index 82b81fe69b..afab885564 100644 --- a/website/docs/r/compute_region_url_map.html.markdown +++ b/website/docs/r/compute_region_url_map.html.markdown @@ -114,6 +114,202 @@ resource "google_compute_region_health_check" "default" { } } ``` +
+## Example Usage - Region Url Map L7 Ilb Path + + +```hcl +resource "google_compute_region_url_map" "regionurlmap" { + provider = "google-beta" + name = "regionurlmap" + description = "a description" + default_service = google_compute_region_backend_service.home.self_link + + host_rule { + hosts = ["mysite.com"] + path_matcher = "allpaths" + } + + path_matcher { + name = "allpaths" + default_service = google_compute_region_backend_service.home.self_link + + path_rule { + paths = ["/home"] + route_action { + cors_policy { + allow_credentials = true + allow_headers = ["Allowed content"] + allow_methods = ["GET"] + allow_origins = ["Allowed origin"] + expose_headers = ["Exposed header"] + max_age = 30 + disabled = false + } + fault_injection_policy { + abort { + http_status = 234 + percentage = 5.6 + } + delay { + fixed_delay { + seconds = 0 + nanos = 50000 + } + percentage = 7.8 + } + } + request_mirror_policy { + backend_service = google_compute_region_backend_service.home.self_link + } + retry_policy { + num_retries = 4 + per_try_timeout { + seconds = 30 + } + retry_conditions = ["5xx", "deadline-exceeded"] + } + timeout { + seconds = 20 + nanos = 750000000 + } + url_rewrite { + host_rewrite = "A replacement header" + path_prefix_rewrite = "A replacement path" + } + weighted_backend_services { + backend_service = google_compute_region_backend_service.home.self_link + weight = 400 + header_action { + request_headers_to_remove = ["RemoveMe"] + request_headers_to_add { + header_name = "AddMe" + header_value = "MyValue" + replace = true + } + response_headers_to_remove = ["RemoveMe"] + response_headers_to_add { + header_name = "AddMe" + header_value = "MyValue" + replace = false + } + } + } + } + } + } + + test { + service = google_compute_region_backend_service.home.self_link + host = "hi.com" + path = "/home" + } +} + +resource "google_compute_region_backend_service" "home" { + provider = "google-beta" + name = "home" + protocol = "HTTP" + timeout_sec = 10 + + health_checks = [google_compute_region_health_check.default.self_link] + load_balancing_scheme = "INTERNAL_MANAGED" +} + +resource "google_compute_region_health_check" "default" { + provider = "google-beta" + name = "health-check" + http_health_check { + port = 80 + } +} +``` + +## Example Usage - Region Url Map L7 Ilb Path Partial + + +```hcl +resource "google_compute_region_url_map" "regionurlmap" { + provider = "google-beta" + name = "regionurlmap" + description = "a description" + default_service = google_compute_region_backend_service.home.self_link + + host_rule { + hosts = ["mysite.com"] + path_matcher = "allpaths" + } + + path_matcher { + name = "allpaths" + default_service = google_compute_region_backend_service.home.self_link + + path_rule { + paths = ["/home"] + route_action { + retry_policy { + num_retries = 4 + per_try_timeout { + seconds = 30 + } + retry_conditions = ["5xx", "deadline-exceeded"] + } + timeout { + seconds = 20 + nanos = 750000000 + } + url_rewrite { + host_rewrite = "A replacement header" + path_prefix_rewrite = "A replacement path" + } + weighted_backend_services { + backend_service = google_compute_region_backend_service.home.self_link + weight = 400 + header_action { + response_headers_to_add { + header_name = "AddMe" + header_value = "MyValue" + replace = false + } + } + } + } + } + } + + test { + service = google_compute_region_backend_service.home.self_link + host = "hi.com" + path = "/home" + } +} + +resource "google_compute_region_backend_service" "home" { + provider = "google-beta" + name = "home" + protocol = "HTTP" + timeout_sec = 10 + + health_checks = [google_compute_region_health_check.default.self_link] + load_balancing_scheme = "INTERNAL_MANAGED" +} + +resource "google_compute_region_health_check" "default" { + provider = "google-beta" + name = "health-check" + http_health_check { + port = 80 + } +} +``` ## Argument Reference @@ -202,23 +398,393 @@ The `path_matcher` block supports: * `path_rule` - (Optional) - The list of path rules. Structure is documented below. + The list of path rules. Use this list instead of routeRules when routing based + on simple path matching is all that's required. The order by which path rules + are specified does not matter. Matches are always done on the longest-path-first + basis. For example: a pathRule with a path /a/b/c/* will match before /a/b/* + irrespective of the order in which those paths appear in this list. Within a + given pathMatcher, only one of pathRules or routeRules must be set. Structure is documented below. The `path_rule` block supports: +* `service` - + (Optional) + The region backend service resource to which traffic is + directed if this rule is matched. If routeAction is additionally specified, + advanced routing actions like URL Rewrites, etc. take effect prior to sending + the request to the backend. However, if service is specified, routeAction cannot + contain any weightedBackendService s. Conversely, if routeAction specifies any + weightedBackendServices, service must not be specified. Only one of urlRedirect, + service or routeAction.weightedBackendService must be set. + * `paths` - (Required) - The list of path patterns to match. Each must start with / - and the only place a * is allowed is at the end following - a /. The string fed to the path matcher does not include - any text after the first ? or #, and those chars are not + The list of path patterns to match. Each must start with / and the only place a + * is allowed is at the end following a /. The string fed to the path matcher + does not include any text after the first ? or #, and those chars are not allowed here. -* `service` - +* `route_action` - + (Optional) + In response to a matching path, the load balancer performs advanced routing + actions like URL rewrites, header transformations, etc. prior to forwarding the + request to the selected backend. If routeAction specifies any + weightedBackendServices, service must not be set. Conversely if service is set, + routeAction cannot contain any weightedBackendServices. Only one of routeAction + or urlRedirect must be set. Structure is documented below. + +* `url_redirect` - + (Optional) + When a path pattern is matched, the request is redirected to a URL specified by + urlRedirect. If urlRedirect is specified, service or routeAction must not be + set. Structure is documented below. + + +The `route_action` block supports: + +* `cors_policy` - + (Optional) + The specification for allowing client side cross-origin requests. Please see W3C + Recommendation for Cross Origin Resource Sharing Structure is documented below. + +* `fault_injection_policy` - + (Optional) + The specification for fault injection introduced into traffic to test the + resiliency of clients to backend service failure. As part of fault injection, + when clients send requests to a backend service, delays can be introduced by + Loadbalancer on a percentage of requests before sending those request to the + backend service. Similarly requests from clients can be aborted by the + Loadbalancer for a percentage of requests. timeout and retry_policy will be + ignored by clients that are configured with a fault_injection_policy. Structure is documented below. + +* `request_mirror_policy` - + (Optional) + Specifies the policy on how requests intended for the route's backends are + shadowed to a separate mirrored backend service. Loadbalancer does not wait for + responses from the shadow service. Prior to sending traffic to the shadow + service, the host / authority header is suffixed with -shadow. Structure is documented below. + +* `retry_policy` - + (Optional) + Specifies the retry policy associated with this route. Structure is documented below. + +* `timeout` - + (Optional) + Specifies the timeout for the selected route. Timeout is computed from the time + the request is has been fully processed (i.e. end-of-stream) up until the + response has been completely processed. Timeout includes all retries. If not + specified, the default value is 15 seconds. Structure is documented below. + +* `url_rewrite` - + (Optional) + The spec to modify the URL of the request, prior to forwarding the request to + the matched service Structure is documented below. + +* `weighted_backend_services` - + (Optional) + A list of weighted backend services to send traffic to when a route match + occurs. The weights determine the fraction of traffic that flows to their + corresponding backend service. If all traffic needs to go to a single backend + service, there must be one weightedBackendService with weight set to a non 0 + number. Once a backendService is identified and before forwarding the request to + the backend service, advanced routing actions like Url rewrites and header + transformations are applied depending on additional settings specified in this + HttpRouteAction. Structure is documented below. + + +The `cors_policy` block supports: + +* `allow_credentials` - + (Optional) + In response to a preflight request, setting this to true indicates that the + actual request can include user credentials. This translates to the Access- + Control-Allow-Credentials header. Defaults to false. + +* `allow_headers` - + (Optional) + Specifies the content for the Access-Control-Allow-Headers header. + +* `allow_methods` - + (Optional) + Specifies the content for the Access-Control-Allow-Methods header. + +* `allow_origin_regexes` - + (Optional) + Specifies the regualar expression patterns that match allowed origins. For + regular expression grammar please see en.cppreference.com/w/cpp/regex/ecmascript + An origin is allowed if it matches either allow_origins or allow_origin_regex. + +* `allow_origins` - + (Optional) + Specifies the list of origins that will be allowed to do CORS requests. An + origin is allowed if it matches either allow_origins or allow_origin_regex. + +* `disabled` - + (Required) + If true, specifies the CORS policy is disabled. + +* `expose_headers` - + (Optional) + Specifies the content for the Access-Control-Expose-Headers header. + +* `max_age` - + (Optional) + Specifies how long the results of a preflight request can be cached. This + translates to the content for the Access-Control-Max-Age header. + +The `fault_injection_policy` block supports: + +* `abort` - + (Optional) + The specification for how client requests are aborted as part of fault + injection. Structure is documented below. + +* `delay` - + (Optional) + The specification for how client requests are delayed as part of fault + injection, before being sent to a backend service. Structure is documented below. + + +The `abort` block supports: + +* `http_status` - + (Required) + The HTTP status code used to abort the request. The value must be between 200 + and 599 inclusive. + +* `percentage` - + (Required) + The percentage of traffic (connections/operations/requests) which will be + aborted as part of fault injection. The value must be between 0.0 and 100.0 + inclusive. + +The `delay` block supports: + +* `fixed_delay` - + (Required) + Specifies the value of the fixed delay interval. Structure is documented below. + +* `percentage` - + (Required) + The percentage of traffic (connections/operations/requests) on which delay will + be introduced as part of fault injection. The value must be between 0.0 and + 100.0 inclusive. + + +The `fixed_delay` block supports: + +* `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. + +* `seconds` - + (Required) + Span of time at a resolution of a second. Must be from 0 to 315,576,000,000 + inclusive. + +The `request_mirror_policy` block supports: + +* `backend_service` - + (Required) + The RegionBackendService resource being mirrored to. + +The `retry_policy` block supports: + +* `num_retries` - + (Optional) + Specifies the allowed number retries. This number must be > 0. + +* `per_try_timeout` - + (Optional) + Specifies a non-zero timeout per retry attempt. Structure is documented below. + +* `retry_conditions` - + (Optional) + Specifies one or more conditions when this retry rule applies. Valid values are: + - 5xx: Loadbalancer will attempt a retry if the backend service responds with + any 5xx response code, or if the backend service does not respond at all, + example: disconnects, reset, read timeout, connection failure, and refused + streams. + - gateway-error: Similar to 5xx, but only applies to response codes + 502, 503 or 504. + - connect-failure: Loadbalancer will retry on failures + connecting to backend services, for example due to connection timeouts. + - retriable-4xx: Loadbalancer will retry for retriable 4xx response codes. + Currently the only retriable error supported is 409. + - refused-stream: Loadbalancer will retry if the backend service resets the stream with a + REFUSED_STREAM error code. This reset type indicates that it is safe to retry. + - cancelled: Loadbalancer will retry if the gRPC status code in the response + header is set to cancelled + - deadline-exceeded: Loadbalancer will retry if the + gRPC status code in the response header is set to deadline-exceeded + - resource-exhausted: Loadbalancer will retry if the gRPC status code in the response + header is set to resource-exhausted + - unavailable: Loadbalancer will retry if + the gRPC status code in the response header is set to unavailable + + +The `per_try_timeout` block supports: + +* `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. + +* `seconds` - + (Required) + Span of time at a resolution of a second. Must be from 0 to 315,576,000,000 + inclusive. + +The `timeout` block supports: + +* `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. + +* `seconds` - + (Required) + Span of time at a resolution of a second. Must be from 0 to 315,576,000,000 + inclusive. + +The `url_rewrite` block supports: + +* `host_rewrite` - + (Optional) + Prior to forwarding the request to the selected service, the request's host + header is replaced with contents of hostRewrite. The value must be between 1 and + 255 characters. + +* `path_prefix_rewrite` - + (Optional) + Prior to forwarding the request to the selected backend service, the matching + portion of the request's path is replaced by pathPrefixRewrite. The value must + be between 1 and 1024 characters. + +The `weighted_backend_services` block supports: + +* `backend_service` - + (Required) + The default RegionBackendService resource. Before + forwarding the request to backendService, the loadbalancer applies any relevant + headerActions specified as part of this backendServiceWeight. + +* `header_action` - + (Optional) + Specifies changes to request and response headers that need to take effect for + the selected backendService. headerAction specified here take effect before + headerAction in the enclosing HttpRouteRule, PathMatcher and UrlMap. Structure is documented below. + +* `weight` - + (Required) + Specifies the fraction of traffic sent to backendService, computed as weight / + (sum of all weightedBackendService weights in routeAction) . The selection of a + backend service is determined only for new traffic. Once a user's request has + been directed to a backendService, subsequent requests will be sent to the same + backendService as determined by the BackendService's session affinity policy. + The value must be between 0 and 1000 + + +The `header_action` block supports: + +* `request_headers_to_add` - + (Optional) + Headers to add to a matching request prior to forwarding the request to the + backendService. Structure is documented below. + +* `request_headers_to_remove` - + (Optional) + A list of header names for headers that need to be removed from the request + prior to forwarding the request to the backendService. + +* `response_headers_to_add` - + (Optional) + Headers to add the response prior to sending the response back to the client. Structure is documented below. + +* `response_headers_to_remove` - + (Optional) + A list of header names for headers that need to be removed from the response + prior to sending the response back to the client. + + +The `request_headers_to_add` block supports: + +* `header_name` - + (Required) + The name of the header. + +* `header_value` - + (Required) + The value of the header to add. + +* `replace` - + (Required) + If false, headerValue is appended to any values that already exist for the + header. If true, headerValue is set for the header, discarding any values that + were set for that header. + +The `response_headers_to_add` block supports: + +* `header_name` - + (Required) + The name of the header. + +* `header_value` - + (Required) + The value of the header to add. + +* `replace` - + (Required) + If false, headerValue is appended to any values that already exist for the + header. If true, headerValue is set for the header, discarding any values that + were set for that header. + +The `url_redirect` block supports: + +* `host_redirect` - + (Optional) + The host that will be used in the redirect response instead of the one that was + supplied in the request. The value must be between 1 and 255 characters. + +* `https_redirect` - + (Optional) + If set to true, the URL scheme in the redirected request is set to https. If set + to false, the URL scheme of the redirected request will remain the same as that + of the request. This must only be set for UrlMaps used in TargetHttpProxys. + Setting this true for TargetHttpsProxy is not permitted. Defaults to false. + +* `path_redirect` - + (Optional) + The path that will be used in the redirect response instead of the one that was + supplied in the request. Only one of pathRedirect or prefixRedirect must be + specified. The value must be between 1 and 1024 characters. + +* `prefix_redirect` - + (Optional) + The prefix that replaces the prefixMatch specified in the HttpRouteRuleMatch, + retaining the remaining portion of the URL before redirecting the request. + +* `redirect_response_code` - + (Optional) + The HTTP Status code to use for this RedirectAction. Supported values are: + - MOVED_PERMANENTLY_DEFAULT, which is the default value and corresponds to 301. + - FOUND, which corresponds to 302. + - SEE_OTHER which corresponds to 303. + - TEMPORARY_REDIRECT, which corresponds to 307. In this case, the request method + will be retained. + - PERMANENT_REDIRECT, which corresponds to 308. In this case, + the request method will be retained. + +* `strip_query` - (Required) - A reference to the RegionBackendService resource if this rule is - matched. + If set to true, any accompanying query portion of the original URL is removed + prior to redirecting the request. If set to false, the query portion of the + original URL is retained. The `test` block supports: diff --git a/website/docs/r/compute_url_map.html.markdown b/website/docs/r/compute_url_map.html.markdown index 04cf7ce1c2..090d574d02 100644 --- a/website/docs/r/compute_url_map.html.markdown +++ b/website/docs/r/compute_url_map.html.markdown @@ -126,7 +126,7 @@ resource "google_storage_bucket" "static" { resource "google_compute_url_map" "urlmap" { name = "urlmap" description = "a description" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link host_rule { hosts = ["mysite.com"] @@ -135,7 +135,7 @@ resource "google_compute_url_map" "urlmap" { path_matcher { name = "allpaths" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link route_rules { priority = 1 @@ -184,7 +184,7 @@ resource "google_compute_url_map" "urlmap" { } test { - service = "${google_compute_backend_service.home.self_link}" + service = google_compute_backend_service.home.self_link host = "hi.com" path = "/home" } @@ -196,7 +196,7 @@ resource "google_compute_backend_service" "home" { protocol = "HTTP" timeout_sec = 10 - health_checks = ["${google_compute_health_check.default.self_link}"] + health_checks = [google_compute_health_check.default.self_link] load_balancing_scheme = "INTERNAL_SELF_MANAGED" } @@ -219,7 +219,7 @@ resource "google_compute_health_check" "default" { resource "google_compute_url_map" "urlmap" { name = "urlmap" description = "a description" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link host_rule { hosts = ["mysite.com"] @@ -228,7 +228,7 @@ resource "google_compute_url_map" "urlmap" { path_matcher { name = "allpaths" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link route_rules { priority = 1 @@ -248,7 +248,7 @@ resource "google_compute_url_map" "urlmap" { } test { - service = "${google_compute_backend_service.home.self_link}" + service = google_compute_backend_service.home.self_link host = "hi.com" path = "/home" } @@ -260,7 +260,7 @@ resource "google_compute_backend_service" "home" { protocol = "HTTP" timeout_sec = 10 - health_checks = ["${google_compute_health_check.default.self_link}"] + health_checks = [google_compute_health_check.default.self_link] load_balancing_scheme = "INTERNAL_SELF_MANAGED" } @@ -283,7 +283,7 @@ resource "google_compute_health_check" "default" { resource "google_compute_url_map" "urlmap" { name = "urlmap" description = "a description" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link host_rule { hosts = ["mysite.com"] @@ -292,7 +292,7 @@ resource "google_compute_url_map" "urlmap" { path_matcher { name = "allpaths" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link path_rule { paths = ["/home"] @@ -321,7 +321,7 @@ resource "google_compute_url_map" "urlmap" { } } request_mirror_policy { - backend_service = "${google_compute_backend_service.home.self_link}" + backend_service = google_compute_backend_service.home.self_link } retry_policy { num_retries = 4 @@ -339,7 +339,7 @@ resource "google_compute_url_map" "urlmap" { path_prefix_rewrite = "A replacement path" } weighted_backend_services { - backend_service = "${google_compute_backend_service.home.self_link}" + backend_service = google_compute_backend_service.home.self_link weight = 400 header_action { request_headers_to_remove = ["RemoveMe"] @@ -361,7 +361,7 @@ resource "google_compute_url_map" "urlmap" { } test { - service = "${google_compute_backend_service.home.self_link}" + service = google_compute_backend_service.home.self_link host = "hi.com" path = "/home" } @@ -373,7 +373,7 @@ resource "google_compute_backend_service" "home" { protocol = "HTTP" timeout_sec = 10 - health_checks = ["${google_compute_health_check.default.self_link}"] + health_checks = [google_compute_health_check.default.self_link] load_balancing_scheme = "INTERNAL_SELF_MANAGED" } @@ -396,7 +396,7 @@ resource "google_compute_health_check" "default" { resource "google_compute_url_map" "urlmap" { name = "urlmap" description = "a description" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link host_rule { hosts = ["mysite.com"] @@ -405,7 +405,7 @@ resource "google_compute_url_map" "urlmap" { path_matcher { name = "allpaths" - default_service = "${google_compute_backend_service.home.self_link}" + default_service = google_compute_backend_service.home.self_link path_rule { paths = ["/home"] @@ -421,7 +421,7 @@ resource "google_compute_url_map" "urlmap" { disabled = false } weighted_backend_services { - backend_service = "${google_compute_backend_service.home.self_link}" + backend_service = google_compute_backend_service.home.self_link weight = 400 header_action { request_headers_to_remove = ["RemoveMe"] @@ -443,7 +443,7 @@ resource "google_compute_url_map" "urlmap" { } test { - service = "${google_compute_backend_service.home.self_link}" + service = google_compute_backend_service.home.self_link host = "hi.com" path = "/home" } @@ -455,7 +455,7 @@ resource "google_compute_backend_service" "home" { protocol = "HTTP" timeout_sec = 10 - health_checks = ["${google_compute_health_check.default.self_link}"] + health_checks = [google_compute_health_check.default.self_link] load_balancing_scheme = "INTERNAL_SELF_MANAGED" } @@ -875,7 +875,7 @@ The `retry_policy` block supports: * `retry_conditions` - (Optional) - Specfies one or more conditions when this retry rule applies. Valid values are: + Specifies one or more conditions when this retry rule applies. Valid values are: - 5xx: Loadbalancer will attempt a retry if the backend service responds with any 5xx response code, or if the backend service does not respond at all, example: disconnects, reset, read timeout, connection failure, and refused @@ -953,7 +953,7 @@ The `weighted_backend_services` block supports: headerAction in the enclosing HttpRouteRule, PathMatcher and UrlMap. Structure is documented below. * `weight` - - (Optional) + (Required) Specifies the fraction of traffic sent to backendService, computed as weight / (sum of all weightedBackendService weights in routeAction) . The selection of a backend service is determined only for new traffic. Once a user's request has