I'm working with AWS VPCs and I created a module for each region to set up a VPC. In the variables to the module I define a mapping of subnet addresses to availability zones, like so
variable "subnet_addresses" {
default {
a = "10.0.0.0/20"
b = "10.0.16.0/20"
d = "10.0.48.0/20"
e = "10.0.64.0/20"
}
}
I then go ahead and reference this mapping, no problem, to set up the VPC. However, if I try to override this mapping in a file referencing this, I get an error, saying a value in the mapping is not set. Here is an example (a full example is on this gist)
variable "vpc_subnet_addresses" {
default = {
a = "10.255.0.0/20"
b = "10.255.16.0/20"
d = "10.255.48.0/20"
e = "10.255.64.0/20"
}
}
module "new_vpc" {
source = "my_vpc_module"
subnet_addresses = "${var.vpc_subnet_addresses}"
}
The error I get is
Error running plan: lookup: lookup in 'vpc_subnet_addresses' failed to find 'e' in:
${lookup(var.subnet_addresses, "e")}
Maybe I'm missing something, I'm just not sure what
Same problem here, trying to use the consul module, which only has ami:s defined for us regions. I'm providing an overide mapping like this
variable "consul_ami" {
default = {
eu-west-1 = "ami-62a10115"
}
}
module "consul" {
source = "github.com/hashicorp/consul/terraform/aws"
key_name = "${var.consul_key_name}"
key_path = "${var.consul_key_path}"
region = "${var.region}" /* this is "eu-west-1" */
ami = "${var.consul_ami}"
servers = "3"
}
and I get a very similar error:
* lookup: lookup in 'consul_ami' failed to find 'eu-west-1' in:
${lookup(var.ami, var.region)}
Ok, I see in the documentation that this is currently not supported. However, this is very limiting!
What I did to overcome this was to fork the entire consul project, patch the modul variable configuration, and source this forked repository in mu module instantiation.
Please tell me if there is an easier way of working around this problem until map variables are supported in modules.
@phinze @catsby @mitchellh since it seems like only being able to pass strings to modules is a fundamental limitation of terraform's HCL, what are your thoughts on loading a map from a string?
This is currently allowed for lists using syntax like:
["${split(delim, str)}"]
What if another function were added to load maps from, say, JSON strings:
{"${json(str)}"}
Our use case for this is we want to have a module that wraps bringing up chef instances to keep our code DRY. For this, we need to be able to specify attributes to that chef instance, which is a map. There's no way currently to pass this as a variable, so this is impossible and we have to copy a bunch of code.
cc @thegedge
fwiw @jamestoyer @kolis we have the same problem and worked around this issue as described in https://github.com/hashicorp/terraform/pull/2704, this doesn't solve the problem of not being able to pass maps, but it allows you to fake a map.
The way it works is it uses the index function (not explicitly needed, we faked the index function using 'replace's regex capabilites, but index makes it much, much nicer which is why we made the PR).
The keys and values for the map are serialized into CSV strings that constitute parallel arrays. You find the index of your key using the 'index' function we wrote, and take that integer index against the values.
It's crude, and only supports flat maps, but it gets the job done.
Hope this helps!
For the value of another data point I'll say this is a major limitation from my experience so far (few weeks). I would say modules are incomplete without this feature (and a few others).
any ETA to address this?
I just have run into this problem. A solution will be really appreciated.
Is this at least under consideration?
It's definitely something we'd like to get fixed - the delay comes from the difficulty in implementation. It will require a lot of significant work in the config type system to support this. We'll definitely do it - just need to find the time to get it done!
+1
ran into it as well
+1
Just ran into this same problem.
+1
same thing here
+1 this would be very handy for things like AMI maps (which I like to keep at the top level of the project), would also be nice from a cleanliness standpoint on being able to write stuff like credentials to maps to keep things logically separated.
+1 this will be very helpful for us.
+1
+1
+1
+1. We're currently symlinking a lot to get around this.
+1 WHY IS THIS NOT A FEATURE??
+1
+1
+1. We pass a large number of standard/repeated variables to different modules so it would make a huge improvement to be able to just pass a map or two instead.
+1
Turns out im not alone in this, made Gist demonstrating this:
https://gist.github.com/kzap/14fc4c9428564dbcff16034219d9fae1
For now i think instead of the complex list, a symlink would work for now
+1
Variables being maps and lists is coming in version 0.7, coming soon!
Is there any workaround?
@themalkolm the workaround seems to be to pass two comma-delimited strings (one with keys, one with values) to your module, and then split and group that back together inside the module. See this comment and the one below, and this PR that it links to.
Same issue here. its a bit frustrating when you use maps around a generic terraform configuration and suddenly when using module the same approach does work.
@apparentlymart - Is this still slated for 0.7 and, If so, is it in the RCs?
from what I see it works in version: 0.7.0 rc2 46a0709
This works for me in 0.7.7, but I had to dig to find the syntax to just pass a map through:
# site.tf
module "modname" {
source = "modname"
mymap = "${var.mymap}"
}
# modname/main.tf
variable "mymap" { type = "map" }
Thanks @greg-jaunt for helping us out.
This indeed does work now!
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.
Most helpful comment
Variables being maps and lists is coming in version 0.7, coming soon!