Merge pull request #26902 from hashicorp/nov20_breakup_exprs_resources_and_modules

website: TF-153: Break up expressions, resources, and modules pages
This commit is contained in:
Nick Fagerlund 2020-11-17 16:36:19 -08:00 committed by GitHub
commit 6a847df392
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 3106 additions and 2432 deletions

View File

@ -15,7 +15,7 @@ potentially save you time and effort.
- [The `terraform console` command](/docs/commands/console.html) starts an
interactive shell for evaluating Terraform
[expressions](/docs/configuration/expressions.html), which can be a faster way
[expressions](/docs/configuration/expressions/index.html), which can be a faster way
to verify that a particular resource argument results in the value you expect.

View File

@ -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/configuration/modules.html#module-versions)
[fix existing configurations to a previous version](/docs/configuration/blocks/modules/syntax.html#version)
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

View File

@ -10,14 +10,14 @@ description: |-
# Command: console
The `terraform console` command provides an interactive console for
evaluating [expressions](/docs/configuration/expressions.html).
evaluating [expressions](/docs/configuration/expressions/index.html).
## Usage
Usage: `terraform console [options]`
This command provides an interactive command-line console for evaluating and
experimenting with [expressions](/docs/configuration/expressions.html).
experimenting with [expressions](/docs/configuration/expressions/index.html).
This is useful for testing interpolations before using them in configurations,
and for interacting with any values currently saved in
[state](/docs/state/index.html).

View File

@ -133,7 +133,7 @@ $ terraform import module.foo.aws_instance.bar i-abcd1234
## Example: Import into Resource configured with count
The example below will import an AWS instance into the first instance of the `aws_instance` resource named `baz` configured with
[`count`](/docs/configuration/resources.html#count-multiple-resource-instances-by-count):
[`count`](/docs/configuration/meta-arguments/count.html):
```shell
$ terraform import 'aws_instance.baz[0]' i-abcd1234
@ -142,7 +142,7 @@ $ terraform import 'aws_instance.baz[0]' i-abcd1234
## Example: Import into Resource configured with for_each
The example below will import an AWS instance into the `"example"` instance of the `aws_instance` resource named `baz` configured with
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
[`for_each`](/docs/configuration/meta-arguments/for_each.html):
Linux, Mac OS, and UNIX:

View File

@ -95,7 +95,7 @@ $ terraform state mv -state-out=other.tfstate 'module.app' 'module.app'
## Example: Move a Resource configured with count
The example below moves the first instance of a `packet_device` resource named `worker` configured with
[`count`](/docs/configuration/resources.html#count-multiple-resource-instances-by-count) to
[`count`](/docs/configuration/meta-arguments/count.html) to
the first instance of a resource named `helper` also configured with `count`:
```shell
@ -105,7 +105,7 @@ $ terraform state mv 'packet_device.worker[0]' 'packet_device.helper[0]'
## Example: Move a Resource configured with for_each
The example below moves the `"example123"` instance of a `packet_device` resource named `worker` configured with
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
[`for_each`](/docs/configuration/meta-arguments/for_each.html)
to the `"example456"` instance of a resource named `helper` also configuring `for_each`:
Linux, Mac OS, and UNIX:

View File

@ -78,7 +78,7 @@ $ terraform state rm 'module.foo.packet_device.worker'
## Example: Remove a Resource configured with count
The example below removes the first instance of a `packet_device` resource named `worker` configured with
[`count`](/docs/configuration/resources.html#count-multiple-resource-instances-by-count):
[`count`](/docs/configuration/meta-arguments/count.html):
```shell
$ terraform state rm 'packet_device.worker[0]'
@ -87,7 +87,7 @@ $ terraform state rm 'packet_device.worker[0]'
## Example: Remove a Resource configured with for_each
The example below removes the `"example"` instance of a `packet_device` resource named `worker` configured with
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
[`for_each`](/docs/configuration/meta-arguments/for_each.html):
Linux, Mac OS, and UNIX:

View File

@ -61,7 +61,7 @@ $ terraform state show 'module.foo.packet_device.worker'
## Example: Show a Resource configured with count
The example below shows the first instance of a `packet_device` resource named `worker` configured with
[`count`](/docs/configuration/resources.html#count-multiple-resource-instances-by-count):
[`count`](/docs/configuration/meta-arguments/count.html):
```shell
$ terraform state show 'packet_device.worker[0]'
@ -70,7 +70,7 @@ $ terraform state show 'packet_device.worker[0]'
## Example: Show a Resource configured with for_each
The example below shows the `"example"` instance of a `packet_device` resource named `worker` configured with
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
[`for_each`](/docs/configuration/meta-arguments/for_each.html):
Linux, Mac OS, and UNIX:

View File

@ -10,7 +10,7 @@ description: |-
-> **Note:** This page is about Terraform 0.11 and earlier. For Terraform 0.12
and later, see
[Configuration Language: Expressions](../configuration/expressions.html) and
[Configuration Language: Expressions](/docs/configuration/expressions/index.html) and
[Configuration Language: Functions](../configuration/functions.html).
Embedded within strings in Terraform, whether you're using the

View File

@ -153,7 +153,7 @@ example = [
For the arguments that use the attributes-as-blocks usage mode, the above is
a better pattern than using
[`dynamic` blocks](/docs/configuration/expressions.html#dynamic-blocks)
[`dynamic` blocks](/docs/configuration/expressions/dynamic-blocks.html)
because the case where the
caller provides an empty list will result in explicitly assigning an empty
list value, rather than assigning no value at all and thus retaining and

View File

@ -48,12 +48,20 @@ module registry for sharing modules internally within your organization.
## Using Modules
- [Module Blocks](/docs/configuration/modules.html) documents the syntax for
- [Module Blocks](/docs/configuration/blocks/modules/syntax.html) documents the syntax for
calling a child module from a parent module, including meta-arguments like
`for_each`.
- [Module Sources](/docs/modules/sources.html) documents what kinds of paths,
addresses, and URIs can be used in the `source` argument of a module block.
- The Meta-Arguments section documents special arguments that can be used with
every module, including
[`providers`](/docs/configuration/meta-arguments/module-providers.html),
[`depends_on`](/docs/configuration/meta-arguments/depends_on.html),
[`count`](/docs/configuration/meta-arguments/count.html),
and [`for_each`](/docs/configuration/meta-arguments/for_each.html).
## Developing Modules
For information about developing reusable modules, see

View File

@ -0,0 +1,201 @@
---
layout: "language"
page_title: "Modules - Configuration Language"
sidebar_current: "docs-config-modules"
description: |-
Modules allow multiple resources to be grouped together and encapsulated.
---
# Module Blocks
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
earlier, see
[0.11 Configuration Language: Modules](../configuration-0-11/modules.html).
> **Hands-on:** Try the [Reuse Configuration with Modules](https://learn.hashicorp.com/collections/terraform/modules?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
A _module_ is a container for multiple resources that are used together.
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.
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. For more information
about creating re-usable child modules, see [Module Development](/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](/docs/configuration/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.
Module calls use the following kinds of arguments:
- The `source` argument is mandatory for all modules.
- The `version` argument is recommended for modules from a registry.
- Most other arguments correspond to [input variables](/docs/configuration/variables.html)
defined by the module. (The `servers` argument in the example above is one of
these.)
- Terraform defines a few other meta-arguments that can be used with all
modules, including `for_each` and `depends_on`.
### Source
All modules **require** a `source` argument, which is a meta-argument defined by
Terraform. Its value is either the path to a local directory containing 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.
### Version
When using modules installed from a module registry, we recommend explicitly
constraining the acceptable version numbers to avoid unexpected or unwanted
changes.
Use the `version` argument in the `module` block to specify versions:
```shell
module "consul" {
source = "hashicorp/consul/aws"
version = "0.0.5"
servers = 3
}
```
The `version` argument accepts a [version constraint string](/docs/configuration/version-constraints.html).
Terraform will use the newest installed version of the module that meets the
constraint; if no acceptable versions are installed, it will download the newest
version that meets the constraint.
Version constraints are supported only for modules installed from a module
registry, such as the public [Terraform Registry](https://registry.terraform.io/)
or [Terraform Cloud's private module registry](/docs/cloud/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.
### Meta-arguments
Along with `source` and `version`, Terraform defines a few more
optional meta-arguments that have special meaning across all modules,
described in more detail in the following pages:
- `count` - Creates multiple instances of a module from a single `module` block.
See [the `count` page](/docs/configuration/meta-arguments/count.html)
for details.
- `for_each` - Creates multiple instances of a module from a single `module`
block. See
[the `for_each` page](/docs/configuration/meta-arguments/for_each.html)
for details.
- `providers` - Passes provider configurations to a child module. See
[the `providers` page](/docs/configuration/meta-arguments/module-providers.html)
for details. If not specified, the child module inherits all of the default
(un-aliased) provider configurations from the calling module.
- `depends_on` - Creates explicit dependencies between the entire
module and the listed targets. See
[the `depends_on` page](/docs/configuration/meta-arguments/depends_on.html)
for details.
In addition to the above, the `lifecycle` argument is not currently used by
Terraform but is reserved for planned future features.
## 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](/docs/configuration/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](/docs/configuration/expressions/index.html).
## Transferring Resource State Into Modules
When refactoring an existing configuration to split code into child modules,
moving resource blocks between modules causes Terraform to see the new location
as an entirely different resource from the old. Always check the execution plan
after moving code across modules to ensure that no resources are deleted by
surprise.
If you want to make sure an existing resource is preserved, use
[the `terraform state mv` command](/docs/commands/state/mv.html) to inform
Terraform that it has moved to a different module.
When passing resource addresses to `terraform state mv`, resources within child
modules must be prefixed with `module.<MODULE NAME>.`. If a module was called with
[`count`](/docs/configuration/meta-arguments/count.html) or
[`for_each`](/docs/configuration/meta-arguments/for_each.html),
its resource addresses must be prefixed with `module.<MODULE NAME>[<INDEX>].`
instead, where `<INDEX>` matches the `count.index` or `each.key` value of a
particular module instance.
Full resource addresses for module contents are used within the UI and on the
command line, but cannot be used within a Terraform configuration. Only
[outputs](/docs/configuration/outputs.html) from a module can be referenced from
elsewhere in your configuration.
## 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.

View File

@ -13,7 +13,7 @@ configuration (like endpoint URLs or cloud regions) before they can be used.
## What Providers Do
Each provider adds a set of [resource types](/docs/configuration/resources.html)
Each provider adds a set of [resource types](/docs/configuration/blocks/resources/index.html)
and/or [data sources](/docs/configuration/data-sources.html) that Terraform can
manage.

View File

@ -0,0 +1,107 @@
---
layout: "language"
page_title: "Resource Behavior - Configuration Language"
---
# Resource Behavior
A `resource` block declares that you want a particular infrastructure object
to exist with the given settings. If you are writing a new configuration for
the first time, the resources it defines will exist _only_ in the configuration,
and will not yet represent real infrastructure objects in the target platform.
_Applying_ a Terraform configuration is the process of creating, updating,
and destroying real infrastructure objects in order to make their settings
match the configuration.
## How Terraform Applies a Configuration
When Terraform creates a new infrastructure object represented by a `resource`
block, the identifier for that real object is saved in Terraform's
[state](/docs/state/index.html), allowing it to be updated and destroyed
in response to future changes. For resource blocks that already have an
associated infrastructure object in the state, Terraform compares the
actual configuration of the object with the arguments given in the
configuration and, if necessary, updates the object to match the configuration.
In summary, applying a Terraform configuration will:
- _Create_ resources that exist in the configuration but are not associated with a real infrastructure object in the state.
- _Destroy_ resources that exist in the state but no longer exist in the configuration.
- _Update in-place_ resources whose arguments have changed.
- _Destroy and re-create_ resources whose arguments have changed but which cannot be updated in-place due to remote API limitations.
This general behavior applies for all resources, regardless of type. The
details of what it means to create, update, or destroy a resource are different
for each resource type, but this standard set of verbs is common across them
all.
The meta-arguments within `resource` blocks, documented in the
sections below, allow some details of this standard resource behavior to be
customized on a per-resource basis.
## Accessing Resource Attributes
[Expressions](/docs/configuration/expressions/index.html) within a Terraform module can access
information about resources in the same module, and you can use that information
to help configure other resources. Use the `<RESOURCE TYPE>.<NAME>.<ATTRIBUTE>`
syntax to reference a resource attribute in an expression.
In addition to arguments specified in the configuration, resources often provide
read-only attributes with information obtained from the remote API; this often
includes things that can't be known until the resource is created, like the
resource's unique random ID.
Many providers also include [data sources](./data-sources.html), which are a
special type of resource used only for looking up information.
For a list of the attributes a resource or data source type provides, consult
its documentation; these are generally included in a second list below its list
of configurable arguments.
For more information about referencing resource attributes in expressions, see
[Expressions: References to Resource Attributes](/docs/configuration/expressions/references.html#references-to-resource-attributes).
## Resource Dependencies
Most resources in a configuration don't have any particular relationship, and
Terraform can make changes to several unrelated resources in parallel.
However, some resources must be processed after other specific resources;
sometimes this is because of how the resource works, and sometimes the
resource's configuration just requires information generated by another
resource.
Most resource dependencies are handled automatically. Terraform analyses any
[expressions](/docs/configuration/expressions/index.html) within a `resource` block to find references
to other objects, and treats those references as implicit ordering requirements
when creating, updating, or destroying resources. Since most resources with
behavioral dependencies on other resources also refer to those resources' data,
it's usually not necessary to manually specify dependencies between resources.
However, some dependencies cannot be recognized implicitly in configuration. For
example, if Terraform must manage access control policies _and_ take actions
that require those policies to be present, there is a hidden dependency between
the access policy and a resource whose creation depends on it. In these rare
cases, [the `depends_on` meta-argument](./depends_on.html) can explicitly specify a
dependency.
## Local-only Resources
While most resource types correspond to an infrastructure object type that
is managed via a remote network API, there are certain specialized resource
types that operate only within Terraform itself, calculating some results and
saving those results in the state for future use.
For example, local-only resource types exist for
[generating private keys](/docs/providers/tls/r/private_key.html),
[issuing self-signed TLS certificates](/docs/providers/tls/r/self_signed_cert.html),
and even [generating random ids](/docs/providers/random/r/id.html).
While these resource types often have a more marginal purpose than those
managing "real" infrastructure objects, they can be useful as glue to help
connect together other resources.
The behavior of local-only resources is the same as all other resources, but
their result data exists only within the Terraform state. "Destroying" such
a resource means only to remove it from the state, discarding its data.

View File

@ -12,8 +12,21 @@ Each resource block describes one or more infrastructure objects, such
as virtual networks, compute instances, or higher-level components such
as DNS records.
- [Resource Blocks](/docs/configuration/resources.html) documents how to declare
resources, including information about meta-arguments like `for_each`.
- [Resource Blocks](/docs/configuration/blocks/resources/syntax.html) documents
the syntax for declaring resources.
- [Resource Behavior](/docs/configuration/resources/behavior.html) explains in
more detail how Terraform handles resource declarations when applying a
configuration.
- The Meta-Arguments section documents special arguments that can be used with
every resource type, including
[`depends_on`](/docs/configuration/meta-arguments/depends_on.html),
[`count`](/docs/configuration/meta-arguments/count.html),
[`for_each`](/docs/configuration/meta-arguments/for_each.html),
[`provider`](/docs/configuration/meta-arguments/resource-provider.html),
and [`lifecycle`](/docs/configuration/meta-arguments/lifecycle.html).
- [Provisioners](/docs/configuration/blocks/resources/provisioners/index.html)
documents configuring post-creation actions for a resource using the
`provisioner` and `connection` blocks. Since provisioners are non-declarative

View File

@ -0,0 +1,171 @@
---
layout: "language"
page_title: "Resources - Configuration Language"
sidebar_current: "docs-config-resources"
description: |-
Resources are the most important element in a Terraform configuration.
Each resource corresponds to an infrastructure object, such as a virtual
network or compute instance.
---
# Resource Blocks
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
earlier, see
[0.11 Configuration Language: Resources](../configuration-0-11/resources.html).
> **Hands-on:** Try the [Terraform: Get Started](https://learn.hashicorp.com/collections/terraform/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
_Resources_ are the most important element in the Terraform language.
Each resource block describes one or more infrastructure objects, such
as virtual networks, compute instances, or higher-level components such
as DNS records.
## Resource Syntax
Resource declarations can include a number of advanced features, but only
a small subset are required for initial use. More advanced syntax features,
such as single resource declarations that produce multiple similar remote
objects, are described later in this page.
```hcl
resource "aws_instance" "web" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
}
```
A `resource` block declares a resource of a given type ("aws_instance")
with a given local name ("web"). The name is used to refer to this resource
from elsewhere in the same Terraform module, but has no significance outside
that module's scope.
The resource type and name together serve as an identifier for a given
resource and so must be unique within a module.
Within the block body (between `{` and `}`) are the configuration arguments
for the resource itself. Most arguments in this section depend on the
resource type, and indeed in this example both `ami` and `instance_type` are
arguments defined specifically for [the `aws_instance` resource type](/docs/providers/aws/r/instance.html).
-> **Note:** Resource names must start with a letter or underscore, and may
contain only letters, digits, underscores, and dashes.
## Resource Types
Each resource is associated with a single _resource type_, which determines
the kind of infrastructure object it manages and what arguments and other
attributes the resource supports.
### Providers
Each resource type is implemented by a [provider](/docs/configuration/provider-requirements.html),
which is a plugin for Terraform that offers a collection of resource types. A
provider usually provides resources to manage a single cloud or on-premises
infrastructure platform. Providers are distributed separately from Terraform
itself, but Terraform can automatically install most providers when initializing
a working directory.
In order to manage resources, a Terraform module must specify which providers it
requires. Additionally, most providers need some configuration in order to
access their remote APIs, and the root module must provide that configuration.
For more information, see:
- [Provider Requirements](/docs/configuration/provider-requirements.html), for declaring which
providers a module uses.
- [Provider Configuration](/docs/configuration/providers.html), for configuring provider settings.
Terraform usually automatically determines which provider to use based on a
resource type's name. (By convention, resource type names start with their
provider's preferred local name.) When using multiple configurations of a
provider (or non-preferred local provider names), you must use the `provider`
meta-argument to manually choose an alternate provider configuration. See
[the `provider` meta-argument](/docs/configuration/meta-arguments/resource-provider.html) for more details.
### Resource Arguments
Most of the arguments within the body of a `resource` block are specific to the
selected resource type. The resource type's documentation lists which arguments
are available and how their values should be formatted.
The values for resource arguments can make full use of
[expressions](/docs/configuration/expressions/index.html) and other dynamic Terraform
language features.
There are also some _meta-arguments_ that are defined by Terraform itself
and apply across all resource types. (See [Meta-Arguments](#meta-arguments) below.)
### Documentation for Resource Types
Every Terraform provider has its own documentation, describing its resource
types and their arguments.
Most publicly available providers are distributed on the
[Terraform Registry](https://registry.terraform.io/browse/providers), which also
hosts their documentation. When viewing a provider's page on the Terraform
Registry, you can click the "Documentation" link in the header to browse its
documentation. Provider documentation on the registry is versioned, and you can
use the dropdown version menu in the header to switch which version's
documentation you are viewing.
To browse the publicly available providers and their documentation, see
[the providers section of the Terraform Registry](https://registry.terraform.io/browse/providers).
-> **Note:** Provider documentation used to be hosted directly on terraform.io,
as part of Terraform's core documentation. Although some provider documentation
might still be hosted here, the Terraform Registry is now the main home for all
public provider docs. (The exception is the built-in
[`terraform` provider](/docs/providers/terraform/index.html) for reading state
data, since it is not available on the Terraform Registry.)
## Resource Behavior
For more information about how Terraform manages resources when applying a
configuration, see
[Resource Behavior](/docs/configuration/blocks/resources/behavior.html).
## Meta-Arguments
The Terraform language defines several meta-arguments, which can be used with
any resource type to change the behavior of resources.
The following meta-arguments are documented on separate pages:
- [`depends_on`, for specifying hidden dependencies](/docs/configuration/meta-arguments/depends_on.html)
- [`count`, for creating multiple resource instances according to a count](/docs/configuration/meta-arguments/count.html)
- [`for_each`, to create multiple instances according to a map, or set of strings](/docs/configuration/meta-arguments/for_each.html)
- [`provider`, for selecting a non-default provider configuration](/docs/configuration/meta-arguments/resource-provider.html)
- [`lifecycle`, for lifecycle customizations](/docs/configuration/meta-arguments/lifecycle.html)
- [`provisioner` and `connection`, for taking extra actions after resource creation](/docs/configuration/blocks/resources/provisioners/index.html)
## Operation Timeouts
Some resource types provide a special `timeouts` nested block argument that
allows you to customize how long certain operations are allowed to take
before being considered to have failed.
For example, [`aws_db_instance`](/docs/providers/aws/r/db_instance.html)
allows configurable timeouts for `create`, `update` and `delete` operations.
Timeouts are handled entirely by the resource type implementation in the
provider, but resource types offering these features follow the convention
of defining a child block called `timeouts` that has a nested argument
named after each operation that has a configurable timeout value.
Each of these arguments takes a string representation of a duration, such
as `"60m"` for 60 minutes, `"10s"` for ten seconds, or `"2h"` for two hours.
```hcl
resource "aws_db_instance" "example" {
# ...
timeouts {
create = "60m"
delete = "2h"
}
}
```
The set of configurable operations is chosen by each resource type. Most
resource types do not support the `timeouts` block at all. Consult the
documentation for each resource type to see which operations it offers
for configuration, if any.

View File

@ -18,7 +18,8 @@ configuration to make use of information defined outside of Terraform,
or defined by another separate Terraform configuration.
Each [provider](./providers.html) may offer data sources
alongside its set of [resource types](./resources.html#resource-types-and-arguments).
alongside its set of [resource](/docs/configuration/blocks/resources/index.html)
types.
## Using Data Sources
@ -71,7 +72,7 @@ infrastructure platform.
Most of the items within the body of a `data` block are defined by and
specific to the selected data source, and these arguments can make full
use of [expressions](./expressions.html) and other dynamic
use of [expressions](/docs/configuration/expressions/index.html) and other dynamic
Terraform language features.
However, there are some "meta-arguments" that are defined by Terraform itself
@ -113,7 +114,7 @@ operation, and is re-calculated each time a new plan is created.
## Data Resource Dependencies
Data resources have the same dependency resolution behavior
[as defined for managed resources](./resources.html#resource-dependencies).
[as defined for managed resources](/docs/configuration/blocks/resources/behavior.html#resource-dependencies).
Setting the `depends_on` meta-argument within `data` blocks defers reading of
the data source until after all changes to the dependencies have been applied.
@ -122,8 +123,8 @@ the data source until after all changes to the dependencies have been applied.
## Multiple Resource Instances
Data resources support [`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)
Data resources support [`count`](/docs/configuration/meta-arguments/count.html)
and [`for_each`](/docs/configuration/meta-arguments/for_each.html)
meta-arguments as defined for managed resources, with the same syntax and behavior.
As with managed resources, when `count` or `for_each` is present it is important to
@ -133,7 +134,7 @@ own variant of the constraint arguments, producing an indexed result.
## Selecting a Non-default Provider Configuration
Data resources support [the `provider` meta-argument](./resources.html#provider-selecting-a-non-default-provider-configuration)
Data resources support [the `provider` meta-argument](/docs/configuration/meta-arguments/resource-provider.html)
as defined for managed resources, with the same syntax and behavior.
## Lifecycle Customizations
@ -187,13 +188,15 @@ resource "aws_instance" "web" {
## Meta-Arguments
As data sources are essentially a read only subset of resources, they also
support the same [meta-arguments](./resources.html#meta-arguments) of resources
support the same [meta-arguments](/docs/configuration/blocks/resources/syntax.html#meta-arguments) of resources
with the exception of the
[`lifecycle` configuration block](./resources.html#lifecycle-lifecycle-customizations).
[`lifecycle` configuration block](/docs/configuration/meta-arguments/lifecycle.html).
### Non-Default Provider Configurations
Similarly to [resources](./resources.html), when a module has multiple configurations for the same provider you can specify which configuration to use with the `provider` meta-argument:
Similarly to [resources](/docs/configuration/blocks/resources/index.html), when
a module has multiple configurations for the same provider you can specify which
configuration to use with the `provider` meta-argument:
```hcl
data "aws_ami" "web" {
@ -204,7 +207,7 @@ data "aws_ami" "web" {
```
See
[Resources: Selecting a Non-Default Provider Configuration](./resources.html#provider-selecting-a-non-default-provider-configuration)
[The Resource `provider` Meta-Argument](/docs/configuration/meta-arguments/resource-provider.html)
for more information.
## Data Source Lifecycle

View File

@ -14,9 +14,9 @@ dependency that come from outside of its own codebase:
* [Providers](./provider-requirements.html), which are plugins for Terraform
that extend it with support for interacting with various external systems.
* [Modules](./modules.html), which allow splitting out groups of Terraform
configuration constructs (written in the Terraform language) into reusable
abstractions.
* [Modules](/docs/configuration/blocks/modules/index.html), which allow
splitting out groups of Terraform configuration constructs (written in the
Terraform language) into reusable abstractions.
Both of these dependency types can be published and updated independently from
Terraform itself and from the configurations that depend on them. For that
@ -168,7 +168,7 @@ block in the dependency lock file.
@@ -6,6 +6,26 @@
]
}
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "2.30.0"
+ constraints = "~> 2.12"
@ -219,7 +219,7 @@ block to reflect that change.
+++ .terraform.lock.hcl 2020-10-07 16:43:42.785665945 -0700
@@ -7,22 +7,22 @@
}
provider "registry.terraform.io/hashicorp/azurerm" {
- version = "2.1.0"
- constraints = "~> 2.1.0"

View File

@ -1,905 +1,123 @@
---
layout: "language"
page_title: "Expressions - Configuration Language"
page_title: "Expressions Landing Page - Configuration Language"
sidebar_current: "docs-config-expressions"
description: |-
The Terraform language allows the use of expressions to access data exported
by resources and to transform and combine that data to produce other values.
---
# Expressions
# Expressions Landing Page
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
earlier, see
[0.11 Configuration Language: Interpolation Syntax](../configuration-0-11/interpolation.html).
To improve navigation, we've split the old Expressions page into several smaller
pages.
_Expressions_ are used to refer to or compute values within a configuration.
The simplest expressions are just literal values, like `"hello"` or `5`,
but the Terraform language also allows more complex expressions such as
references to data exported by resources, arithmetic, conditional evaluation,
and a number of built-in functions.
<a id="types-and-values"></a>
<a id="advanced-type-details"></a>
<a id="type-conversion"></a>
<a id="literal-expressions"></a>
<a id="indices-and-attributes"></a>
Expressions can be used in a number of places in the Terraform language,
but some contexts limit which expression constructs are allowed,
such as requiring a literal value of a particular type or forbidding
[references to resource attributes](/docs/configuration/expressions.html#references-to-resource-attributes).
Each language feature's documentation describes any restrictions it places on expressions.
## Types and Values, Literal Expressions, Indices and Attributes
You can experiment with the behavior of Terraform's expressions from
the Terraform expression console, by running
[the `terraform console` command](/docs/commands/console.html).
Terraform's types are `string`, `number`, `bool`, `list`, `tuple`, `map`,
`object`, and `null`.
The rest of this page describes all of the features of Terraform's
expression syntax.
This information has moved to
[Types and Values](/docs/configuration/expressions/types.html).
## Types and Values
<a id="references-to-named-values"></a>
<a id="local-named-values"></a>
<a id="named-values-and-dependencies"></a>
<a id="references-to-resource-attributes"></a>
<a id="local-named-values-1"></a>
<a id="values-not-yet-known"></a>
The result of an expression is a _value_. All values have a _type_, which
dictates where that value can be used and what transformations can be
applied to it.
## References to Named Values (Resource Attributes, Variables, etc.)
The Terraform language uses the following types for its values:
You can refer to certain values by name, like `var.some_variable` or
`aws_instance.example.ami`.
* `string`: a sequence of Unicode characters representing some text, like
`"hello"`.
* `number`: a numeric value. The `number` type can represent both whole
numbers like `15` and fractional values like `6.283185`.
* `bool`: either `true` or `false`. `bool` values can be used in conditional
logic.
* `list` (or `tuple`): a sequence of values, like
`["us-west-1a", "us-west-1c"]`. Elements in a list or tuple are identified by
consecutive whole numbers, starting with zero.
* `map` (or `object`): a group of values identified by named labels, like
`{name = "Mabel", age = 52}`.
This information has moved to
[References to Values](/docs/configuration/expressions/references.html).
Strings, numbers, and bools are sometimes called _primitive types._ Lists/tuples and maps/objects are sometimes called _complex types,_ _structural types,_ or _collection types._
Finally, there is one special value that has _no_ type:
* `null`: a value that represents _absence_ or _omission._ If you set an
argument of a resource or module to `null`, Terraform behaves as though you
had completely omitted it — it will use the argument's default value if it has
one, or raise an error if the argument is mandatory. `null` is most useful in
conditional expressions, so you can dynamically omit an argument if a
condition isn't met.
### Advanced Type Details
In most situations, lists and tuples behave identically, as do maps and objects.
Whenever the distinction isn't relevant, the Terraform documentation uses each
pair of terms interchangeably (with a historical preference for "list" and
"map").
However, module authors and provider developers should understand the
differences between these similar types (and the related `set` type), since they
offer different ways to restrict the allowed values for input variables and
resource arguments.
For complete details about these types (and an explanation of why the difference
usually doesn't matter), see [Type Constraints](./types.html).
### Type Conversion
Expressions are most often used to set values for the arguments of resources and
child modules. In these cases, the argument has an expected type and the given
expression must produce a value of that type.
Where possible, Terraform automatically converts values from one type to
another in order to produce the expected type. If this isn't possible, Terraform
will produce a type mismatch error and you must update the configuration with a
more suitable expression.
Terraform automatically converts number and bool values to strings when needed.
It also converts strings to numbers or bools, as long as the string contains a
valid representation of a number or bool value.
* `true` converts to `"true"`, and vice-versa
* `false` converts to `"false"`, and vice-versa
* `15` converts to `"15"`, and vice-versa
## Literal Expressions
A _literal expression_ is an expression that directly represents a particular
constant value. Terraform has a literal expression syntax for each of the value
types described above:
* Strings are usually represented by a double-quoted sequence of Unicode
characters, `"like this"`. There is also a "heredoc" syntax for more complex
strings. String literals are the most complex kind of literal expression in
Terraform, and have additional documentation on this page:
* See [String Literals](#string-literals) below for information about escape
sequences and the heredoc syntax.
* See [String Templates](#string-templates) below for information about
interpolation and template directives.
* Numbers are represented by unquoted sequences of digits with or without a
decimal point, like `15` or `6.283185`.
* Bools are represented by the unquoted symbols `true` and `false`.
* The null value is represented by the unquoted symbol `null`.
* Lists/tuples are represented by a pair of square brackets containing a
comma-separated sequence of values, like `["a", 15, true]`.
List literals can be split into multiple lines for readability, but always
require a comma between values. A comma after the final value is allowed,
but not required. Values in a list can be arbitrary expressions.
* Maps/objects are represented by a pair of curly braces containing a series of
`<KEY> = <VALUE>` pairs:
```hcl
{
name = "John"
age = 52
}
```
Key/value pairs can be separated by either a comma or a line break. Values
can be arbitrary expressions. Keys are strings; they can be left unquoted if
they are a valid [identifier](./syntax.html#identifiers), but must be quoted
otherwise. You can use a non-literal expression as a key by wrapping it in
parentheses, like `(var.business_unit_tag_name) = "SRE"`.
## Indices and Attributes
[inpage-index]: #indices-and-attributes
Elements of list/tuple and map/object values can be accessed using
the square-bracket index notation, like `local.list[3]`. The expression within
the brackets must be a whole number for list and tuple values or a string
for map and object values.
Map/object attributes with names that are valid identifiers can also be accessed
using the dot-separated attribute notation, like `local.object.attrname`.
In cases where a map might contain arbitrary user-specified keys, we recommend
using only the square-bracket index notation (`local.map["keyname"]`).
## References to Named Values
Terraform makes several kinds of named values available. Each of these names is
an expression that references the associated value; you can use them as
standalone expressions, or combine them with other expressions to compute new
values.
The following named values are available:
* `<RESOURCE TYPE>.<NAME>` is an object representing a
[managed resource](./resources.html) of the given type
and name. The attributes of the resource can be accessed using
[dot or square bracket notation][inpage-index].
Any named value that does not match another pattern listed below
will be interpreted by Terraform as a reference to a managed resource.
If the resource has the `count` argument set, the value of this expression
is a _list_ of objects representing its instances.
If the resource has the `for_each` argument set, the value of this expression
is a _map_ of objects representing its instances.
For more information, see
[references to resource attributes](#references-to-resource-attributes) below.
* `var.<NAME>` is the value of the
[input variable](./variables.html) of the given name.
* `local.<NAME>` is the value of the
[local value](./locals.html) of the given name.
* `module.<MODULE NAME>.<OUTPUT NAME>` is the value of the specified
[output value](./outputs.html) from a
[child module](./modules.html) called by the current module.
* `data.<DATA TYPE>.<NAME>` is an object representing a
[data resource](./data-sources.html) of the given data
source type and name. If the resource has the `count` argument set, the value
is a list of objects representing its instances. If the resource has the `for_each`
argument set, the value is a map of objects representing its instances.
* `path.module` is the filesystem path of the module where the expression
is placed.
* `path.root` is the filesystem path of the root module of the configuration.
* `path.cwd` is the filesystem path of the current working directory. In
normal use of Terraform this is the same as `path.root`, but some advanced
uses of Terraform run it from a directory other than the root module
directory, causing these paths to be different.
* `terraform.workspace` is the name of the currently selected
[workspace](/docs/state/workspaces.html).
Although many of these names use dot-separated paths that resemble
[attribute notation][inpage-index] for elements of object values, they are not
implemented as real objects. This means you must use them exactly as written:
you cannot use square-bracket notation to replace the dot-separated paths, and
you cannot iterate over the "parent object" of a named entity (for example, you
cannot use `aws_instance` in a `for` expression).
### Local Named Values
Within the bodies of certain expressions, or in some other specific contexts,
there are other named values available beyond the global values listed above.
These local names are described in the documentation for the specific contexts
where they appear. Some of most common local names are:
- `count.index`, in resources that use
[the `count` meta-argument](./resources.html#count-multiple-resource-instances-by-count).
- `each.key` / `each.value`, in resources that use
[the `for_each` meta-argument](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings).
- `self`, in [provisioner](../provisioners/index.html) and
[connection](../provisioners/connection.html) blocks.
-> **Note:** Local names are often referred to as _variables_ or
_temporary variables_ in their documentation. These are not [input
variables](./variables.html); they are just arbitrary names
that temporarily represent a value.
### Named Values and Dependencies
Constructs like resources and module calls often use references to named values
in their block bodies, and Terraform analyzes these expressions to automatically
infer dependencies between objects. For example, an expression in a resource
argument that refers to another managed resource creates an implicit dependency
between the two resources.
### References to Resource Attributes
The most common reference type is a reference to an attribute of a resource
which has been declared either with a `resource` or `data` block. Because
the contents of such blocks can be quite complicated themselves, expressions
referring to these contents can also be complicated.
Consider the following example resource block:
```hcl
resource "aws_instance" "example" {
ami = "ami-abc123"
instance_type = "t2.micro"
ebs_block_device {
device_name = "sda2"
volume_size = 16
}
ebs_block_device {
device_name = "sda3"
volume_size = 20
}
}
```
The documentation for [`aws_instance`](/docs/providers/aws/r/instance.html)
lists all of the arguments and nested blocks supported for this resource type,
and also lists a number of attributes that are _exported_ by this resource
type. All of these different resource type schema constructs are available
for use in references, as follows:
* The `ami` argument set in the configuration can be used elsewhere with
the reference expression `aws_instance.example.ami`.
* The `id` attribute exported by this resource type can be read using the
same syntax, giving `aws_instance.example.id`.
* The arguments of the `ebs_block_device` nested blocks can be accessed using
a [splat expression](#splat-expressions). For example, to obtain a list of
all of the `device_name` values, use
`aws_instance.example.ebs_block_device[*].device_name`.
* The nested blocks in this particular resource type do not have any exported
attributes, but if `ebs_block_device` were to have a documented `id`
attribute then a list of them could be accessed similarly as
`aws_instance.example.ebs_block_device[*].id`.
* Sometimes nested blocks are defined as taking a logical key to identify each
block, which serves a similar purpose as the resource's own name by providing
a convenient way to refer to that single block in expressions. If `aws_instance`
had a hypothetical nested block type `device` that accepted such a key, it
would look like this in configuration:
```hcl
device "foo" {
size = 2
}
device "bar" {
size = 4
}
```
Arguments inside blocks with _keys_ can be accessed using index syntax, such
as `aws_instance.example.device["foo"].size`.
To obtain a map of values of a particular argument for _labelled_ nested
block types, use a [`for` expression](#for-expressions):
`{for k, device in aws_instance.example.device : k => device.size}`.
When a resource has the
[`count`](https://www.terraform.io/docs/configuration/resources.html#count-multiple-resource-instances-by-count)
argument set, the resource itself becomes a _list_ of instance objects rather than
a single object. In that case, access the attributes of the instances using
either [splat expressions](#splat-expressions) or index syntax:
* `aws_instance.example[*].id` returns a list of all of the ids of each of the
instances.
* `aws_instance.example[0].id` returns just the id of the first instance.
When a resource has the
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
argument set, the resource itself becomes a _map_ of instance objects rather than
a single object, and attributes of instances must be specified by key, or can
be accessed using a [`for` expression](#for-expressions).
* `aws_instance.example["a"].id` returns the id of the "a"-keyed resource.
* `[for value in aws_instance.example: value.id]` returns a list of all of the ids
of each of the instances.
Note that unlike `count`, splat expressions are _not_ directly applicable to resources managed with `for_each`, as splat expressions are for lists only. You may apply a splat expression to values in a map like so:
* `values(aws_instance.example)[*].id`
### Values Not Yet Known
When Terraform is planning a set of changes that will apply your configuration,
some resource attribute values cannot be populated immediately because their
values are decided dynamically by the remote system. For example, if a
particular remote object type is assigned a generated unique id on creation,
Terraform cannot predict the value of this id until the object has been created.
To allow expressions to still be evaluated during the plan phase, Terraform
uses special "unknown value" placeholders for these results. In most cases you
don't need to do anything special to deal with these, since the Terraform
language automatically handles unknown values during expressions, so that
for example adding a known value to an unknown value automatically produces
an unknown value as the result.
However, there are some situations where unknown values _do_ have a significant
effect:
* The `count` meta-argument for resources cannot be unknown, since it must
be evaluated during the plan phase to determine how many instances are to
be created.
* If unknown values are used in the configuration of a data resource, that
data resource cannot be read during the plan phase and so it will be deferred
until the apply phase. In this case, the results of the data resource will
_also_ be unknown values.
* If an unknown value is assigned to an argument inside a `module` block,
any references to the corresponding input variable within the child module
will use that unknown value.
* If an unknown value is used in the `value` argument of an output value,
any references to that output value in the parent module will use that
unknown value.
* Terraform will attempt to validate that unknown values are of suitable
types where possible, but incorrect use of such values may not be detected
until the apply phase, causing the apply to fail.
Unknown values appear in the `terraform plan` output as `(not yet known)`.
<a id="arithmetic-operators"></a>
<a id="equality-operators"></a>
<a id="comparison-operators"></a>
<a id="logical-operators"></a>
## Arithmetic and Logical Operators
An _operator_ is a type of expression that transforms or combines one or more
other expressions. Operators either combine two values in some way to
produce a third result value, or transform a single given value to
produce a single result.
Operators are expressions that transform other expressions, like adding two
numbers (`+`) or comparing two values to get a bool (`==`, `>=`, etc.).
Operators that work on two values place an operator symbol between the two
values, similar to mathematical notation: `1 + 2`. Operators that work on
only one value place an operator symbol before that value, like
`!true`.
The Terraform language has a set of operators for both arithmetic and logic,
which are similar to operators in programming languages such as JavaScript
or Ruby.
When multiple operators are used together in an expression, they are evaluated
in the following order of operations:
1. `!`, `-` (multiplication by `-1`)
1. `*`, `/`, `%`
1. `+`, `-` (subtraction)
1. `>`, `>=`, `<`, `<=`
1. `==`, `!=`
1. `&&`
1. `||`
Parentheses can be used to override the default order of operations. Without
parentheses, higher levels are evaluated first, so `1 + 2 * 3` is interpreted
as `1 + (2 * 3)` and _not_ as `(1 + 2) * 3`.
The different operators can be gathered into a few different groups with
similar behavior, as described below. Each group of operators expects its
given values to be of a particular type. Terraform will attempt to convert
values to the required type automatically, or will produce an error message
if this automatic conversion is not possible.
### Arithmetic Operators
The arithmetic operators all expect number values and produce number values
as results:
* `a + b` returns the result of adding `a` and `b` together.
* `a - b` returns the result of subtracting `b` from `a`.
* `a * b` returns the result of multiplying `a` and `b`.
* `a / b` returns the result of dividing `a` by `b`.
* `a % b` returns the remainder of dividing `a` by `b`. This operator is
generally useful only when used with whole numbers.
* `-a` returns the result of multiplying `a` by `-1`.
### Equality Operators
The equality operators both take two values of any type and produce boolean
values as results.
* `a == b` returns `true` if `a` and `b` both have the same type and the same
value, or `false` otherwise.
* `a != b` is the opposite of `a == b`.
### Comparison Operators
The comparison operators all expect number values and produce boolean values
as results.
* `a < b` returns `true` if `a` is less than `b`, or `false` otherwise.
* `a <= b` returns `true` if `a` is less than or equal to `b`, or `false`
otherwise.
* `a > b` returns `true` if `a` is greater than `b`, or `false` otherwise.
* `a >= b` returns `true` if `a` is greater than or equal to `b`, or `false` otherwise.
### Logical Operators
The logical operators all expect bool values and produce bool values as results.
* `a || b` returns `true` if either `a` or `b` is `true`, or `false` if both are `false`.
* `a && b` returns `true` if both `a` and `b` are `true`, or `false` if either one is `false`.
* `!a` returns `true` if `a` is `false`, and `false` if `a` is `true`.
This information has moved to
[Operators](/docs/configuration/expressions/references.html).
## Conditional Expressions
A _conditional expression_ uses the value of a bool expression to select one of
two values.
The `condition ? true_val : false_val` expression chooses between two
expressions based on a bool condition.
The syntax of a conditional expression is as follows:
This information has moved to
[Conditional Expressions](/docs/configuration/expressions/conditionals.html).
```hcl
condition ? true_val : false_val
```
If `condition` is `true` then the result is `true_val`. If `condition` is
`false` then the result is `false_val`.
A common use of conditional expressions is to define defaults to replace
invalid values:
```
var.a != "" ? var.a : "default-a"
```
If `var.a` is an empty string then the result is `"default-a"`, but otherwise
it is the actual value of `var.a`.
Any of the equality, comparison, and logical operators can be used to define
the condition. The two result values may be of any type, but they must both
be of the _same_ type so that Terraform can determine what type the whole
conditional expression will return without knowing the condition value.
<a id="expanding-function-arguments"></a>
<a id="available-functions"></a>
## Function Calls
The Terraform language has a number of
[built-in functions](./functions.html) that can be used
within expressions as another way to transform and combine values. These
are similar to the operators but all follow a common syntax:
Terraform's functions can be called like `function_name(arg1, arg2)`.
```hcl
<FUNCTION NAME>(<ARGUMENT 1>, <ARGUMENT 2>)
```
This information has moved to
[Function Calls](/docs/configuration/expressions/function-calls.html).
The function name specifies which function to call. Each defined function
expects a specific number of arguments with specific value types, and returns a
specific value type as a result.
Some functions take an arbitrary number of arguments. For example, the `min`
function takes any amount of number arguments and returns the one that is
numerically smallest:
```hcl
min(55, 3453, 2)
```
### Expanding Function Arguments
If the arguments to pass to a function are available in a list or tuple value,
that value can be _expanded_ into separate arguments. Provide the list value as
an argument and follow it with the `...` symbol:
```hcl
min([55, 2453, 2]...)
```
The expansion symbol is three periods (`...`), not a Unicode ellipsis character
(`…`). Expansion is a special syntax that is only available in function calls.
### Available Functions
For a full list of available functions, see
[the function reference](./functions.html).
<a id="for-expressions"></a>
## `for` Expressions
A _`for` expression_ creates a complex type value by transforming
another complex type value. Each element in the input value
can correspond to either one or zero values in the result, and an arbitrary
expression can be used to transform each input element into an output element.
Expressions like `[for s in var.list : upper(s)]` can transform a complex type
value into another complex type value.
For example, if `var.list` is a list of strings, then the following expression
produces a list of strings with all-uppercase letters:
This information has moved to
[For Expressions](/docs/configuration/expressions/for.html).
```hcl
[for s in var.list : upper(s)]
```
This `for` expression iterates over each element of `var.list`, and then
evaluates the expression `upper(s)` with `s` set to each respective element.
It then builds a new tuple value with all of the results of executing that
expression in the same order.
The type of brackets around the `for` expression decide what type of result
it produces. The above example uses `[` and `]`, which produces a tuple. If
`{` and `}` are used instead, the result is an object, and two result
expressions must be provided separated by the `=>` symbol:
```hcl
{for s in var.list : s => upper(s)}
```
This expression produces an object whose attributes are the original elements
from `var.list` and their corresponding values are the uppercase versions.
A `for` expression can also include an optional `if` clause to filter elements
from the source collection, which can produce a value with fewer elements than
the source:
```
[for s in var.list : upper(s) if s != ""]
```
The source value can also be an object or map value, in which case two
temporary variable names can be provided to access the keys and values
respectively:
```
[for k, v in var.map : length(k) + length(v)]
```
Finally, if the result type is an object (using `{` and `}` delimiters) then
the value result expression can be followed by the `...` symbol to group
together results that have a common key:
```
{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).
<a id="splat-expressions"></a>
<a id="legacy-attribute-only-splat-expressions"></a>
## Splat Expressions
A _splat expression_ provides a more concise way to express a common
operation that could otherwise be performed with a `for` expression.
Expressions like `var.list[*].id` can extract simpler collections from complex
collections.
If `var.list` is a list of objects that all have an attribute `id`, then
a list of the ids could be produced with the following `for` expression:
This information has moved to
[Splat Expressions](/docs/configuration/expressions/splat.html).
```hcl
[for o in var.list : o.id]
```
<a id="dynamic-blocks"></a>
<a id="best-practices-for-dynamic-blocks"></a>
This is equivalent to the following _splat expression:_
## `dynamic` Blocks
```hcl
var.list[*].id
```
The special `dynamic` block type serves the same purpose as a `for` expression,
except it creates multiple repeatable nested blocks instead of a complex value.
The special `[*]` symbol iterates over all of the elements of the list given
to its left and accesses from each one the attribute name given on its
right. A splat expression can also be used to access attributes and indexes
from lists of complex types by extending the sequence of operations to the
right of the symbol:
This information has moved to
[Dynamic Blocks](/docs/configuration/expressions/dynamic-blocks.html).
```hcl
var.list[*].interfaces[0].name
```
<a id="string-literals"></a>
<a id="string-templates"></a>
<a id="interpolation"></a>
<a id="directives"></a>
The above expression is equivalent to the following `for` expression:
## String Literals and String Templates
```hcl
[for o in var.list : o.interfaces[0].name]
```
Splat expressions are for lists only (and thus cannot be used [to reference resources
created with `for_each`](/docs/configuration/resources.html#referring-to-instances-1),
which are represented as maps in Terraform). However, if a splat expression is applied
to a value that is _not_ a list or tuple then the value is automatically wrapped in
a single-element list before processing.
For example, `var.single_object[*].id` is equivalent to `[var.single_object][*].id`,
or effectively `[var.single_object.id]`. This behavior is not interesting in most cases,
but it is particularly useful when referring to resources that may or may
not have `count` set, and thus may or may not produce a tuple value:
```hcl
aws_instance.example[*].id
```
The above will produce a list of ids whether `aws_instance.example` has
`count` set or not, avoiding the need to revise various other expressions
in the configuration when a particular resource switches to and from
having `count` set.
### Legacy (Attribute-only) Splat Expressions
An older variant of the splat expression is available for compatibility with
code written in older versions of the Terraform language. This is a less useful
version of the splat expression, and should be avoided in new configurations.
An "attribute-only" splat expression is indicated by the sequence `.*` (instead
of `[*]`):
```
var.list.*.interfaces[0].name
```
This form has a subtly different behavior, equivalent to the following
`for` expression:
```
[for o in var.list : o.interfaces][0].name
```
Notice that with the attribute-only splat expression the index operation
`[0]` is applied to the result of the iteration, rather than as part of
the iteration itself.
## `dynamic` blocks
Within top-level block constructs like resources, expressions can usually be
used only when assigning a value to an argument using the `name = expression`
form. This covers many uses, but some resource types include repeatable _nested
blocks_ in their arguments, which do not accept expressions:
```hcl
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name" # can use expressions here
setting {
# but the "setting" block is always a literal block
}
}
```
You can dynamically construct repeatable nested blocks like `setting` using a
special `dynamic` block type, which is supported inside `resource`, `data`,
`provider`, and `provisioner` blocks:
```hcl
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name"
application = "${aws_elastic_beanstalk_application.tftest.name}"
solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"
dynamic "setting" {
for_each = var.settings
content {
namespace = setting.value["namespace"]
name = setting.value["name"]
value = setting.value["value"]
}
}
}
```
A `dynamic` block acts much like a `for` expression, but produces nested blocks
instead of a complex typed value. It iterates over a given complex value, and
generates a nested block for each element of that complex value.
- The label of the dynamic block (`"setting"` in the example above) specifies
what kind of nested block to generate.
- The `for_each` argument provides the complex value to iterate over.
- The `iterator` argument (optional) sets the name of a temporary variable
that represents the current element of the complex value. If omitted, the name
of the variable defaults to the label of the `dynamic` block (`"setting"` in
the example above).
- The `labels` argument (optional) is a list of strings that specifies the block
labels, in order, to use for each generated block. You can use the temporary
iterator variable in this value.
- The nested `content` block defines the body of each generated block. You can
use the temporary iterator variable inside this block.
Since the `for_each` argument accepts any collection or structural value,
you can use a `for` expression or splat expression to transform an existing
collection.
The iterator object (`setting` in the example above) has two attributes:
* `key` is the map key or list element index for the current element. If the
`for_each` expression produces a _set_ value then `key` is identical to
`value` and should not be used.
* `value` is the value of the current element.
A `dynamic` block can only generate arguments that belong to the resource type,
data source, provider or provisioner being configured. It is _not_ possible
to generate meta-argument blocks such as `lifecycle` and `provisioner`
blocks, since Terraform must process these before it is safe to evaluate
expressions.
The `for_each` value must be a map or set with one element per desired
nested block. 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 some common examples of such situations, see the
[`flatten`](/docs/configuration/functions/flatten.html)
and
[`setproduct`](/docs/configuration/functions/setproduct.html)
functions.
### Best Practices for `dynamic` Blocks
Overuse of `dynamic` blocks can make configuration hard to read and maintain, so
we recommend using them only when you need to hide details in order to build a
clean user interface for a re-usable module. Always write nested blocks out
literally where possible.
## String Literals
The Terraform language has two different syntaxes for string literals. The
most common is to delimit the string with quote characters (`"`), like
`"hello"`. In quoted strings, the backslash character serves as an escape
sequence, with the following characters selecting the escape behavior:
| Sequence | Replacement |
| ------------ | ----------------------------------------------------------------------------- |
| `\n` | Newline |
| `\r` | Carriage Return |
| `\t` | Tab |
| `\"` | Literal quote (without terminating the string) |
| `\\` | Literal backslash |
| `\uNNNN` | Unicode character from the basic multilingual plane (NNNN is four hex digits) |
| `\UNNNNNNNN` | Unicode character from supplementary planes (NNNNNNNN is eight hex digits) |
The alternative syntax for string literals is the so-called "heredoc" style,
inspired by Unix shell languages. This style allows multi-line strings to
be expressed more clearly by using a custom delimiter word on a line of its
own to close the string:
Strings can be `"double-quoted"` or
```hcl
<<EOT
hello
world
heredocs
EOT
```
The `<<` marker followed by any identifier at the end of a line introduces the
sequence. Terraform then processes the following lines until it finds one that
consists entirely of the identifier given in the introducer. In the above
example, `EOT` is the identifier selected. Any identifier is allowed, but
conventionally this identifier is in all-uppercase and begins with `EO`, meaning
"end of". `EOT` in this case stands for "end of text".
Strings can also include escape sequences like `\n`, interpolation sequences
(`${ ... }`), and template sequences (`%{ ... }`).
The "heredoc" form shown above requires that the lines following be flush with
the left margin, which can be awkward when an expression is inside an indented
block:
```hcl
block {
value = <<EOT
hello
world
EOT
}
```
To improve on this, Terraform also accepts an _indented_ heredoc string variant
that is introduced by the `<<-` sequence:
```hcl
block {
value = <<-EOT
hello
world
EOT
}
```
In this case, Terraform analyses the lines in the sequence to find the one
with the smallest number of leading spaces, and then trims that many spaces
from the beginning of all of the lines, leading to the following result:
```
hello
world
```
Backslash sequences are not interpreted in a heredoc string expression.
Instead, the backslash character is interpreted literally.
In both quoted and heredoc string expressions, Terraform supports template
sequences that begin with `${` and `%{`. These are described in more detail
in the following section. To include these sequences _literally_ without
beginning a template sequence, double the leading character: `$${` or `%%{`.
## String Templates
Within quoted and heredoc string expressions, the sequences `${` and `%{` begin
_template sequences_. Templates let you directly embed expressions into a string
literal, to dynamically construct strings from other values.
### Interpolation
A `${ ... }` sequence is an _interpolation,_ which evaluates the expression
given between the markers, converts the result to a string if necessary, and
then inserts it into the final string:
```hcl
"Hello, ${var.name}!"
```
In the above example, the named object `var.name` is accessed and its value
inserted into the string, producing a result like "Hello, Juan!".
### Directives
A `%{ ... }` sequence is a _directive_, which allows for conditional
results and iteration over collections, similar to conditional
and `for` expressions.
The following directives are supported:
* The `if <BOOL>`/`else`/`endif` directive chooses between two templates based
on the value of a bool expression:
```hcl
"Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"
```
The `else` portion may be omitted, in which case the result is an empty
string if the condition expression returns `false`.
* The `for <NAME> in <COLLECTION>` / `endfor` directive iterates over the
elements of a given collection or structural value and evaluates a given
template once for each element, concatenating the results together:
```hcl
<<EOT
%{ for ip in aws_instance.example.*.private_ip }
server ${ip}
%{ endfor }
EOT
```
The name given immediately after the `for` keyword is used as a temporary
variable name which can then be referenced from the nested template.
To allow template directives to be formatted for readability without adding
unwanted spaces and newlines to the result, all template sequences can include
optional _strip markers_ (`~`), immediately after the opening characters or
immediately before the end. When a strip marker is present, the template
sequence consumes all of the literal whitespace (spaces and newlines) either
before the sequence (if the marker appears at the beginning) or after (if the
marker appears at the end):
```hcl
<<EOT
%{ for ip in aws_instance.example.*.private_ip ~}
server ${ip}
%{ endfor ~}
EOT
```
In the above example, the newline after each of the directives is not included
in the output, but the newline after the `server ${ip}` sequence is retained,
causing only one line to be generated for each element:
```
server 10.1.16.154
server 10.1.16.1
server 10.1.16.34
```
When using template directives, we recommend always using the "heredoc" string
literal form and then formatting the template over multiple lines for
readability. Quoted string literals should usually include only interpolation
sequences.
This information has moved to
[Strings and Templates](/docs/configuration/expressions/strings.html).

View File

@ -0,0 +1,41 @@
---
layout: "language"
page_title: "Conditional Expressions - Configuration Language"
---
# Conditional Expressions
A _conditional expression_ uses the value of a bool expression to select one of
two values.
The syntax of a conditional expression is as follows:
```hcl
condition ? true_val : false_val
```
If `condition` is `true` then the result is `true_val`. If `condition` is
`false` then the result is `false_val`.
A common use of conditional expressions is to define defaults to replace
invalid values:
```
var.a != "" ? var.a : "default-a"
```
If `var.a` is an empty string then the result is `"default-a"`, but otherwise
it is the actual value of `var.a`.
## Conditions
The condition can be any expression that resolves to a boolean value. This will
usually be an expression that uses the equality, comparison, or logical
operators.
## Result Types
The two result values may be of any type, but they must both
be of the _same_ type so that Terraform can determine what type the whole
conditional expression will return without knowing the condition value.

View File

@ -0,0 +1,95 @@
---
layout: "language"
page_title: "Dynamic Blocks - Configuration Language"
---
# `dynamic` Blocks
Within top-level block constructs like resources, expressions can usually be
used only when assigning a value to an argument using the `name = expression`
form. This covers many uses, but some resource types include repeatable _nested
blocks_ in their arguments, which do not accept expressions:
```hcl
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name" # can use expressions here
setting {
# but the "setting" block is always a literal block
}
}
```
You can dynamically construct repeatable nested blocks like `setting` using a
special `dynamic` block type, which is supported inside `resource`, `data`,
`provider`, and `provisioner` blocks:
```hcl
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name"
application = "${aws_elastic_beanstalk_application.tftest.name}"
solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"
dynamic "setting" {
for_each = var.settings
content {
namespace = setting.value["namespace"]
name = setting.value["name"]
value = setting.value["value"]
}
}
}
```
A `dynamic` block acts much like a `for` expression, but produces nested blocks
instead of a complex typed value. It iterates over a given complex value, and
generates a nested block for each element of that complex value.
- The label of the dynamic block (`"setting"` in the example above) specifies
what kind of nested block to generate.
- The `for_each` argument provides the complex value to iterate over.
- The `iterator` argument (optional) sets the name of a temporary variable
that represents the current element of the complex value. If omitted, the name
of the variable defaults to the label of the `dynamic` block (`"setting"` in
the example above).
- The `labels` argument (optional) is a list of strings that specifies the block
labels, in order, to use for each generated block. You can use the temporary
iterator variable in this value.
- The nested `content` block defines the body of each generated block. You can
use the temporary iterator variable inside this block.
Since the `for_each` argument accepts any collection or structural value,
you can use a `for` expression or splat expression to transform an existing
collection.
The iterator object (`setting` in the example above) has two attributes:
* `key` is the map key or list element index for the current element. If the
`for_each` expression produces a _set_ value then `key` is identical to
`value` and should not be used.
* `value` is the value of the current element.
A `dynamic` block can only generate arguments that belong to the resource type,
data source, provider or provisioner being configured. It is _not_ possible
to generate meta-argument blocks such as `lifecycle` and `provisioner`
blocks, since Terraform must process these before it is safe to evaluate
expressions.
The `for_each` value must be a map or set with one element per desired
nested block. 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 some common examples of such situations, see the
[`flatten`](/docs/configuration/functions/flatten.html)
and
[`setproduct`](/docs/configuration/functions/setproduct.html)
functions.
## Best Practices for `dynamic` Blocks
Overuse of `dynamic` blocks can make configuration hard to read and maintain, so
we recommend using them only when you need to hide details in order to build a
clean user interface for a re-usable module. Always write nested blocks out
literally where possible.

View File

@ -0,0 +1,71 @@
---
layout: "language"
page_title: "For Expressions - Configuration Language"
---
# `for` Expressions
A _`for` expression_ creates a complex type value by transforming
another complex type value. Each element in the input value
can correspond to either one or zero values in the result, and an arbitrary
expression can be used to transform each input element into an output element.
For example, if `var.list` is a list of strings, then the following expression
produces a list of strings with all-uppercase letters:
```hcl
[for s in var.list : upper(s)]
```
This `for` expression iterates over each element of `var.list`, and then
evaluates the expression `upper(s)` with `s` set to each respective element.
It then builds a new tuple value with all of the results of executing that
expression in the same order.
The type of brackets around the `for` expression decide what type of result
it produces. The above example uses `[` and `]`, which produces a tuple. If
`{` and `}` are used instead, the result is an object, and two result
expressions must be provided separated by the `=>` symbol:
```hcl
{for s in var.list : s => upper(s)}
```
This expression produces an object whose attributes are the original elements
from `var.list` and their corresponding values are the uppercase versions.
A `for` expression can also include an optional `if` clause to filter elements
from the source collection, which can produce a value with fewer elements than
the source:
```
[for s in var.list : upper(s) if s != ""]
```
The source value can also be an object or map value, in which case two
temporary variable names can be provided to access the keys and values
respectively:
```
[for k, v in var.map : length(k) + length(v)]
```
Finally, if the result type is an object (using `{` and `}` delimiters) then
the value result expression can be followed by the `...` symbol to group
together results that have a common key:
```
{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
[the `for_each` meta-argument](/docs/configuration/meta-arguments/for_each.html):
* Transform a multi-level nested structure into a flat list by
[using nested `for` expressions with the `flatten` function](/docs/configuration/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](/docs/configuration/functions/setproduct.html#finding-combinations-for-for_each).

View File

@ -0,0 +1,48 @@
---
layout: "language"
page_title: "Function Calls - Configuration Language"
---
# Function Calls
The Terraform language has a number of
[built-in functions](/docs/configuration/functions.html) that can be used
in expressions to transform and combine values. These
are similar to the operators but all follow a common syntax:
```hcl
<FUNCTION NAME>(<ARGUMENT 1>, <ARGUMENT 2>)
```
The function name specifies which function to call. Each defined function
expects a specific number of arguments with specific value types, and returns a
specific value type as a result.
Some functions take an arbitrary number of arguments. For example, the `min`
function takes any amount of number arguments and returns the one that is
numerically smallest:
```hcl
min(55, 3453, 2)
```
A function call expression evaluates to the function's return value.
## Expanding Function Arguments
If the arguments to pass to a function are available in a list or tuple value,
that value can be _expanded_ into separate arguments. Provide the list value as
an argument and follow it with the `...` symbol:
```hcl
min([55, 2453, 2]...)
```
The expansion symbol is three periods (`...`), not a Unicode ellipsis character
(`…`). Expansion is a special syntax that is only available in function calls.
## Available Functions
For a full list of available functions, see
[the function reference](/docs/configuration/functions.html).

View File

@ -15,7 +15,8 @@ Expressions can be used in a number of places in the Terraform language,
but some contexts limit which expression constructs are allowed,
such as requiring a literal value of a particular type or forbidding
[references to resource attributes](/docs/configuration/expressions/references.html#references-to-resource-attributes).
Each language feature's documentation describes any restrictions it places on expressions.
Each language feature's documentation describes any restrictions it places on
expressions.
You can experiment with the behavior of Terraform's expressions from
the Terraform expression console, by running
@ -23,3 +24,44 @@ the Terraform expression console, by running
The other pages in this section describe the features of Terraform's
expression syntax.
- [Types and Values](/docs/configuration/expressions/types.html)
documents the data types that Terraform expressions can resolve to, and the
literal syntaxes for values of those types.
- [Strings and Templates](/docs/configuration/expressions/strings.html)
documents the syntaxes for string literals, including interpolation sequences
and template directives.
- [References to Values](/docs/configuration/expressions/references.html)
documents how to refer to named values like variables and resource attributes.
- [Operators](/docs/configuration/expressions/references.html)
documents the arithmetic, comparison, and logical operators.
- [Function Calls](/docs/configuration/expressions/function-calls.html)
documents the syntax for calling Terraform's built-in functions.
- [Conditional Expressions](/docs/configuration/expressions/conditionals.html)
documents the `<CONDITION> ? <TRUE VAL> : <FALSE VAL>` expression, which
chooses between two values based on a bool condition.
- [For Expressions](/docs/configuration/expressions/for.html)
documents expressions like `[for s in var.list : upper(s)]`, which can
transform a complex type value into another complex type value.
- [Splat Expressions](/docs/configuration/expressions/splat.html)
documents expressions like `var.list[*].id`, which can extract simpler
collections from more complicated expressions.
- [Dynamic Blocks](/docs/configuration/expressions/dynamic-blocks.html)
documents a way to create multiple repeatable nested blocks within a resource
or other construct.
- [Type Constraints](/docs/configuration/types.html)
documents the syntax for referring to a type, rather than a value of that
type. Input variables expect this syntax in their `type` argument.
- [Version Constraints](/docs/configuration/version-constraints.html)
documents the syntax of special strings that define a set of allowed software
versions. Terraform uses version constraints in several places.

View File

@ -0,0 +1,82 @@
---
layout: "language"
page_title: "Operators - Configuration Language"
---
# Arithmetic and Logical Operators
An _operator_ is a type of expression that transforms or combines one or more
other expressions. Operators either combine two values in some way to
produce a third result value, or transform a single given value to
produce a single result.
Operators that work on two values place an operator symbol between the two
values, similar to mathematical notation: `1 + 2`. Operators that work on
only one value place an operator symbol before that value, like
`!true`.
The Terraform language has a set of operators for both arithmetic and logic,
which are similar to operators in programming languages such as JavaScript
or Ruby.
When multiple operators are used together in an expression, they are evaluated
in the following order of operations:
1. `!`, `-` (multiplication by `-1`)
1. `*`, `/`, `%`
1. `+`, `-` (subtraction)
1. `>`, `>=`, `<`, `<=`
1. `==`, `!=`
1. `&&`
1. `||`
Parentheses can be used to override the default order of operations. Without
parentheses, higher levels are evaluated first, so `1 + 2 * 3` is interpreted
as `1 + (2 * 3)` and _not_ as `(1 + 2) * 3`.
The different operators can be gathered into a few different groups with
similar behavior, as described below. Each group of operators expects its
given values to be of a particular type. Terraform will attempt to convert
values to the required type automatically, or will produce an error message
if this automatic conversion is not possible.
## Arithmetic Operators
The arithmetic operators all expect number values and produce number values
as results:
* `a + b` returns the result of adding `a` and `b` together.
* `a - b` returns the result of subtracting `b` from `a`.
* `a * b` returns the result of multiplying `a` and `b`.
* `a / b` returns the result of dividing `a` by `b`.
* `a % b` returns the remainder of dividing `a` by `b`. This operator is
generally useful only when used with whole numbers.
* `-a` returns the result of multiplying `a` by `-1`.
## Equality Operators
The equality operators both take two values of any type and produce boolean
values as results.
* `a == b` returns `true` if `a` and `b` both have the same type and the same
value, or `false` otherwise.
* `a != b` is the opposite of `a == b`.
## Comparison Operators
The comparison operators all expect number values and produce boolean values
as results.
* `a < b` returns `true` if `a` is less than `b`, or `false` otherwise.
* `a <= b` returns `true` if `a` is less than or equal to `b`, or `false`
otherwise.
* `a > b` returns `true` if `a` is greater than `b`, or `false` otherwise.
* `a >= b` returns `true` if `a` is greater than or equal to `b`, or `false` otherwise.
## Logical Operators
The logical operators all expect bool values and produce bool values as results.
* `a || b` returns `true` if either `a` or `b` is `true`, or `false` if both are `false`.
* `a && b` returns `true` if both `a` and `b` are `true`, or `false` if either one is `false`.
* `!a` returns `true` if `a` is `false`, and `false` if `a` is `true`.

View File

@ -0,0 +1,247 @@
---
layout: "language"
page_title: "References to Values - Configuration Language"
---
# References to Named Values
Terraform makes several kinds of named values available. Each of these names is
an expression that references the associated value; you can use them as
standalone expressions, or combine them with other expressions to compute new
values.
## Types of Named Values
The main kinds of named values available in Terraform are:
- Resources
- Input variables
- Local values
- Child module outputs
- Data sources
- Filesystem and workspace info
- Block-local values
The sections below explain each kind of named value in detail.
Although many of these names use dot-separated paths that resemble
[attribute notation](./types.html#indices-and-attributes) for elements of object values, they are not
implemented as real objects. This means you must use them exactly as written:
you cannot use square-bracket notation to replace the dot-separated paths, and
you cannot iterate over the "parent object" of a named entity; for example, you
cannot use `aws_instance` in a `for` expression to iterate over every AWS
instance resource.
### Resources
`<RESOURCE TYPE>.<NAME>` represents a [managed resource](/docs/configuration/blocks/resources/index.html) of
the given type and name.
The value of a resource reference can vary, depending on whether the resource
uses `count` or `for_each`:
- If the resource doesn't use `count` or `for_each`, the reference's value is an
object. The resource's attributes are elements of the object, and you can
access them using [dot or square bracket notation](./types.html#indices-and-attributes).
- If the resource has the `count` argument set, the reference's value is a
_list_ of objects representing its instances.
- If the resource has the `for_each` argument set, the reference's value is a
_map_ of objects representing its instances.
Any named value that does not match another pattern listed below
will be interpreted by Terraform as a reference to a managed resource.
For more information about how to use resource references, see
[references to resource attributes](#references-to-resource-attributes) below.
### Input Variables
`var.<NAME>` is the value of the [input variable](/docs/configuration/variables.html) of the given name.
### Local Values
`local.<NAME>` is the value of the [local value](/docs/configuration/locals.html) of the given name.
### Child Module Outputs
* `module.<MODULE NAME>.<OUTPUT NAME>` is the value of the specified
[output value](/docs/configuration/outputs.html) from a
[child module](/docs/configuration/blocks/modules/index.html) called by the
current module.
### Data Sources
* `data.<DATA TYPE>.<NAME>` is an object representing a
[data resource](/docs/configuration/data-sources.html) of the given data
source type and name. If the resource has the `count` argument set, the value
is a list of objects representing its instances. If the resource has the `for_each`
argument set, the value is a map of objects representing its instances.
### Filesystem and Workspace Info
* `path.module` is the filesystem path of the module where the expression
is placed.
* `path.root` is the filesystem path of the root module of the configuration.
* `path.cwd` is the filesystem path of the current working directory. In
normal use of Terraform this is the same as `path.root`, but some advanced
uses of Terraform run it from a directory other than the root module
directory, causing these paths to be different.
* `terraform.workspace` is the name of the currently selected
[workspace](/docs/state/workspaces.html).
### Block-Local Values
Within the bodies of certain blocks, or in some other specific contexts,
there are other named values available beyond the global values listed above.
These local names are described in the documentation for the specific contexts
where they appear. Some of most common local names are:
- `count.index`, in resources that use
[the `count` meta-argument](/docs/configuration/meta-arguments/count.html).
- `each.key` / `each.value`, in resources that use
[the `for_each` meta-argument](/docs/configuration/meta-arguments/for_each.html).
- `self`, in [provisioner](/docs/provisioners/index.html) and
[connection](/docs/provisioners/connection.html) blocks.
-> **Note:** Local names are often referred to as _variables_ or
_temporary variables_ in their documentation. These are not [input
variables](/docs/configuration/variables.html); they are just arbitrary names
that temporarily represent a value.
## Named Values and Dependencies
Constructs like resources and module calls often use references to named values
in their block bodies, and Terraform analyzes these expressions to automatically
infer dependencies between objects. For example, an expression in a resource
argument that refers to another managed resource creates an implicit dependency
between the two resources.
## References to Resource Attributes
The most common reference type is a reference to an attribute of a resource
which has been declared either with a `resource` or `data` block. Because
the contents of such blocks can be quite complicated themselves, expressions
referring to these contents can also be complicated.
Consider the following example resource block:
```hcl
resource "aws_instance" "example" {
ami = "ami-abc123"
instance_type = "t2.micro"
ebs_block_device {
device_name = "sda2"
volume_size = 16
}
ebs_block_device {
device_name = "sda3"
volume_size = 20
}
}
```
The documentation for [`aws_instance`](/docs/providers/aws/r/instance.html)
lists all of the arguments and nested blocks supported for this resource type,
and also lists a number of attributes that are _exported_ by this resource
type. All of these different resource type schema constructs are available
for use in references, as follows:
* The `ami` argument set in the configuration can be used elsewhere with
the reference expression `aws_instance.example.ami`.
* The `id` attribute exported by this resource type can be read using the
same syntax, giving `aws_instance.example.id`.
* The arguments of the `ebs_block_device` nested blocks can be accessed using
a [splat expression](./splat.html). For example, to obtain a list of
all of the `device_name` values, use
`aws_instance.example.ebs_block_device[*].device_name`.
* The nested blocks in this particular resource type do not have any exported
attributes, but if `ebs_block_device` were to have a documented `id`
attribute then a list of them could be accessed similarly as
`aws_instance.example.ebs_block_device[*].id`.
* Sometimes nested blocks are defined as taking a logical key to identify each
block, which serves a similar purpose as the resource's own name by providing
a convenient way to refer to that single block in expressions. If `aws_instance`
had a hypothetical nested block type `device` that accepted such a key, it
would look like this in configuration:
```hcl
device "foo" {
size = 2
}
device "bar" {
size = 4
}
```
Arguments inside blocks with _keys_ can be accessed using index syntax, such
as `aws_instance.example.device["foo"].size`.
To obtain a map of values of a particular argument for _labelled_ nested
block types, use a [`for` expression](./for.html):
`{for k, device in aws_instance.example.device : k => device.size}`.
When a resource has the
[`count`](/docs/configuration/meta-arguments/count.html)
argument set, the resource itself becomes a _list_ of instance objects rather than
a single object. In that case, access the attributes of the instances using
either [splat expressions](./splat.html) or index syntax:
* `aws_instance.example[*].id` returns a list of all of the ids of each of the
instances.
* `aws_instance.example[0].id` returns just the id of the first instance.
When a resource has the
[`for_each`](/docs/configuration/meta-arguments/for_each.html)
argument set, the resource itself becomes a _map_ of instance objects rather than
a single object, and attributes of instances must be specified by key, or can
be accessed using a [`for` expression](./for.html).
* `aws_instance.example["a"].id` returns the id of the "a"-keyed resource.
* `[for value in aws_instance.example: value.id]` returns a list of all of the ids
of each of the instances.
Note that unlike `count`, splat expressions are _not_ directly applicable to resources managed with `for_each`, as splat expressions must act on a list value. However, you can use the `values()` function to extract the instances as a list and use that list value in a splat expression:
* `values(aws_instance.example)[*].id`
### Values Not Yet Known
When Terraform is planning a set of changes that will apply your configuration,
some resource attribute values cannot be populated immediately because their
values are decided dynamically by the remote system. For example, if a
particular remote object type is assigned a generated unique id on creation,
Terraform cannot predict the value of this id until the object has been created.
To allow expressions to still be evaluated during the plan phase, Terraform
uses special "unknown value" placeholders for these results. In most cases you
don't need to do anything special to deal with these, since the Terraform
language automatically handles unknown values during expressions, so that
for example adding a known value to an unknown value automatically produces
an unknown value as the result.
However, there are some situations where unknown values _do_ have a significant
effect:
* The `count` meta-argument for resources cannot be unknown, since it must
be evaluated during the plan phase to determine how many instances are to
be created.
* If unknown values are used in the configuration of a data resource, that
data resource cannot be read during the plan phase and so it will be deferred
until the apply phase. In this case, the results of the data resource will
_also_ be unknown values.
* If an unknown value is assigned to an argument inside a `module` block,
any references to the corresponding input variable within the child module
will use that unknown value.
* If an unknown value is used in the `value` argument of an output value,
any references to that output value in the parent module will use that
unknown value.
* Terraform will attempt to validate that unknown values are of suitable
types where possible, but incorrect use of such values may not be detected
until the apply phase, causing the apply to fail.
Unknown values appear in the `terraform plan` output as `(not yet known)`.

View File

@ -0,0 +1,82 @@
---
layout: "language"
page_title: "Splat Expressions - Configuration Language"
---
# Splat Expressions
A _splat expression_ provides a more concise way to express a common
operation that could otherwise be performed with a `for` expression.
If `var.list` is a list of objects that all have an attribute `id`, then
a list of the ids could be produced with the following `for` expression:
```hcl
[for o in var.list : o.id]
```
This is equivalent to the following _splat expression:_
```hcl
var.list[*].id
```
The special `[*]` symbol iterates over all of the elements of the list given
to its left and accesses from each one the attribute name given on its
right. A splat expression can also be used to access attributes and indexes
from lists of complex types by extending the sequence of operations to the
right of the symbol:
```hcl
var.list[*].interfaces[0].name
```
The above expression is equivalent to the following `for` expression:
```hcl
[for o in var.list : o.interfaces[0].name]
```
Splat expressions are for lists only (and thus cannot be used [to reference resources
created with `for_each`](/docs/configuration/meta-arguments/for_each.html#referring-to-instances),
which are represented as maps in Terraform). However, if a splat expression is applied
to a value that is _not_ a list or tuple then the value is automatically wrapped in
a single-element list before processing.
For example, `var.single_object[*].id` is equivalent to `[var.single_object][*].id`,
or effectively `[var.single_object.id]`. This behavior is not interesting in most cases,
but it is particularly useful when referring to resources that may or may
not have `count` set, and thus may or may not produce a tuple value:
```hcl
aws_instance.example[*].id
```
The above will produce a list of ids whether `aws_instance.example` has
`count` set or not, avoiding the need to revise various other expressions
in the configuration when a particular resource switches to and from
having `count` set.
## Legacy (Attribute-only) Splat Expressions
An older variant of the splat expression is available for compatibility with
code written in older versions of the Terraform language. This is a less useful
version of the splat expression, and should be avoided in new configurations.
An "attribute-only" splat expression is indicated by the sequence `.*` (instead
of `[*]`):
```
var.list.*.interfaces[0].name
```
This form has a subtly different behavior, equivalent to the following
`for` expression:
```
[for o in var.list : o.interfaces][0].name
```
Notice that with the attribute-only splat expression the index operation
`[0]` is applied to the result of the iteration, rather than as part of
the iteration itself.

View File

@ -0,0 +1,208 @@
---
layout: "language"
page_title: "Strings and Templates - Configuration Language"
---
# Strings and Templates
String literals are the most complex kind of literal expression in
Terraform, and also the most commonly used.
Terraform supports both a quoted syntax and a "heredoc" syntax for strings.
Both of these syntaxes support template sequences for interpolating values and
manipulating text.
## Quoted Strings
A quoted string is a series of characters delimited by straight double-quote
characters (`"`).
```
"hello"
```
### Escape Sequences
In quoted strings, the backslash character serves as an escape
sequence, with the following characters selecting the escape behavior:
| Sequence | Replacement |
| ------------ | ----------------------------------------------------------------------------- |
| `\n` | Newline |
| `\r` | Carriage Return |
| `\t` | Tab |
| `\"` | Literal quote (without terminating the string) |
| `\\` | Literal backslash |
| `\uNNNN` | Unicode character from the basic multilingual plane (NNNN is four hex digits) |
| `\UNNNNNNNN` | Unicode character from supplementary planes (NNNNNNNN is eight hex digits) |
There are also two special escape sequences that do not use backslashes:
| Sequence | Replacement |
| --- | ---- |
| `$${` | Literal `${`, without beginning an interpolation sequence. |
| `%%{` | Literal `%{`, without beginning a template directive sequence. |
## Heredoc Strings
Terraform also supports a "heredoc" style of string literal inspired by Unix
shell languages, which allows multi-line strings to be expressed more clearly.
```hcl
<<EOT
hello
world
EOT
```
A heredoc string consists of:
- An opening sequence consisting of:
- A heredoc marker (`<<` or `<<-` two less-than signs, with an optional hyphen for indented heredocs)
- A delimiter word of your own choosing
- A line break
- The contents of the string, which can span any number of lines
- The delimiter word you chose, alone on its own line (with indentation allowed for indented heredocs)
The `<<` marker followed by any identifier at the end of a line introduces the
sequence. Terraform then processes the following lines until it finds one that
consists entirely of the identifier given in the introducer.
In the above example, `EOT` is the identifier selected. Any identifier is
allowed, but conventionally this identifier is in all-uppercase and begins with
`EO`, meaning "end of". `EOT` in this case stands for "end of text".
### Indented Heredocs
The standard heredoc form (shown above) treats all space characters as literal
spaces. If you don't want each line to begin with spaces, then each line must be
flush with the left margin, which can be awkward for expressions in an
indented block:
```hcl
block {
value = <<EOT
hello
world
EOT
}
```
To improve on this, Terraform also accepts an _indented_ heredoc string variant
that is introduced by the `<<-` sequence:
```hcl
block {
value = <<-EOT
hello
world
EOT
}
```
In this case, Terraform analyses the lines in the sequence to find the one
with the smallest number of leading spaces, and then trims that many spaces
from the beginning of all of the lines, leading to the following result:
```
hello
world
```
### Escape Sequences
Backslash sequences are not interpreted as escapes in a heredoc string
expression. Instead, the backslash character is interpreted literally.
Heredocs support two special escape sequences that do not use backslashes:
| Sequence | Replacement |
| --- | ---- |
| `$${` | Literal `${`, without beginning an interpolation sequence. |
| `%%{` | Literal `%{`, without beginning a template directive sequence. |
## String Templates
Within quoted and heredoc string expressions, the sequences `${` and `%{` begin
_template sequences_. Templates let you directly embed expressions into a string
literal, to dynamically construct strings from other values.
### Interpolation
A `${ ... }` sequence is an _interpolation,_ which evaluates the expression
given between the markers, converts the result to a string if necessary, and
then inserts it into the final string:
```hcl
"Hello, ${var.name}!"
```
In the above example, the named object `var.name` is accessed and its value
inserted into the string, producing a result like "Hello, Juan!".
### Directives
A `%{ ... }` sequence is a _directive_, which allows for conditional
results and iteration over collections, similar to conditional
and `for` expressions.
The following directives are supported:
* The `%{if <BOOL>}`/`%{else}`/`%{endif}` directive chooses between two templates based
on the value of a bool expression:
```hcl
"Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"
```
The `else` portion may be omitted, in which case the result is an empty
string if the condition expression returns `false`.
* The `%{for <NAME> in <COLLECTION>}` / `%{endfor}` directive iterates over the
elements of a given collection or structural value and evaluates a given
template once for each element, concatenating the results together:
```hcl
<<EOT
%{ for ip in aws_instance.example.*.private_ip }
server ${ip}
%{ endfor }
EOT
```
The name given immediately after the `for` keyword is used as a temporary
variable name which can then be referenced from the nested template.
### Whitespace Stripping
To allow template directives to be formatted for readability without adding
unwanted spaces and newlines to the result, all template sequences can include
optional _strip markers_ (`~`), immediately after the opening characters or
immediately before the end. When a strip marker is present, the template
sequence consumes all of the literal whitespace (spaces and newlines) either
before the sequence (if the marker appears at the beginning) or after (if the
marker appears at the end):
```hcl
<<EOT
%{ for ip in aws_instance.example.*.private_ip ~}
server ${ip}
%{ endfor ~}
EOT
```
In the above example, the newline after each of the directives is not included
in the output, but the newline after the `server ${ip}` sequence is retained,
causing only one line to be generated for each element:
```
server 10.1.16.154
server 10.1.16.1
server 10.1.16.34
```
When using template directives, we recommend always using the "heredoc" string
literal form and then formatting the template over multiple lines for
readability. Quoted string literals should usually include only interpolation
sequences.

View File

@ -0,0 +1,147 @@
---
layout: "language"
page_title: "Types and Values - Configuration Language"
---
# Types and Values
The result of an expression is a _value_. All values have a _type_, which
dictates where that value can be used and what transformations can be
applied to it.
## Types
The Terraform language uses the following types for its values:
* `string`: a sequence of Unicode characters representing some text, like
`"hello"`.
* `number`: a numeric value. The `number` type can represent both whole
numbers like `15` and fractional values like `6.283185`.
* `bool`: a boolean value, either `true` or `false`. `bool` values can be used in conditional
logic.
* `list` (or `tuple`): a sequence of values, like
`["us-west-1a", "us-west-1c"]`. Elements in a list or tuple are identified by
consecutive whole numbers, starting with zero.
* `map` (or `object`): a group of values identified by named labels, like
`{name = "Mabel", age = 52}`.
Strings, numbers, and bools are sometimes called _primitive types._ Lists/tuples and maps/objects are sometimes called _complex types,_ _structural types,_ or _collection types._
Finally, there is one special value that has _no_ type:
* `null`: a value that represents _absence_ or _omission._ If you set an
argument of a resource or module to `null`, Terraform behaves as though you
had completely omitted it — it will use the argument's default value if it has
one, or raise an error if the argument is mandatory. `null` is most useful in
conditional expressions, so you can dynamically omit an argument if a
condition isn't met.
## Literal Expressions
A _literal expression_ is an expression that directly represents a particular
constant value. Terraform has a literal expression syntax for each of the value
types described above.
### Strings
Strings are usually represented by a double-quoted sequence of Unicode
characters, `"like this"`. There is also a "heredoc" syntax for more complex
strings.
String literals are the most complex kind of literal expression in
Terraform, and have their own page of documentation. See [Strings](./strings.html)
for information about escape sequences, the heredoc syntax, interpolation, and
template directives.
### Numbers
Numbers are represented by unquoted sequences of digits with or without a
decimal point, like `15` or `6.283185`.
### Bools
Bools are represented by the unquoted symbols `true` and `false`.
### Null
The null value is represented by the unquoted symbol `null`.
### Lists/Tuples
Lists/tuples are represented by a pair of square brackets containing a
comma-separated sequence of values, like `["a", 15, true]`.
List literals can be split into multiple lines for readability, but always
require a comma between values. A comma after the final value is allowed,
but not required. Values in a list can be arbitrary expressions.
### Maps/Objects
Maps/objects are represented by a pair of curly braces containing a series of
`<KEY> = <VALUE>` pairs:
```hcl
{
name = "John"
age = 52
}
```
Key/value pairs can be separated by either a comma or a line break.
The values in a map
can be arbitrary expressions.
The keys in a map must be strings; they can be left unquoted if
they are a valid [identifier](/docs/configuration/syntax.html#identifiers), but must be quoted
otherwise. You can use a non-literal string expression as a key by wrapping it in
parentheses, like `(var.business_unit_tag_name) = "SRE"`.
## Indices and Attributes
[inpage-index]: #indices-and-attributes
Elements of list/tuple and map/object values can be accessed using
the square-bracket index notation, like `local.list[3]`. The expression within
the brackets must be a whole number for list and tuple values or a string
for map and object values.
Map/object attributes with names that are valid identifiers can also be accessed
using the dot-separated attribute notation, like `local.object.attrname`.
In cases where a map might contain arbitrary user-specified keys, we recommend
using only the square-bracket index notation (`local.map["keyname"]`).
## More About Complex Types
In most situations, lists and tuples behave identically, as do maps and objects.
Whenever the distinction isn't relevant, the Terraform documentation uses each
pair of terms interchangeably (with a historical preference for "list" and
"map").
However, module authors and provider developers should understand the
differences between these similar types (and the related `set` type), since they
offer different ways to restrict the allowed values for input variables and
resource arguments.
For complete details about these types (and an explanation of why the difference
usually doesn't matter), see [Type Constraints](/docs/configuration/types.html).
## Type Conversion
Expressions are most often used to set values for the arguments of resources and
child modules. In these cases, the argument has an expected type and the given
expression must produce a value of that type.
Where possible, Terraform automatically converts values from one type to
another in order to produce the expected type. If this isn't possible, Terraform
will produce a type mismatch error and you must update the configuration with a
more suitable expression.
Terraform automatically converts number and bool values to strings when needed.
It also converts strings to numbers or bools, as long as the string contains a
valid representation of a number or bool value.
* `true` converts to `"true"`, and vice-versa
* `false` converts to `"false"`, and vice-versa
* `15` converts to `"15"`, and vice-versa

View File

@ -34,7 +34,7 @@ treating the entire module as a single document. Separating various blocks into
different files is purely for the convenience of readers and maintainers, and
has no effect on the module's behavior.
A Terraform module can use [module calls](/docs/configuration/modules.html) to
A Terraform module can use [module calls](/docs/configuration/blocks/modules/index.html) to
explicitly include other modules into the configuration. These child modules can
come from local directories (nested in the parent module's directory, or
anywhere else on disk), or from external sources like the

View File

@ -23,8 +23,8 @@ max(5, 12, 9)
```
For more details on syntax, see
[_Function Calls_](./expressions.html#function-calls)
on the Expressions page.
[_Function Calls_](/docs/configuration/expressions/function-calls.html)
in the Expressions section.
The Terraform language does not support user-defined functions, and so only
the functions built in to the language are available for use. The navigation

View File

@ -70,7 +70,7 @@ platforms.
```
You can use nested `cidrsubnets` calls with
[`for` expressions](/docs/configuration/expressions.html#for-expressions)
[`for` expressions](/docs/configuration/expressions/for.html)
to concisely allocate groups of network address blocks:
```

View File

@ -46,7 +46,7 @@ number of fields, or this function will produce an error.
## Use with the `for_each` meta-argument
You can use the result of `csvdecode` with
[the `for_each` meta-argument](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
[the `for_each` meta-argument](/docs/configuration/meta-arguments/for_each.html)
to describe a collection of similar objects whose differences are
described by the rows in the given CSV file.
@ -94,7 +94,7 @@ create or destroy associated instances as appropriate.
If there is no reasonable value you can use as a unique identifier in your CSV
then you could instead use
[the `count` meta-argument](/docs/configuration/resources.html#count-multiple-resource-instances-by-count)
[the `count` meta-argument](/docs/configuration/meta-arguments/count.html)
to define an object for each CSV row, with each one identified by its index into
the list returned by `csvdecode`. However, in that case any future updates to
the CSV may be disruptive if they change the positions of particular objects in

View File

@ -69,7 +69,7 @@ before Terraform takes any actions.
```
A common use of `fileset` is to create one resource instance per matched file, using
[the `for_each` meta-argument](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
[the `for_each` meta-argument](/docs/configuration/meta-arguments/for_each.html):
```hcl
resource "example_thing" "example" {

View File

@ -35,9 +35,9 @@ Indirectly-nested lists, such as those in maps, are _not_ flattened.
## Flattening nested structures for `for_each`
The
[resource `for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
[resource `for_each`](/docs/configuration/meta-arguments/for_each.html)
and
[`dynamic` block](/docs/configuration/expressions.html#dynamic-blocks)
[`dynamic` block](/docs/configuration/expressions/dynamic-blocks.html)
language features both require a collection value that has one element for
each repetition.

View File

@ -19,7 +19,7 @@ of the result of decoding that string.
The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
This function maps JSON values to
[Terraform language values](../expressions.html#types-and-values)
[Terraform language values](/docs/configuration/expressions/types.html)
in the following way:
| JSON type | Terraform type |

View File

@ -17,7 +17,7 @@ earlier, see
The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
This function maps
[Terraform language values](../expressions.html#types-and-values)
[Terraform language values](/docs/configuration/expressions/types.html)
to JSON values in the following way:
| Terraform type | JSON type |

View File

@ -121,9 +121,9 @@ elements all have a consistent type:
## Finding combinations for `for_each`
The
[resource `for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
[resource `for_each`](/docs/configuration/meta-arguments/for_each.html)
and
[`dynamic` block](/docs/configuration/expressions.html#dynamic-blocks)
[`dynamic` block](/docs/configuration/expressions/dynamic-blocks.html)
language features both require a collection value that has one element for
each repetition.

View File

@ -21,10 +21,10 @@ templatefile(path, vars)
```
The template syntax is the same as for
[string templates](../expressions.html#string-templates) in the main Terraform
language, including interpolation sequences delimited with `${` ... `}`.
This function just allows longer template sequences to be factored out
into a separate file for readability.
[string templates](/docs/configuration/expressions/strings.html#string-templates)
in the main Terraform language, including interpolation sequences delimited with
`${` ... `}`. This function just allows longer template sequences to be factored
out into a separate file for readability.
The "vars" argument must be a map. Within the template file, each of the keys
in the map is available as a variable for interpolation. The template may
@ -78,8 +78,8 @@ The `templatefile` function renders the template:
```
> templatefile(
"${path.module}/backends.tmpl",
{
"${path.module}/backends.tmpl",
{
config = {
"x" = "y"
"foo" = "bar"
@ -102,7 +102,7 @@ interpolation sequences and directives.
Instead, you can write a template that consists only of a single interpolated
call to either [`jsonencode`](./jsonencode.html) or
[`yamlencode`](./yamlencode.html), specifying the value to encode using
[normal Terraform expression syntax](/docs/configuration/expressions.html)
[normal Terraform expression syntax](/docs/configuration/expressions/index.html)
as in the following examples:
```
@ -122,9 +122,9 @@ this will produce a valid JSON or YAML representation of the given data
structure, without the need to manually handle escaping or delimiters.
In the latest examples above, the repetition based on elements of `ip_addrs` is
achieved by using a
[`for` expression](/docs/configuration/expressions.html#for-expressions)
[`for` expression](/docs/configuration/expressions/for.html)
rather than by using
[template directives](/docs/configuration/expressions.html#directives).
[template directives](/docs/configuration/expressions/strings.html#directives).
```json
{"backends":["10.0.0.1:8080","10.0.0.2:8080"]}

View File

@ -24,7 +24,7 @@ The result of this function will change every second, so using this function
directly with resource attributes will cause a diff to be detected on every
Terraform run. We do not recommend using this function in resource attributes,
but in rare cases it can be used in conjunction with
[the `ignore_changes` lifecycle meta-argument](../resources.html#ignore_changes)
[the `ignore_changes` lifecycle meta-argument](/docs/configuration/meta-arguments/lifecycle.html#ignore_changes)
to take the timestamp only on initial creation of the resource. For more stable
time handling, see the [Time Provider](https://registry.terraform.io/providers/hashicorp/time/).

View File

@ -23,7 +23,7 @@ This function produces a new value each time it is called, and so using it
directly in resource arguments will result in spurious diffs. We do not
recommend using the `uuid` function in resource configurations, but it can
be used with care in conjunction with
[the `ignore_changes` lifecycle meta-argument](../resources.html#ignore_changes).
[the `ignore_changes` lifecycle meta-argument](/docs/configuration/meta-arguments/lifecycle.html#ignore_changes).
In most cases we recommend using [the `random` provider](/docs/providers/random/index.html)
instead, since it allows the one-time generation of random values that are

View File

@ -20,7 +20,7 @@ This function supports a subset of [YAML 1.2](https://yaml.org/spec/1.2/spec.htm
as described below.
This function maps YAML values to
[Terraform language values](../expressions.html#types-and-values)
[Terraform language values](/docs/configuration/expressions/types.html)
in the following way:
| YAML type | Terraform type |

View File

@ -33,7 +33,7 @@ results are also valid YAML because YAML is a JSON superset.
-->
This function maps
[Terraform language values](../expressions.html#types-and-values)
[Terraform language values](/docs/configuration/expressions/types.html)
to YAML tags in the following way:
| Terraform type | YAML type |

View File

@ -19,7 +19,7 @@ heart of the workflow.
## About the Terraform Language
The main purpose of the Terraform language is declaring
[resources](./resources.html), which represent infrastructure objects. All other
[resources](/docs/configuration/blocks/resources/index.html), which represent infrastructure objects. All other
language features exist only to make the definition of resources more flexible
and convenient.

View File

@ -13,7 +13,7 @@ description: |-
earlier, see
[0.11 Configuration Language: Local Values](../configuration-0-11/locals.html).
A local value assigns a name to an [expression](./expressions.html),
A local value assigns a name to an [expression](/docs/configuration/expressions/index.html),
so you can use it multiple times within a module without repeating
it.
@ -61,7 +61,7 @@ locals {
## Using Local Values
Once a local value is declared, you can reference it in
[expressions](./expressions.html) as `local.<NAME>`.
[expressions](/docs/configuration/expressions/index.html) as `local.<NAME>`.
-> **Note:** Local values are _created_ by a `locals` block (plural), but you
_reference_ them as attributes on an object named `local` (singular). Make sure

View File

@ -0,0 +1,122 @@
---
layout: "language"
page_title: "The count Meta-Argument - Configuration Language"
---
# The `count` Meta-Argument
-> **Version note:** Module support for `count` was added in Terraform 0.13, and
previous versions can only use it with resources.
-> **Note:** A given resource or module block cannot use both `count` and `for_each`.
> **Hands-on:** Try the [Manage Similar Resources With Count](https://learn.hashicorp.com/tutorials/terraform/count?in=terraform/0-13&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn.
By default, a [resource block](/docs/configuration/blocks/resources/syntax.html) configures one real
infrastructure object. (Similarly, a
[module block](/docs/configuration/blocks/modules/syntax.html) includes a
child module's contents into the configuration one time.)
However, sometimes you want to manage several similar objects (like a fixed
pool of compute instances) without writing a separate block for each one.
Terraform has two ways to do this:
`count` and [`for_each`](/docs/configuration/meta-arguments/for_each.html).
If a resource or module block includes a `count` argument whose value is a whole number,
Terraform will create that many instances.
## Basic Syntax
`count` is a meta-argument defined by the Terraform language. It can be used
with modules and with every resource type.
The `count` meta-argument accepts a whole number, and creates that many
instances of the resource or module. Each instance has a distinct infrastructure object
associated with it, and each is separately created,
updated, or destroyed when the configuration is applied.
```hcl
resource "aws_instance" "server" {
count = 4 # create four similar EC2 instances
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
tags = {
Name = "Server ${count.index}"
}
}
```
## The `count` Object
In 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:
- `count.index` The distinct index number (starting with `0`) corresponding
to this instance.
## Using Expressions in `count`
The `count` meta-argument accepts numeric [expressions](/docs/configuration/expressions/index.html).
However, unlike most 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).
## Referring to Instances
When `count` is set, Terraform distinguishes between the block itself
and the multiple _resource or module instances_ associated with it. Instances are
identified by an index number, starting with `0`.
- `<TYPE>.<NAME>` or `module.<NAME>` (for example, `aws_instance.server`) refers to the resource block.
- `<TYPE>.<NAME>[<INDEX>]` or `module.<NAME>[<INDEX>]` (for example, `aws_instance.server[0]`,
`aws_instance.server[1]`, etc.) refers to individual instances.
This is different from resources and modules without `count` or `for_each`, which can be
referenced without an index or key.
Similarly, resources from child modules with multiple instances are prefixed
with `module.<NAME>[<KEY>]` when displayed in plan output and elsewhere in the UI.
For a module without `count` or `for_each`, the address will not contain
the module index as the module's name suffices to reference the module.
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
`self` object refers to the current _resource instance,_ not the resource block
as a whole.
## When to Use `for_each` Instead of `count`
If your 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" {
type = list(string)
}
resource "aws_instance" "server" {
# Create one instance for each subnet
count = length(var.subnet_ids)
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
subnet_id = var.subnet_ids[count.index]
tags = {
Name = "Server ${count.index}"
}
}
```
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.

View File

@ -0,0 +1,76 @@
---
layout: "language"
page_title: "The depends_on Meta-Argument - Configuration Language"
---
# The `depends_on` Meta-Argument
-> **Version note:** Module support for `depends_on` was added in Terraform 0.13, and
previous versions can only use it with resources.
Use the `depends_on` meta-argument to handle hidden resource or module dependencies that
Terraform can't automatically infer.
Explicitly specifying a dependency is only necessary when a resource or module relies on
some other resource's behavior but _doesn't_ access any of that resource's data
in its arguments.
This argument is available in `module` blocks and in all `resource` blocks,
regardless of resource type. For example:
```hcl
resource "aws_iam_role" "example" {
name = "example"
# assume_role_policy is omitted for brevity in this example. See the
# documentation for aws_iam_role for a complete example.
assume_role_policy = "..."
}
resource "aws_iam_instance_profile" "example" {
# Because this expression refers to the role, Terraform can infer
# automatically that the role must be created first.
role = aws_iam_role.example.name
}
resource "aws_iam_role_policy" "example" {
name = "example"
role = aws_iam_role.example.name
policy = jsonencode({
"Statement" = [{
# This policy allows software running on the EC2 instance to
# access the S3 API.
"Action" = "s3:*",
"Effect" = "Allow",
}],
})
}
resource "aws_instance" "example" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
# Terraform can infer from this that the instance profile must
# be created before the EC2 instance.
iam_instance_profile = aws_iam_instance_profile.example
# However, if software running in this EC2 instance needs access
# to the S3 API in order to boot properly, there is also a "hidden"
# dependency on the aws_iam_role_policy that Terraform cannot
# automatically infer, so it must be declared explicitly:
depends_on = [
aws_iam_role_policy.example,
]
}
```
The `depends_on` meta-argument, if present, must be a list of references
to other resources or child modules in the same calling module.
Arbitrary expressions are not allowed in the `depends_on` argument value,
because its value must be known before Terraform knows resource relationships
and thus before it can safely evaluate expressions.
The `depends_on` argument should be used only as a last resort. When using it,
always include a comment explaining why it is being used, to help future
maintainers understand the purpose of the additional dependency.

View File

@ -0,0 +1,199 @@
---
layout: "language"
page_title: "The for_each Meta-Argument - Configuration Language"
---
# The `for_each` Meta-Argument
-> **Version note:** `for_each` was added in Terraform 0.12.6. Module support
for `for_each` was added in Terraform 0.13, and previous versions can only use
it with resources.
-> **Note:** A given resource or module block cannot use both `count` and `for_each`.
> **Hands-on:** Try the [Manage Similar Resources With For Each](https://learn.hashicorp.com/tutorials/terraform/for-each?in=terraform/0-13&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn.
By default, a [resource block](/docs/configuration/blocks/resources/syntax.html) configures one real
infrastructure object. (Similarly, a
[module block](/docs/configuration/blocks/modules/syntax.html) includes a
child module's contents into the configuration one time.)
However, sometimes you want to manage several similar objects (like a fixed
pool of compute instances) without writing a separate block for each one.
Terraform has two ways to do this:
[`count`](/docs/configuration/meta-arguments/count.html) and `for_each`.
If a resource or module block includes a `for_each` argument whose value is a map or
a set of strings, Terraform will create one instance for each member of
that map or set.
## Basic Syntax
`for_each` is a meta-argument defined by the Terraform language. It can be used
with modules and with every resource type.
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, and each is separately created,
updated, or destroyed when the configuration is applied.
-> **Note:** The keys of the map (or all the values in the case of a set of strings) must
be _known values_, or you will get an error message that `for_each` has dependencies
that cannot be determined before apply, and a `-target` may be needed. `for_each` keys
cannot be the result (or rely on the result of) of impure functions, including `uuid`, `bcrypt`,
or `timestamp`, as their evaluation is deferred during the main evaluation step.
Map:
```hcl
resource "azurerm_resource_group" "rg" {
for_each = {
a_group = "eastus"
another_group = "westus2"
}
name = each.key
location = each.value
}
```
Set of strings:
```hcl
resource "aws_iam_user" "the-accounts" {
for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
name = each.key
}
```
Child module:
```hcl
# my_buckets.tf
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" {
# Because var.name includes each.key in the calling
# module block, its value will be different for
# each instance of this module.
bucket = var.name
# ...
}
resource "aws_iam_user" "deploy_user" {
# ...
}
```
## The `each` Object
In 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`.)
## Using Expressions in `for_each`
The `for_each` meta-argument accepts map or set [expressions](/docs/configuration/expressions/index.html).
However, unlike most 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. When providing a set, you must use an expression that
explicitly returns a set value, like the [`toset`](/docs/configuration/functions/toset.html)
function; to prevent unwanted surprises during conversion, the `for_each`
argument does not implicitly convert lists or tuples to sets.
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](/docs/configuration/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](/docs/configuration/functions/setproduct.html#finding-combinations-for-for_each).
## Referring to Instances
When `for_each` is set, Terraform distinguishes between the block itself
and the multiple _resource or module instances_ associated with it. Instances are
identified by a map key (or set member) from the value provided to `for_each`.
- `<TYPE>.<NAME>` or `module.<NAME>` (for example, `azurerm_resource_group.rg`) refers to the block.
- `<TYPE>.<NAME>[<KEY>]` or `module.<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 and modules without `count` or `for_each`, which can be
referenced without an index or key.
Similarly, resources from child modules with multiple instances are prefixed
with `module.<NAME>[<KEY>]` when displayed in plan output and elsewhere in the UI.
For a module without `count` or `for_each`, the address will not contain
the module index as the module's name suffices to reference the module.
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
`self` object refers to the current _resource instance,_ not the resource block
as a whole.
## Using Sets
The Terraform language doesn't have a literal syntax for
[set values](/docs/configuration/types.html#collection-types), but you can use the `toset`
function to explicitly convert a list of strings to a set:
```hcl
locals {
subnet_ids = toset([
"subnet-abcdef",
"subnet-012345",
])
}
resource "aws_instance" "server" {
for_each = local.subnet_ids
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
subnet_id = each.key # note: each.key and each.value are the same for a set
tags = {
Name = "Server ${each.key}"
}
}
```
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.
If you are writing a module with an [input variable](/docs/configuration/variables.html) that
will be used as a set of strings for `for_each`, you can set its type to
`set(string)` to avoid the need for an explicit type conversion:
```hcl
variable "subnet_ids" {
type = set(string)
}
resource "aws_instance" "server" {
for_each = var.subnet_ids
# (and the other arguments as above)
}
```

View File

@ -0,0 +1,110 @@
---
layout: "language"
page_title: "The lifecycle Meta-Argument - Configuration Language"
---
# The `lifecycle` Meta-Argument
The general lifecycle for resources is described in the
[Resource Behavior](/docs/configuration/blocks/resources/behavior.html) page. Some details of
that behavior can be customized using the special nested `lifecycle` block
within a resource block body:
```hcl
resource "azurerm_resource_group" "example" {
# ...
lifecycle {
create_before_destroy = true
}
}
```
## Syntax and Arguments
`lifecycle` is a nested block that can appear within a resource block.
The `lifecycle` block and its contents are meta-arguments, available
for all `resource` blocks regardless of type.
The following arguments can be used within a `lifecycle` block:
* `create_before_destroy` (bool) - By default, when Terraform must change
a resource argument that cannot be updated in-place due to
remote API limitations, Terraform will instead destroy the existing object
and then create a new replacement object with the new configured arguments.
The `create_before_destroy` meta-argument changes this behavior so that
the new replacement object is created _first,_ and the prior object
is destroyed after the replacement is created.
This is an opt-in behavior because many remote object types have unique
name requirements or other constraints that must be accommodated for
both a new and an old object to exist concurrently. Some resource types
offer special options to append a random suffix onto each object name to
avoid collisions, for example. Terraform CLI cannot automatically activate
such features, so you must understand the constraints for each resource
type before using `create_before_destroy` with it.
* `prevent_destroy` (bool) - This meta-argument, when set to `true`, will
cause Terraform to reject with an error any plan that would destroy the
infrastructure object associated with the resource, as long as the argument
remains present in the configuration.
This can be used as a measure of safety against the accidental replacement
of objects that may be costly to reproduce, such as database instances.
However, it will make certain configuration changes impossible to apply,
and will prevent the use of the `terraform destroy` command once such
objects are created, and so this option should be used sparingly.
Since this argument must be present in configuration for the protection to
apply, note that this setting does not prevent the remote object from
being destroyed if the `resource` block were removed from configuration
entirely: in that case, the `prevent_destroy` setting is removed along
with it, and so Terraform will allow the destroy operation to succeed.
* `ignore_changes` (list of attribute names) - By default, Terraform detects
any difference in the current settings of a real infrastructure object
and plans to update the remote object to match configuration.
The `ignore_changes` feature is intended to be used when a resource is
created with references to data that may change in the future, but should
not affect said resource after its creation. In some rare cases, settings
of a remote object are modified by processes outside of Terraform, which
Terraform would then attempt to "fix" on the next run. In order to make
Terraform share management responsibilities of a single object with a
separate process, the `ignore_changes` meta-argument specifies resource
attributes that Terraform should ignore when planning updates to the
associated remote object.
The arguments corresponding to the given attribute names are considered
when planning a _create_ operation, but are ignored when planning an
_update_. The arguments are the relative address of the attributes in the
resource. Map and list elements can be referenced using index notation,
like `tags["Name"]` and `list[0]` respectively.
```hcl
resource "aws_instance" "example" {
# ...
lifecycle {
ignore_changes = [
# Ignore changes to tags, e.g. because a management agent
# updates these based on some ruleset managed elsewhere.
tags,
]
}
}
```
Instead of a list, the special keyword `all` may be used to instruct
Terraform to ignore _all_ attributes, which means that Terraform can
create and destroy the remote object but will never propose updates to it.
Only attributes defined by the resource type can be ignored.
`ignore_changes` cannot be applied to itself or to any other meta-arguments.
## Literal Values Only
The `lifecycle` settings all affect how Terraform constructs and traverses
the dependency graph. As a result, only literal values can be used because
the processing happens too early for arbitrary expression evaluation.

View File

@ -0,0 +1,123 @@
---
layout: "language"
page_title: "The Module providers Meta-Argument - Configuration Language"
---
# The Module `providers` Meta-Argument
In a [module call](/docs/configuration/blocks/modules/syntax.html) block, the
optional `providers` meta-argument specifies which
[provider configurations](/docs/configuration/providers.html) from the parent
module will be available inside the child module.
```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"
}
# An alternate configuration is also defined for a different
# region, using the alias "usw2".
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
# An example child module is instantiated with the alternate configuration,
# so any AWS resources it defines will use the us-west-2 region.
module "example" {
source = "./example"
providers = {
aws = aws.usw2
}
}
```
## Default Behavior: Inherit Default Providers
The `providers` argument is optional. If you omit it, a child module inherits
all of the _default_ provider configurations from its parent module. (Default
provider configurations are ones that don't use the `alias` argument.)
If you specify a `providers` argument, it cancels this default behavior, and the
child module will _only_ have access to the provider configurations you specify.
## Usage and Behavior
The value of `providers` is a map, where:
- The keys are the provider configuration names used inside the child module.
- The values are provider configuration names from the parent module.
Both keys and values should be unquoted references to provider configurations.
For default configurations, this is the local name of the provider; for
alternate configurations, this is a `<PROVIDER>.<ALIAS>` reference.
Within a child module, resources are assigned to provider configurations as
normal — either Terraform chooses a default based on the name of the resource
type, or the resource specifies an alternate configuration with the `provider`
argument. If the module receives a `providers` map when it's called, the
provider configuration names used within the module are effectively remapped to
refer the specified configurations from the parent module.
## When to Specify Providers
There are two main reasons to use the `providers` argument:
- Using different default provider configurations for a child module.
- Configuring a module that requires multiple configurations of the same provider.
### Changing Default Provider Configurations
Most re-usable modules only use default provider configurations, which they can
automatically inherit from their caller when `providers` is omitted.
However, in Terraform configurations that use multiple configurations of the
same provider, you might want some child modules to use the default provider
configuration and other ones to use an alternate. (This usually happens when
using one configuration to manage resources in multiple different regions of the
same cloud provider.)
By using the `providers` argument (like in the code example above), you can
accommodate this without needing to edit the child module. Although the code
within the child module always refers to the default provider configuration, the
actual configuration of that default can be different for each instance.
### Modules With Alternate Provider Configurations
In rare cases, a single re-usable module might require multiple configurations
of the same provider. 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
}
}
```
Non-default provider configurations are never automatically inherited, so any
module that works like this will always need a `providers` argument. The
documentation for the module should specify all of the provider configuration
names it needs.
## More Information for Module Developers
For more details and guidance about working with providers inside a re-usable
child module, see
[Module Development: Providers Within Modules](/docs/modules/providers.html).

View File

@ -0,0 +1,58 @@
---
layout: "language"
page_title: "The Resource provider Meta-Argument - Configuration Language"
---
# The Resource `provider` Meta-Argument
The `provider` meta-argument specifies which provider configuration to use for a resource,
overriding Terraform's default behavior of selecting one based on the resource
type name. Its value should be an unquoted `<PROVIDER>.<ALIAS>` reference.
As described in [Provider Configuration](/docs/configuration/providers.html), you can optionally
create multiple configurations for a single provider (usually to manage
resources in different regions of multi-region services). Each provider can have
one default configuration, and any number of alternate configurations that
include an extra name segment (or "alias").
By default, Terraform interprets the initial word in the resource type name
(separated by underscores) as the local name of a provider, and uses that
provider's default configuration. For example, the resource type
`google_compute_instance` is associated automatically with the default
configuration for the provider named `google`.
By using the `provider` meta-argument, you can select an alternate provider
configuration for a resource:
```hcl
# default configuration
provider "google" {
region = "us-central1"
}
# alternate configuration, whose alias is "europe"
provider "google" {
alias = "europe"
region = "europe-west1"
}
resource "google_compute_instance" "example" {
# This "provider" meta-argument selects the google provider
# configuration whose alias is "europe", rather than the
# default configuration.
provider = google.europe
# ...
}
```
A resource always has an implicit dependency on its associated provider, to
ensure that the provider is fully configured before any resource actions
are taken.
The `provider` meta-argument expects
[a `<PROVIDER>.<ALIAS>` reference](/docs/configuration/providers.html#referring-to-alternate-providers),
which does not need to be quoted. Arbitrary expressions are not permitted for
`provider` because it must be resolved while Terraform is constructing the
dependency graph, before it is safe to evaluate expressions.

View File

@ -1,632 +1,44 @@
---
layout: "language"
page_title: "Modules - Configuration Language"
sidebar_current: "docs-config-modules"
description: |-
Modules allow multiple resources to be grouped together and encapsulated.
page_title: "Modules Landing Page - Configuration Language"
---
# Modules
# Modules Landing Page
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
earlier, see
[0.11 Configuration Language: Modules](../configuration-0-11/modules.html).
To improve navigation, we've split the old Modules page into several smaller
pages.
> **Hands-on:** Try the [Reuse Configuration with Modules](https://learn.hashicorp.com/collections/terraform/modules?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
<a id="calling-a-child-module"></a>
<a id="accessing-module-output-values"></a>
<a id="transferring-resource-state-into-modules"></a>
<a id="tainting-resources-within-a-module"></a>
<a id="module-versions"></a>
<a id="other-meta-arguments"></a>
A _module_ is a container for multiple resources that are used together.
## Syntax and Elements of Module Blocks
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.
This information has moved to
[Module Blocks](/docs/configuration/blocks/modules/syntax.html).
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.
<a id="multiple-instances-of-a-module"></a>
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).
## Multiple Instances with `count` and `for_each`
## Calling a Child Module
This information has moved to
[`count`](/docs/configuration/meta-arguments/count.html) and
[`for_each`](/docs/configuration/meta-arguments/for_each.html).
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:
<a id="providers-within-modules"></a>
<a id="provider-version-constraints-in-modules"></a>
<a id="implicit-provider-inheritance"></a>
<a id="passing-providers-explicitly"></a>
<a id="proxy-configuration-blocks"></a>
<a id="legacy-shared-modules-with-provider-configurations"></a>
```hcl
module "servers" {
source = "./app-cluster"
## Handling Provider Configurations in Re-usable Modules
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. Its value is either the path to a local directory containing 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).
## Transferring Resource State Into Modules
When refactoring an existing configuration to split code into child modules,
moving resource blocks between modules causes Terraform to see the new location
as an entirely different resource from the old. Always check the execution plan
after moving code across modules to ensure that no resources are deleted by
surprise.
If you want to make sure an existing resource is preserved, use
[the `terraform state mv` command](/docs/commands/state/mv.html) to inform
Terraform that it has moved to a different module.
When passing resource addresses to `terraform state mv`, resources within child
modules must be prefixed with `module.<MODULE NAME>.`. If a module was called
with `count` or `for_each` ([see below][inpage-multiple]), its resource
addresses must be prefixed with `module.<MODULE NAME>[<INDEX>].` instead, where
`<INDEX>` matches the `count.index` or `each.key` value of a particular module
instance.
Full resource addresses for module contents are used within the UI and on the
command line, but cannot be used within a Terraform configuration. Only
[outputs](./outputs.html) from a module can be referenced from
elsewhere in your configuration.
## Other Meta-arguments
Along with the `source` meta-argument described above, module blocks have
some optional meta-arguments that have special meaning across all modules,
described in more detail below:
- `version` - A [version constraint string](./version-constraints.html)
that specifies acceptable versions of the module. Described in detail under
[Module Versions][inpage-versions] below.
- `count` and `for_each` - Both of these arguments create multiple instances of a
module from a single `module` block. Described in detail under
[Multiple Instances of a Module][inpage-multiple] below.
- `providers` - A map whose keys are provider configuration names
that are expected by child module and whose values are the corresponding
provider configurations in the calling module. This allows
[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. Described in detail under
[Providers Within Modules][inpage-providers]
- `depends_on` - Creates explicit dependencies between the entire
module and the listed targets. This will delay the final evaluation of the
module, and any sub-modules, until after the dependencies have been applied.
Modules have the same dependency resolution behavior
[as defined for managed resources](./resources.html#resource-dependencies).
In addition to the above, the `lifecycle` argument is not currently used by
Terraform but is 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).
## Module Versions
[inpage-versions]: #module-versions
When using modules installed from a module registry, we recommend explicitly
constraining the acceptable version numbers to avoid unexpected or unwanted
changes.
Use the `version` attribute in the `module` block to specify versions:
```shell
module "consul" {
source = "hashicorp/consul/aws"
version = "0.0.5"
servers = 3
}
```
The `version` attribute accepts a [version constraint string](./version-constraints.html).
Terraform will use the newest installed version of the module that meets the
constraint; if no acceptable versions are installed, it will download the newest
version that meets the constraint.
Version constraints are supported only for modules installed from a module
registry, such as the public [Terraform Registry](https://registry.terraform.io/)
or [Terraform Cloud's private module registry](/docs/cloud/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.
## Multiple Instances of a Module
[inpage-multiple]: #multiple-instances-of-a-module
-> **Note:** Module support for the `for_each` and `count` meta-arguments was
added in Terraform 0.13. Previous versions can only use these arguments with
individual resources.
Use the `for_each` or the `count` argument to create multiple instances of a
module from a single `module` block. These arguments have the same syntax and
type constraints as
[`for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
and
[`count`](./resources.html#count-multiple-resource-instances-by-count)
when used with resources.
```hcl
# my_buckets.tf
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" {
# Because var.name includes each.key in the calling
# module block, its value will be different for
# each instance of this module.
bucket = var.name
# ...
}
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 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 special `each.key` value 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_name[module index]`
when displayed in plan output and elsewhere in the UI. For a module 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.
## Providers Within Modules
[inpage-providers]: #providers-within-modules
In a configuration with multiple modules, there are some special considerations
for how resources are associated with provider configurations.
Each resource in the configuration must be associated with one provider
configuration. Provider configurations, unlike most other concepts in
Terraform, are global to an entire Terraform configuration and can be shared
across module boundaries. Provider configurations can be defined only in a
root Terraform 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.
A module intended to be called by one or more other modules must not contain
any `provider` blocks, with the exception of the special
"proxy provider blocks" discussed under
_[Passing Providers Explicitly](#passing-providers-explicitly)_
below.
For backward compatibility with configurations targeting Terraform v0.10 and
earlier Terraform does not produce an error for a `provider` block in a shared
module if the `module` block only uses features available in Terraform v0.10,
but that is a legacy usage pattern that is no longer recommended. A legacy
module containing its own provider configurations is not compatible with the
`for_each`, `count`, and `depends_on` arguments that were introduced in
Terraform v0.13. For more information, see
[Legacy Shared Modules with Provider Configurations](#legacy-shared-modules-with-provider-configurations).
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 will be used to locate
the appropriate configuration because the resource's `provider` argument
(if any) will no longer be present in the configuration.
As a consequence, you must ensure that all resources that belong to a
particular provider configuration are destroyed before you can remove that
provider configuration's block from your configuration. If Terraform finds
a resource instance tracked in the state whose provider configuration block is
no longer available then it will return an error during planning, prompting you
to reintroduce the provider configuration.
### Provider Version Constraints in Modules
Although provider _configurations_ are shared between modules, each module must
declare its own [provider requirements](provider-requirements.html), so that
Terraform can ensure that there is a single version of the provider that is
compatible with all modules in the configuration and to specify the
[source address](provider-requirements.html#source-addresses) that serves as
the global (module-agnostic) identifier for a provider.
To declare that a module requires particular versions of a specific provider,
use a `required_providers` block inside a `terraform` block:
```hcl
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
}
}
}
```
A provider requirement says, for example, "This module requires version v2.7.0
of the provider `hashicorp/aws` and will refer to it as `aws`." It doesn't,
however, specify any of the configuration settings that determine what remote
endpoints the provider will access, such as an AWS region; configuration
settings come from provider _configurations_, and a particular overall Terraform
configuration can potentially have
[several different configurations for the same provider](providers.html#alias-multiple-provider-instances).
If you are writing a shared Terraform module, constrain only the minimum
required provider version using a `>=` constraint. This should specify the
minimum version containing the features your module relies on, and thus allow a
user of your module to potentially select a newer provider version if other
features are needed by other parts of their overall configuration.
### 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"
}
```
We recommend using this approach when a single configuration for each provider
is sufficient for an entire configuration.
~> **Note:** Only provider configurations are inherited by child modules, not provider source or version requirements. Each module must [declare its own provider requirements](provider-requirements.html). This is especially important for non-HashiCorp providers.
In more complex situations there may be
[multiple provider configurations](/docs/configuration/providers.html#alias-multiple-provider-configurations),
or a child module may need to use different provider settings than
its parent. For such situations, you must pass providers explicitly.
### 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, you can use the `providers` argument within a `module` block
to explicitly define which provider configurations are 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"
}
# An alternate configuration is also defined for a different
# region, using the alias "usw2".
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
# An example child module is instantiated with the alternate 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](resources.html#provider-selecting-a-non-default-provider-configuration)
within a resource, but is a map rather than a single string because a module may
contain resources from many different providers.
The keys of the `providers` map are provider configuration names as expected by
the child module, and the values are the names of corresponding configurations
in the _current_ module.
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
}
}
```
The subdirectory `./tunnel` must then contain _proxy configuration blocks_ like
the following, to declare that it requires its calling module to pass
configurations with these names in its `providers` argument:
```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 configurations to
use.
### Proxy Configuration Blocks
A proxy configuration block is one that contains only the `alias` argument. It
serves as a placeholder for provider configurations passed between modules, and
declares that a module expects to be explicitly passed an additional (aliased)
provider configuration.
-> **Note:** Although a completely empty proxy configuration block is also
valid, it is not necessary: proxy configuration blocks are needed only to
establish which _aliased_ provider configurations a child module expects.
Don't use a proxy configuration block if a module only needs a single default
provider configuration, and don't use proxy configuration blocks only to imply
[provider requirements](./provider-requirements.html).
## Legacy Shared Modules with Provider Configurations
In Terraform v0.10 and earlier there was no explicit way to use different
configurations of a provider in different modules in the same configuration,
and so module authors commonly worked around this by writing `provider` blocks
directly inside their modules, making the module have its own separate
provider configurations separate from those declared in the root module.
However, that pattern had a significant drawback: because a provider
configuration is required to destroy the remote object associated with a
resource instance as well as to create or update it, a provider configuration
must always stay present in the overall Terraform configuration for longer
than all of the resources it manages. If a particular module includes
both resources and the provider configurations for those resources then
removing the module from its caller would violate that constraint: both the
resources and their associated providers would, in effect, be removed
simultaneously.
Terraform v0.11 introduced the mechanisms described in earlier sections to
allow passing provider configurations between modules in a structured way, and
thus we explicitly recommended against writing a child module with its own
provider configuration blocks. However, that legacy pattern continued to work
for compatibility purposes -- though with the same drawback -- until Terraform
v0.13.
Terraform v0.13 introduced the possibility for a module itself to use the
`for_each`, `count`, and `depends_on` arguments, but the implementation of
those unfortunately conflicted with the support for the legacy pattern.
To retain the backward compatibility as much as possible, Terraform v0.13
continues to support the legacy pattern for module blocks that do not use these
new features, but a module with its own provider configurations is not
compatible with `for_each`, `count`, or `depends_on`. Terraform will produce an
error if you attempt to combine these features. For example:
```
Error: Module does not support count
on main.tf line 15, in module "child":
15: count = 2
Module "child" cannot be used with count because it contains a nested provider
configuration for "aws", at child/main.tf:2,10-15.
This module can be made compatible with count by changing it to receive all of
its provider configurations from the calling module, by using the "providers"
argument in the calling module block.
```
To make a module compatible with the new features, you must either remove all
of the `provider` blocks from its definition or, if you need multiple
configurations for the same provider, replace them with
_proxy configuration blocks_ as described in
[Passing Providers Explicitly](#passing-providers-explicitly).
If the new version of the module uses proxy configuration blocks, or if the
calling module needs the child module to use different provider configurations
than its own default provider configurations, the calling module must then
include an explicit `providers` argument to describe which provider
configurations the child module will use:
```hcl
provider "aws" {
region = "us-west-1"
}
provider "aws" {
region = "us-east-1"
alias = "east"
}
module "child" {
count = 2
providers = {
# By default, the child module would use the
# default (unaliased) AWS provider configuration
# using us-west-1, but this will override it
# to use the additional "east" configuration
# for its resources instead.
aws = aws.east
}
}
```
Since the association between resources and provider configurations is
static, module calls using `for_each` or `count` cannot pass different
provider configurations to different instances. If you need different
instances of your module to use different provider configurations then you
must use a separate `module` block for each distinct set of provider
configurations:
```hcl
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
}
}
```
## 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.
This information has moved to
[The `providers` Meta-Argument](/docs/configuration/meta-arguments/module-providers.html)
(for users of re-usable modules) and
[Providers Within Modules](/docs/modules/providers.html)
(for module developers).

View File

@ -46,7 +46,7 @@ valid [identifier](./syntax.html#identifiers). In a root module, this name is
displayed to the user; in a child module, it can be used to access the output's
value.
The `value` argument takes an [expression](./expressions.html)
The `value` argument takes an [expression](/docs/configuration/expressions/index.html)
whose result is to be returned to the user. In this example, the expression
refers to the `private_ip` attribute exposed by an `aws_instance` resource
defined elsewhere in this module (not shown). Any valid expression is allowed
@ -98,7 +98,7 @@ output "db_password" {
}
```
Setting an output value as sensitive prevents Terraform from showing its value
Setting an output value as sensitive prevents Terraform from showing its value
in `plan` and `apply`. In the following scenario, our root module has an output declared as sensitive
and a module call with a sensitive output, which we then use in a resource attribute.
@ -163,7 +163,7 @@ correctly determine the dependencies between resources defined in different
modules.
Just as with
[resource dependencies](./resources.html#resource-dependencies),
[resource dependencies](/docs/configuration/blocks/resources/behavior.html#resource-dependencies),
Terraform analyzes the `value` expression for an output value and automatically
determines a set of dependencies, but in less-common cases there are
dependencies that cannot be recognized implicitly. In these rare cases, the

View File

@ -28,7 +28,8 @@ configuration (like endpoint URLs or cloud regions) before they can be used.
Provider configurations belong in the root module of a Terraform configuration.
(Child modules receive their provider configurations from the root module; for
more information, see
[Providers Within Modules](./modules.html#providers-within-modules).)
[The Module `providers` Meta-Argument](/docs/configuration/meta-arguments/module-providers.html)
and [Module Development: Providers Within Modules](/docs/modules/providers.html).)
A provider configuration is created using a `provider` block:
@ -49,7 +50,7 @@ the provider. Most arguments in this section are defined by the provider itself;
in this example both `project` and `region` are specific to the `google`
provider.
You can use [expressions](./expressions.html) in the values of these
You can use [expressions](/docs/configuration/expressions/index.html) in the values of these
configuration arguments, but can only reference values that are known before the
configuration is applied. This means you can safely reference input variables,
but not attributes exported by resources (with an exception for resource
@ -160,7 +161,7 @@ module "aws_vpc" {
```
Modules have some special requirements when passing in providers; see
[Providers Within Modules](./modules.html#providers-within-modules)
[The Module `providers` Meta-Argument](/docs/configuration/meta-arguments/module-providers.html)
for more details. In most cases, only _root modules_ should define provider
configurations, with all child modules obtaining their provider configurations
from their parents.
@ -177,7 +178,7 @@ works the same way as the `version` argument in a
constraint in a provider configuration is only used if `required_providers`
does not include one for that provider.
**The `version` argument in provider configurations is deprecated.**
**The `version` argument in provider configurations is deprecated.**
In Terraform 0.13 and later, version constraints should always be declared in
[the `required_providers` block](./provider-requirements.html). The `version`
argument will be removed in a future version of Terraform.

View File

@ -1,764 +1,86 @@
---
layout: "language"
page_title: "Resources - Configuration Language"
sidebar_current: "docs-config-resources"
description: |-
Resources are the most important element in a Terraform configuration.
Each resource corresponds to an infrastructure object, such as a virtual
network or compute instance.
page_title: "Resources Landing Page - Configuration Language"
---
# Resources
# Resources Landing Page
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
earlier, see
[0.11 Configuration Language: Resources](../configuration-0-11/resources.html).
To improve navigation, we've split the old Resources page into several smaller
pages.
> **Hands-on:** Try the [Terraform: Get Started](https://learn.hashicorp.com/collections/terraform/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
<a id="resource-syntax"></a>
<a id="resource-types"></a>
<a id="providers"></a>
<a id="resource-arguments"></a>
<a id="documentation-for-resource-types"></a>
<a id="meta-arguments"></a>
<a id="operation-timeouts"></a>
_Resources_ are the most important element in the Terraform language.
Each resource block describes one or more infrastructure objects, such
as virtual networks, compute instances, or higher-level components such
as DNS records.
## Syntax and Elements of Resource Blocks
## Resource Syntax
This information has moved to
[Resource Blocks](/docs/configuration/blocks/resources/syntax.html).
Resource declarations can include a number of advanced features, but only
a small subset are required for initial use. More advanced syntax features,
such as single resource declarations that produce multiple similar remote
objects, are described later in this page.
<a id="resource-behavior"></a>
<a id="accessing-resource-attributes"></a>
<a id="resource-dependencies"></a>
<a id="local-only-resources"></a>
```hcl
resource "aws_instance" "web" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
}
```
## Details of Resource Behavior
A `resource` block declares a resource of a given type ("aws_instance")
with a given local name ("web"). The name is used to refer to this resource
from elsewhere in the same Terraform module, but has no significance outside
that module's scope.
This information has moved to
[Resource Behavior](/docs/configuration/blocks/resources/behavior.html).
The resource type and name together serve as an identifier for a given
resource and so must be unique within a module.
## Resource Meta-Arguments
Within the block body (between `{` and `}`) are the configuration arguments
for the resource itself. Most arguments in this section depend on the
resource type, and indeed in this example both `ami` and `instance_type` are
arguments defined specifically for [the `aws_instance` resource type](/docs/providers/aws/r/instance.html).
Each resource meta-argument has moved to its own page.
-> **Note:** Resource names must start with a letter or underscore, and may
contain only letters, digits, underscores, and dashes.
<a id="depends_on-explicit-resource-dependencies"></a>
## Resource Types
### `depends_on`
Each resource is associated with a single _resource type_, which determines
the kind of infrastructure object it manages and what arguments and other
attributes the resource supports.
This information has moved to
[`depends_on`](/docs/configuration/meta-arguments/depends_on.html).
### Providers
<a id="count-multiple-resource-instances-by-count"></a>
<a id="the-count-object"></a>
<a id="referring-to-instances"></a>
<a id="using-expressions-in-count"></a>
<a id="when-to-use-for_each-instead-of-count"></a>
Each resource type is implemented by a [provider](./provider-requirements.html),
which is a plugin for Terraform that offers a collection of resource types. A
provider usually provides resources to manage a single cloud or on-premises
infrastructure platform. Providers are distributed separately from Terraform
itself, but Terraform can automatically install most providers when initializing
a working directory.
### `count`
In order to manage resources, a Terraform module must specify which providers it
requires. Additionally, most providers need some configuration in order to
access their remote APIs, and the root module must provide that configuration.
This information has moved to
[`count`](/docs/configuration/meta-arguments/count.html).
For more information, see:
<a id="for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings"></a>
<a id="the-each-object"></a>
<a id="using-expressions-in-for_each"></a>
<a id="referring-to-instances-1"></a>
<a id="using-sets"></a>
- [Provider Requirements](./provider-requirements.html), for declaring which
providers a module uses.
- [Provider Configuration](./providers.html), for configuring provider settings.
### `for_each`
Terraform usually automatically determines which provider to use based on a
resource type's name. (By convention, resource type names start with their
provider's preferred local name.) When using multiple configurations of a
provider (or non-preferred local provider names), you must use the `provider`
meta-argument to manually choose an alternate provider configuration. See
[the section on `provider` below][inpage-provider] for more details.
This information has moved to
[`for_each`](/docs/configuration/meta-arguments/for_each.html).
### Resource Arguments
<a id="provider-selecting-a-non-default-provider-configuration"></a>
Most of the arguments within the body of a `resource` block are specific to the
selected resource type. The resource type's documentation lists which arguments
are available and how their values should be formatted.
### `provider`
The values for resource arguments can make full use of
[expressions](./expressions.html) and other dynamic Terraform
language features.
This information has moved to
[`provider`](/docs/configuration/meta-arguments/resource-provider.html).
There are also some _meta-arguments_ that are defined by Terraform itself
and apply across all resource types. (See [Meta-Arguments](#meta-arguments) below.)
<a id="lifecycle-lifecycle-customizations"></a>
### Documentation for Resource Types
### `lifecycle`
Every Terraform provider has its own documentation, describing its resource
types and their arguments.
This information has moved to
[`lifecycle`](/docs/configuration/meta-arguments/lifecycle.html).
Most publicly available providers are distributed on the
[Terraform Registry](https://registry.terraform.io/browse/providers), which also
hosts their documentation. When viewing a provider's page on the Terraform
Registry, you can click the "Documentation" link in the header to browse its
documentation. Provider documentation on the registry is versioned, and you can
use the dropdown version menu in the header to switch which version's
documentation you are viewing.
<a id="provisioner-and-connection-resource-provisioners"></a>
To browse the publicly available providers and their documentation, see
[the providers section of the Terraform Registry](https://registry.terraform.io/browse/providers).
### Provisioners
-> **Note:** Provider documentation used to be hosted directly on terraform.io,
as part of Terraform's core documentation. Although some provider documentation
might still be hosted here, the Terraform Registry is now the main home for all
public provider docs. (The exception is the built-in
[`terraform` provider](/docs/providers/terraform/index.html) for reading state
data, since it is not available on the Terraform Registry.)
## Resource Behavior
A `resource` block declares that you want a particular infrastructure object
to exist with the given settings. If you are writing a new configuration for
the first time, the resources it defines will exist _only_ in the configuration,
and will not yet represent real infrastructure objects in the target platform.
_Applying_ a Terraform configuration is the process of creating, updating,
and destroying real infrastructure objects in order to make their settings
match the configuration.
When Terraform creates a new infrastructure object represented by a `resource`
block, the identifier for that real object is saved in Terraform's
[state](/docs/state/index.html), allowing it to be updated and destroyed
in response to future changes. For resource blocks that already have an
associated infrastructure object in the state, Terraform compares the
actual configuration of the object with the arguments given in the
configuration and, if necessary, updates the object to match the configuration.
This general behavior applies for all resources, regardless of type. The
details of what it means to create, update, or destroy a resource are different
for each resource type, but this standard set of verbs is common across them
all.
The meta-arguments within `resource` blocks, documented in the
sections below, allow some details of this standard resource behavior to be
customized on a per-resource basis.
### Accessing Resource Attributes
[Expressions](./expressions.html) within a Terraform module can access
information about resources in the same module, and you can use that information
to help configure other resources. Use the `<RESOURCE TYPE>.<NAME>.<ATTRIBUTE>`
syntax to reference a resource attribute in an expression.
In addition to arguments specified in the configuration, resources often provide
read-only attributes with information obtained from the remote API; this often
includes things that can't be known until the resource is created, like the
resource's unique random ID.
Many providers also include [data sources](./data-sources.html), which are a
special type of resource used only for looking up information.
For a list of the attributes a resource or data source type provides, consult
its documentation; these are generally included in a second list below its list
of configurable arguments.
For more information about referencing resource attributes in expressions, see
[Expressions: References to Resource Attributes](./expressions.html#references-to-resource-attributes).
### Resource Dependencies
Most resources in a configuration don't have any particular relationship, and
Terraform can make changes to several unrelated resources in parallel.
However, some resources must be processed after other specific resources;
sometimes this is because of how the resource works, and sometimes the
resource's configuration just requires information generated by another
resource.
Most resource dependencies are handled automatically. Terraform analyses any
[expressions](./expressions.html) within a `resource` block to find references
to other objects, and treats those references as implicit ordering requirements
when creating, updating, or destroying resources. Since most resources with
behavioral dependencies on other resources also refer to those resources' data,
it's usually not necessary to manually specify dependencies between resources.
However, some dependencies cannot be recognized implicitly in configuration. For
example, if Terraform must manage access control policies _and_ take actions
that require those policies to be present, there is a hidden dependency between
the access policy and a resource whose creation depends on it. In these rare
cases, [the `depends_on` meta-argument][inpage-depend] can explicitly specify a
dependency.
## Meta-Arguments
Terraform CLI defines the following meta-arguments, which can be used with
any resource type to change the behavior of resources:
- [`depends_on`, for specifying hidden dependencies][inpage-depend]
- [`count`, for creating multiple resource instances according to a count][inpage-count]
- [`for_each`, to create multiple instances according to a map, or set of strings][inpage-for_each]
- [`provider`, for selecting a non-default provider configuration][inpage-provider]
- [`lifecycle`, for lifecycle customizations][inpage-lifecycle]
- [`provisioner` and `connection`, for taking extra actions after resource creation][inpage-provisioner]
These arguments often have additional restrictions on what language features can
be used with them, which are described in each
### `depends_on`: Explicit Resource Dependencies
[inpage-depend]: #depends_on-explicit-resource-dependencies
Use the `depends_on` meta-argument to handle hidden resource dependencies that
Terraform can't automatically infer.
Explicitly specifying a dependency is only necessary when a resource relies on
some other resource's behavior but _doesn't_ access any of that resource's data
in its arguments.
This argument is available in all `resource` blocks, regardless of resource
type. For example:
```hcl
resource "aws_iam_role" "example" {
name = "example"
# assume_role_policy is omitted for brevity in this example. See the
# documentation for aws_iam_role for a complete example.
assume_role_policy = "..."
}
resource "aws_iam_instance_profile" "example" {
# Because this expression refers to the role, Terraform can infer
# automatically that the role must be created first.
role = aws_iam_role.example.name
}
resource "aws_iam_role_policy" "example" {
name = "example"
role = aws_iam_role.example.name
policy = jsonencode({
"Statement" = [{
# This policy allows software running on the EC2 instance to
# access the S3 API.
"Action" = "s3:*",
"Effect" = "Allow",
}],
})
}
resource "aws_instance" "example" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
# Terraform can infer from this that the instance profile must
# be created before the EC2 instance.
iam_instance_profile = aws_iam_instance_profile.example
# However, if software running in this EC2 instance needs access
# to the S3 API in order to boot properly, there is also a "hidden"
# dependency on the aws_iam_role_policy that Terraform cannot
# automatically infer, so it must be declared explicitly:
depends_on = [
aws_iam_role_policy.example,
]
}
```
The `depends_on` meta-argument, if present, must be a list of references
to other resources in the same module. Arbitrary expressions are not allowed
in the `depends_on` argument value, because its value must be known before
Terraform knows resource relationships and thus before it can safely
evaluate expressions.
The `depends_on` argument should be used only as a last resort. When using it,
always include a comment explaining why it is being used, to help future
maintainers understand the purpose of the additional dependency.
### `count`: Multiple Resource Instances By Count
[inpage-count]: #count-multiple-resource-instances-by-count
-> **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].
> **Hands-on:** Try the [Manage Similar Resources With Count](https://learn.hashicorp.com/tutorials/terraform/count?in=terraform/0-13&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn.
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" {
count = 4 # create four similar EC2 instances
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
tags = {
Name = "Server ${count.index}"
}
}
```
#### The `count` Object
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:
- `count.index` The distinct index number (starting with `0`) corresponding
to this instance.
#### Referring to Instances
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.
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
`self` object refers to the current _resource instance,_ not the resource block
as a whole.
#### 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" {
type = list(string)
}
resource "aws_instance" "server" {
# Create one instance for each subnet
count = length(var.subnet_ids)
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
subnet_id = var.subnet_ids[count.index]
tags = {
Name = "Server ${count.index}"
}
}
```
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
-> **Version note:** `for_each` was added in Terraform 0.12.6.
-> **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`.
> **Hands-on:** Try the [Manage Similar Resources With For Each](https://learn.hashicorp.com/tutorials/terraform/for-each?in=terraform/0-13&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn.
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.
-> **Note:** The keys of the map (or all the values in the case of a set of strings) must
be _known values_, or you will get an error message that `for_each` has dependencies
that cannot be determined before apply, and a `-target` may be needed. `for_each` keys
cannot be the result (or rely on the result of) of impure functions, including `uuid`, `bcrypt`,
or `timestamp`, as their evaluation is deferred resource during evaluation.
Map:
```hcl
resource "azurerm_resource_group" "rg" {
for_each = {
a_group = "eastus"
another_group = "westus2"
}
name = each.key
location = each.value
}
```
Set of strings:
```hcl
resource "aws_iam_user" "the-accounts" {
for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
name = each.key
}
```
#### The `each` Object
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`.)
#### 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. When providing a set, you must use an expression that
explicitly returns a set value, like the [`toset`](/docs/configuration/functions/toset.html)
function; to prevent unwanted surprises during conversion, the `for_each`
argument does not implicitly convert lists or tuples to sets.
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
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.
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
`self` object refers to the current _resource instance,_ not the resource block
as a whole.
#### Using Sets
The Terraform language doesn't have a literal syntax for
[set values](./types.html#collection-types), but you can use the `toset`
function to explicitly convert a list of strings to a set:
```hcl
locals {
subnet_ids = toset([
"subnet-abcdef",
"subnet-012345",
])
}
resource "aws_instance" "server" {
for_each = local.subnet_ids
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
subnet_id = each.key # note: each.key and each.value are the same for a set
tags = {
Name = "Server ${each.key}"
}
}
```
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.
If you are writing a module with an [input variable](./variables.html) that
will be used as a set of strings for `for_each`, you can set its type to
`set(string)` to avoid the need for an explicit type conversion:
```
variable "subnet_ids" {
type = set(string)
}
resource "aws_instance" "server" {
for_each = var.subnet_ids
# (and the other arguments as above)
}
```
### `provider`: Selecting a Non-default Provider Configuration
[inpage-provider]: #provider-selecting-a-non-default-provider-configuration
The `provider` meta-argument specifies which provider configuration to use,
overriding Terraform's default behavior of selecting one based on the resource
type name. Its value should be an unquoted `<PROVIDER>.<ALIAS>` reference.
As described in [Provider Configuration](./providers.html), you can optionally
create multiple configurations for a single provider (usually to manage
resources in different regions of multi-region services). Each provider can have
one default configuration, and any number of alternate configurations that
include an extra name segment (or "alias").
By default, Terraform interprets the initial word in the resource type name
(separated by underscores) as the local name of a provider, and uses that
provider's default configuration. For example, the resource type
`google_compute_instance` is associated automatically with the default
configuration for the provider named `google`.
By using the `provider` meta-argument, you can select an alternate provider
configuration for a resource:
```hcl
# default configuration
provider "google" {
region = "us-central1"
}
# alternate configuration, whose alias is "europe"
provider "google" {
alias = "europe"
region = "europe-west1"
}
resource "google_compute_instance" "example" {
# This "provider" meta-argument selects the google provider
# configuration whose alias is "europe", rather than the
# default configuration.
provider = google.europe
# ...
}
```
A resource always has an implicit dependency on its associated provider, to
ensure that the provider is fully configured before any resource actions
are taken.
The `provider` meta-argument expects
[a `<PROVIDER>.<ALIAS>` reference](./providers.html#referring-to-alternate-providers),
which does not need to be quoted. Arbitrary expressions are not permitted for
`provider` because it must be resolved while Terraform is constructing the
dependency graph, before it is safe to evaluate expressions.
### `lifecycle`: Lifecycle Customizations
[inpage-lifecycle]: #lifecycle-lifecycle-customizations
The general lifecycle for resources is described above in the
[Resource Behavior](#resource-behavior) section. Some details of that behavior
can be customized using the special nested `lifecycle` block within a resource
block body:
```
resource "azurerm_resource_group" "example" {
# ...
lifecycle {
create_before_destroy = true
}
}
```
The `lifecycle` block and its contents are meta-arguments, available
for all `resource` blocks regardless of type. The following lifecycle
meta-arguments are supported:
* `create_before_destroy` (bool) - By default, when Terraform must make a
change to a resource argument that cannot be updated in-place due to
remote API limitations, Terraform will instead destroy the existing object
and then create a new replacement object with the new configured arguments.
The `create_before_destroy` meta-argument changes this behavior so that
the new replacement object is created _first,_ and then the prior object
is destroyed only once the replacement is created.
This is an opt-in behavior because many remote object types have unique
name requirements or other constraints that must be accommodated for
both a new and an old object to exist concurrently. Some resource types
offer special options to append a random suffix onto each object name to
avoid collisions, for example. Terraform CLI cannot automatically activate
such features, so you must understand the constraints for each resource
type before using `create_before_destroy` with it.
* `prevent_destroy` (bool) - This meta-argument, when set to `true`, will
cause Terraform to reject with an error any plan that would destroy the
infrastructure object associated with the resource, as long as the argument
remains present in the configuration.
This can be used as a measure of safety against the accidental replacement
of objects that may be costly to reproduce, such as database instances.
However, it will make certain configuration changes impossible to apply,
and will prevent the use of the `terraform destroy` command once such
objects are created, and so this option should be used sparingly.
Since this argument must be present in configuration for the protection to
apply, note that this setting does not prevent the remote object from
being destroyed if the `resource` block were removed from configuration
entirely: in that case, the `prevent_destroy` setting is removed along
with it, and so Terraform will allow the destroy operation to succeed.
* `ignore_changes` (list of attribute names) - By default, Terraform detects
any difference in the current settings of a real infrastructure object
and plans to update the remote object to match configuration.
The `ignore_changes` feature is intended to be used when a resource is
created with references to data that may change in the future, but should
not effect said resource after its creation. In some rare cases, settings
of a remote object are modified by processes outside of Terraform, which
Terraform would then attempt to "fix" on the next run. In order to make
Terraform share management responsibilities of a single object with a
separate process, the `ignore_changes` meta-argument specifies resource
attributes that Terraform should ignore when planning updates to the
associated remote object.
The arguments corresponding to the given attribute names are considered
when planning a _create_ operation, but are ignored when planning an
_update_. The arguments are the relative address of the attributes in the
resource. Map and list elements can be referenced using index notation,
like `tags["Name"]` and `list[0]` respectively.
```hcl
resource "aws_instance" "example" {
# ...
lifecycle {
ignore_changes = [
# Ignore changes to tags, e.g. because a management agent
# updates these based on some ruleset managed elsewhere.
tags,
]
}
}
```
Instead of a list, the special keyword `all` may be used to instruct
Terraform to ignore _all_ attributes, which means that Terraform can
create and destroy the remote object but will never propose updates to it.
Only attributes defined by the resource type can be ignored.
`ignore_changes` cannot be applied to itself or to any other meta-arguments.
The `lifecycle` settings all effect how Terraform constructs and traverses
the dependency graph. As a result, only literal values can be used because
the processing happens too early for arbitrary expression evaluation.
### `provisioner` and `connection`: Resource Provisioners
[inpage-provisioner]: #provisioner-and-connection-resource-provisioners
> **Hands-on:** To learn about more declarative ways to handle provisioning actions, try the [Provision Infrastructure Deployed with Terraform](https://learn.hashicorp.com/collections/terraform/provision?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
Some infrastructure objects require some special actions to be taken after they
are created before they can become fully functional. For example, compute
instances may require configuration to be uploaded or a configuration management
program to be run before they can begin their intended operation.
Create-time actions like these can be described using _resource provisioners_.
A provisioner is another type of plugin supported by Terraform, and each
provisioner takes a different kind of action in the context of a resource
being created.
Provisioning steps should be used sparingly, since they represent
non-declarative actions taken during the creation of a resource and so
Terraform is not able to model changes to them as it can for the declarative
portions of the Terraform language.
Provisioners can also be defined to run when a resource is _destroyed_, with
certain limitations.
The `provisioner` and `connection` block types within `resource` blocks are
meta-arguments available across all resource types. Provisioners and their
usage are described in more detail in
[the Provisioners section](/docs/provisioners/index.html).
## Local-only Resources
While most resource types correspond to an infrastructure object type that
is managed via a remote network API, there are certain specialized resource
types that operate only within Terraform itself, calculating some results and
saving those results in the state for future use.
For example, local-only resource types exist for
[generating private keys](/docs/providers/tls/r/private_key.html),
[issuing self-signed TLS certificates](/docs/providers/tls/r/self_signed_cert.html),
and even [generating random ids](/docs/providers/random/r/id.html).
While these resource types often have a more marginal purpose than those
managing "real" infrastructure objects, they can be useful as glue to help
connect together other resources.
The behavior of local-only resources is the same as all other resources, but
their result data exists only within the Terraform state. "Destroying" such
a resource means only to remove it from the state, discarding its data.
## Operation Timeouts
Some resource types provide a special `timeouts` nested block argument that
allows you to customize how long certain operations are allowed to take
before being considered to have failed.
For example, [`aws_db_instance`](/docs/providers/aws/r/db_instance.html)
allows configurable timeouts for `create`, `update` and `delete` operations.
Timeouts are handled entirely by the resource type implementation in the
provider, but resource types offering these features follow the convention
of defining a child block called `timeouts` that has a nested argument
named after each operation that has a configurable timeout value.
Each of these arguments takes a string representation of a duration, such
as `"60m"` for 60 minutes, `"10s"` for ten seconds, or `"2h"` for two hours.
```hcl
resource "aws_db_instance" "example" {
# ...
timeouts {
create = "60m"
delete = "2h"
}
}
```
The set of configurable operations is chosen by each resource type. Most
resource types do not support the `timeouts` block at all. Consult the
documentation for each resource type to see which operations it offers
for configuration, if any.
This information has moved to
[Provisioners](/docs/configuration/blocks/resources/provisioners/index.html).

View File

@ -99,7 +99,7 @@ different (see the [block-type-specific exceptions](#block-type-specific-excepti
correspond either to argument names or to nested block type names.
* Where a property corresponds to an argument that accepts
[arbitrary expressions](./expressions.html) in the native syntax, the
[arbitrary expressions](/docs/configuration/expressions/index.html) in the native syntax, the
property value is mapped to an expression as described under
[_Expression Mapping_](#expression-mapping) below. For arguments that
do _not_ accept arbitrary expressions, the interpretation of the property
@ -116,20 +116,22 @@ different (see the [block-type-specific exceptions](#block-type-specific-excepti
## Expression Mapping
Since JSON grammar is not able to represent all of the Terraform language
[expression syntax](./expressions.html), JSON values interpreted as expressions
[expression syntax](/docs/configuration/expressions/index.html), JSON values interpreted as expressions
are mapped as follows:
| JSON | Terraform Language Interpretation |
| ------- | ------------------------------------------------------------------------------------------------------------- |
| Boolean | A literal `bool` value. |
| Number | A literal `number` value. |
| String | Parsed as a [string template](./expressions.html#string-templates) and then evaluated as described below. |
| String | Parsed as a [string template][] and then evaluated as described below. |
| Object | Each property value is mapped per this table, producing an `object(...)` value with suitable attribute types. |
| Array | Each element is mapped per this table, producing a `tuple(...)` value with suitable element types. |
| Null | A literal `null`. |
[string template]: /docs/configuration/expressions/strings.html#string-templates
When a JSON string is encountered in a location where arbitrary expressions are
expected, its value is first parsed as a [string template](./expressions.html#string-templates)
expected, its value is first parsed as a [string template][]
and then it is evaluated to produce the final result.
If the given template consists _only_ of a single interpolation sequence,

View File

@ -53,7 +53,7 @@ after the equals sign is the argument's value.
The context where the argument appears determines what value types are valid
(for example, each resource type has a schema that defines the types of its
arguments), but many arguments accept arbitrary
[expressions](./expressions.html), which allow the value to
[expressions](/docs/configuration/expressions/index.html), which allow the value to
either be specified literally or generated from other values programmatically.
-> **Note:** Terraform's configuration language is based on a more general

View File

@ -51,7 +51,7 @@ can be used with your configuration.
If the running version of Terraform doesn't match the constraints specified,
Terraform will produce an error and exit without taking any further actions.
When you use [child modules](./modules.html), each module can specify its own
When you use [child modules](/docs/configuration/blocks/modules/index.html), each module can specify its own
version requirements. The requirements of all modules in the tree must be
satisfied.

View File

@ -32,7 +32,7 @@ function-like constructs called _type constructors._
represent a type; instead, it represents a _kind_ of similar types.
Type constraints look like other kinds of Terraform
[expressions](./expressions.html), but are a special syntax. Within the
[expressions](/docs/configuration/expressions/index.html), but are a special syntax. Within the
Terraform language, they are only valid in the `type` argument of an
[input variable](./variables.html).
@ -160,7 +160,7 @@ like the following:
The Terraform language has literal expressions for creating tuple and object
values, which are described in
[Expressions: Literal Expressions](./expressions.html#literal-expressions) as
[Expressions: Literal Expressions](/docs/configuration/expressions/types.html#literal-expressions) as
"list/tuple" literals and "map/object" literals, respectively.
Terraform does _not_ provide any way to directly represent lists, maps, or sets.

View File

@ -21,7 +21,7 @@ and allowing modules to be shared between different configurations.
When you declare variables in the root module of your configuration, you can
set their values using CLI options and environment variables.
When you declare them in [child modules](./modules.html),
When you declare them in [child modules](/docs/configuration/blocks/modules/index.html),
the calling module should pass values in the `module` block.
If you're familiar with traditional programming languages, it can be useful to
@ -36,7 +36,7 @@ compare Terraform modules to function definitions:
variable is being discussed. Other kinds of variables in Terraform include
_environment variables_ (set by the shell where Terraform runs) and _expression
variables_ (used to indirectly represent a value in an
[expression](./expressions.html)).
[expression](/docs/configuration/expressions/index.html)).
## Declaring an Input Variable
@ -78,7 +78,7 @@ The name of a variable can be any valid [identifier](./syntax.html#identifiers)
_except_ the following: `source`, `version`, `providers`, `count`, `for_each`, `lifecycle`, `depends_on`, `locals`.
These names are reserved for meta-arguments in
[module configuration blocks](./modules.html), and cannot be
[module configuration blocks](/docs/configuration/blocks/modules/syntax.html), and cannot be
declared as variable names.
## Arguments
@ -106,7 +106,7 @@ configuration.
[inpage-type]: #type-constraints
The `type` argument in a `variable` block allows you to restrict the
[type of value](./expressions.html#types-and-values) that will be accepted as
[type of value](/docs/configuration/expressions/types.html) that will be accepted as
the value for a variable. If no type constraint is set then a value of any type
is accepted.
@ -302,7 +302,7 @@ random_pet.animal: Creation complete after 0s [id=jae-known-mongoose]
## Using Input Variable Values
Within the module that declared a variable, its value can be accessed from
within [expressions](./expressions.html) as `var.<NAME>`,
within [expressions](/docs/configuration/expressions/index.html) as `var.<NAME>`,
where `<NAME>` matches the label given in the declaration block:
-> **Note:** Input variables are _created_ by a `variable` block, but you
@ -332,7 +332,7 @@ can be set in a number of ways:
The following sections describe these options in more detail. This section does
not apply to _child_ modules, where values for input variables are instead
assigned in the configuration of their parent module, as described in
[_Modules_](./modules.html).
[_Modules_](/docs/configuration/blocks/modules/index.html).
### Variables on the Command Line
@ -411,9 +411,10 @@ and lower case letters as in the above example.
### Complex-typed Values
When variable values are provided in a variable definitions file, Terraform's
[usual syntax](./expressions.html#structural-types) can be used to assign
complex-typed values, like lists and maps.
When variable values are provided in a variable definitions file, you can use
Terraform's usual syntax for
[literal expressions](/docs/configuration/expressions/types.html#literal-expressions)
to assign complex-typed values, like lists and maps.
Some special rules apply to the `-var` command line option and to environment
variables. For convenience, Terraform defaults to interpreting `-var` and

View File

@ -9,7 +9,7 @@ Anywhere that Terraform lets you specify a range of acceptable versions for
something, it expects a specially formatted string known as a version
constraint. Version constraints are used when configuring:
- [Modules](./modules.html)
- [Modules](/docs/configuration/blocks/modules/index.html)
- [Provider requirements](./provider-requirements.html)
- [The `required_version` setting](./terraform.html#specifying-a-required-terraform-version) in the `terraform` block.
@ -22,7 +22,7 @@ other dependency management systems like Bundler and NPM.
version = ">= 1.2.0, < 2.0.0"
```
A version constraint is a [string literal](./expressions.html#string-literals)
A version constraint is a [string literal](/docs/configuration/expressions/strings.html)
containing one or more conditions, which are separated by commas.
Each condition consists of an operator and a version number.

View File

@ -17,11 +17,11 @@ directly in terms of physical objects.
The `.tf` files in your working directory when you run [`terraform plan`](/docs/commands/plan.html)
or [`terraform apply`](/docs/commands/apply.html) together form the _root_
module. That module may [call other modules](/docs/configuration/modules.html#calling-a-child-module)
module. That module may [call other modules](/docs/configuration/blocks/modules/syntax.html#calling-a-child-module)
and connect them together by passing output values from one to input values
of another.
To learn how to _use_ modules, see [the Modules configuration section](/docs/configuration/modules.html).
To learn how to _use_ modules, see [the Modules configuration section](/docs/configuration/blocks/modules/index.html).
This section is about _creating_ re-usable modules that other configurations
can include using `module` blocks.
@ -35,7 +35,7 @@ Most commonly, modules use:
the calling module.
* [Output values](/docs/configuration/outputs.html) to return results to the
calling module, which it can then use to populate arguments elsewhere.
* [Resources](/docs/configuration/resources.html) to define one or more
* [Resources](/docs/configuration/blocks/resources/index.html) to define one or more
infrastructure objects that the module will manage.
To define a module, create a new directory for it and place one or more `.tf`
@ -71,126 +71,3 @@ your module is not creating any new abstraction and so the module is
adding unnecessary complexity. Just use the resource type directly in the
calling module instead.
## Standard Module Structure
The standard module structure is a file and directory layout we recommend for
reusable modules distributed in separate repositories. Terraform tooling is
built to understand the standard module structure and use that structure to
generate documentation, index modules for the module registry, and more.
The standard module structure expects the layout documented below. The list may
appear long, but everything is optional except for the root module. Most modules
don't need to do any extra work to follow the standard structure.
* **Root module**. This is the **only required element** for the standard
module structure. Terraform files must exist in the root directory of
the repository. This should be the primary entrypoint for the module and is
expected to be opinionated. For the
[Consul module](https://registry.terraform.io/modules/hashicorp/consul)
the root module sets up a complete Consul cluster. It makes a lot of assumptions
however, and we expect that advanced users will use specific _nested modules_
to more carefully control what they want.
* **README**. The root module and any nested modules should have README
files. This file should be named `README` or `README.md`. The latter will
be treated as markdown. There should be a description of the module and
what it should be used for. If you want to include an example for how this
module can be used in combination with other resources, put it in an [examples
directory like this](https://github.com/hashicorp/terraform-aws-consul/tree/master/examples).
Consider including a visual diagram depicting the infrastructure resources
the module may create and their relationship.
The README doesn't need to document inputs or outputs of the module because
tooling will automatically generate this. If you are linking to a file or
embedding an image contained in the repository itself, use a commit-specific
absolute URL so the link won't point to the wrong version of a resource in the
future.
* **LICENSE**. The license under which this module is available. If you are
publishing a module publicly, many organizations will not adopt a module
unless a clear license is present. We recommend always having a license
file, even if it is not an open source license.
* **`main.tf`, `variables.tf`, `outputs.tf`**. These are the recommended filenames for
a minimal module, even if they're empty. `main.tf` should be the primary
entrypoint. For a simple module, this may be where all the resources are
created. For a complex module, resource creation may be split into multiple
files but any nested module calls should be in the main file. `variables.tf`
and `outputs.tf` should contain the declarations for variables and outputs,
respectively.
* **Variables and outputs should have descriptions.** All variables and
outputs should have one or two sentence descriptions that explain their
purpose. This is used for documentation. See the documentation for
[variable configuration](/docs/configuration/variables.html) and
[output configuration](/docs/configuration/outputs.html) for more details.
* **Nested modules**. Nested modules should exist under the `modules/`
subdirectory. Any nested module with a `README.md` is considered usable
by an external user. If a README doesn't exist, it is considered for internal
use only. These are purely advisory; Terraform will not actively deny usage
of internal modules. Nested modules should be used to split complex behavior
into multiple small modules that advanced users can carefully pick and
choose. For example, the
[Consul module](https://registry.terraform.io/modules/hashicorp/consul)
has a nested module for creating the Cluster that is separate from the
module to setup necessary IAM policies. This allows a user to bring in their
own IAM policy choices.
If the root module includes calls to nested modules, they should use relative
paths like `./modules/consul-cluster` so that Terraform will consider them
to be part of the same repository or package, rather than downloading them
again separately.
If a repository or package contains multiple nested modules, they should
ideally be [composable](./composition.html) by the caller, rather than
calling directly to each other and creating a deeply-nested tree of modules.
* **Examples**. Examples of using the module should exist under the
`examples/` subdirectory at the root of the repository. Each example may have
a README to explain the goal and usage of the example. Examples for
submodules should also be placed in the root `examples/` directory.
Because examples will often be copied into other repositories for
customization, any `module` blocks should have their `source` set to the
address an external caller would use, not to a relative path.
A minimal recommended module following the standard structure is shown below.
While the root module is the only required element, we recommend the structure
below as the minimum:
```sh
$ tree minimal-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
```
A complete example of a module following the standard structure is shown below.
This example includes all optional elements and is therefore the most
complex a module can become:
```sh
$ tree complete-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── ...
├── modules/
│   ├── nestedA/
│   │   ├── README.md
│   │   ├── variables.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   ├── nestedB/
│   ├── .../
├── examples/
│   ├── exampleA/
│   │   ├── main.tf
│   ├── exampleB/
│   ├── .../
```

View File

@ -0,0 +1,369 @@
---
layout: "language"
page_title: "Providers Within Modules - Configuration Language"
---
# Providers Within Modules
[inpage-providers]: #providers-within-modules
In a configuration with multiple modules, there are some special considerations
for how resources are associated with provider configurations.
Each resource in the configuration must be associated with one provider
configuration. Provider configurations, unlike most other concepts in
Terraform, are global to an entire Terraform configuration and can be shared
across module boundaries. Provider configurations can be defined only in a
root Terraform 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.
A module intended to be called by one or more other modules must not contain
any `provider` blocks, with the exception of the special
"proxy provider blocks" discussed under
_[Passing Providers Explicitly](#passing-providers-explicitly)_
below.
For backward compatibility with configurations targeting Terraform v0.10 and
earlier Terraform does not produce an error for a `provider` block in a shared
module if the `module` block only uses features available in Terraform v0.10,
but that is a legacy usage pattern that is no longer recommended. A legacy
module containing its own provider configurations is not compatible with the
`for_each`, `count`, and `depends_on` arguments that were introduced in
Terraform v0.13. For more information, see
[Legacy Shared Modules with Provider Configurations](#legacy-shared-modules-with-provider-configurations).
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 will be used to locate
the appropriate configuration because the resource's `provider` argument
(if any) will no longer be present in the configuration.
As a consequence, you must ensure that all resources that belong to a
particular provider configuration are destroyed before you can remove that
provider configuration's block from your configuration. If Terraform finds
a resource instance tracked in the state whose provider configuration block is
no longer available then it will return an error during planning, prompting you
to reintroduce the provider configuration.
## Provider Version Constraints in Modules
Although provider _configurations_ are shared between modules, each module must
declare its own [provider requirements](/docs/configuration/provider-requirements.html), so that
Terraform can ensure that there is a single version of the provider that is
compatible with all modules in the configuration and to specify the
[source address](/docs/configuration/provider-requirements.html#source-addresses) that serves as
the global (module-agnostic) identifier for a provider.
To declare that a module requires particular versions of a specific provider,
use a `required_providers` block inside a `terraform` block:
```hcl
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
}
}
}
```
A provider requirement says, for example, "This module requires version v2.7.0
of the provider `hashicorp/aws` and will refer to it as `aws`." It doesn't,
however, specify any of the configuration settings that determine what remote
endpoints the provider will access, such as an AWS region; configuration
settings come from provider _configurations_, and a particular overall Terraform
configuration can potentially have
[several different configurations for the same provider](/docs/configuration/providers.html#alias-multiple-provider-instances).
If you are writing a shared Terraform module, constrain only the minimum
required provider version using a `>=` constraint. This should specify the
minimum version containing the features your module relies on, and thus allow a
user of your module to potentially select a newer provider version if other
features are needed by other parts of their overall configuration.
## 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"
}
```
We recommend using this approach when a single configuration for each provider
is sufficient for an entire configuration.
~> **Note:** Only provider configurations are inherited by child modules, not provider source or version requirements. Each module must [declare its own provider requirements](/docs/configuration/provider-requirements.html). This is especially important for non-HashiCorp providers.
In more complex situations there may be
[multiple provider configurations](/docs/configuration/providers.html#alias-multiple-provider-configurations),
or a child module may need to use different provider settings than
its parent. For such situations, you must pass providers explicitly.
## 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, you can use the `providers` argument within a `module` block
to explicitly define which provider configurations are 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"
}
# An alternate configuration is also defined for a different
# region, using the alias "usw2".
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
# An example child module is instantiated with the alternate 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](/docs/configuration/meta-arguments/resource-provider.html)
within a resource, but is a map rather than a single string because a module may
contain resources from many different providers.
The keys of the `providers` map are provider configuration names as expected by
the child module, and the values are the names of corresponding configurations
in the _current_ module.
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
}
}
```
The subdirectory `./tunnel` must then contain _proxy configuration blocks_ like
the following, to declare that it requires its calling module to pass
configurations with these names in its `providers` argument:
```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 configurations to
use.
## Proxy Configuration Blocks
A proxy configuration block is one that contains only the `alias` argument. It
serves as a placeholder for provider configurations passed between modules, and
declares that a module expects to be explicitly passed an additional (aliased)
provider configuration.
-> **Note:** Although a completely empty proxy configuration block is also
valid, it is not necessary: proxy configuration blocks are needed only to
establish which _aliased_ provider configurations a child module expects.
Don't use a proxy configuration block if a module only needs a single default
provider configuration, and don't use proxy configuration blocks only to imply
[provider requirements](/docs/configuration/provider-requirements.html).
## Legacy Shared Modules with Provider Configurations
In Terraform v0.10 and earlier there was no explicit way to use different
configurations of a provider in different modules in the same configuration,
and so module authors commonly worked around this by writing `provider` blocks
directly inside their modules, making the module have its own separate
provider configurations separate from those declared in the root module.
However, that pattern had a significant drawback: because a provider
configuration is required to destroy the remote object associated with a
resource instance as well as to create or update it, a provider configuration
must always stay present in the overall Terraform configuration for longer
than all of the resources it manages. If a particular module includes
both resources and the provider configurations for those resources then
removing the module from its caller would violate that constraint: both the
resources and their associated providers would, in effect, be removed
simultaneously.
Terraform v0.11 introduced the mechanisms described in earlier sections to
allow passing provider configurations between modules in a structured way, and
thus we explicitly recommended against writing a child module with its own
provider configuration blocks. However, that legacy pattern continued to work
for compatibility purposes -- though with the same drawback -- until Terraform
v0.13.
Terraform v0.13 introduced the possibility for a module itself to use the
`for_each`, `count`, and `depends_on` arguments, but the implementation of
those unfortunately conflicted with the support for the legacy pattern.
To retain the backward compatibility as much as possible, Terraform v0.13
continues to support the legacy pattern for module blocks that do not use these
new features, but a module with its own provider configurations is not
compatible with `for_each`, `count`, or `depends_on`. Terraform will produce an
error if you attempt to combine these features. For example:
```
Error: Module does not support count
on main.tf line 15, in module "child":
15: count = 2
Module "child" cannot be used with count because it contains a nested provider
configuration for "aws", at child/main.tf:2,10-15.
This module can be made compatible with count by changing it to receive all of
its provider configurations from the calling module, by using the "providers"
argument in the calling module block.
```
To make a module compatible with the new features, you must either remove all
of the `provider` blocks from its definition or, if you need multiple
configurations for the same provider, replace them with
_proxy configuration blocks_ as described in
[Passing Providers Explicitly](#passing-providers-explicitly).
If the new version of the module uses proxy configuration blocks, or if the
calling module needs the child module to use different provider configurations
than its own default provider configurations, the calling module must then
include an explicit `providers` argument to describe which provider
configurations the child module will use:
```hcl
provider "aws" {
region = "us-west-1"
}
provider "aws" {
region = "us-east-1"
alias = "east"
}
module "child" {
count = 2
providers = {
# By default, the child module would use the
# default (unaliased) AWS provider configuration
# using us-west-1, but this will override it
# to use the additional "east" configuration
# for its resources instead.
aws = aws.east
}
}
```
Since the association between resources and provider configurations is
static, module calls using `for_each` or `count` cannot pass different
provider configurations to different instances. If you need different
instances of your module to use different provider configurations then you
must use a separate `module` block for each distinct set of provider
configurations:
```hcl
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
}
}
```

View File

@ -14,7 +14,7 @@ If you've built a module that you intend to be reused, we recommend
your module, generate documentation, and more.
Published modules can be easily consumed by Terraform, and users can
[constrain module versions](/docs/configuration/modules.html#module-versions)
[constrain module versions](/docs/configuration/blocks/modules/syntax.html#version)
for safe and predictable updates. The following example shows how a caller
might use a module from the Terraform Registry:
@ -37,6 +37,6 @@ do not support the first-class versioning mechanism, but some sources have
their own mechanisms for selecting particular VCS commits, etc.
We recommend that modules distributed via other protocols still use the
[standard module structure](./#standard-module-structure) so that it can
be used in a similar way to a registry module, or even _become_ a registry
module at a later time.
[standard module structure](/docs/modules/structure.html) so that they can
be used in a similar way as a registry module or be published on the registry
at a later time.

View File

@ -7,7 +7,7 @@ description: The source argument within a module block specifies the location of
# Module Sources
The `source` argument in [a `module` block](/docs/configuration/modules.html)
The `source` argument in [a `module` block](/docs/configuration/blocks/modules/syntax.html)
tells Terraform where to find the source code for the desired child module.
Terraform uses this during the module installation step of `terraform init`
@ -122,7 +122,7 @@ access the Terraform Cloud application.
Registry modules support versioning. You can provide a specific version as shown
in the above examples, or use flexible
[version constraints](/docs/configuration/modules.html#module-versions).
[version constraints](/docs/configuration/blocks/modules/syntax.html#version).
You can learn more about the registry at the
[Terraform Registry documentation](/docs/registry/modules/use.html#using-modules).
@ -349,7 +349,7 @@ module "vpc" {
```
-> **Note:** If the content of the archive file is a directory, you will need to
include that directory in the module source. Read the section on
include that directory in the module source. Read the section on
[Modules in Package Sub-directories](#modules-in-package-sub-directories) for more
information.

View File

@ -0,0 +1,128 @@
---
layout: "language"
page_title: "Standard Module Structure"
---
# Standard Module Structure
The standard module structure is a file and directory layout we recommend for
reusable modules distributed in separate repositories. Terraform tooling is
built to understand the standard module structure and use that structure to
generate documentation, index modules for the module registry, and more.
The standard module structure expects the layout documented below. The list may
appear long, but everything is optional except for the root module. Most modules
don't need to do any extra work to follow the standard structure.
* **Root module**. This is the **only required element** for the standard
module structure. Terraform files must exist in the root directory of
the repository. This should be the primary entrypoint for the module and is
expected to be opinionated. For the
[Consul module](https://registry.terraform.io/modules/hashicorp/consul)
the root module sets up a complete Consul cluster. It makes a lot of assumptions
however, and we expect that advanced users will use specific _nested modules_
to more carefully control what they want.
* **README**. The root module and any nested modules should have README
files. This file should be named `README` or `README.md`. The latter will
be treated as markdown. There should be a description of the module and
what it should be used for. If you want to include an example for how this
module can be used in combination with other resources, put it in an [examples
directory like this](https://github.com/hashicorp/terraform-aws-consul/tree/master/examples).
Consider including a visual diagram depicting the infrastructure resources
the module may create and their relationship.
The README doesn't need to document inputs or outputs of the module because
tooling will automatically generate this. If you are linking to a file or
embedding an image contained in the repository itself, use a commit-specific
absolute URL so the link won't point to the wrong version of a resource in the
future.
* **LICENSE**. The license under which this module is available. If you are
publishing a module publicly, many organizations will not adopt a module
unless a clear license is present. We recommend always having a license
file, even if it is not an open source license.
* **`main.tf`, `variables.tf`, `outputs.tf`**. These are the recommended filenames for
a minimal module, even if they're empty. `main.tf` should be the primary
entrypoint. For a simple module, this may be where all the resources are
created. For a complex module, resource creation may be split into multiple
files but any nested module calls should be in the main file. `variables.tf`
and `outputs.tf` should contain the declarations for variables and outputs,
respectively.
* **Variables and outputs should have descriptions.** All variables and
outputs should have one or two sentence descriptions that explain their
purpose. This is used for documentation. See the documentation for
[variable configuration](/docs/configuration/variables.html) and
[output configuration](/docs/configuration/outputs.html) for more details.
* **Nested modules**. Nested modules should exist under the `modules/`
subdirectory. Any nested module with a `README.md` is considered usable
by an external user. If a README doesn't exist, it is considered for internal
use only. These are purely advisory; Terraform will not actively deny usage
of internal modules. Nested modules should be used to split complex behavior
into multiple small modules that advanced users can carefully pick and
choose. For example, the
[Consul module](https://registry.terraform.io/modules/hashicorp/consul)
has a nested module for creating the Cluster that is separate from the
module to setup necessary IAM policies. This allows a user to bring in their
own IAM policy choices.
If the root module includes calls to nested modules, they should use relative
paths like `./modules/consul-cluster` so that Terraform will consider them
to be part of the same repository or package, rather than downloading them
again separately.
If a repository or package contains multiple nested modules, they should
ideally be [composable](./composition.html) by the caller, rather than
calling directly to each other and creating a deeply-nested tree of modules.
* **Examples**. Examples of using the module should exist under the
`examples/` subdirectory at the root of the repository. Each example may have
a README to explain the goal and usage of the example. Examples for
submodules should also be placed in the root `examples/` directory.
Because examples will often be copied into other repositories for
customization, any `module` blocks should have their `source` set to the
address an external caller would use, not to a relative path.
A minimal recommended module following the standard structure is shown below.
While the root module is the only required element, we recommend the structure
below as the minimum:
```sh
$ tree minimal-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
```
A complete example of a module following the standard structure is shown below.
This example includes all optional elements and is therefore the most
complex a module can become:
```sh
$ tree complete-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── ...
├── modules/
│   ├── nestedA/
│   │   ├── README.md
│   │   ├── variables.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   ├── nestedB/
│   ├── .../
├── examples/
│   ├── exampleA/
│   │   ├── main.tf
│   ├── exampleB/
│   ├── .../
```

View File

@ -42,7 +42,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/index.html#standard-module-structure).
[standard module structure](/docs/modules/structure.html).
This allows the registry to inspect your module and generate documentation,
track resource usage, parse submodules and examples, and more.

View File

@ -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/configuration/modules.html#module-versions) and
[module version constraints](/docs/configuration/blocks/modules/syntax.html#version) 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

View File

@ -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/configuration/modules.html#module-versions) or a browsable
constraints](/docs/configuration/blocks/modules/syntax.html#version) or a browsable
marketplace of modules, both of which are important for enabling a
producers-and-consumers content model in a large organization.

View File

@ -50,7 +50,36 @@
</li>
<li>
<a href="/docs/configuration/resources.html">Resource Blocks</a>
<a href="/docs/configuration/blocks/resources/syntax.html">Resource Blocks</a>
</li>
<li>
<a href="/docs/configuration/blocks/resources/behavior.html">Resource Behavior</a>
</li>
<li>
<a href="#">Meta-Arguments</a>
<ul class="nav nav-auto-expand">
<li>
<a href="/docs/configuration/meta-arguments/depends_on.html"><code>depends_on</code></a>
</li>
<li>
<a href="/docs/configuration/meta-arguments/count.html"><code>count</code></a>
</li>
<li>
<a href="/docs/configuration/meta-arguments/for_each.html"><code>for_each</code></a>
</li>
<li>
<a href="/docs/configuration/meta-arguments/resource-provider.html"><code>provider</code></a>
</li>
<li>
<a href="/docs/configuration/meta-arguments/lifecycle.html"><code>lifecycle</code></a>
</li>
</ul>
</li>
<li>
@ -216,13 +245,34 @@
</li>
<li>
<a href="/docs/configuration/modules.html">Module Blocks</a>
<a href="/docs/configuration/blocks/modules/syntax.html">Module Blocks</a>
</li>
<li>
<a href="/docs/modules/sources.html">Module Sources</a>
</li>
<li>
<a href="#">Meta-Arguments</a>
<ul class="nav nav-auto-expand">
<li>
<a href="/docs/configuration/meta-arguments/module-providers.html"><code>providers</code></a>
</li>
<li>
<a href="/docs/configuration/meta-arguments/depends_on.html"><code>depends_on</code></a>
</li>
<li>
<a href="/docs/configuration/meta-arguments/count.html"><code>count</code></a>
</li>
<li>
<a href="/docs/configuration/meta-arguments/for_each.html"><code>for_each</code></a>
</li>
</ul>
</li>
<li>
<a href="#">Module Development</a>
<ul class="nav">
@ -230,6 +280,14 @@
<a href="/docs/modules/index.html">Overview</a>
</li>
<li>
<a href="/docs/modules/structure.html">Standard Module Structure</a>
</li>
<li>
<a href="/docs/modules/providers.html">Providers Within Modules</a>
</li>
<li>
<a href="/docs/modules/composition.html">Best Practices: Module Composition</a>
</li>
@ -250,7 +308,39 @@
</li>
<li>
<a href="/docs/configuration/expressions.html">Standard Expressions</a>
<a href="/docs/configuration/expressions/types.html">Types and Values</a>
</li>
<li>
<a href="/docs/configuration/expressions/strings.html">Strings and Templates</a>
</li>
<li>
<a href="/docs/configuration/expressions/references.html">References to Values</a>
</li>
<li>
<a href="/docs/configuration/expressions/operators.html">Operators</a>
</li>
<li>
<a href="/docs/configuration/expressions/function-calls.html">Function Calls</a>
</li>
<li>
<a href="/docs/configuration/expressions/conditionals.html">Conditional Expressions</a>
</li>
<li>
<a href="/docs/configuration/expressions/for.html">For Expressions</a>
</li>
<li>
<a href="/docs/configuration/expressions/splat.html">Splat Expressions</a>
</li>
<li>
<a href="/docs/configuration/expressions/dynamic-blocks.html">Dynamic Blocks</a>
</li>
<li>