Accessing local variables by name in a for construct

One section of my config gathers a bunch of local variables in a module and puts them in a mapping, so that they can all be dumped to Parameter Store. At first thought I’ve tried to do:

locals {
    store_keys = ["aws_region", "ami", "sqs_arn", "vpc_id", "scheduler_subnet", "compute_subnets", "security_group", "ec2_access_key", "efs_dns_name", "efs_mount_ip"]
    store_params = { for attr in local.store_keys : attr => local[attr] }

However this did not pass validation, Terraform basically complained that local cannot be accessed like a map. In the end I’ve resorted to doing:

locals {
  store_params = {
    aws_region       = local.aws_region
    sqs_arn          = local.sqs_arn
    ami              = local.ami
    vpc_id           = local.vpc_id
    scheduler_subnet = local.scheduler_subnet
    compute_subnets  = local.compute_subnets
    security_group   = local.security_group
    ec2_access_key   = local.ec2_access_key
    efs_dns_name     = local.efs_dns_name
    efs_mount_ip     = local.efs_mount_ip

This works, but I’m thinking that surely there must be a better way to gather a large number of local variables? Is there something obvious that I’m missing?

For what it’s worth, I find the second version much more readable and understandable. Thinking about the people who need to read this code in the future, including you in a month or two, you may find this version preferable as well :slight_smile:

1 Like

Indeed, this is the best way to write it if indeed you do need them both as individual local values and in the map, because Terraform uses those references to understand that local.store_params depends on each of those other local values. As @kpfleming noted, it could also allow future readers to more easily understand what’s going on, but of course that’s subjective. The Terraform language design generally optimizes for the future reader over the initial author when their needs are in conflict, on the assumption that most configurations will be written once but read many times.

One way to simplify this further would be to remove the separate local values altogether and just put them literally inside the map:

locals {
  store_params = {
    aws_region = "us-west-2"
    sqs_arn    = "aws:arn:etc,etc"
    ami        = "ami-abc123"

Then elsewhere in the configuration you could say local.store_params.aws_region instead of just local.aws_region. Whether it’s more important to have a smaller locals block or to have more direct references to the values inside is a design tradeoff; I’d personally do this only if those values are here only to be used as “store params”, and not as part of anything else.

Thanks a lot for the response guys. It’s nice to gain some insight into the design ethos of the config language.