Terraform: Terraform - Variable inside Variable

Created on 26 Oct 2018  ·  5Comments  ·  Source: hashicorp/terraform

Environment

Terraform Version: 0.11.8
OS: Mac OS 10.14 (18A391)

Code

variable "functions" {
  type    = "list"
  default = ["function0", "function1"]
}

variable "function0_vars" {
  type = "map"

  default = {
    "URL" = "https://google.com"
    "ONE" = "TWO"
  }
}

variable "function1_vars" {
  type = "map"

  default = {
    "URL"   = "https://yahoo.com"
    "THREE" = "FOUR"
  }
}

resource "aws_lambda_function" "test" {
  count         = "${length(var.functions)}"
  function_name = "${element(var.functions, count.index)}"
  handler       = "some_handler"
  runtime       = "python2.7"
  role          = "some_role"

  environment = {
    # works
    variables = "${var.function0_vars}"

    # does not works
    variables = "${var.${element(var.functions, count.index)}_vars}"
  }
}

Problem

I am trying to use a variable inside a variable in aws_lambda_function but this problem is generic I think.

I know what I am trying to achieve can be done through locals (#17229) but unfortunately, you cannot use count in locals.

The code I have posted here is just a _short_ version of what I actually have. I have a long list of lambda functions, which I want to iterate over.

question waiting-response

Most helpful comment

I know what I am trying to achieve can be done through locals (#17229) but unfortunately, you cannot use count in locals.

I was initially attempting to accomplish a similar goal to yours, and ran into the same problems. What worked for me was simplifying the data structure altogether. Try this:

locals {
  function_vars = [
    {
      name = "function_1"
      foo = "tree"
      baz = "plant"
    },
    {
      name = "function_2"
      foo = "apple"
      baz = "orange"
    },
  ]
}

resource "aws_lambda_function" "test" {
  function_name = "${lookup(local.function_vars[count.index], "name")}"
  handler       = "some_handler"
  runtime       = "python2.7"
  role          = "some_role"

  environment = {
    variables = "${local.function_vars[count.index]}"
  }

count = "${length(local.function_vars)}"
}

If these values need to be configurable by the parent sourcing this, then simply use variables for initializing the values:


variable "func1" {
  type = "map"
  default = {
    name = "function_1"
    foo = "tree"
    baz = "plant"
  }
}

variable "func2" {
  type = "map"
  default = {
    name = "function_2"
    foo = "apple"
    baz = "orange"
  }
}

locals {
  function_vars = [
    "${var.func1}",
    "${var.func2}",
  ]
}

The key here is that the item you're iterating over is locals.function_vars,

All 5 comments

How about creating a two-level map?

variable "function_vars" {
  type = "map"

  default = {
    "function0" = {
      "URL" = "https://google.com"
      "ONE" = "TWO"
    },
    "function1" = {
      "URL"   = "https://yahoo.com"
      "THREE" = "FOUR"
    }
  }
}

And then index that:

variables = "${lookup(var.function_vars, element(var.functions, count.index))}"

Does that solve your problem?

hey @jeremywadsack ,

Thanks for your response. I did try that earlier but got this error.

  ~/vikas  terraform plan

Error: aws_lambda_function.test: 2 error(s) occurred:

* aws_lambda_function.test[1]: lookup: lookup() may only be used with flat maps, this map contains elements of type map in:

${lookup(var.function_vars, element(var.functions, count.index))}
* aws_lambda_function.test[0]: lookup: lookup() may only be used with flat maps, this map contains elements of type map in:

${lookup(var.function_vars, element(var.functions, count.index))}
  ~/vikas 

I know what I am trying to achieve can be done through locals (#17229) but unfortunately, you cannot use count in locals.

I was initially attempting to accomplish a similar goal to yours, and ran into the same problems. What worked for me was simplifying the data structure altogether. Try this:

locals {
  function_vars = [
    {
      name = "function_1"
      foo = "tree"
      baz = "plant"
    },
    {
      name = "function_2"
      foo = "apple"
      baz = "orange"
    },
  ]
}

resource "aws_lambda_function" "test" {
  function_name = "${lookup(local.function_vars[count.index], "name")}"
  handler       = "some_handler"
  runtime       = "python2.7"
  role          = "some_role"

  environment = {
    variables = "${local.function_vars[count.index]}"
  }

count = "${length(local.function_vars)}"
}

If these values need to be configurable by the parent sourcing this, then simply use variables for initializing the values:


variable "func1" {
  type = "map"
  default = {
    name = "function_1"
    foo = "tree"
    baz = "plant"
  }
}

variable "func2" {
  type = "map"
  default = {
    name = "function_2"
    foo = "apple"
    baz = "orange"
  }
}

locals {
  function_vars = [
    "${var.func1}",
    "${var.func2}",
  ]
}

The key here is that the item you're iterating over is locals.function_vars,

Thanks much @sudoforge !!! That worked perfectly.

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.

Was this page helpful?
0 / 5 - 0 ratings