Merge pull request #24635 from hashicorp/pselle/docs-mod-count

Docs for count/for_each on modules
This commit is contained in:
Pam Selle 2020-04-13 18:39:59 -04:00 committed by GitHub
commit ab101f99df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 113 additions and 36 deletions

View File

@ -155,7 +155,7 @@ described in more detail in other sections:
If not specified, the child module inherits all of the default (un-aliased) If not specified, the child module inherits all of the default (un-aliased)
provider configurations from the calling module. provider configurations from the calling module.
In addition to the above, the argument names `count`, `for_each` and In addition to the above, the argument names `depends_on` and
`lifecycle` are not currently used by Terraform but are reserved for planned `lifecycle` are not currently used by Terraform but are reserved for planned
future features. future features.
@ -361,25 +361,23 @@ setting inside a `terraform` block.
## Multiple Instances of a Module ## Multiple Instances of a Module
A particular module source can be instantiated multiple times: Use the `count` or `for_each` arguments to create multiple instances of a module.
These arguments have the same syntax and type constraints as
[`count`](./resources.html#count-multiple-resource-instances-by-count) and
[`for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
as defined for managed resources.
```hcl ```hcl
# my_buckets.tf # my_buckets.tf
module "bucket" {
module "assets_bucket" { for_each = toset(["assets", "media"])
source = "./publish_bucket" source = "./publish_bucket"
name = "assets" name = "${each.key}_bucket"
}
module "media_bucket" {
source = "./publish_bucket"
name = "media"
} }
``` ```
```hcl ```hcl
# publish_bucket/bucket-and-cloudfront.tf # publish_bucket/bucket-and-cloudfront.tf
variable "name" {} # this is the input parameter of the module variable "name" {} # this is the input parameter of the module
resource "aws_s3_bucket" "example" { resource "aws_s3_bucket" "example" {
@ -396,18 +394,23 @@ subdirectory. That module has configuration to create an S3 bucket. The module
wraps the bucket and all the other implementation details required to configure wraps the bucket and all the other implementation details required to configure
a bucket. a bucket.
We can then instantiate the module multiple times in our configuration by We declare multiple module instances by using the `for_each` attribute,
giving each instance a unique name -- here `module "assets_bucket"` and which accepts a map (with string keys) or a set of strings as its value. Additionally,
`module "media_bucket"` -- whilst specifying the same `source` value. we use the `each.key` in our module block, because the
[`each`](/docs/configuration/resources.html#the-each-object) object is available when
we have declared `for_each` on the module block. When using the `count` argument, the
[`count`](/docs/configuration/resources.html#the-count-object) object is available.
Resources from child modules are prefixed with `module.<module-instance-name>` Resources from child modules are prefixed with `module.module_name[module index]`
when displayed in plan output and elsewhere in the UI. For example, the when displayed in plan output and elsewhere in the UI. For a module with without
`./publish_bucket` module contains `aws_s3_bucket.example`, and so the two `count` or `for_each`, the address will not contain the module index as the module's
instances of this module produce S3 bucket resources with [_resource addresses_](/docs/internals/resource-addressing.html) name suffices to reference the module.
`module.assets_bucket.aws_s3_bucket.example` and `module.media_bucket.aws_s3_bucket.example`
respectively. These full addresses are used within the UI and on the command In our example, the `./publish_bucket` module contains `aws_s3_bucket.example`, and so the two
line, but are not valid within interpolation expressions due to the instances of this module produce S3 bucket resources with [resource addresses](/docs/internals/resource-addressing.html) of `module.bucket["assets"].aws_s3_bucket.example`
encapsulation behavior described above. and `module.bucket["media"].aws_s3_bucket.example` respectively. These full addresses
are used within the UI and on the command line, but only [outputs](docs/configuration/outputs.html)
from a module can be referenced from elsewhere in your configuration.
When refactoring an existing configuration to introduce modules, moving When refactoring an existing configuration to introduce modules, moving
resource blocks between modules causes Terraform to see the new location resource blocks between modules causes Terraform to see the new location
@ -415,10 +418,64 @@ as an entirely separate resource to the old. Always check the execution plan
after performing such actions to ensure that no resources are surprisingly after performing such actions to ensure that no resources are surprisingly
deleted. deleted.
Each instance of a module may optionally have different providers passed to it ### Limitations when using module expansion
using the `providers` argument described above. This can be useful in situations
where, for example, a duplicated set of resources must be created across Modules using `count` or `for_each` cannot pass different sets of providers to different instances.
several regions or datacenters. This is because when a module instance is destroyed (such as a key-value being removed from the
`for_each` map), the provider must be available in order to perform the destroy. You can pass
different sets of providers by using multiple `module` blocks:
```
# my_buckets.tf
provider "aws" {
alias = "usw1"
region = "us-west-1"
}
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
provider "google" {
alias = "usw1"
credentials = "${file("account.json")}"
project = "my-project-id"
region = "us-west1"
zone = "us-west1-a"
}
provider "google" {
alias = "usw2"
credentials = "${file("account.json")}"
project = "my-project-id"
region = "us-west2"
zone = "us-west2-a"
}
module "bucket_w1" {
source = "./publish_bucket"
providers = {
aws.src = "aws.usw1"
google.src = "google.usw2"
}
}
module "bucket_w2" {
source = "./publish_bucket"
providers = {
aws.src = "aws.usw2"
google.src = "google.usw2"
}
}
```
Each module block may optionally have different providers passed to it
using the [`providers`](/docs/configuration/modules.html#passing-providers-explicitly)
argument. This can be useful in situations where, for example, a duplicated set of
resources must be created across several regions or datacenters.
## Tainting resources within a module ## Tainting resources within a module

View File

@ -16,19 +16,37 @@ larger infrastructure. An address is made up of two parts:
[module path][resource spec] [module path][resource spec]
``` ```
__Module path__: ## Module path
A module path addresses a module within the tree of modules. It takes the form: A module path addresses a module within the tree of modules. It takes the form:
``` ```
module.A.module.B.module.C... module.module_name[module index]
``` ```
Multiple modules in a path indicate nesting. If a module path is specified * `module` - Module keyword indicating a child module (non-root). Multiple `module`
without a resource spec, the address applies to every resource within the keywords in a path indicate nesting.
module. If the module path is omitted, this addresses the root module. * `module_name` - User-defined name of the module.
* `[module index]` - (Optional) [Index](#index-values-for-modules-and-resources) into a
module with multiple instances, surrounded by square brace characters (`[` and `]`).
__Resource spec__: An address without a resource spec, i.e. `module.foo` applies to every resource within
the module if a single module, or all instances of a module if a module has multiple instances.
To address all resources of a particular module instance, include the module index in the address,
such as `module.foo[0]`.
If the module path is omitted, the address applies to the root module.
An example of the `module` keyword delineating between two modules that have multiple instances:
```
module.foo[0].module.bar["a"]
```
-> Module index only applies to modules in Terraform v0.13 or later, as in earlier
versions of Terraform, a module could not have multiple instances.
## Resource spec
A resource spec addresses a specific resource in the config. It takes the form: A resource spec addresses a specific resource in the config. It takes the form:
@ -38,15 +56,17 @@ resource_type.resource_name[resource index]
* `resource_type` - Type of the resource being addressed. * `resource_type` - Type of the resource being addressed.
* `resource_name` - User-defined name of the resource. * `resource_name` - User-defined name of the resource.
* `[resource index]` - an optional index into a resource with multiple * `[resource index]` - (Optional) [Index](#index-values-for-modules-and-resources)
instances, surrounded by square brace characters (`[` and `]`). into a resource with multiple instances, surrounded by square brace characters (`[` and `]`).
-> In Terraform v0.12 and later, a resource spec without a module path prefix -> In Terraform v0.12 and later, a resource spec without a module path prefix
matches only resources in the root module. In earlier versions, a resource spec matches only resources in the root module. In earlier versions, a resource spec
without a module path prefix will match resources with the same type and name without a module path prefix will match resources with the same type and name
in any descendent module. in any descendent module.
__Resource index__: ## Index values for Modules and Resources
The following specifications apply to index values on modules and resources with multiple instances:
* `[N]` where `N` is a `0`-based numerical index into a resource with multiple * `[N]` where `N` is a `0`-based numerical index into a resource with multiple
instances specified by the `count` meta-argument. Omitting an index when instances specified by the `count` meta-argument. Omitting an index when