-
Notifications
You must be signed in to change notification settings - Fork 9.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
count and for_each for modules #17519
Comments
Hi @AnthonyWC! I'm not sure I understood correctly your question, but you can use any reference in the locals {
map1 = {
name1 = "foo"
name2 = "bar"
}
selector = "name1"
}
module "x1" {
source = "../"
parameter = "${local.map1[local.selector]}"
} If I'm not answering the write question here, it'd help to have a more concrete, real-world example so that it's easier to understand what you're trying to achieve. It can be hard to figure out your intent with just generic names like "map1", "name1", etc. |
Ok so originally I had something like this:
I want to reduce the number of copying, so I change it:
But I think I should able to go further with something like this:
Where I can select the local map variable based on another variable on a per module basis. Not sure if locals is the right way to achieve it. |
I think I am still not understanding properly... in your second example you shown indexes I think maybe what you want to do is insert the module's own name in there? So in that case your tag map would look like this: locals {
tag_Name_map = {
x1 = "value1"
x2 = "value2"
}
} In that case, what you want to do here is not possible at this time. Terraform's configuration format prefers being explicit over implicit, and also being direct rather than indirect. While of course this is subjective, the design principles for the language actually consider your first example to be better because the value can be seen directly inside the I think the closest thing to what you want here would be a future feature to address the request in #953. Other work has prevented us from prototyping that further since my last comment here, but we want to eventually support both locals {
tag_Name_map = {
name1 = "value1"
name2 = "value2"
}
}
# Not yet implemented and details may change before release
module "x" {
# Create an instance of this module for each element in locals.tag_Name_map
for_each = "${locals.tag_Name_map}"
source = "../"
tag_Name = "${each.value}" # use each value from the map
} |
Thanks for the detailed response. I was thinking maybe it was possible to somehow set the value of $var.name differently within each module. Maybe with inline template if it was allowed to be set differently within each module (which doesn't look to work that way currently). The other direction may be to look outside of Terraform and use something else to dynamically generate the terraform file, which separate out the templating logic and won't affect Terraform itself. Maybe something like a lightweight version of pongo2 for Terraform or some other project like this one (https://github.com/mjuenema/python-terrascript). |
I'm not personally familiar with The {
"module": {
"x1": {
"source": "../",
"tag_Name": "foo"
},
"x2": {
"source": "../",
"tag_Name": "bar"
}
}
} Once something like that |
We're currently also doing something similar to @AnthonyWC, running a templating engine to preprocess input and generate Terraform from them. I'm sure this comes up often, but are there any plans for Terraform to introduce a native way to do this? I dont meant as a part of HCL which will handle the actual runtime options. Instead, I was thinking of something similar to the way that Ansible processes templates to generate python before using it for execution, Terraform can generate HCL from templates. |
@pselle Now with resource for_each implemented, I was curious what it might look like for module for_each? Is most of the heavy lifting done at this point or is it still quite a large effort? |
@jakauppila Effort is hard to say, but modules and resources are handled in different areas of Terraform -- additionally, resources already have As described in the 0.12 preview last year, I expect some groundwork has already been made (necessary changes to the statefile, reserving those keywords ...). I hope that gives some better picture of where the project is at with regards to modules and |
Any timelines on the implementation of this? |
we need a list based variable for both domain and path, please suggest how to use loops in terraform |
Can we get any kind of committment or anti-committment? Not having for_each on modules is blocking a lot of user-friendliness and consistency we want. We're halfway there with resource for_each, so it's particularly frustrating. I'm pondering creating a local exec script that generates the module definitions from a template as a halfway step. There will still need to be some |
@jspiro We're using a separate templating engine to generate terraform files with the modules, then we commit them into the repo, so that Terraform Cloud can just read from the compiled directory. When module Maybe you can try a similar workaround to prevent the "hack", namely the |
Makes sense. In my case, I am trying to create an abstraction layer for users to not have to know terraform or github or do any cloning–I want them editing YAML files in Github directly, and it resulting in changes. I have this working well for resources, but not modules. Which templating system did you pick? |
@jspiro We chose nunjucks, which is a js version of jinja2. I work for npm and since we are a js shop and have some legacy ansible, this choice made sense. Another thing we've thought about doing is introduce a GitHub actions workflow that takes care of templating portion automatically. If you're looking to create an abstraction layer, maybe create some CI/CD pipelines that does this: CI Pipeline
CD Pipeline
|
An alternative work-around, that potentially requires some more work (on the module side) that I have used is to create a fake This have worked well and the down-side is that the module becomes slightly more complicated (always working with list of things). |
@mitchellh @apparentlymart As great a tool terraform is(more so after the 0.12.6 release with |
i have a use case for this for creating multiple vpcs using a complex data structure to steer the specifics. e.g.
i would like to do
i already have
this would create
not ideal. :) i just realized that
is not possible. so i'll have to do something like this:
so, i definitely need we're in the process of re-spinning our aws infrastructure from scratch and being able to use terraform 0.12 makes a lot of things possible that weren't possible before and starting from scratch means that we can make the most of all the new features. any indication as to schedule for this feature would be greatly appreciated. i'm under pressure to deliver something so unless thanks. |
another use case is driving terraform config via data structs when using 3rd party modules. i'd like to build a data struct that defines all the inputs for my eks clusters and then use the gruntworks' eks module to actually instantiate them. |
Another use case I'm looking at is enabling AWS guard duty on every region. This requires multiple providers, and I need to iterate over a list of regions for a module invocation (due to OTHER restrictions on the provider resource). A for_each makes this easy. No for_each means this is tedious. |
Workaround: I ended up creating the new module for the whole set of resources for particular value of list/map and then copying definition like below instead of creating a map and iterate over its keys: module "m1" {
source = "../module"
var1 = "m1"
...
}
module "m2" {
source = "../module"
var1 = "m2"
...
} |
Ran into this again today and I'm really surprised this isn't a bigger deal. Any update on @jspiro commitment question? |
we also could use this. in particular it would be great for k8s deployments across multiple clusters simultaneously |
Does this actually work? I'm asking because what you describe as a working feature seems to cover part of this issue. |
@conet. Yes passing any arbitrary variable into a module to tell it to turn things in the module on or off or even to control the count of said resources in the module will work. This issue is for something on a much higher level to remove any of the issues you would get from passing your own variable in. Anyone right now could mimic this issues request at least partially if your module is simple enough. But if your module is already making use of the count feature on resources it becomes much harder to merge that with an arbitrary count passed in at the module level. As an example say you have a module that creates an ecs service and all the things needed for it (sg, albs, taskdefs, etc...). This service can either be a worker or a web app so inside you're module you use a variable like This problem is exacerbated when you start using modules in your modules, like if we wanted an alb module to reuse in other cases outside of this ecs module. You also have a big headache of a mess when it comes to outputs. If the count was handled by terraform at the module level you wouldn't need to worry about the counts on all the resources in the module other than for turning resources on or off. |
OK, that is what I thought, propagating the |
Also just ran into this issue again, and found both threads on the Edit: Thumbs down @blalor and @dreamrace ? Really? You don't think this should be fixed asap? This issue of |
@KptnKMan Terraform is going to do this. They are close, or so they claim. https://www.hashicorp.com/blog/hashicorp-terraform-0-12-preview-for-and-for-each/ |
I don't think that post is relevant to this as that's the preview blog post prior to release. As of now, I'm not sure the issue has been solved for using |
I recently hit this problem, and am working around this lack of functionality by using a template file. It is working well so far. |
I wish this gets implemented soon :) @apparentlymart |
The original (#953) issue has been around for more than five years already. It's anniversary, let's celebrate! Seriously, guys, when it is going to be implemented? |
As noted in the comment I left above, implementation is in progress right now. |
any update on this ? |
Sooner then later terraform journey leads you to using
Terraform team, thank you for v0.12.x and ongoing work with enhancement! |
Will this include support for looping over regions to simplify multi-region provisioning? I.e. being able to loop over providers as well? |
@mightyguava OOC, what would the expected syntax for that be? Something like: provider "google" {
alias = "goog-us-east1"
region = "us-east1"
}
provider "google" {
alias = "goog-us-west1"
region = "us-west1"
}
locals {
regions = toset(['us-east1', 'us-west1'])
providers = {
us-east1 = google.goog-us-east1
us-west1 = google.goog-us-west1
}
}
module "vpc" {
for_each = local.regions
providers = {
google = local.providers[each.key]
}
...
} |
Yes! That looks amazing. We deploy most of our infra in 2 regions in an active-passive configuration. So being able to instantiate both regions using the same module block would be a huuuge win. It's also our primary use case for for_each on modules. I think it might be slightly nicer if you could iterate over the |
(FYI I'm not on the terraform team; just an interested bystander) Yes, good point. I think no reason you theoretically couldn't iterate such a map. The problem is you currently can't build such a map, since it seems referencing You have my +1 that this would be awesome :) |
Hi @mightyguava, That feature is not in scope for this issue, but I'd encourage you to open a new feature request issue to capture that use-case. |
Thanks, added issue #24476. I think this is a natural extension to |
Hello folks, I've locked this issue to collaborators to reduce noise for the many subscribed. The work on this is in progress right now and is in the 0.13 release milestone. |
I'm very excited to announce that beta 1 of terraform 0.13.0 will be available on June 3rd. Module |
We turned on I'm closing this issue to reflect that the work is done and will be released soon! |
Terraform 0.13.0 beta 1 launched today with |
Is it possible to dynamically select map variable, e.g?
Currently I am doing this:
vars.tf
main.tf
This works but it's repetitive/DRY to hardcode the key name.
Ideally I want to able to do something like this:
Where I can dynamically alter the key variable in the same file. I thought about using null_data_source:
But don't think I will able to inject different variable to selector value since I can't use locals within module block.
The text was updated successfully, but these errors were encountered: