website: Align `count` and `for_each` sections
- Make these descriptions more similar, since they do basically the same thing. - Add some subheaders to break up the wall of text and make it more skimmable. - Nudge people more firmly toward `for_each` if they need to actually incorporate data from a variable into their instances. - Add version note so you know whether you can use this yet.
This commit is contained in:
parent
d3dc1263bf
commit
979a2fa6d1
|
@ -226,11 +226,18 @@ maintainers understand the purpose of the additional dependency.
|
|||
|
||||
[inpage-count]: #count-multiple-resource-instances-by-count
|
||||
|
||||
By default, a single `resource` block corresponds to only one real
|
||||
infrastructure object. Sometimes it is desirable to instead manage a set
|
||||
of _similar_ objects of the same type, such as a fixed pool of compute
|
||||
instances. You can achieve this by using the `count` meta-argument,
|
||||
which is allowed in all `resource` blocks:
|
||||
-> **Note:** A given resource block cannot use both `count` and `for_each`.
|
||||
|
||||
By default, a `resource` block configures one real infrastructure object.
|
||||
However, sometimes you want to manage several similar objects, such as a fixed
|
||||
pool of compute instances. Terraform has two ways to do this:
|
||||
`count` and [`for_each`][inpage-for_each].
|
||||
|
||||
The `count` meta-argument accepts a whole number, and creates that many
|
||||
instances of the resource. Each instance has a distinct infrastructure object
|
||||
associated with it (as described above in
|
||||
[Resource Behavior](#resource-behavior)), and each is separately created,
|
||||
updated, or destroyed when the configuration is applied.
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "server" {
|
||||
|
@ -245,32 +252,45 @@ resource "aws_instance" "server" {
|
|||
}
|
||||
```
|
||||
|
||||
When the `count` meta-argument is present, a distinction exists between
|
||||
the resource block itself — identified as `aws_instance.server` —
|
||||
and the multiple _resource instances_ associated with it, identified as
|
||||
`aws_instance.server[0]`, `aws_instance.server[1]`, etc. Each instance has a
|
||||
distinct infrastructure object associated with it (as described above in
|
||||
[Resource Behavior](#resource-behavior)), and each is separately created,
|
||||
updated, or destroyed when the configuration is applied.
|
||||
#### The `count` Object
|
||||
|
||||
When `count` is _not_ present, a resource block has only a single resource
|
||||
instance, which has no associated index.
|
||||
In resource blocks where `count` is set, an additional `count` object is
|
||||
available in expressions, so you can modify the configuration of each instance.
|
||||
This object has one attribute:
|
||||
|
||||
Within resource blocks where `count` is set, an additional `count` object is
|
||||
available for use in expressions so you can modify the configuration of each
|
||||
instance. This object has one attribute, `count.index`, which provides the
|
||||
distinct index number (starting with `0`) for each instance.
|
||||
- `count.index` — The distinct index number (starting with `0`) corresponding
|
||||
to this instance.
|
||||
|
||||
The `count` meta-argument accepts [expressions](./expressions.html)
|
||||
in its value, similar to the resource-type-specific arguments for a resource.
|
||||
However, Terraform must interpret the `count` argument _before_ any actions
|
||||
are taken from remote resources, and so (unlike the resource-type-specifc arguments)
|
||||
the `count` expressions may not refer to any resource attributes that are
|
||||
not known until after a configuration is applied, such as a unique id
|
||||
generated by the remote API when an object is created.
|
||||
#### Referring to Instances
|
||||
|
||||
For example, `count` can be used with an input variable that carries a list
|
||||
value, to create one instance for each element of the list:
|
||||
When `count` is set, Terraform distinguishes between the resource block itself
|
||||
and the multiple _resource instances_ associated with it. Instances are
|
||||
identified by an index number, starting with `0`.
|
||||
|
||||
- `<TYPE>.<NAME>` (for example, `aws_instance.server`) refers to the resource block.
|
||||
- `<TYPE>.<NAME>[<INDEX>]` (for example, `aws_instance.server[0]`,
|
||||
`aws_instance.server[1]`, etc.) refers to individual instances.
|
||||
|
||||
This is different from resources without `count` or `for_each`, which can be
|
||||
referenced without an index or key.
|
||||
|
||||
#### Using Expressions in `count`
|
||||
|
||||
The `count` meta-argument accepts numeric [expressions](./expressions.html).
|
||||
However, unlike most resource arguments, the `count` value must be known
|
||||
_before_ Terraform performs any remote resource actions. This means `count`
|
||||
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).
|
||||
|
||||
#### When to Use `for_each` Instead of `count`
|
||||
|
||||
If your resource instances are almost identical, `count` is appropriate. If some
|
||||
of their arguments need distinct values that can't be directly derived from an
|
||||
integer, it's safer to use `for_each`.
|
||||
|
||||
Before `for_each` was available, it was common to derive `count` from the
|
||||
length of a list and use `count.index` to look up the original list value:
|
||||
|
||||
```hcl
|
||||
variable "subnet_ids" {
|
||||
|
@ -291,25 +311,30 @@ resource "aws_instance" "server" {
|
|||
}
|
||||
```
|
||||
|
||||
Note that the separate resource instances created by `count` are still
|
||||
identified by their _index_, and not by the string values in the given
|
||||
list. This means that if an element is removed from the middle of the list,
|
||||
all of the indexed instances _after_ it will see their `subnet_id` values
|
||||
change, which will cause more remote object changes than were probably
|
||||
intended. The practice of generating multiple instances from lists should
|
||||
be used sparingly, and with due care given to what will happen if the list is
|
||||
changed later.
|
||||
This was fragile, because the resource instances were still identified by their
|
||||
_index_ instead of the string values in the list. If an element was removed from
|
||||
the middle of the list, every instance _after_ that element would see its
|
||||
`subnet_id` value change, resulting in more remote object changes than intended.
|
||||
Using `for_each` gives the same flexibility without the extra churn.
|
||||
|
||||
### `for_each`: Multiple Resource Instances Defined By a Map, or Set of Strings
|
||||
|
||||
[inpage-for_each]: #for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings
|
||||
|
||||
When the `for_each` meta-argument is present, Terraform will create instances
|
||||
based on the keys and values present in a provided map, or set of strings, and expose the values
|
||||
of the map to the resource for its configuration.
|
||||
-> **Version note:** `for_each` was added in Terraform 0.12.6.
|
||||
|
||||
The keys and values of the map, or strings in the case of a set, are exposed via the `each` attribute,
|
||||
which can only be used in blocks with a `for_each` argument set.
|
||||
-> **Note:** A given resource block cannot use both `count` and `for_each`.
|
||||
|
||||
By default, a `resource` block configures one real infrastructure object.
|
||||
However, sometimes you want to manage several similar objects, such as a fixed
|
||||
pool of compute instances. Terraform has two ways to do this:
|
||||
[`count`][inpage-count] and `for_each`.
|
||||
|
||||
The `for_each` meta-argument accepts a map or a set of strings, and creates an
|
||||
instance for each item in that map or set. Each instance has a distinct
|
||||
infrastructure object associated with it (as described above in
|
||||
[Resource Behavior](#resource-behavior)), and each is separately created,
|
||||
updated, or destroyed when the configuration is applied.
|
||||
|
||||
```hcl
|
||||
resource "azurerm_resource_group" "rg" {
|
||||
|
@ -322,16 +347,34 @@ resource "azurerm_resource_group" "rg" {
|
|||
}
|
||||
```
|
||||
|
||||
Resources created by `for_each` are identified by the key associated with the instance -
|
||||
that is, if we have `azurerm_resource_group.rg` as above, the instances will be `azurerm_resource_group.rg["a_group"]`
|
||||
and `azurerm_resource_group.rg["another_group"]`, as those are the keys in the map provided
|
||||
to the `for_each` argument.
|
||||
#### The `each` Object
|
||||
|
||||
The `for_each` argument also supports a set of strings in addition to maps; convert a list
|
||||
to a set using the `toset` function. As such, we can take the example
|
||||
in `count` and make it safer to use, as we can change items in our set
|
||||
and because the string keys are used to identify the instances,
|
||||
we will only change the items we intend to:
|
||||
In resource blocks where `for_each` is set, an additional `each` object is
|
||||
available in expressions, so you can modify the configuration of each instance.
|
||||
This object has two attributes:
|
||||
|
||||
- `each.key` — The map key (or set member) corresponding to this instance.
|
||||
- `each.value` — The map value corresponding to this instance. (If a set was
|
||||
provided, this is the same as `each.key`.)
|
||||
|
||||
#### Referring to Instances
|
||||
|
||||
When `for_each` is set, Terraform distinguishes between the resource block itself
|
||||
and the multiple _resource instances_ associated with it. Instances are
|
||||
identified by a map key (or set member) from the value provided to `for_each`.
|
||||
|
||||
- `<TYPE>.<NAME>` (for example, `azurerm_resource_group.rg`) refers to the resource block.
|
||||
- `<TYPE>.<NAME>[<KEY>]` (for example, `azurerm_resource_group.rg["a_group"]`,
|
||||
`azurerm_resource_group.rg["another_group"]`, etc.) refers to individual instances.
|
||||
|
||||
This is different from resources without `count` or `for_each`, which can be
|
||||
referenced without an index or key.
|
||||
|
||||
#### Using Sets
|
||||
|
||||
The Terraform language doesn't have a literal syntax for
|
||||
[sets](./types.html#collection-types), but you can use the `toset` function to
|
||||
convert a list of strings to a set:
|
||||
|
||||
```hcl
|
||||
variable "subnet_ids" {
|
||||
|
@ -343,7 +386,7 @@ resource "aws_instance" "server" {
|
|||
|
||||
ami = "ami-a1b2c3d4"
|
||||
instance_type = "t2.micro"
|
||||
subnet_id = each.key # note, each.key and each.value will be the same on a set
|
||||
subnet_id = each.key # note: each.key and each.value are the same for a set
|
||||
|
||||
tags {
|
||||
Name = "Server ${each.key}"
|
||||
|
@ -351,6 +394,15 @@ resource "aws_instance" "server" {
|
|||
}
|
||||
```
|
||||
|
||||
#### 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).
|
||||
|
||||
### `provider`: Selecting a Non-default Provider Configuration
|
||||
|
||||
[inpage-provider]: #provider-selecting-a-non-default-provider-configuration
|
||||
|
|
Loading…
Reference in New Issue