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
|
You can use the result of `csvdecode` with
|
||||||
using the `count` meta-argument, as in this example:
|
[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
|
```hcl
|
||||||
locals {
|
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" {
|
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
|
instance_type = each.value.instance_type
|
||||||
ami = local.instances[count.index].ami
|
ami = each.value.ami
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The above example will work on initial creation, but if any rows are removed
|
The `for` expression in our `for_each` argument transforms the list produced
|
||||||
from the CSV file, or if the records in the CSV file are re-ordered, Terraform
|
by `csvdecode` into a map using the `local_id` as a key, which tells
|
||||||
will not understand that the ordering has changed and will instead interpret
|
Terraform to use the `local_id` value to track each instance it creates.
|
||||||
this as requests for changes to many or all of the instances, which will in
|
Terraform will create and manage the following instance addresses:
|
||||||
turn force these instances to be destroyed and re-created.
|
|
||||||
|
|
||||||
The above pattern can be used with care in situations where, for example, the
|
- `aws_instance.example["foo1"]`
|
||||||
CSV file is only ever appended to, or if mass-updating the resources would
|
- `aws_instance.example["foo2"]`
|
||||||
not be harmful, but in general we recommend avoiding the above pattern.
|
- `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