diff --git a/website/docs/commands/0.12upgrade.html.markdown b/website/docs/commands/0.12upgrade.html.markdown index 169c469053..a36cdb0c16 100644 --- a/website/docs/commands/0.12upgrade.html.markdown +++ b/website/docs/commands/0.12upgrade.html.markdown @@ -71,7 +71,7 @@ the change. Once upgraded the configuration will no longer be compatible with Terraform v0.11 and earlier. When upgrading a shared module that is called from multiple configurations, you may need to -[fix existing configurations to a previous version](/docs/modules/usage.html#module-versions) +[fix existing configurations to a previous version](/docs/configuration/modules.html#module-versions) to allow for a gradual upgrade. If the module is published via [a Terraform registry](/docs/registry/), assign a new _major_ version number to the upgraded module source to represent the fact that this is a breaking diff --git a/website/docs/configuration-0-11/environment-variables.html.md b/website/docs/configuration-0-11/environment-variables.html.md index fce09890a4..083d950489 100644 --- a/website/docs/configuration-0-11/environment-variables.html.md +++ b/website/docs/configuration-0-11/environment-variables.html.md @@ -54,7 +54,7 @@ When given a value, causes terraform commands to behave as if the `-module-depth export TF_MODULE_DEPTH=0 ``` -For more information regarding modules, check out the section on [Using Modules](/docs/modules/usage.html). +For more information regarding modules, see [Configuration Language: Modules](/docs/configuration/modules.html). ## TF_VAR_name diff --git a/website/docs/configuration-0-11/modules.html.md b/website/docs/configuration-0-11/modules.html.md index 4cbbd1f4d2..942c13f0af 100644 --- a/website/docs/configuration-0-11/modules.html.md +++ b/website/docs/configuration-0-11/modules.html.md @@ -12,43 +12,138 @@ description: |- and later, see [Configuration Language: Modules](../configuration/modules.html). -Modules are used in Terraform to modularize and encapsulate groups of -resources in your infrastructure. For more information on modules, see -the dedicated -[modules section](/docs/modules/index.html). +A _module_ is a container for multiple resources that are used together. -This page assumes you're familiar with the -[configuration syntax](./syntax.html) -already. +Every Terraform configuration has at least one module, known as its +_root module_, which consists of the resources defined in the `.tf` files in +the main working directory. -## Example +A module can call other modules, which lets you include the child module's +resources into the configuration in a concise way. Modules +can also be called multiple times, either within the same configuration or +in separate configurations, allowing resource configurations to be packaged +and re-used. + +This page describes how to call one module from another. Other pages in this +section of the documentation describe the different elements that make up +modules, and there is further information about how modules can be used, +created, and published in [the dedicated _Modules_ section](/docs/modules/index.html). + +## Calling a Child Module + +To _call_ a module means to include the contents of that module into the +configuration with specific values for its +[input variables](./variables.html). Modules are called +from within other modules using `module` blocks: + +```hcl +module "servers" { + source = "./app-cluster" + + servers = 5 +} +``` + +A module that includes a `module` block like this is the _calling module_ of the +child module. + +The label immediately after the `module` keyword is a local name, which the +calling module can use to refer to this instance of the module. + +Within the block body (between `{` and `}`) are the arguments for the module. +Most of the arguments correspond to [input variables](./variables.html) +defined by the module, including the `servers` argument in the above example. +Terraform also defines a few meta-arguments that are reserved by Terraform +and used for its own purposes; we will discuss those throughout the rest of +this section. + +All modules require a `source` argument, which is a meta-argument defined by +Terraform CLI. Its value is either the path to a local directory of the +module's configuration files, or a remote module source that Terraform should +download and use. This value must be a literal string with no template +sequences; arbitrary expressions are not allowed. For more information on +possible values for this argument, see [Module Sources](/docs/modules/sources.html). + +The same source address can be specified in multiple `module` blocks to create +multiple copies of the resources defined within, possibly with different +variable values. + +After adding, removing, or modifying `module` blocks, you must re-run +`terraform init` to allow Terraform the opportunity to adjust the installed +modules. By default this command will not upgrade an already-installed module; +use the `-upgrade` option to instead upgrade to the newest available version. + +## Accessing Module Output Values + +The resources defined in a module are encapsulated, so the calling module +cannot access their attributes directly. However, the child module can +declare [output values](./outputs.html) to selectively +export certain values to be accessed by the calling module. + +For example, if the `./app-cluster` module referenced in the example above +exported an output value named `instance_ids` then the calling module +can reference that result using the expression `module.servers.instance_ids`: ```hcl +resource "aws_elb" "example" { + # ... + + instances = module.servers.instance_ids +} +``` + +For more information about referring to named values, see +[Expressions](./expressions.html). + +## Module Versions + +We recommend explicitly constraining the acceptable version numbers for +each external module to avoid unexpected or unwanted changes. + +Use the `version` attribute in the `module` block to specify versions: + +```shell module "consul" { source = "hashicorp/consul/aws" - servers = 5 + version = "0.0.5" + + servers = 3 } ``` -## Description +The `version` attribute value may either be a single explicit version or +a version constraint expression. Constraint expressions use the following +syntax to specify a _range_ of versions that are acceptable: + +* `>= 1.2.0`: version 1.2.0 or newer +* `<= 1.2.0`: version 1.2.0 or older +* `~> 1.2.0`: any non-beta version `>= 1.2.0` and `< 1.3.0`, e.g. `1.2.X` +* `~> 1.2`: any non-beta version `>= 1.2.0` and `< 2.0.0`, e.g. `1.X.Y` +* `>= 1.0.0, <= 2.0.0`: any version between 1.0.0 and 2.0.0 inclusive + +When depending on third-party modules, references to specific versions are +recommended since this ensures that updates only happen when convenient to you. -A `module` block instructs Terraform to create an instance of a module, -and in turn to instantiate any resources defined within it. +For modules maintained within your organization, a version range strategy +may be appropriate if a semantic versioning methodology is used consistently +or if there is a well-defined release process that avoids unwanted updates. -The name given in the block header is used to reference the particular module -instance from expressions within the calling module, and to refer to the -module on the command line. It has no meaning outside of a particular -Terraform configuration. +Version constraints are supported only for modules installed from a module +registry, such as the [Terraform Registry](https://registry.terraform.io/) or +[Terraform Enterprise's private module registry](/docs/enterprise/registry/index.html). +Other module sources can provide their own versioning mechanisms within the +source string itself, or might not support versions at all. In particular, +modules sourced from local file paths do not support `version`; since +they're loaded from the same source repository, they always share the same +version as their caller. -Within the block body is the configuration for the module. All attributes -within the block must correspond to [variables](./variables.html) -within the module, with the exception of the following which Terraform -treats as special: +## Other Meta-arguments -* `source` - (Required) A [module source](/docs/modules/sources.html) string - specifying the location of the child module source code. +Along with the `source` meta-argument described above, module blocks have +some more meta-arguments that have special meaning across all modules, +described in more detail in other sections: -* `version` - (Optional) A [version constraint](/docs/modules/usage.html#module-versions) +* `version` - (Optional) A [version constraint](#module-versions) string that specifies which versions of the referenced module are acceptable. The newest version matching the constraint will be used. `version` is supported only for modules retrieved from module registries. @@ -56,6 +151,266 @@ treats as special: * `providers` - (Optional) A map whose keys are provider configuration names that are expected by child module and whose values are corresponding provider names in the calling module. This allows - [provider configurations to be passed explicitly to child modules](/docs/modules/usage.html#providers-within-modules). + [provider configurations to be passed explicitly to child modules](#passing-providers-explicitly). 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 +`lifecycle` are not currently used by Terraform but are reserved for planned +future features. + +Since modules are a complex feature in their own right, further detail +about how modules can be used, created, and published is included in +[the dedicated section on modules](/docs/modules/index.html). + +## Providers within Modules + +In a configuration with multiple modules, there are some special considerations +for how resources are associated with provider configurations. + +While in principle `provider` blocks can appear in any module, it is recommended +that they be placed only in the _root_ module of a configuration, since this +approach allows users to configure providers just once and re-use them across +all descendent modules. + +Each resource in the configuration must be associated with one provider +configuration, which may either be within the same module as the resource +or be passed from the parent module. Providers can be passed down to descendent +modules in two ways: either _implicitly_ through inheritance, or _explicitly_ +via the `providers` argument within a `module` block. These two options are +discussed in more detail in the following sections. + +In all cases it is recommended to keep explicit provider configurations only in +the root module and pass them (whether implicitly or explicitly) down to +descendent modules. This avoids the provider configurations from being "lost" +when descendent modules are removed from the configuration. It also allows +the user of a configuration to determine which providers require credentials +by inspecting only the root module. + +Provider configurations are used for all operations on associated resources, +including destroying remote objects and refreshing state. Terraform retains, as +part of its state, a reference to the provider configuration that was most +recently used to apply changes to each resource. When a `resource` block is +removed from the configuration, this record in the state is used to locate the +appropriate configuration because the resource's `provider` argument (if any) +is no longer present in the configuration. + +As a consequence, it is required that all resources created for a particular +provider configuration must be destroyed before that provider configuration is +removed, unless the related resources are re-configured to use a different +provider configuration first. + +### Implicit Provider Inheritance + +For convenience in simple configurations, a child module automatically inherits +default (un-aliased) provider configurations from its parent. This means that +explicit `provider` blocks appear only in the root module, and downstream +modules can simply declare resources for that provider and have them +automatically associated with the root provider configurations. + +For example, the root module might contain only a `provider` block and a +`module` block to instantiate a child module: + +```hcl +provider "aws" { + region = "us-west-1" +} + +module "child" { + source = "./child" +} +``` + +The child module can then use any resource from this provider with no further +provider configuration required: + +```hcl +resource "aws_s3_bucket" "example" { + bucket = "provider-inherit-example" +} +``` + +This approach is recommended in the common case where only a single +configuration is needed for each provider across the entire configuration. + +In more complex situations there may be [multiple provider instances](/docs/configuration/providers.html#multiple-provider-instances), +or a child module may need to use different provider settings than +its parent. For such situations, it's necessary to pass providers explicitly +as we will see in the next section. + +## Passing Providers Explicitly + +When child modules each need a different configuration of a particular +provider, or where the child module requires a different provider configuration +than its parent, the `providers` argument within a `module` block can be +used to define explicitly which provider configs are made available to the +child module. For example: + +```hcl +# The default "aws" configuration is used for AWS resources in the root +# module where no explicit provider instance is selected. +provider "aws" { + region = "us-west-1" +} + +# A non-default, or "aliased" configuration is also defined for a different +# region. +provider "aws" { + alias = "usw2" + region = "us-west-2" +} + +# An example child module is instantiated with the _aliased_ configuration, +# so any AWS resources it defines will use the us-west-2 region. +module "example" { + source = "./example" + providers = { + aws = "aws.usw2" + } +} +``` + +The `providers` argument within a `module` block is similar to +the `provider` argument within a resource as described for +[multiple provider instances](/docs/configuration/providers.html#multiple-provider-instances), +but is a map rather than a single string because a module may contain resources +from many different providers. + +Once the `providers` argument is used in a `module` block, it overrides all of +the default inheritance behavior, so it is necessary to enumerate mappings +for _all_ of the required providers. This is to avoid confusion and surprises +that may result when mixing both implicit and explicit provider passing. + +Additional provider configurations (those with the `alias` argument set) are +_never_ inherited automatically by child modules, and so must always be passed +explicitly using the `providers` map. For example, a module +that configures connectivity between networks in two AWS regions is likely +to need both a source and a destination region. In that case, the root module +may look something like this: + +```hcl +provider "aws" { + alias = "usw1" + region = "us-west-1" +} + +provider "aws" { + alias = "usw2" + region = "us-west-2" +} + +module "tunnel" { + source = "./tunnel" + providers = { + aws.src = "aws.usw1" + aws.dst = "aws.usw2" + } +} +``` + +In the `providers` map, the keys are provider names as expected by the child +module, while the values are the names of corresponding configurations in +the _current_ module. The subdirectory `./tunnel` must then contain +_proxy configuration blocks_ like the following, to declare that it +requires configurations to be passed with these from the `providers` block in +the parent's `module` block: + +```hcl +provider "aws" { + alias = "src" +} + +provider "aws" { + alias = "dst" +} +``` + +Each resource should then have its own `provider` attribute set to either +`"aws.src"` or `"aws.dst"` to choose which of the two provider instances to use. + +At this time it is required to write an explicit proxy configuration block +even for default (un-aliased) provider configurations when they will be passed +via an explicit `providers` block: + +```hcl +provider "aws" { +} +``` + +If such a block is not present, the child module will behave as if it has no +configurations of this type at all, which may cause input prompts to supply +any required provider configuration arguments. This limitation will be +addressed in a future version of Terraform. + +## Multiple Instances of a Module + +A particular module source can be instantiated multiple times: + +```hcl +# my_buckets.tf + +module "assets_bucket" { + source = "./publish_bucket" + name = "assets" +} + +module "media_bucket" { + source = "./publish_bucket" + name = "media" +} +``` + +```hcl +# publish_bucket/bucket-and-cloudfront.tf + +variable "name" {} # this is the input parameter of the module + +resource "aws_s3_bucket" "example" { + # ... +} + +resource "aws_iam_user" "deploy_user" { + # ... +} +``` + +This example defines a local child module in the `./publish_bucket` +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. + +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. + +When refactoring an existing configuration to introduce modules, moving +resource blocks between modules causes Terraform to see the new location +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. + +## Tainting resources within a module + +The [taint command](/docs/commands/taint.html) can be used to _taint_ specific +resources within a module: + +```shell +$ terraform taint -module=salt_master aws_instance.salt_master +``` + +It is not possible to taint an entire module. Instead, each resource within +the module must be tainted separately. diff --git a/website/docs/configuration-0-11/providers.html.md b/website/docs/configuration-0-11/providers.html.md index f9577d22bb..d74aba634b 100644 --- a/website/docs/configuration-0-11/providers.html.md +++ b/website/docs/configuration-0-11/providers.html.md @@ -190,7 +190,7 @@ alias separated by a period, such as `"aws.west"` above. Provider configurations may also be passed from a parent module into a child module, as described in -[_Providers within Modules_](/docs/modules/usage.html#providers-within-modules). +[_Providers within Modules_](./modules.html#providers-within-modules). ## Interpolation diff --git a/website/docs/configuration/modules.html.md b/website/docs/configuration/modules.html.md index b77d1cad1c..f1760e50ac 100644 --- a/website/docs/configuration/modules.html.md +++ b/website/docs/configuration/modules.html.md @@ -143,7 +143,7 @@ Along with the `source` meta-argument described above, module blocks have some more meta-arguments that have special meaning across all modules, described in more detail in other sections: -* `version` - (Optional) A [version constraint](/docs/modules/usage.html#module-versions) +* `version` - (Optional) A [version constraint](#module-versions) string that specifies which versions of the referenced module are acceptable. The newest version matching the constraint will be used. `version` is supported only for modules retrieved from module registries. @@ -151,7 +151,7 @@ described in more detail in other sections: * `providers` - (Optional) A map whose keys are provider configuration names that are expected by child module and whose values are corresponding provider names in the calling module. This allows - [provider configurations to be passed explicitly to child modules](/docs/modules/usage.html#providers-within-modules). + [provider configurations to be passed explicitly to child modules](#passing-providers-explicitly). If not specified, the child module inherits all of the default (un-aliased) provider configurations from the calling module. diff --git a/website/docs/configuration/providers.html.md b/website/docs/configuration/providers.html.md index 5a60cd34ca..d8b6771d26 100644 --- a/website/docs/configuration/providers.html.md +++ b/website/docs/configuration/providers.html.md @@ -225,7 +225,7 @@ module "aws_vpc" { ``` Modules have some special requirements when passing in providers; see -[Providers within Modules](/docs/modules/usage.html#providers-within-modules) +[Providers within Modules](./modules.html#providers-within-modules) for more details. In most cases, only _root modules_ should define provider configurations, with all child modules obtaining their provider configurations from their parents. diff --git a/website/docs/modules/sources.html.markdown b/website/docs/modules/sources.html.markdown index 24d15a18ff..d37540007b 100644 --- a/website/docs/modules/sources.html.markdown +++ b/website/docs/modules/sources.html.markdown @@ -120,7 +120,7 @@ access your Terraform Enterprise instance. Registry modules support versioning. You can provide a specific version as shown in the above examples, or use flexible -[version constraints](/docs/modules/usage.html#module-versions). +[version constraints](/docs/configuration/modules.html#module-versions). You can learn more about the registry at the [Terraform Registry documentation](/docs/registry/modules/use.html#using-modules). diff --git a/website/docs/registry/modules/publish.html.md b/website/docs/registry/modules/publish.html.md index c0d3431685..093edc5d99 100644 --- a/website/docs/registry/modules/publish.html.md +++ b/website/docs/registry/modules/publish.html.md @@ -45,7 +45,7 @@ to populate the short description of the module. This should be a simple one sentence description of the module. - **Standard module structure.** The module must adhere to the -[standard module structure](/docs/modules/create.html#standard-module-structure). +[standard module structure](/docs/modules/index.html#standard-module-structure). This allows the registry to inspect your module and generate documentation, track resource usage, parse submodules and examples, and more. diff --git a/website/docs/registry/modules/use.html.md b/website/docs/registry/modules/use.html.md index 9623d7fb08..bf6b721bf8 100644 --- a/website/docs/registry/modules/use.html.md +++ b/website/docs/registry/modules/use.html.md @@ -76,7 +76,7 @@ follow [semantic versioning](http://semver.org/). In addition to pure syntax, we encourage all modules to follow the full guidelines of semantic versioning. Terraform since version 0.11 will resolve any provided -[module version constraints](/docs/modules/usage.html#module-versions) and +[module version constraints](/docs/configuration/modules.html#module-versions) and using them is highly recommended to avoid pulling in breaking changes. Terraform versions after 0.10.6 but before 0.11 have partial support for the registry diff --git a/website/docs/registry/private.html.md b/website/docs/registry/private.html.md index 1d7380bde5..5e296e6a71 100644 --- a/website/docs/registry/private.html.md +++ b/website/docs/registry/private.html.md @@ -14,7 +14,7 @@ can't, shouldn't, or don't need to be public. You can load private modules [directly from version control and other sources](/docs/modules/sources.html), but those sources don't support [version -constraints](/docs/modules/usage.html#module-versions) or a browsable +constraints](/docs/configuration/modules.html#module-versions) or a browsable marketplace of modules, both of which are important for enabling a producers-and-consumers content model in a large organization. diff --git a/website/upgrade-guides/0-11.html.markdown b/website/upgrade-guides/0-11.html.markdown index b57c241845..e70b92c18a 100644 --- a/website/upgrade-guides/0-11.html.markdown +++ b/website/upgrade-guides/0-11.html.markdown @@ -96,7 +96,7 @@ situations: * If a `provider` block is present in a child module, it must either contain a complete configuration for its associated provider or a configuration must be passed from the parent module using - [the new `providers` attribute](/docs/modules/usage.html#providers-within-modules). + [the new `providers` attribute](/docs/configuration-0-11/modules.html#providers-within-modules). In the latter case, an empty provider block is a placeholder that declares that the child module requires a configuration to be passed from its parent. @@ -157,7 +157,7 @@ now inherit only as a whole, rather than on a per-argument basis. **Action**: In existing configurations where a descendent module inherits _aliased_ providers from an ancestor module, use -[the new `providers` attribute](/docs/modules/usage.html#providers-within-modules) +[the new `providers` attribute](/docs/configuration-0-11/modules.html#providers-within-modules) to explicitly pass those aliased providers. **Action**: Consider refactoring existing configurations so that all provider @@ -266,7 +266,7 @@ to actual infrastructure, since no resource configurations were changed. For more details on the explicit `providers` map, and discussion of more complex possibilities such as child modules with additional (aliased) provider -configurations, see [_Providers Within Modules_](/docs/modules/usage.html#providers-within-modules). +configurations, see [_Providers Within Modules_](/docs/configuration-0-11/modules.html#providers-within-modules). ## Error Checking for Output Values