Using for/maps in outputs

I have the following in terraform v12 which works:

main.tf

locals {
  fileserver_modules = {
    fs_001 = module.fs_001
    fs_002 = module.fs_002
}

module "fs_001" {
  source       = "./fileserver"
  uid          = "team_001"
}
module "fs_002" {
  source       = "./fileserver"
  uid          = "team_002"
}

output "map_uid_dns__fileserver" {
  # <instance_uid> = [ipv4_1,ipv4_2...]
  value = {
    for storage_module in local.fileserver_modules :
    storage_module.uid => storage_module.private_ip
  }
}

and in my “fileserver” directory I have:

resource "aws_network_interface" "eni" {
  subnet_id       = data.aws_subnet.this.id
  security_groups = local.vpc_security_group_ids
}

output "private_ip" {
  value = aws_network_interface.eni.private_ip
}
output "uid" {
  value = var.uid
}

This all works, and the output “map_uid_dns__fileserver” outputs a map correctly:

map_uid_dns__fileserver = {
  "team001" = "1.2.3.4"
  "team002" = "4.2.3.4"
}

I’m upgrading to terraform v13 and will be making use of the new “count” attribute for modules. Now I want to deploy fs_001 and fs_002 in my Prod environment, but only fs_001 in Preprod.

In my main.tf, if I change to the following:

locals {
  fileserver_modules = {
	prod = {
	  fs_001 = module.fs_001
	  fs_002 = module.fs_002
	}
	preprod = {
	  fs_001 = module.fs_001
	}
  }
}

output "map_uid_dns__fileserver" {
  # <instance_uid> = [ipv4_1,ipv4_2...]
  value = {
    for storage_module in local.fileserver_modules[var.stack_env] :
    storage_module.uid => storage_module.private_ip
  }
}

where “var.stack_env” evaluates to either “preprod” or “prod”, I get the following error in the terraform plan:

Error: Unsupported attribute

  on main.tf line 1012, in output "map_uid_dns__fileserver":
1012:     storage_module.uid => storage_module.private_ip

This value does not have any attributes.

If I run for Prod, I get this error twice (2 modules) and if I run for PreProd then I get it once (1 module).

I’ve tried simplifying by doing the following:

locals {
  map_uid_dns__fileserver = local.fileserver_modules[var.stack_env]
}
output "map_uid_dns__fileserver" {
  # <instance_uid> = [ipv4_1,ipv4_2...]
  value = {
    for storage_module in local.map_uid_dns__fileserver :
    storage_module.uid => storage_module.private_ip
  }
}

but I get the same error, so I’m guessing that I can use “for storage_module in local.fileserver_modules[var.stack_env] :” (i.e. I can index into the ‘fileserver_modules’ map) but something is still not valid.

How do I successfully get a working output?

I got this working by changing from this (terraform v12):

output "map_uid_dns__fileserver" {
  # <instance_uid> = [ipv4_1,ipv4_2...]
  value = {
    for storage_module in local.fileserver_modules[var.stack_env] :
    storage_module.uid => storage_module.private_ip
  }
}

to this (terraform v13):

output "map_uid_dns__fileserver" {
  # <instance_uid> = [ipv4_1,ipv4_2...]
  value = {
    for storage_module in local.fileserver_modules[var.stack_env] :
    storage_module[0].uid => storage_module[0].private_ip
  }
}

I found the difference after outputting local.fileserver_modules[var.stack_env] and finding that it was outputting a list of map instead of just map:

Changes to Outputs:
  + stuff = {
      + fs_001 = [
          + {
              + instance_id = (known after apply)
              + private_ip  = (known after apply)
              + uid         = "team001"
            },
        ]
      + fs_002 = [
          + {
              + instance_id = (known after apply)
              + private_ip  = (known after apply)
              + uid         = "team002"
            },
        ]
    }

Another formalising/tidying of the syntax/outputs between v12 & 13?