Create Lambda environment variables from list of object

Hey guys,

could you help me with the following problem? I have a list(objects) and would like to hand over some variables within AWS lambda as environment variables.

variable "accounts" {
  type = list(object({
    name   = string # Name of the AWS account
    number = string # Number of the AWS account
    blabla = string
  }))
}

The lambda code is like this:

module "lambda" {
  source  = "terraform-aws-modules/lambda/aws"
  version = "4.18.0"
  function_name = "test"
  handler       = "lambda_function.lambda_handler"
  runtime       = "python3.8"
  source_path   = ".lambda_function.py"
  environment_variables = {
    "foo" = "bar"
  }
}

How could I transform the list into key-value pairs? I tried something like this but did not succeed:

locals {
  key_value_tuples = {
    for obj in var.accounts :
    obj.name => obj.number
  }
}

And in Lambda

  environment_variables = {
    "foo" = "bar",
    for obj in local.key_value_tuples :
    obj.key => obj.value
  }

which resulted in the following:

│ Error: Unsupported attribute
│
│   on test.tf line 97, in module "lambda":
│   97:     obj.key => obj.value
│
│ Cant access attributes on a primitive-typed value (string).

Thanks in advance! :slight_smile:

Hi @FuriouZ07,

It seems like your local.key_value_tuples has a shape like this:

{
  "foo" = "1"
  "bar" = "2"
}

(You specified number as having type string rather than number in your variable "accounts" block, which is a little confusing but I’ve honored that in the example above.)

If you use { for obj in local.key_value_tuples : ... } with this value then obj will contain just the values from the map, so it would take on the following values in sequence:

  • "2"
  • "1"

That means that when you access obj.key and obj.value you are trying to access attributes on those strings, and thus Terraform returns this error.

I’m guessing from the context that your intent is to use the keys and values separately, in which case you can use the form of for expression with two variable declarations like this:

  environment_variables = {
    "foo" = "bar",
    for key, value in local.key_value_tuples :
    key => value
  }

When you use two variable declarations after for they get set to the key and value of each element in turn, and so both of those will be strings in your case, following the following sequence:

  • key = "bar", value = "2"
  • key = "foo", value = "1"

However, in this particular case the expression is a bit useless: it’s just projecting the key and value pairs directly to the same key and value pairs. In other words, local.environment_variables would always have the same keys and values as local.key_value_tuples.

If I’m guessing correctly what your ultimate goal is, I think the merge function might help: it can merge multiple mappings together into a single mapping.

  environment_variables = tomap(merge(
    {
      "foo" = "bar"
    },
    local.key_value_tuples,
  ))

Since I used foo as one of the keys in my example local.key_value_tuples value, note that due to the rules of merge the one from local.key_value_tuples would override the one in the first argument to merge and therefore be effectively ignored. But if your local.key_value_tuples doesn’t include a foo key then you should see the two maps get merged together so that the final result contains all of the key/value pairs from both.