terraform-provider-azurerm icon indicating copy to clipboard operation
terraform-provider-azurerm copied to clipboard

[App Gateway] URL Rewrites don't support undefined values

Open dhensby opened this issue 4 years ago • 7 comments

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform (and AzureRM Provider) Version

= 2.54.0

Affected Resource(s)

  • azurerm_application_gateway

Terraform Configuration Files

  rewrite_rule_set {
    name = "test-rewrite-ruleset"

    rewrite_rule {
      name          = "test-rewrite-rule"
      rule_sequence = 1

      condition {
        variable = "var_uri_path"
        pattern  = ".*article/(.*)/(.*)"
      }

      url {
      }
    }
  }

This configuration, which should cause an error, does not because the url.path and url.query_string values become "" (empty strings) instead of nil. Empty strings are valid values but should not be the value when nothing is declared. As such, this causes a mis-configuration of the re-write as the path and query strings are removed rather than retained.

Debug Output

Panic Output

Expected Behaviour

Undefined properties should not be passed to the underlying API as empty strings

Actual Behaviour

Undefined properties are passed to the underlying API as empty strings

Steps to Reproduce

  1. terraform apply

Important Factoids

References

  • #10950

cc-ing previously involved participants: @jackofallops, @katbyte, @ido-tr

dhensby avatar May 03 '21 09:05 dhensby

Since the url block has a property reroute which has a default value, which causes the empty url block defined in config ends up to be a map with all the keys at least has its zero value if absent. This means the nil checks below actually are always true:

https://github.com/terraform-providers/terraform-provider-azurerm/blob/79b76b6588198e0087a44ee652371580bc305919/azurerm/internal/services/network/application_gateway_resource.go#L2982-L2993

I'm wondering whether the empty string makes sense under this scenario, or can we simply not construct it in the api request if it is an empty string (as Portal can also not set an empty string) ?

magodo avatar May 10 '21 03:05 magodo

Empty strings are valid / sensible values for a rewrite path and string, so we can't really ignore them, but "undefined" reroutes are allowed (the backend assumes false) so we may be able to fix this by removing the default value for reroute, then?


Edit: Though thinking about it, it seems that even with an empty block (url { }) in TF config we'd see empty strings for und-declared values, which is not what we want. The API docs for this show that the values should essentially be string|null for the values.

dhensby avatar May 10 '21 06:05 dhensby

FWIK, there is no way in current Terraform plugin SDK to differ the zero value/absent for a nested property inside a block. One trick have ever been used is to use a insensible value of that type to indicate the absence, e.g. using -1 to indicate absence for a property whose sensible range starts from 0. However, back to your use case, it is a string. Maybe, we shall modify the schema a bit so as to express the absence of the path/query_string, e.g.

query_string {
  value = ""
}

magodo avatar May 10 '21 07:05 magodo

I found a workaround for this issue till it will be resolved. You can add query_string = "{var_query_string}" under the URL section For example:

url {
   path = foo
   query_string = "{var_query_string}"
  }

ido-re avatar May 11 '21 06:05 ido-re

I was trying to track this bug down this weekend and didn't find the existing report until now—the workaround suggested above is the only way I can come up with to generate non-breaking URL rewrite rules. In case the root cause of this is unclear to anybody looking at it, I did get the following from the debug logs:

2021-05-24T14:32:25.369-0400 [WARN]  Provider "registry.terraform.io/hashicorp/azurerm" produced an invalid plan for module.app_gateway.azurerm_application_gateway.load_balancer, but we are tolerating it because it is using the legacy plugin SDK.
    The following problems may be the cause of any confusing errors from downstream operations:
      - .zones: planned value cty.ListValEmpty(cty.String) for a non-computed attribute
      - .enable_http2: planned value cty.False for a non-computed attribute
      - .rewrite_rule_set[0].rewrite_rule[0].url[0].query_string: planned value cty.StringVal("") for a non-computed attribute
      - .rewrite_rule_set[0].rewrite_rule[2].condition[0].negate: planned value cty.False for a non-computed attribute
      - .rewrite_rule_set[0].rewrite_rule[2].url[0].query_string: planned value cty.StringVal("") for a non-computed attribute

(output truncated, but there were quite a few others in my specific configuration.)

The bit that is related to the configuration breakage is .rewrite_rule_set[0].rewrite_rule[2].url[0].query_string: planned value cty.StringVal("") for a non-computed attribute, but the part about "using the legacy plugin SDK" seems like the actual root cause?

benwarfield-usds avatar May 24 '21 19:05 benwarfield-usds

I just submitted a PR which can circumvents the limitations we currently have by using a components option, similar to the UI:

...
   rewrite_rule_set {
     name = "${local.rewrite_rule_set_name}_1"
     rewrite_rule {
       name          = "${local.rewrite_rule_name}_1"
       rule_sequence = 1
       condition {
         variable = "var_uri_path"
         pattern  = ".*article/(.*)/(.*)"
       }
       url {
         path       = "/article.aspx"
         components = "path_only"
       }
     }
     rewrite_rule {
       name          = "${local.rewrite_rule_name}_2"
       rule_sequence = 2
       condition {
         variable = "var_uri_path"
         pattern  = ".*article2/(.*)/(.*)"
       }
       url {
         query_string = "id={var_uri_path_1}&title={var_uri_path_2}"
         components   = "query_string_only"
       }
     }
   }
...

Happy to hear your thoughts about it!

aristosvo avatar Oct 26 '21 10:10 aristosvo

This functionality has been released in v3.4.0 of the Terraform Provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template. Thank you!

github-actions[bot] avatar Apr 22 '22 00:04 github-actions[bot]

This functionality has been released in v3.19.0 of the Terraform Provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template. Thank you!

github-actions[bot] avatar Aug 23 '22 15:08 github-actions[bot]

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

github-actions[bot] avatar Sep 23 '22 02:09 github-actions[bot]