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.72k stars 9.55k forks source link

empty list comparison does not work if the list contains an object #23562

Open shanmugakarna opened 4 years ago

shanmugakarna commented 4 years ago

Terraform Version

Terraform v0.12.17

Terraform Configuration Files

Thanks @dpiddockcmp for a simpler example. https://github.com/hashicorp/terraform/issues/23562#issuecomment-562669467

variable "object" {
  type    = list(object({ a = string }))
  default = [] 
}

output "equal" {
  value = var.object == [] ? "empty" : "not empty"
} 

output "not_equal" {
  value = var.object != [] ? "not empty" : "empty"
}

Expected Behavior

Outputs:
equal = empty
not_equal = empty

Actual Behavior

Outputs:
equal = not empty
not_equal = not empty

Steps to Reproduce

terraform init
terraform apply -auto-approve

Solution

variable "object" {
  type    = list(object({ a = string }))
  default = []
}

output "equal" {
  value = length(var.object) == 0 ? "empty" : "not empty"
}

output "not_equal" {
  value = length(var.object) != 0 ? "not empty" : "empty"
}

References

https://github.com/terraform-aws-modules/terraform-aws-eks/pull/606#issuecomment-561795104

dpiddockcmp commented 4 years ago

Hi, this is more generic that the reporter implies. Empty list comparison does not work if the list contains an object:

variable "object" {
  type    = list(object({ a = string }))
  default = [] 
}

output "equal" {
  value = var.object == [] ? "empty" : "not empty"
} 

output "not_equal" {
  value = var.object != [] ? "not empty" : "empty"
}
Outputs:
equal = not empty
not_equal = not empty
shanmugakarna commented 4 years ago

ok, i was testing only yamlencode, let me change the title. Updating my example with @dpiddockcmp as the his generic example is simple and clear

jbardin commented 4 years ago

Hi @shanmugakarna,

Thanks for filing the issue. The comparison here is failing because the equality operator first compares types.

The type of var.object here (using the internal representation) is cty.List(cty.Object(map[string]cty.Type{"a":cty.String})), while the [] literal is of type cty.EmptyTuple, which do not compare as equal.

The preferred way to check for an empty set or series of any type would be to check its length, rather than compare it against a literal value

value = length(var.object) == 0 ? "empty" : "not empty"

There are however some cases where comparison against a literal value may be quite useful. In these cases we will need to decide on and implement a limited set of automatic type conversion rules for comparing equality.

Related: #21978

shanmugakarna commented 4 years ago

Hi @jbardin

Thank you. I already have the length solution as part of the issue description. So, if this behaviour is expected, then we can close the issue.

pieterza commented 3 years ago

List comparisons are broken regardless of it being type object or not, see: https://github.com/hashicorp/terraform/issues/29187

md5 commented 2 years ago

@jbardin would it make sense to update the title of this issue since it is broader than the title implies? The title of https://github.com/hashicorp/terraform/issues/29187 seems to describe the problem better.