module.fs_abc has outputs which are string variables, including “uid” and “instance_id”, so creating the “storage_map_uid_instanceid” output is simple and it works, to create me a map which looks like:
My “storage_modules” use a module that calls 2 instances of the fileserver_module. It has outputs which are maps, in the same form (i.e. the top-level local.storage_modules[“st_abc”].storage_map_uid_instanceid contains a map looking exactly like the example immediately above, but with different values for uid and instance_id).
I’m trying to create a single output which contains all the uid/instance_id key/value pairs at the top level. This would change my original storage_map_uid_instanceid output at the top of this post to look something like the following:
output "storage_map_uid_instanceid" {
# <uid> = <instance_id>
value = merge(
{
for storage_module in local.fileserver_modules :
storage_module.uid => storage_module.instance_id
},
{
for storage_module, v in local.storage_modules :
for keys, values in v.storage_map_uid_instanceid :
keys => values
}
)
}
But this doesn’t work.
Can I use a nested for loop in an Ouput value like this? I essentially want to say, “merge the fileserver_modules child map values (uids => instance_ids) with the storage_modules.storage_map_uid_instanceid child map values (uids => instance_ids)”. I’m not sure I have my syntax correct in my output.
Ideally I would also like to structure my locals so that I have something like the following, because I have other outputs on the “module.st_abc” that I need to output at the higher level in a similar way:
I think I understand what you’re trying to do here! There are a couple of language features that should help.
First of all, it looks like you only care about the values of local.storage_modules for building this output, and the keys are irrelevant. The values function helps with this, as it takes a map and returns a list of its values, ignoring the keys.
Secondly, you want to call merge with each of those values. A for expression won’t work here, as it must result in a tuple or an object (depending on the [] or {} brackets used). Instead, you can use the ... function argument expansion operator to convert the list from values into a series of arguments.
Here’s a working example that I think does what you want (if I’ve understood the structure of your module outputs properly):
As an aside, a request for future: if possible, please try to provide a complete but isolated configuration. It makes it much easier to experiment if I can just copy & paste a single Terraform file, instead of trying to figure out module outputs or other dependencies. Thanks!
Hi @alisdair - thanks for this, yes I think that would do it! It is just the values I care about, so the Outputs you got is correct.
Apologies if the question was verbose, sometimes it’s difficult to condense it all down. I will definitely try to keep it more simple in the future.
Unfortunately I found an issue. If you use a “merge” like this, you run into this “feature” of terraform:
So whilst your solution logically is correct, and is the exact code I was trying to write myself, terraform thinks it can’t determine all the resources for the for_each which these outputs are being constructed for as inputs - even if all the keys inside the merges are static and known at plan time.
I might still be able to use your “values” code for my submodule outputs, and that will keep it tidier. I did manage to solve this myself yesterday, by duplicating all the outputs of my submodule - it simplified it but is far less elegant - so I will try using “values” instead with my original code and see if that gives me the result I need.