-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
for_each attribute for creating multiple resources based on a map #17179
Comments
Hi @mirogta! Thanks for this feature request, and your detailed use-case. This is definitely a request that has come up before, though it seems like it's only previously been discussed within the comments of other issues, so this issue seems like a good anchor for talking about our plans here, and updating as we make progress. The current design sketch we have is a new # NOT YET IMPLEMENTED; some details may change before implementation
resource "azurerm_network_security_rule" "allow-in" {
for_each = "${local.rules}"
name = "allow-${each.key}-in"
direction = "Inbound"
access = "Allow"
priority = "${each.value.priority}"
protocol = "${lookup(each.value, "protocol", "*")}"
source_port_range = "*"
destination_port_range = "${lookup(each.value, "destination_port", "*")}"
source_address_prefix = "${lookup(each.value, "source_address", "*")}"
destination_address_prefix = "${lookup(each.value, "destination_address", "*")}"
resource_group_name = "${azurerm_resource_group.resource_group.name}"
network_security_group_name = "${azurerm_network_security_group.nsg.name}"
} The primary benefit of this, as you correctly suggested, is that if the If a user provides a list to We are currently focused on some more general work to improve the configuration language's handling of collection types, which is a pre-requisite for this I'm going to update the summary of this issue so that it's more specific about our currently-planned approach, since that should help us find it again to post updates when we have them. Thanks again for this feature request! |
@apparentlymart: For the sake of readability - could this be implemented as a block directive instead? Per following example:
or with list as input:
|
Hi @slawekm, Unfortunately HCL syntax doesn't work quite like that, so your nested iterator {
on = "${var.repositories}""
} Given that we expect In practice today lots of users have the pattern of specifying the # NOT YET IMPLEMENTED; some details may change before implementation
resource "azurerm_network_security_rule" "allow-in" {
for_each = local.rules
name = "allow-${each.key}-in"
direction = "Inbound"
access = "Allow"
priority = each.value.priority
protocol = lookup(each.value, "protocol", "*")
source_port_range = "*"
destination_port_range = lookup(each.value, "destination_port", "*")
source_address_prefix = lookup(each.value, "source_address", "*")
destination_address_prefix = lookup(each.value, "destination_address", "*")
resource_group_name = azurerm_resource_group.resource_group.name
network_security_group_name = azurerm_network_security_group.nsg.name
} The above also illustrates a capability of the new configuration parser where it's no longer required to use Our current configuration work will also include an overhaul of the configuration-related documentation on the website that should include more "opinionated" best-practices than are currently given (since most of the documentation was written before best-practices emerged) and so we can explicitly recommend the above usage and make sure all of our examples follow it. |
First of all, thanks for a detailed response.
A product of c&p typo, my bad.
Right. Erm, I guess the main reason I've asked for this is that I'm subconsciously looking for a simpler way to define dynamic resources. A configurable iterator which could also perform basic operations on input data, such like grouping or filtering on values and This would make "feeding" dictionaries into And with that in mind, turning |
Hi @slawekm, Thanks for the additional information about your use-case. The new configuration language interpreter has a feature called "
This |
Whoa, I'd love to see this. Very exciting |
Definitely exciting. Has any progress been made on the new config language interpreter that includes |
Really hope this happens soon. To get around this type of problem, I've resorted to templating the .tf files using jinja to create individual resources rather than use |
Will the |
Is there any indication of when these will be rolled out? |
I had the same requirements for the NSG's and used this solution which lets me change ports as the rules are grouped and delete all previous rules with an update. This is just an example. nsg_rules.tf.json (seperate global variables file for nsg rules.)
main.tf
core module code
We then split the rules by manipulating the string values form the json. Split by comma for count of rules "22_inbound_allow_tcp__ Then split using the underscores in order for port, direction, action, protocol, source and destination
|
I also think the count feature is not really the best way to achieve creation of multiple resources. Is there any progress with the |
how would this design handle sub resources? would there be a way to create a resource conditionally? For example, would i be able to say given condition X in one iteration, skip creating this resource. |
@apparentlymart , will there be migration guide/document provided from |
Is this currently being worked on? Is there any expected delivery date? |
Looks like it's getting close, https://www.hashicorp.com/blog/terraform-0-1-2-preview |
Recent activity in the PR, so I'm hopeful. |
I wish there was some documentation to indicate to users that count should not be used dynamically. I've had to refactor a a chunk of my code and throw out another project that would have relied on that after discovering the count issue. |
@ViggyNash As with so many docs, the explanation is there, it just needs to be read carefully and probably doesn't make a lot of sense until it bites you. :/
https://www.terraform.io/docs/configuration/resources.html#count-multiple-resource-instances |
Is there anything I could do to help get this feature added or the PR merged? |
@tmccombs Thank you for the kind offer! We are indeed prioritizing this for a near release of Terraform, at which point I'd say the best way to help is to use it and help us find bugs that will inevitably show up in the first pass of the feature (you could do this now, by building the active PR; it would help me best if anything you find you comment on the PR itself). |
for_each fails for me when using a local variable map |
I have a question regarding "count" vs "for". I am experiencing all the issues discussed here, too. But my design was planned to have something like
wich means I would need to maintain a two-dimensional array of |
Using TF 0.12.4 this is how I am dealing with disks with a The
The variables come from a file specific to the virtual machine similar to what you have above:
Note: I exclude disk 0 as its part of our image but we have the disk in the server spec file for completness, hence the skipping on disk 0 in the dynamic loop. |
thanks @simonbirtles I get the idea. |
Hi @desixma , If I understand correctly I will briefly describe our workflow.... We have a workflow which starts with a file per resource (i.e. vm) which is our own DDL spec which contains all details required for a virtual machine (vm specific, configuration and software), each file is converted using a j2 template into a terraform config file per resource/vm which contains the module config with variables as I showed in the second snippet. These files (per vm) and a basic main/var/output.tf files for the full terraform configuration. The files above import a generic module for a vmware virtual machine, the first snippet is part of a generic vmware vm resource which is imported by each terraform config file (file per vm). From what I see, I think your approach is fine, you would need to have seperate modules for TF does not yet support dynamic Hope that helps. |
ah I see. Thanks for the clarification |
How do you access all resources when using for_each. For example I have the following: # create required policies
resource "aws_iam_policy" "main" {
for_each = var.policies
name = each.key
path = lookup(each.value, "path", "/")
policy = templatefile("${var.policies_dir}/${lookup(each.value, "template", each.key)}.tmpl",
lookup(each.value, "vars", {}))
} Prior to this I just used count on a list and then could perform the following: /* create a map with key = policy name and value being the policy arn */
policy_name_arn_mapping = zipmap(aws_iam_policy.main.*.name, aws_iam_policy.main.*.arn) With for_each I get
|
Unfortunately, HCL's splat syntax only supports lists (perhaprs that should be changed in the upstream hcl project?). You can still access all of them by using the /* create a map with key = policy name and value being the policy arn */
policy_name_arn_mapping = zipmap(values(aws_iam_policy.main)[*].name, values(aws_iam_policy.main)[*].arn) Although in this case it might be better just to use a for_each comrehension such as:
|
How dynamically we can create such map , so it can be passed to for_each within resource block
input params:
where
i tried different methods, but no luck. the closest is
which gives this output
|
@timota It's not very clear to me what your desired output is, but if it's that: "<nth>-vol-<i>" = {
"0" = {...}
"1" = {...}
} should instead have only the { for k, v in var.disks : k => v } to: var.disks[local.counter] (but that |
ahg sorry. my goal is to get this map
so i can use keys (inst-xxx-vol-xxx) in for_each for resource to create named resources |
@timota I think you want something like: {
for instdisk in setproduct(var.instance_ids, var.disks)
: "inst-${index(var.instance_ids, instdisk[0])}-vol-${index(var.disks, instdisk[1])}"
=> instdisk[1]
} (but note I haven't tested it!) This is quite a good of where an 'enumerate' function would be helpful (#21940). |
cool, thanks. will test and let you know |
it works like a charm Many thanks. |
Hi guys im currently try to create dynamically data disk for some virtual machines. The creation of data disk. For exemple : I want to create 2 VM with 3 data disks Creation of data disks
Attach the created data disk to virtual machine
Everything works fine, datadisks are created with the right name is correctly attached to vm but once i restart an "apply" Terraform wants to change the id of the datadisks and therefore destroy and recreate it..
Im using Terraform v0.11.11. Do you know where the error may come from or is it possible to dynamically create data disks with an "for each" with the azurerm provider ? Thx for your feedback |
Hi Guys, I need to dynamically generate an entire resource block based on a map. So, in one file, I need something like the following, repeated for each.value:
How can I achieve this for_each? So far what I've tried is not working. Note that I've successfully generated one single resource block with a bunch of path definitions based on a map, but I don't exactly know what the syntax should look like for generating repeated resource blocks. Thanks for feedback/help. |
Hi friends! While I appreciate seeing folks help each other, please use the community forums to ask questions, and help future people who are asking similar questions. Thank you! |
Hi All, I am using a for_each to assign a new network to each VM that I create data "vsphere_network" "network1" { data "vsphere_virtual_machine" "template" { =========================================================FOLDER, TFVM RESOURCES ETC.=========================================================resource "vsphere_folder" "chefinfra" { resource "vsphere_virtual_machine" "tfvm" { datastore_id = data.vsphere_datastore.datastore.id unfortunately since I am using v0.12.6, I cannot use the count.index to dynamically name my VMs - since I have the for_each. What is the alternative to create VM names dynamically while in a for_each? The VM names need to increment by 1. Thanks in advance |
Hi,
We are missing a better support for loops which would be based on keys, not on indexes.
Below is an example of the problem we currently have and would like Terraform to address:
As you can guess, if we e.g. remove the first item from the hash, Terraform would not see that as a removal of the first resource (index 0), but rather removal of the last resource (index 2) and a related unexpected change of all the other resources (old index 1 becomes new index 0, old index 2 becomes new index 1).
Unfortunately this can also cause Azure provider to fail, because it may get into a conflict where an actual resource (old index 1) still exists in Azure, but Terraform now tries to modify the actual resource (old index 0) to have the same properties, but that is not possible (e.g. NSG priority and port have to be unique).
I've shown an example with 3 rules, but in reality we can have 50 rules and the tf file is 5x longer and more difficult to manage with individual resources compared to using a hash.
We would like to use hashes in Terraform in such a way that a position of an element inside a hash doesn't matter. That's why many other languages provide two ways of looping - by index (e.g.
for i=0; i<list.length;i++
) and by key (foreach key in list
).I'm sure that smart guys like you can figure out how to make this work in Terraform.
Thanks
The text was updated successfully, but these errors were encountered: