Skip to content
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

Weird behavior when using the lookup function in terraform 0.12.x #22267

Closed
manniche opened this issue Jul 31, 2019 · 3 comments · Fixed by #22269
Closed

Weird behavior when using the lookup function in terraform 0.12.x #22267

manniche opened this issue Jul 31, 2019 · 3 comments · Fixed by #22269

Comments

@manniche
Copy link

Description of the issue

I am trying to use the lookup function with a variable, which fails. At the same time, using the function on a local with similar characteristics succeeds. The error message given seems to imply different semantics than what is described in the documentation

Terraform version

0.12.2 and 0.12.5

Minimal example

Files to reproduce the issue

terraform.tfvars:

test_elem1 = {
  "instance-01" = {
    name = "foo"
  }
}

main.tf

variable "test_elem1" {
  type = "map"
}
locals {
  test_elem1 = var.test_elem1
  test_elem2 = {"instance-01" = {"name" = "bar"}}
}

Commands to reproduce the issue

sme@ada: ~/tmp/terraform_lookup_bug > terraform_0_12_2 init

Initializing the backend...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
sme@ada: ~/tmp/terraform_lookup_bug > terraform_0_12_2 console
> local.test_elem1
{
  "instance-01" = {
    "name" = "foo"
  }
}
> local.test_elem2
{
  "instance-01" = {
    "name" = "bar"
  }
}
> lookup(local.test_elem1, "instance-01")

>  
Error: Error in function call

  on <console-input> line 1:
  (source code not available)
    |----------------
    | local.test_elem1 is map of object with 1 element

Call to function "lookup" failed: lookup() can only be used with flat lists.

> lookup(local.test_elem2, "instance-01")
{
  "name" = "bar"
}
>  

Expected output

I was expecting the lookup on the variable to behave in the same way as the lookup on the local.

As an aside (and as mentioned in the top of this issue), I am puzzled by the error message coming from terraform: lookup() can only be used with flat lists., which to me differs in explanation to that of the documentation:

lookup retrieves the value of a single element from a map, given its key

@teamterraform
Copy link
Contributor

Hi @manniche ! Thank you for reporting this unexpected behavior and inconsistent documentation.

Under the hood, local.test_elem2 is an object and var.test_elem1 is a map of type object. That is what's triggering the different responses from lookup() - I'm including links to the relevant code blocks below.

As a workaround, you can declare your variable an object (this might not be useful depending on what your "real" configuration looks like):

variable "test_elem1" {
  type = object({
    instance-01 = map(string)
  })
}

Here's the relevant code, under the hood.
Argument is an object:

if mapVar.Type().IsObjectType() {
if mapVar.Type().HasAttribute(lookupKey) {
return mapVar.GetAttr(lookupKey), nil
}

Argument is a Map of type object which triggers the default case:

if ty := v.Type(); !ty.Equals(cty.NilType) {
switch {
case ty.Equals(cty.String):
return cty.StringVal(v.AsString()), nil
case ty.Equals(cty.Number):
return cty.NumberVal(v.AsBigFloat()), nil
case ty.Equals(cty.Bool):
return cty.BoolVal(v.True()), nil
default:
return cty.NilVal, errors.New("lookup() can only be used with maps of primitive types")
}

@manniche
Copy link
Author

manniche commented Aug 1, 2019

As a workaround until the fix lands in a version, I do this in my locals:

  test_elem1_object = {for k, v in var.test_elem1: k => v}

and now the result in the terraform console is:

> lookup(local.test_elem1_object, "instance-01")
{
  "name" = "foo"
}

thanks for the quick reply, clarification and not least the PR!

@ghost
Copy link

ghost commented Sep 1, 2019

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.

@ghost ghost locked and limited conversation to collaborators Sep 1, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants