diff --git a/website/docs/configuration/modules.html.md b/website/docs/configuration/modules.html.md index 400e7449e..a7cae0895 100644 --- a/website/docs/configuration/modules.html.md +++ b/website/docs/configuration/modules.html.md @@ -155,7 +155,7 @@ described in more detail in other sections: If not specified, the child module inherits all of the default (un-aliased) 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 future features. @@ -361,25 +361,23 @@ setting inside a `terraform` block. ## 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 # my_buckets.tf - -module "assets_bucket" { - source = "./publish_bucket" - name = "assets" -} - -module "media_bucket" { - source = "./publish_bucket" - name = "media" +module "bucket" { + for_each = toset(["assets", "media"]) + source = "./publish_bucket" + name = "${each.key}_bucket" } ``` ```hcl # publish_bucket/bucket-and-cloudfront.tf - variable "name" {} # this is the input parameter of the module 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 a bucket. -We can then instantiate the module multiple times in our configuration by -giving each instance a unique name -- here `module "assets_bucket"` and -`module "media_bucket"` -- whilst specifying the same `source` value. +We declare multiple module instances by using the `for_each` attribute, +which accepts a map (with string keys) or a set of strings as its value. Additionally, +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.` -when displayed in plan output and elsewhere in the UI. For example, the -`./publish_bucket` module contains `aws_s3_bucket.example`, and so the two -instances of this module produce S3 bucket resources with [_resource addresses_](/docs/internals/resource-addressing.html) -`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 -line, but are not valid within interpolation expressions due to the -encapsulation behavior described above. +Resources from child modules are prefixed with `module.module_name[module index]` +when displayed in plan output and elsewhere in the UI. For a module with without +`count` or `for_each`, the address will not contain the module index as the module's +name suffices to reference the module. + +In our example, the `./publish_bucket` module contains `aws_s3_bucket.example`, and so the two +instances of this module produce S3 bucket resources with [resource addresses](/docs/internals/resource-addressing.html) of `module.bucket["assets"].aws_s3_bucket.example` +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 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 deleted. -Each instance of a module may optionally have different providers passed to it -using the `providers` argument described above. This can be useful in situations -where, for example, a duplicated set of resources must be created across -several regions or datacenters. +### Limitations when using module expansion + +Modules using `count` or `for_each` cannot pass different sets of providers to different instances. +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 diff --git a/website/docs/internals/resource-addressing.html.markdown b/website/docs/internals/resource-addressing.html.markdown index e88c2cead..51ff80c97 100644 --- a/website/docs/internals/resource-addressing.html.markdown +++ b/website/docs/internals/resource-addressing.html.markdown @@ -16,19 +16,37 @@ larger infrastructure. An address is made up of two parts: [module path][resource spec] ``` -__Module path__: +## Module path 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 -without a resource spec, the address applies to every resource within the -module. If the module path is omitted, this addresses the root module. + * `module` - Module keyword indicating a child module (non-root). Multiple `module` + keywords in a path indicate nesting. + * `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: @@ -38,15 +56,17 @@ resource_type.resource_name[resource index] * `resource_type` - Type of the resource being addressed. * `resource_name` - User-defined name of the resource. - * `[resource index]` - an optional index into a resource with multiple - instances, surrounded by square brace characters (`[` and `]`). + * `[resource index]` - (Optional) [Index](#index-values-for-modules-and-resources) + 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 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 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 instances specified by the `count` meta-argument. Omitting an index when