-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conditional operator doesn't short-circuit evaluation based on result #50
Comments
Not complaining, just noting that it is more than cpu cycles. For example, my module was intended to have var.accounts optional. group = "${lookup(var.accounts, "unset", "") != ""
? element(aws_iam_group.default.*.id, count.index)
: aws_iam_group.default.id}" aws_iam_group.default does not exist when var.accounts is set. |
Completely breaks patterns such as:
or
Which is not so great because it means there's literally no way as far as I know to support generating OR importing a certificate. Except if you always create the CA resource, use heredocs to specify the existing PEM-Encoded CA cert in tfvars then use either. Hacks all over the place. Is there a timeline for that one? It's quite incapacitating. |
* don't condition the creation of the VPC resource (hashicorp/hil#50) * pass external subnet IDs into the VPC module
* don't condition the creation of the VPC resource (hashicorp/hil#50) * pass external subnet IDs into the VPC module
* don't condition the creation of the VPC resource (hashicorp/hil#50) * pass external subnet IDs into the VPC module
* don't condition the creation of the VPC resource (hashicorp/hil#50) * pass external subnet IDs into the VPC module
Actually, here is a wacky workaround for the second use-case:
|
Fixes for BYO VPC: * pass external subnet IDs into the VPC module * diabolical use of join() to circumvent conditional operator limitation on missing resources (hashicorp/hil#50)
* modules/bootkube: fix error when a CA cert/key is provided * modules/bootkube: add missing wiring for provided CA cert in templating Due to hashicorp/hil#50 the `join()` interpolation function is used to work around it.
Just to add a scenario that I've just attempted that's hit this issue: # CloudInit config
data "template_cloudinit_config" "instance_userdata" {
count = "${length(var.userdata_template) > 0 ? var.count * length(split(",", lookup(var.common, "azs"))): 0}"
/* count = "${var.count * length(split(",", lookup(var.common, "azs")))}" */
part {
content_type = "text/cloud-config"
content = "${element(data.template_file.instance_userdata.*.rendered, count.index)}"
}
}
# Create required instance(s)
resource "openstack_compute_instance_v2" "instance" {
count = "${var.count * length(split(",", lookup(var.common, "azs")))}"
... snipped for brevity...
user_data = "${length(var.userdata_template) > 0 ? element(data.template_cloudinit_config.instance_userdata.*.rendered, count.index) : ""}"
... snip ...
} You can see my commented However the above code fails with:
|
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
- Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: coreos@7ab31b0)
* platforms/azure: add missing master_count to the tectonic module * modules/azure: Enable the use of external master & worker subnets - Only create master & worker subnets if no external vnets exist - The `join()` interpolation function is used to work around hashicorp/hil#50 when the subnets are conditionally created. For more detail, see: 7ab31b0)
Looks like #53 addresses this? |
This allows to have multiple CloudFront distributions pointing to the same S3 bucket, such as to different paths. Note, due to the way the conditional parser works in current version of Terraform we're using the workaround using join() and the .*. operator, see hashicorp/hil#50
* allow not creating/managing the S3 bucket This allows to have multiple CloudFront distributions pointing to the same S3 bucket, such as to different paths. Note, due to the way the conditional parser works in current version of Terraform we're using the workaround using join() and the .*. operator, see hashicorp/hil#50 * update readme * improve handling CloudFront origin access identity This allows to still create the CloudFront origin access identity even if not creating the S3 bucket, and will output the iam_arn of the newly created CloudFront origin access identity. Addresses issue #7.
We hit this problem with this evaluation, name_prefix = "${length(var.customer_name) < 5 ? "${var.customer_name}-" : "${substr(var.customer_name, 0, 5)}-"}" substr: 'offset + length' cannot be larger than the length of the string |
This change sets the `ports` list to [""] when `backend_params` is empty. Ideally this would be done with an expression like: ``` "${length(var.backend_params) == 0 ? "" : element(split(",", element(var.backend_params, count.index)), 2)}" ``` But because of a limitation with HCL, it cannot be done and we've resorted to the trick described in this issue: hashicorp/hil#50 (comment) The pipe `|` delimiter is used because it is not valid to use in GCP names. Contributed according to the Google CLA.
This change sets the `ports` list to [""] when `backend_params` is empty. Ideally this would be done with an expression like: ``` "${length(var.backend_params) == 0 ? "" : element(split(",", element(var.backend_params, count.index)), 2)}" ``` But because of a limitation with HCL, it cannot be done and we've resorted to the trick described in this issue: hashicorp/hil#50 (comment) The pipe `|` delimiter is used because it is not valid to use in GCP names. Contributed according to the Google CLA.
@apparentlymart: Your problem can be solved without conditional logic:
This returns the first element of the list More complex cases, such as @ooesili 's case can be solved using this basic pattern. His example:
And the solution:
With this approach, the last element of the list is an empty string. We use These solutions are entirely declarative. Arguably, they are more correct than using conditional logic. |
Thanks for sharing all the workarounds! Please note that this is an issue about HIL itself rather than about Terraform, so (for the benefit of other readers) many of these solutions are Terraform-specific and wouldn't apply to other users of HIL unless they were to replicate some of Terraform's functions. However, it is unlikely that this issue will ever be addressed in this codebase because Terraform is moving away from separate HIL to the new version of HCL that has HIL-like functionality integrated into it, and has a fully-functional conditional operator. That is coming in the next major version of Terraform and this particular change has its own article. If you'd like to get updates on this being fixed in the context of Terraform, I suggest instead tracking hashicorp/terraform#15605. If anyone monitoring this is the maintainer of another caller of the HIL library, I would suggest to investigate the new version of HCL, whose template syntax is the spiritual successor of HIL and includes the fully-featured conditional operator and a number of other enhancements. |
Totally understood. My suggestions aren't intended to close the ticket, but instead to help anyone who runs into this particular problem. 👍 |
is this fixed with TF12? |
Yes @MalloZup. Check hashicorp/terraform#15605. |
No, this still wont work :-(
|
Can confirm this is fixed
@Ranger-X it complains about the resource not being defined, that's a name binding issue not an evaluation issue. In most programming languages you cannot do |
You can do that both in javascript and ruby, so it's not that unreasonable expectation. |
Hi all, As I noted in my previous comment, Terraform no longer uses HIL as of Terraform 0.12, so this is not the right place to discuss Terraform's behaviors. If you have feedback about the behavior of the Terraform language I'd suggest opening an issue in the Terraform repository and then the Terraform team can route bug reports and enhancement requests upstream to Terraform's dependencies as appropriate. I also noted before that this issue is unlikely to be fixed in HIL, because HIL has been superseded by the second-generation implementation of HCL now incorporating a HIL-like expression language. HIL's featureset is therefore frozen and there are no plans to change its behavior except for minor maintenance in support of any remaining applications that are still calling into it. For that reason, I'm going to close this issue as a "wont fix". If you are the maintainer of an application that is using HIL and would like conditional evaluation to behave as this issue describes, your likely path forward would be to transition to using the template language in HCL 2. |
To avoid extensive refactoring of the evaluator while implementing the conditional syntax, we accepted the limitation that it would evaluate both "sides" and then discard the inappropriate one when given syntax like this:
This is in most cases just a small waste of compute to evaluate a result that will never be used, but it's troublesome in cases where one of the expressions can be evaluated without error only if its associated condition state is true. For example:
This doesn't work as intended because we fail on trying to index into the empty list
foo
in spite of the conditional.The correct behavior is for the evaluator to evaluate the boolean expression first and then visit only one of the given expressions.
The text was updated successfully, but these errors were encountered: