hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.46k stars 9.51k forks source link

sorted_list == sort(sorted_list) evaluates to false #35407

Closed adam-rummer-hpe closed 3 months ago

adam-rummer-hpe commented 3 months ago

Terraform Version

Terraform v1.9.0
on darwin_arm64

(also tested with 1.8.2)

Terraform Configuration Files

locals {
  a = ["a", "b", "c"]
}

output "a" {
  value = local.a
}

output "a_sorted" {
  value = sort(local.a)
}

output "sorted" {
  value = local.a == sort(local.a) // evaluates to false
}

Debug Output

https://gist.github.com/adam-rummer-hpe/fb3629195481d99879099950992f36e5

Expected Behavior

when already sorted, the list should be equal to the sorted list

Actual Behavior

they are not evaluated as being equal, despite outputting the same

e.g. a plan produces

Changes to Outputs:
  + a        = [
      + "a",
      + "b",
      + "c",
    ]
  + a_sorted = [
      + "a",
      + "b",
      + "c",
    ]
  + sorted   = false

You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

Steps to Reproduce

  1. terraform init
  2. terraform plan

Additional Context

No response

References

No response

apparentlymart commented 3 months ago

Hi @adam-rummer-hpe,

The sort function is defined as taking a list(string) and returning a list(string). Therefore when you call sort(local.a), Terraform implicitly converts this tuple([string, string, string]) value into list(string) before passing it to the function, and then the result is list(string).

That means that your output value sorted is comparing a tuple([string, string, string]) value to a list(string) value, and that will always return false because two values can be equal only if they have the same type.

I expect you can achieve the result you wanted by setting local.a to also be a list(string) value, by forcing conversion to a list type:

locals {
  a = tolist(["a", "b", "c"])
}

Once local.a is also a list(string) value, local.a == sort(local.a) should produce true as you wanted.

Please let me know if that doesn't work!

adam-rummer-hpe commented 3 months ago

Got it, thanks very much @apparentlymart :)

github-actions[bot] commented 2 months ago

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.