website: Draw better attention to for and for_each patterns
When helping folks in the community forum, I commonly see questions around more complex patterns in transforming deep data structures into different shapes to work with for_each. We have examples of these patterns in the docs for the functions that they rely on, but they were not previously very discoverable in the main configuration language documentation sections. Here I've moved the "Using Expressions in for_each" subsection on the Resources page above some of the other sub-sections to hopefully make it easier to see, and written out in more detail the two specific patterns that answer a significant number of for_each-related user questions in the hope that readers will be more likely to realize that the links are relevant to what their goals. I also added some more elaboration about the behavior of converting from list to set in the "Using Sets" subsection, because this feature is often a user's first encounter with the set data type and I've inferred from some of the questions I've answered that a number of Terraform users don't have prior experience with set data types in other languages to draw assumptions from. Finally, I added some similar links to the for_each patterns within the for expression documentation itself, to try to make those examples more visible to those who might be discovering the documentation in a different sequence, e.g. by following a deep link shared in an answer to a question in the community forum.
This commit is contained in:
parent
ded30b6836
commit
67311f73fd
|
@ -578,6 +578,17 @@ together results that have a common key:
|
||||||
{for s in var.list : substr(s, 0, 1) => s... if s != ""}
|
{for s in var.list : substr(s, 0, 1) => s... if s != ""}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For expressions are particularly useful when combined with other language
|
||||||
|
features to combine collections together in various ways. For example,
|
||||||
|
the following two patterns are commonly used when constructing map values
|
||||||
|
to use with [resource `for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
|
||||||
|
|
||||||
|
* Transform a multi-level nested structure into a flat list by
|
||||||
|
[using nested `for` expressions with the `flatten` function](./functions/flatten.html#flattening-nested-structures-for-for_each).
|
||||||
|
* Produce an exhaustive list of combinations of elements from two or more
|
||||||
|
collections by
|
||||||
|
[using the `setproduct` function inside a `for` expression](./functions/setproduct.html#finding-combinations-for-for_each).
|
||||||
|
|
||||||
## Splat Expressions
|
## Splat Expressions
|
||||||
|
|
||||||
A _splat expression_ provides a more concise way to express a common
|
A _splat expression_ provides a more concise way to express a common
|
||||||
|
|
|
@ -376,6 +376,27 @@ This object has two attributes:
|
||||||
- `each.value` — The map value corresponding to this instance. (If a set was
|
- `each.value` — The map value corresponding to this instance. (If a set was
|
||||||
provided, this is the same as `each.key`.)
|
provided, this is the same as `each.key`.)
|
||||||
|
|
||||||
|
#### Using Expressions in `for_each`
|
||||||
|
|
||||||
|
The `for_each` meta-argument accepts map or set [expressions](./expressions.html).
|
||||||
|
However, unlike most resource arguments, the `for_each` value must be known
|
||||||
|
_before_ Terraform performs any remote resource actions. This means `for_each`
|
||||||
|
can't refer to any resource attributes that aren't known until after a
|
||||||
|
configuration is applied (such as a unique ID generated by the remote API when
|
||||||
|
an object is created).
|
||||||
|
|
||||||
|
The `for_each` value must be a map or set with one element per desired
|
||||||
|
resource instance. If you need to declare resource instances based on a nested
|
||||||
|
data structure or combinations of elements from multiple data structures you
|
||||||
|
can use Terraform expressions and functions to derive a suitable value.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
* Transform a multi-level nested structure into a flat list by
|
||||||
|
[using nested `for` expressions with the `flatten` function](./functions/flatten.html#flattening-nested-structures-for-for_each).
|
||||||
|
* Produce an exhaustive list of combinations of elements from two or more
|
||||||
|
collections by
|
||||||
|
[using the `setproduct` function inside a `for` expression](./functions/setproduct.html#finding-combinations-for-for_each).
|
||||||
|
|
||||||
#### Referring to Instances
|
#### Referring to Instances
|
||||||
|
|
||||||
When `for_each` is set, Terraform distinguishes between the resource block itself
|
When `for_each` is set, Terraform distinguishes between the resource block itself
|
||||||
|
@ -396,16 +417,19 @@ as a whole.
|
||||||
#### Using Sets
|
#### Using Sets
|
||||||
|
|
||||||
The Terraform language doesn't have a literal syntax for
|
The Terraform language doesn't have a literal syntax for
|
||||||
[sets](./types.html#collection-types), but you can use the `toset` function to
|
[set values](./types.html#collection-types), but you can use the `toset`
|
||||||
convert a list of strings to a set:
|
function to explicitly convert a list of strings to a set:
|
||||||
|
|
||||||
```hcl
|
```hcl
|
||||||
variable "subnet_ids" {
|
locals {
|
||||||
type = list(string)
|
subnet_ids = toset([
|
||||||
|
"subnet-abcdef",
|
||||||
|
"subnet-012345",
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_instance" "server" {
|
resource "aws_instance" "server" {
|
||||||
for_each = toset(var.subnet_ids)
|
for_each = local.subnet_ids
|
||||||
|
|
||||||
ami = "ami-a1b2c3d4"
|
ami = "ami-a1b2c3d4"
|
||||||
instance_type = "t2.micro"
|
instance_type = "t2.micro"
|
||||||
|
@ -417,24 +441,26 @@ resource "aws_instance" "server" {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Using Expressions in `for_each`
|
Conversion from list to set discards the ordering of the items in the list and
|
||||||
|
removes any duplicate elements. `toset(["b", "a", "b"])` will produce a set
|
||||||
|
containing only `"a"` and `"b"` in no particular order; the second `"b"` is
|
||||||
|
discarded.
|
||||||
|
|
||||||
The `for_each` meta-argument accepts map or set [expressions](./expressions.html).
|
If you are writing a module with an [input variable](./variables.html) that
|
||||||
However, unlike most resource arguments, the `for_each` value must be known
|
will be used as a set of strings for `for_each`, you can set its type to
|
||||||
_before_ Terraform performs any remote resource actions. This means `for_each`
|
`set(string)` to avoid the need for an explicit type conversion:
|
||||||
can't refer to any resource attributes that aren't known until after a
|
|
||||||
configuration is applied (such as a unique ID generated by the remote API when
|
|
||||||
an object is created).
|
|
||||||
|
|
||||||
The `for_each` value must be a map or set with one element per desired
|
```
|
||||||
resource instance. If you need to declare resource instances based on a nested
|
variable "subnet_ids" {
|
||||||
data structure or combinations of elements from multiple data structures you
|
type = set(string)
|
||||||
can use Terraform expressions and functions to derive a suitable value.
|
}
|
||||||
For some common examples of such situations, see the
|
|
||||||
[`flatten`](/docs/configuration/functions/flatten.html)
|
resource "aws_instance" "server" {
|
||||||
and
|
for_each = var.subnet_ids
|
||||||
[`setproduct`](/docs/configuration/functions/setproduct.html)
|
|
||||||
functions.
|
# (and the other arguments as above)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `provider`: Selecting a Non-default Provider Configuration
|
### `provider`: Selecting a Non-default Provider Configuration
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue