website: example of csvdecode with for_each
We added the csvdecode function originally with the intent of it being used with for_each, but because csvdecode was released first we had a section in its documentation warning about the downsides of using it with "count", since that seemed like something people would be likely to try. With resource "for_each" now merged, we can replace that scary section with a more positive example of using these two features together. We still include a paragraph noting that "count" _could_ be used here, but with a caution against doing so. This is in the hope of helping users understand the difference between these two patterns and why for_each is the superior choice for most situations.
This commit is contained in:
parent
caf5bc847d
commit
5cb80c43c1
|
@ -43,30 +43,60 @@ number of fields, or this function will produce an error.
|
|||
]
|
||||
```
|
||||
|
||||
## Use with the `count` meta-argument
|
||||
## Use with the `for_each` meta-argument
|
||||
|
||||
It can be tempting to use `csvdecode` to generate a set of similar resources
|
||||
using the `count` meta-argument, as in this example:
|
||||
You can use the result of `csvdecode` with
|
||||
[the `for_each` meta-argument](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
||||
to describe a collection of similar objects whose differences are
|
||||
described by the rows in the given CSV file.
|
||||
|
||||
There must be one column in the CSV file that can serve as a unique id for each
|
||||
row, which we can then use as the tracking key for the individual instances in
|
||||
the `for_each` expression. For example:
|
||||
|
||||
```hcl
|
||||
locals {
|
||||
instances = csvdecode(file("${path.module}/instances.csv"))
|
||||
# We've included this inline to create a complete example, but in practice
|
||||
# this is more likely to be loaded from a file using the "file" function.
|
||||
csv_data = <<-CSV
|
||||
local_id,instance_type,ami
|
||||
foo1,t2.micro,ami-54d2a63b
|
||||
foo2,t2.micro,ami-54d2a63b
|
||||
foo3,t2.micro,ami-54d2a63b
|
||||
bar1,m3.large,ami-54d2a63b
|
||||
CSV
|
||||
|
||||
instances = csvdecode(local.csv_data)
|
||||
}
|
||||
|
||||
resource "aws_instance" "example" {
|
||||
count = len(local.instances) # Beware! (see below)
|
||||
for_each = { for inst in local.instances : inst.local_id => inst }
|
||||
|
||||
instance_type = local.instances[count.index].instance_type
|
||||
ami = local.instances[count.index].ami
|
||||
instance_type = each.value.instance_type
|
||||
ami = each.value.ami
|
||||
}
|
||||
```
|
||||
|
||||
The above example will work on initial creation, but if any rows are removed
|
||||
from the CSV file, or if the records in the CSV file are re-ordered, Terraform
|
||||
will not understand that the ordering has changed and will instead interpret
|
||||
this as requests for changes to many or all of the instances, which will in
|
||||
turn force these instances to be destroyed and re-created.
|
||||
The `for` expression in our `for_each` argument transforms the list produced
|
||||
by `csvdecode` into a map using the `local_id` as a key, which tells
|
||||
Terraform to use the `local_id` value to track each instance it creates.
|
||||
Terraform will create and manage the following instance addresses:
|
||||
|
||||
The above pattern can be used with care in situations where, for example, the
|
||||
CSV file is only ever appended to, or if mass-updating the resources would
|
||||
not be harmful, but in general we recommend avoiding the above pattern.
|
||||
- `aws_instance.example["foo1"]`
|
||||
- `aws_instance.example["foo2"]`
|
||||
- `aws_instance.example["foo3"]`
|
||||
- `aws_instance.example["bar1"]`
|
||||
|
||||
If you modify a row in the CSV on a subsequent plan, Terraform will interpret
|
||||
that as an update to the existing object as long as the `local_id` value is
|
||||
unchanged. If you add or remove rows from the CSV then Terraform will plan to
|
||||
create or destroy associated instances as appropriate.
|
||||
|
||||
If there is no reasonable value you can use as a unique identifier in your CSV
|
||||
then you could instead use
|
||||
[the `count` meta-argument](/docs/configuration/resources.html#count-multiple-resource-instances-by-count)
|
||||
to define an object for each CSV row, with each one identified by its index into
|
||||
the list returned by `csvdecode`. However, in that case any future updates to
|
||||
the CSV may be disruptive if they change the positions of particular objects in
|
||||
the list. We recommend using `for_each` with a unique id column to make
|
||||
behavior more predictable on future changes.
|
||||
|
|
Loading…
Reference in New Issue