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:
commit
6a847df392
|
@ -15,7 +15,7 @@ potentially save you time and effort.
|
||||||
|
|
||||||
- [The `terraform console` command](/docs/commands/console.html) starts an
|
- [The `terraform console` command](/docs/commands/console.html) starts an
|
||||||
interactive shell for evaluating Terraform
|
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.
|
to verify that a particular resource argument results in the value you expect.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ the change.
|
||||||
Once upgraded the configuration will no longer be compatible with Terraform
|
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
|
v0.11 and earlier. When upgrading a shared module that is called from multiple
|
||||||
configurations, you may need to
|
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
|
to allow for a gradual upgrade. If the module is published via
|
||||||
[a Terraform registry](/docs/registry/), assign a new _major_ version number
|
[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
|
to the upgraded module source to represent the fact that this is a breaking
|
||||||
|
|
|
@ -10,14 +10,14 @@ description: |-
|
||||||
# Command: console
|
# Command: console
|
||||||
|
|
||||||
The `terraform console` command provides an interactive console for
|
The `terraform console` command provides an interactive console for
|
||||||
evaluating [expressions](/docs/configuration/expressions.html).
|
evaluating [expressions](/docs/configuration/expressions/index.html).
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Usage: `terraform console [options]`
|
Usage: `terraform console [options]`
|
||||||
|
|
||||||
This command provides an interactive command-line console for evaluating and
|
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,
|
This is useful for testing interpolations before using them in configurations,
|
||||||
and for interacting with any values currently saved in
|
and for interacting with any values currently saved in
|
||||||
[state](/docs/state/index.html).
|
[state](/docs/state/index.html).
|
||||||
|
|
|
@ -133,7 +133,7 @@ $ terraform import module.foo.aws_instance.bar i-abcd1234
|
||||||
## Example: Import into Resource configured with count
|
## 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
|
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
|
```shell
|
||||||
$ terraform import 'aws_instance.baz[0]' i-abcd1234
|
$ 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
|
## 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
|
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:
|
Linux, Mac OS, and UNIX:
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ $ terraform state mv -state-out=other.tfstate 'module.app' 'module.app'
|
||||||
## Example: Move a Resource configured with count
|
## Example: Move a Resource configured with count
|
||||||
|
|
||||||
The example below moves the first instance of a `packet_device` resource named `worker` configured with
|
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`:
|
the first instance of a resource named `helper` also configured with `count`:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
@ -105,7 +105,7 @@ $ terraform state mv 'packet_device.worker[0]' 'packet_device.helper[0]'
|
||||||
## Example: Move a Resource configured with for_each
|
## Example: Move a Resource configured with for_each
|
||||||
|
|
||||||
The example below moves the `"example123"` instance of a `packet_device` resource named `worker` configured with
|
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`:
|
to the `"example456"` instance of a resource named `helper` also configuring `for_each`:
|
||||||
|
|
||||||
Linux, Mac OS, and UNIX:
|
Linux, Mac OS, and UNIX:
|
||||||
|
|
|
@ -78,7 +78,7 @@ $ terraform state rm 'module.foo.packet_device.worker'
|
||||||
## Example: Remove a Resource configured with count
|
## Example: Remove a Resource configured with count
|
||||||
|
|
||||||
The example below removes the first instance of a `packet_device` resource named `worker` configured with
|
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
|
```shell
|
||||||
$ terraform state rm 'packet_device.worker[0]'
|
$ 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
|
## Example: Remove a Resource configured with for_each
|
||||||
|
|
||||||
The example below removes the `"example"` instance of a `packet_device` resource named `worker` configured with
|
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:
|
Linux, Mac OS, and UNIX:
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ $ terraform state show 'module.foo.packet_device.worker'
|
||||||
## Example: Show a Resource configured with count
|
## Example: Show a Resource configured with count
|
||||||
|
|
||||||
The example below shows the first instance of a `packet_device` resource named `worker` configured with
|
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
|
```shell
|
||||||
$ terraform state show 'packet_device.worker[0]'
|
$ 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
|
## Example: Show a Resource configured with for_each
|
||||||
|
|
||||||
The example below shows the `"example"` instance of a `packet_device` resource named `worker` configured with
|
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:
|
Linux, Mac OS, and UNIX:
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ description: |-
|
||||||
|
|
||||||
-> **Note:** This page is about Terraform 0.11 and earlier. For Terraform 0.12
|
-> **Note:** This page is about Terraform 0.11 and earlier. For Terraform 0.12
|
||||||
and later, see
|
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).
|
[Configuration Language: Functions](../configuration/functions.html).
|
||||||
|
|
||||||
Embedded within strings in Terraform, whether you're using the
|
Embedded within strings in Terraform, whether you're using the
|
||||||
|
|
|
@ -153,7 +153,7 @@ example = [
|
||||||
|
|
||||||
For the arguments that use the attributes-as-blocks usage mode, the above is
|
For the arguments that use the attributes-as-blocks usage mode, the above is
|
||||||
a better pattern than using
|
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
|
because the case where the
|
||||||
caller provides an empty list will result in explicitly assigning an empty
|
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
|
list value, rather than assigning no value at all and thus retaining and
|
||||||
|
|
|
@ -48,12 +48,20 @@ module registry for sharing modules internally within your organization.
|
||||||
|
|
||||||
## Using Modules
|
## 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
|
calling a child module from a parent module, including meta-arguments like
|
||||||
`for_each`.
|
`for_each`.
|
||||||
|
|
||||||
- [Module Sources](/docs/modules/sources.html) documents what kinds of paths,
|
- [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.
|
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
|
## Developing Modules
|
||||||
|
|
||||||
For information about developing reusable modules, see
|
For information about developing reusable modules, see
|
||||||
|
|
|
@ -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.
|
|
@ -13,7 +13,7 @@ configuration (like endpoint URLs or cloud regions) before they can be used.
|
||||||
|
|
||||||
## What Providers Do
|
## 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
|
and/or [data sources](/docs/configuration/data-sources.html) that Terraform can
|
||||||
manage.
|
manage.
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 virtual networks, compute instances, or higher-level components such
|
||||||
as DNS records.
|
as DNS records.
|
||||||
|
|
||||||
- [Resource Blocks](/docs/configuration/resources.html) documents how to declare
|
- [Resource Blocks](/docs/configuration/blocks/resources/syntax.html) documents
|
||||||
resources, including information about meta-arguments like `for_each`.
|
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)
|
- [Provisioners](/docs/configuration/blocks/resources/provisioners/index.html)
|
||||||
documents configuring post-creation actions for a resource using the
|
documents configuring post-creation actions for a resource using the
|
||||||
`provisioner` and `connection` blocks. Since provisioners are non-declarative
|
`provisioner` and `connection` blocks. Since provisioners are non-declarative
|
||||||
|
|
|
@ -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.
|
|
@ -18,7 +18,8 @@ configuration to make use of information defined outside of Terraform,
|
||||||
or defined by another separate Terraform configuration.
|
or defined by another separate Terraform configuration.
|
||||||
|
|
||||||
Each [provider](./providers.html) may offer data sources
|
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
|
## Using Data Sources
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ infrastructure platform.
|
||||||
|
|
||||||
Most of the items within the body of a `data` block are defined by and
|
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
|
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.
|
Terraform language features.
|
||||||
|
|
||||||
However, there are some "meta-arguments" that are defined by Terraform itself
|
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 Resource Dependencies
|
||||||
|
|
||||||
Data resources have the same dependency resolution behavior
|
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
|
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.
|
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
|
## Multiple Resource Instances
|
||||||
|
|
||||||
Data resources support [`count`](./resources.html#count-multiple-resource-instances-by-count)
|
Data resources support [`count`](/docs/configuration/meta-arguments/count.html)
|
||||||
and [`for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
and [`for_each`](/docs/configuration/meta-arguments/for_each.html)
|
||||||
meta-arguments as defined for managed resources, with the same syntax and behavior.
|
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
|
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
|
## 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.
|
as defined for managed resources, with the same syntax and behavior.
|
||||||
|
|
||||||
## Lifecycle Customizations
|
## Lifecycle Customizations
|
||||||
|
@ -187,13 +188,15 @@ resource "aws_instance" "web" {
|
||||||
## Meta-Arguments
|
## Meta-Arguments
|
||||||
|
|
||||||
As data sources are essentially a read only subset of resources, they also
|
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
|
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
|
### 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
|
```hcl
|
||||||
data "aws_ami" "web" {
|
data "aws_ami" "web" {
|
||||||
|
@ -204,7 +207,7 @@ data "aws_ami" "web" {
|
||||||
```
|
```
|
||||||
|
|
||||||
See
|
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.
|
for more information.
|
||||||
|
|
||||||
## Data Source Lifecycle
|
## Data Source Lifecycle
|
||||||
|
|
|
@ -14,9 +14,9 @@ dependency that come from outside of its own codebase:
|
||||||
|
|
||||||
* [Providers](./provider-requirements.html), which are plugins for Terraform
|
* [Providers](./provider-requirements.html), which are plugins for Terraform
|
||||||
that extend it with support for interacting with various external systems.
|
that extend it with support for interacting with various external systems.
|
||||||
* [Modules](./modules.html), which allow splitting out groups of Terraform
|
* [Modules](/docs/configuration/blocks/modules/index.html), which allow
|
||||||
configuration constructs (written in the Terraform language) into reusable
|
splitting out groups of Terraform configuration constructs (written in the
|
||||||
abstractions.
|
Terraform language) into reusable abstractions.
|
||||||
|
|
||||||
Both of these dependency types can be published and updated independently from
|
Both of these dependency types can be published and updated independently from
|
||||||
Terraform itself and from the configurations that depend on them. For that
|
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 @@
|
@@ -6,6 +6,26 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
+provider "registry.terraform.io/hashicorp/azurerm" {
|
+provider "registry.terraform.io/hashicorp/azurerm" {
|
||||||
+ version = "2.30.0"
|
+ version = "2.30.0"
|
||||||
+ constraints = "~> 2.12"
|
+ constraints = "~> 2.12"
|
||||||
|
@ -219,7 +219,7 @@ block to reflect that change.
|
||||||
+++ .terraform.lock.hcl 2020-10-07 16:43:42.785665945 -0700
|
+++ .terraform.lock.hcl 2020-10-07 16:43:42.785665945 -0700
|
||||||
@@ -7,22 +7,22 @@
|
@@ -7,22 +7,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "registry.terraform.io/hashicorp/azurerm" {
|
provider "registry.terraform.io/hashicorp/azurerm" {
|
||||||
- version = "2.1.0"
|
- version = "2.1.0"
|
||||||
- constraints = "~> 2.1.0"
|
- constraints = "~> 2.1.0"
|
||||||
|
|
|
@ -1,905 +1,123 @@
|
||||||
---
|
---
|
||||||
layout: "language"
|
layout: "language"
|
||||||
page_title: "Expressions - Configuration Language"
|
page_title: "Expressions Landing Page - Configuration Language"
|
||||||
sidebar_current: "docs-config-expressions"
|
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
|
To improve navigation, we've split the old Expressions page into several smaller
|
||||||
earlier, see
|
pages.
|
||||||
[0.11 Configuration Language: Interpolation Syntax](../configuration-0-11/interpolation.html).
|
|
||||||
|
|
||||||
_Expressions_ are used to refer to or compute values within a configuration.
|
<a id="types-and-values"></a>
|
||||||
The simplest expressions are just literal values, like `"hello"` or `5`,
|
<a id="advanced-type-details"></a>
|
||||||
but the Terraform language also allows more complex expressions such as
|
<a id="type-conversion"></a>
|
||||||
references to data exported by resources, arithmetic, conditional evaluation,
|
<a id="literal-expressions"></a>
|
||||||
and a number of built-in functions.
|
<a id="indices-and-attributes"></a>
|
||||||
|
|
||||||
Expressions can be used in a number of places in the Terraform language,
|
## Types and Values, Literal Expressions, Indices and Attributes
|
||||||
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.
|
|
||||||
|
|
||||||
You can experiment with the behavior of Terraform's expressions from
|
Terraform's types are `string`, `number`, `bool`, `list`, `tuple`, `map`,
|
||||||
the Terraform expression console, by running
|
`object`, and `null`.
|
||||||
[the `terraform console` command](/docs/commands/console.html).
|
|
||||||
|
|
||||||
The rest of this page describes all of the features of Terraform's
|
This information has moved to
|
||||||
expression syntax.
|
[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
|
## References to Named Values (Resource Attributes, Variables, etc.)
|
||||||
dictates where that value can be used and what transformations can be
|
|
||||||
applied to it.
|
|
||||||
|
|
||||||
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
|
This information has moved to
|
||||||
`"hello"`.
|
[References to Values](/docs/configuration/expressions/references.html).
|
||||||
* `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}`.
|
|
||||||
|
|
||||||
Strings, numbers, and bools are sometimes called _primitive types._ Lists/tuples and maps/objects are sometimes called _complex types,_ _structural types,_ or _collection types._
|
<a id="arithmetic-operators"></a>
|
||||||
|
<a id="equality-operators"></a>
|
||||||
Finally, there is one special value that has _no_ type:
|
<a id="comparison-operators"></a>
|
||||||
|
<a id="logical-operators"></a>
|
||||||
* `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)`.
|
|
||||||
|
|
||||||
## Arithmetic and Logical Operators
|
## Arithmetic and Logical Operators
|
||||||
|
|
||||||
An _operator_ is a type of expression that transforms or combines one or more
|
Operators are expressions that transform other expressions, like adding two
|
||||||
other expressions. Operators either combine two values in some way to
|
numbers (`+`) or comparing two values to get a bool (`==`, `>=`, etc.).
|
||||||
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
|
This information has moved to
|
||||||
values, similar to mathematical notation: `1 + 2`. Operators that work on
|
[Operators](/docs/configuration/expressions/references.html).
|
||||||
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`.
|
|
||||||
|
|
||||||
## Conditional Expressions
|
## Conditional Expressions
|
||||||
|
|
||||||
A _conditional expression_ uses the value of a bool expression to select one of
|
The `condition ? true_val : false_val` expression chooses between two
|
||||||
two values.
|
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
|
<a id="expanding-function-arguments"></a>
|
||||||
condition ? true_val : false_val
|
<a id="available-functions"></a>
|
||||||
```
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Function Calls
|
## Function Calls
|
||||||
|
|
||||||
The Terraform language has a number of
|
Terraform's functions can be called like `function_name(arg1, arg2)`.
|
||||||
[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:
|
|
||||||
|
|
||||||
```hcl
|
This information has moved to
|
||||||
<FUNCTION NAME>(<ARGUMENT 1>, <ARGUMENT 2>)
|
[Function Calls](/docs/configuration/expressions/function-calls.html).
|
||||||
```
|
|
||||||
|
|
||||||
The function name specifies which function to call. Each defined function
|
<a id="for-expressions"></a>
|
||||||
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).
|
|
||||||
|
|
||||||
## `for` Expressions
|
## `for` Expressions
|
||||||
|
|
||||||
A _`for` expression_ creates a complex type value by transforming
|
Expressions like `[for s in var.list : upper(s)]` can transform a complex type
|
||||||
another complex type value. Each element in the input value
|
value into another complex type 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
|
This information has moved to
|
||||||
produces a list of strings with all-uppercase letters:
|
[For Expressions](/docs/configuration/expressions/for.html).
|
||||||
|
|
||||||
```hcl
|
<a id="splat-expressions"></a>
|
||||||
[for s in var.list : upper(s)]
|
<a id="legacy-attribute-only-splat-expressions"></a>
|
||||||
```
|
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
## Splat Expressions
|
## Splat Expressions
|
||||||
|
|
||||||
A _splat expression_ provides a more concise way to express a common
|
Expressions like `var.list[*].id` can extract simpler collections from complex
|
||||||
operation that could otherwise be performed with a `for` expression.
|
collections.
|
||||||
|
|
||||||
If `var.list` is a list of objects that all have an attribute `id`, then
|
This information has moved to
|
||||||
a list of the ids could be produced with the following `for` expression:
|
[Splat Expressions](/docs/configuration/expressions/splat.html).
|
||||||
|
|
||||||
```hcl
|
<a id="dynamic-blocks"></a>
|
||||||
[for o in var.list : o.id]
|
<a id="best-practices-for-dynamic-blocks"></a>
|
||||||
```
|
|
||||||
|
|
||||||
This is equivalent to the following _splat expression:_
|
## `dynamic` Blocks
|
||||||
|
|
||||||
```hcl
|
The special `dynamic` block type serves the same purpose as a `for` expression,
|
||||||
var.list[*].id
|
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
|
This information has moved to
|
||||||
to its left and accesses from each one the attribute name given on its
|
[Dynamic Blocks](/docs/configuration/expressions/dynamic-blocks.html).
|
||||||
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
|
<a id="string-literals"></a>
|
||||||
var.list[*].interfaces[0].name
|
<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
|
Strings can be `"double-quoted"` or
|
||||||
[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:
|
|
||||||
|
|
||||||
```hcl
|
```hcl
|
||||||
<<EOT
|
<<EOT
|
||||||
hello
|
heredocs
|
||||||
world
|
|
||||||
EOT
|
EOT
|
||||||
```
|
```
|
||||||
|
|
||||||
The `<<` marker followed by any identifier at the end of a line introduces the
|
Strings can also include escape sequences like `\n`, interpolation sequences
|
||||||
sequence. Terraform then processes the following lines until it finds one that
|
(`${ ... }`), and template sequences (`%{ ... }`).
|
||||||
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".
|
|
||||||
|
|
||||||
The "heredoc" form shown above requires that the lines following be flush with
|
This information has moved to
|
||||||
the left margin, which can be awkward when an expression is inside an indented
|
[Strings and Templates](/docs/configuration/expressions/strings.html).
|
||||||
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.
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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).
|
|
@ -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).
|
||||||
|
|
|
@ -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,
|
but some contexts limit which expression constructs are allowed,
|
||||||
such as requiring a literal value of a particular type or forbidding
|
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).
|
[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
|
You can experiment with the behavior of Terraform's expressions from
|
||||||
the Terraform expression console, by running
|
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
|
The other pages in this section describe the features of Terraform's
|
||||||
expression syntax.
|
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.
|
||||||
|
|
|
@ -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`.
|
|
@ -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)`.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
||||||
|
|
|
@ -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
|
different files is purely for the convenience of readers and maintainers, and
|
||||||
has no effect on the module's behavior.
|
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
|
explicitly include other modules into the configuration. These child modules can
|
||||||
come from local directories (nested in the parent module's directory, or
|
come from local directories (nested in the parent module's directory, or
|
||||||
anywhere else on disk), or from external sources like the
|
anywhere else on disk), or from external sources like the
|
||||||
|
|
|
@ -23,8 +23,8 @@ max(5, 12, 9)
|
||||||
```
|
```
|
||||||
|
|
||||||
For more details on syntax, see
|
For more details on syntax, see
|
||||||
[_Function Calls_](./expressions.html#function-calls)
|
[_Function Calls_](/docs/configuration/expressions/function-calls.html)
|
||||||
on the Expressions page.
|
in the Expressions section.
|
||||||
|
|
||||||
The Terraform language does not support user-defined functions, and so only
|
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
|
the functions built in to the language are available for use. The navigation
|
||||||
|
|
|
@ -70,7 +70,7 @@ platforms.
|
||||||
```
|
```
|
||||||
|
|
||||||
You can use nested `cidrsubnets` calls with
|
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:
|
to concisely allocate groups of network address blocks:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -46,7 +46,7 @@ number of fields, or this function will produce an error.
|
||||||
## Use with the `for_each` meta-argument
|
## Use with the `for_each` meta-argument
|
||||||
|
|
||||||
You can use the result of `csvdecode` with
|
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
|
to describe a collection of similar objects whose differences are
|
||||||
described by the rows in the given CSV file.
|
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
|
If there is no reasonable value you can use as a unique identifier in your CSV
|
||||||
then you could instead use
|
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
|
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 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
|
the CSV may be disruptive if they change the positions of particular objects in
|
||||||
|
|
|
@ -69,7 +69,7 @@ before Terraform takes any actions.
|
||||||
```
|
```
|
||||||
|
|
||||||
A common use of `fileset` is to create one resource instance per matched file, using
|
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
|
```hcl
|
||||||
resource "example_thing" "example" {
|
resource "example_thing" "example" {
|
||||||
|
|
|
@ -35,9 +35,9 @@ Indirectly-nested lists, such as those in maps, are _not_ flattened.
|
||||||
## Flattening nested structures for `for_each`
|
## Flattening nested structures for `for_each`
|
||||||
|
|
||||||
The
|
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
|
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
|
language features both require a collection value that has one element for
|
||||||
each repetition.
|
each repetition.
|
||||||
|
|
||||||
|
|
|
@ -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).
|
The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
|
||||||
|
|
||||||
This function maps JSON values to
|
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:
|
in the following way:
|
||||||
|
|
||||||
| JSON type | Terraform type |
|
| JSON type | Terraform type |
|
||||||
|
|
|
@ -17,7 +17,7 @@ earlier, see
|
||||||
The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
|
The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
|
||||||
|
|
||||||
This function maps
|
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:
|
to JSON values in the following way:
|
||||||
|
|
||||||
| Terraform type | JSON type |
|
| Terraform type | JSON type |
|
||||||
|
|
|
@ -121,9 +121,9 @@ elements all have a consistent type:
|
||||||
## Finding combinations for `for_each`
|
## Finding combinations for `for_each`
|
||||||
|
|
||||||
The
|
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
|
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
|
language features both require a collection value that has one element for
|
||||||
each repetition.
|
each repetition.
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ templatefile(path, vars)
|
||||||
```
|
```
|
||||||
|
|
||||||
The template syntax is the same as for
|
The template syntax is the same as for
|
||||||
[string templates](../expressions.html#string-templates) in the main Terraform
|
[string templates](/docs/configuration/expressions/strings.html#string-templates)
|
||||||
language, including interpolation sequences delimited with `${` ... `}`.
|
in the main Terraform language, including interpolation sequences delimited with
|
||||||
This function just allows longer template sequences to be factored out
|
`${` ... `}`. This function just allows longer template sequences to be factored
|
||||||
into a separate file for readability.
|
out into a separate file for readability.
|
||||||
|
|
||||||
The "vars" argument must be a map. Within the template file, each of the keys
|
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
|
in the map is available as a variable for interpolation. The template may
|
||||||
|
@ -78,8 +78,8 @@ The `templatefile` function renders the template:
|
||||||
|
|
||||||
```
|
```
|
||||||
> templatefile(
|
> templatefile(
|
||||||
"${path.module}/backends.tmpl",
|
"${path.module}/backends.tmpl",
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
"x" = "y"
|
"x" = "y"
|
||||||
"foo" = "bar"
|
"foo" = "bar"
|
||||||
|
@ -102,7 +102,7 @@ interpolation sequences and directives.
|
||||||
Instead, you can write a template that consists only of a single interpolated
|
Instead, you can write a template that consists only of a single interpolated
|
||||||
call to either [`jsonencode`](./jsonencode.html) or
|
call to either [`jsonencode`](./jsonencode.html) or
|
||||||
[`yamlencode`](./yamlencode.html), specifying the value to encode using
|
[`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:
|
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.
|
structure, without the need to manually handle escaping or delimiters.
|
||||||
In the latest examples above, the repetition based on elements of `ip_addrs` is
|
In the latest examples above, the repetition based on elements of `ip_addrs` is
|
||||||
achieved by using a
|
achieved by using a
|
||||||
[`for` expression](/docs/configuration/expressions.html#for-expressions)
|
[`for` expression](/docs/configuration/expressions/for.html)
|
||||||
rather than by using
|
rather than by using
|
||||||
[template directives](/docs/configuration/expressions.html#directives).
|
[template directives](/docs/configuration/expressions/strings.html#directives).
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{"backends":["10.0.0.1:8080","10.0.0.2:8080"]}
|
{"backends":["10.0.0.1:8080","10.0.0.2:8080"]}
|
||||||
|
|
|
@ -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
|
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,
|
Terraform run. We do not recommend using this function in resource attributes,
|
||||||
but in rare cases it can be used in conjunction with
|
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
|
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/).
|
time handling, see the [Time Provider](https://registry.terraform.io/providers/hashicorp/time/).
|
||||||
|
|
||||||
|
|
|
@ -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
|
directly in resource arguments will result in spurious diffs. We do not
|
||||||
recommend using the `uuid` function in resource configurations, but it can
|
recommend using the `uuid` function in resource configurations, but it can
|
||||||
be used with care in conjunction with
|
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)
|
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
|
instead, since it allows the one-time generation of random values that are
|
||||||
|
|
|
@ -20,7 +20,7 @@ This function supports a subset of [YAML 1.2](https://yaml.org/spec/1.2/spec.htm
|
||||||
as described below.
|
as described below.
|
||||||
|
|
||||||
This function maps YAML values to
|
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:
|
in the following way:
|
||||||
|
|
||||||
| YAML type | Terraform type |
|
| YAML type | Terraform type |
|
||||||
|
|
|
@ -33,7 +33,7 @@ results are also valid YAML because YAML is a JSON superset.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
This function maps
|
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:
|
to YAML tags in the following way:
|
||||||
|
|
||||||
| Terraform type | YAML type |
|
| Terraform type | YAML type |
|
||||||
|
|
|
@ -19,7 +19,7 @@ heart of the workflow.
|
||||||
## About the Terraform Language
|
## About the Terraform Language
|
||||||
|
|
||||||
The main purpose of the Terraform language is declaring
|
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
|
language features exist only to make the definition of resources more flexible
|
||||||
and convenient.
|
and convenient.
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ description: |-
|
||||||
earlier, see
|
earlier, see
|
||||||
[0.11 Configuration Language: Local Values](../configuration-0-11/locals.html).
|
[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
|
so you can use it multiple times within a module without repeating
|
||||||
it.
|
it.
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ locals {
|
||||||
## Using Local Values
|
## Using Local Values
|
||||||
|
|
||||||
Once a local value is declared, you can reference it in
|
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
|
-> **Note:** Local values are _created_ by a `locals` block (plural), but you
|
||||||
_reference_ them as attributes on an object named `local` (singular). Make sure
|
_reference_ them as attributes on an object named `local` (singular). Make sure
|
||||||
|
|
|
@ -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.
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
```
|
|
@ -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.
|
|
@ -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).
|
|
@ -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.
|
||||||
|
|
|
@ -1,632 +1,44 @@
|
||||||
---
|
---
|
||||||
layout: "language"
|
layout: "language"
|
||||||
page_title: "Modules - Configuration Language"
|
page_title: "Modules Landing Page - Configuration Language"
|
||||||
sidebar_current: "docs-config-modules"
|
|
||||||
description: |-
|
|
||||||
Modules allow multiple resources to be grouped together and encapsulated.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Modules
|
# Modules Landing Page
|
||||||
|
|
||||||
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
|
To improve navigation, we've split the old Modules page into several smaller
|
||||||
earlier, see
|
pages.
|
||||||
[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 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
|
This information has moved to
|
||||||
_root module_, which consists of the resources defined in the `.tf` files in
|
[Module Blocks](/docs/configuration/blocks/modules/syntax.html).
|
||||||
the main working directory.
|
|
||||||
|
|
||||||
A module can call other modules, which lets you include the child module's
|
<a id="multiple-instances-of-a-module"></a>
|
||||||
resources into the configuration in a concise way. Modules
|
|
||||||
can also be called multiple times, either within the same configuration or
|
|
||||||
in separate configurations, allowing resource configurations to be packaged
|
|
||||||
and re-used.
|
|
||||||
|
|
||||||
This page describes how to call one module from another. Other pages in this
|
## Multiple Instances with `count` and `for_each`
|
||||||
section of the documentation describe the different elements that make up
|
|
||||||
modules, and there is further information about how modules can be used,
|
|
||||||
created, and published in [the dedicated _Modules_
|
|
||||||
section](/docs/modules/index.html).
|
|
||||||
|
|
||||||
## Calling a Child Module
|
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
|
<a id="providers-within-modules"></a>
|
||||||
configuration with specific values for its
|
<a id="provider-version-constraints-in-modules"></a>
|
||||||
[input variables](./variables.html). Modules are called
|
<a id="implicit-provider-inheritance"></a>
|
||||||
from within other modules using `module` blocks:
|
<a id="passing-providers-explicitly"></a>
|
||||||
|
<a id="proxy-configuration-blocks"></a>
|
||||||
|
<a id="legacy-shared-modules-with-provider-configurations"></a>
|
||||||
|
|
||||||
```hcl
|
## Handling Provider Configurations in Re-usable Modules
|
||||||
module "servers" {
|
|
||||||
source = "./app-cluster"
|
|
||||||
|
|
||||||
servers = 5
|
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)
|
||||||
A module that includes a `module` block like this is the _calling module_ of the
|
(for module developers).
|
||||||
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.
|
|
||||||
|
|
|
@ -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
|
displayed to the user; in a child module, it can be used to access the output's
|
||||||
value.
|
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
|
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
|
refers to the `private_ip` attribute exposed by an `aws_instance` resource
|
||||||
defined elsewhere in this module (not shown). Any valid expression is allowed
|
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
|
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.
|
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.
|
modules.
|
||||||
|
|
||||||
Just as with
|
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
|
Terraform analyzes the `value` expression for an output value and automatically
|
||||||
determines a set of dependencies, but in less-common cases there are
|
determines a set of dependencies, but in less-common cases there are
|
||||||
dependencies that cannot be recognized implicitly. In these rare cases, the
|
dependencies that cannot be recognized implicitly. In these rare cases, the
|
||||||
|
|
|
@ -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.
|
Provider configurations belong in the root module of a Terraform configuration.
|
||||||
(Child modules receive their provider configurations from the root module; for
|
(Child modules receive their provider configurations from the root module; for
|
||||||
more information, see
|
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:
|
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`
|
in this example both `project` and `region` are specific to the `google`
|
||||||
provider.
|
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 arguments, but can only reference values that are known before the
|
||||||
configuration is applied. This means you can safely reference input variables,
|
configuration is applied. This means you can safely reference input variables,
|
||||||
but not attributes exported by resources (with an exception for resource
|
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
|
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
|
for more details. In most cases, only _root modules_ should define provider
|
||||||
configurations, with all child modules obtaining their provider configurations
|
configurations, with all child modules obtaining their provider configurations
|
||||||
from their parents.
|
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`
|
constraint in a provider configuration is only used if `required_providers`
|
||||||
does not include one for that provider.
|
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
|
In Terraform 0.13 and later, version constraints should always be declared in
|
||||||
[the `required_providers` block](./provider-requirements.html). The `version`
|
[the `required_providers` block](./provider-requirements.html). The `version`
|
||||||
argument will be removed in a future version of Terraform.
|
argument will be removed in a future version of Terraform.
|
||||||
|
|
|
@ -1,764 +1,86 @@
|
||||||
---
|
---
|
||||||
layout: "language"
|
layout: "language"
|
||||||
page_title: "Resources - Configuration Language"
|
page_title: "Resources Landing Page - 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.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Resources
|
# Resources Landing Page
|
||||||
|
|
||||||
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
|
To improve navigation, we've split the old Resources page into several smaller
|
||||||
earlier, see
|
pages.
|
||||||
[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.
|
<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.
|
## Syntax and Elements of Resource Blocks
|
||||||
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
|
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 id="resource-behavior"></a>
|
||||||
a small subset are required for initial use. More advanced syntax features,
|
<a id="accessing-resource-attributes"></a>
|
||||||
such as single resource declarations that produce multiple similar remote
|
<a id="resource-dependencies"></a>
|
||||||
objects, are described later in this page.
|
<a id="local-only-resources"></a>
|
||||||
|
|
||||||
```hcl
|
## Details of Resource Behavior
|
||||||
resource "aws_instance" "web" {
|
|
||||||
ami = "ami-a1b2c3d4"
|
|
||||||
instance_type = "t2.micro"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A `resource` block declares a resource of a given type ("aws_instance")
|
This information has moved to
|
||||||
with a given local name ("web"). The name is used to refer to this resource
|
[Resource Behavior](/docs/configuration/blocks/resources/behavior.html).
|
||||||
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 Meta-Arguments
|
||||||
resource and so must be unique within a module.
|
|
||||||
|
|
||||||
Within the block body (between `{` and `}`) are the configuration arguments
|
Each resource meta-argument has moved to its own page.
|
||||||
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
|
<a id="depends_on-explicit-resource-dependencies"></a>
|
||||||
contain only letters, digits, underscores, and dashes.
|
|
||||||
|
|
||||||
## Resource Types
|
### `depends_on`
|
||||||
|
|
||||||
Each resource is associated with a single _resource type_, which determines
|
This information has moved to
|
||||||
the kind of infrastructure object it manages and what arguments and other
|
[`depends_on`](/docs/configuration/meta-arguments/depends_on.html).
|
||||||
attributes the resource supports.
|
|
||||||
|
|
||||||
### 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),
|
### `count`
|
||||||
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
|
This information has moved to
|
||||||
requires. Additionally, most providers need some configuration in order to
|
[`count`](/docs/configuration/meta-arguments/count.html).
|
||||||
access their remote APIs, and the root module must provide that configuration.
|
|
||||||
|
|
||||||
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
|
### `for_each`
|
||||||
providers a module uses.
|
|
||||||
- [Provider Configuration](./providers.html), for configuring provider settings.
|
|
||||||
|
|
||||||
Terraform usually automatically determines which provider to use based on a
|
This information has moved to
|
||||||
resource type's name. (By convention, resource type names start with their
|
[`for_each`](/docs/configuration/meta-arguments/for_each.html).
|
||||||
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.
|
|
||||||
|
|
||||||
### 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
|
### `provider`
|
||||||
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
|
This information has moved to
|
||||||
[expressions](./expressions.html) and other dynamic Terraform
|
[`provider`](/docs/configuration/meta-arguments/resource-provider.html).
|
||||||
language features.
|
|
||||||
|
|
||||||
There are also some _meta-arguments_ that are defined by Terraform itself
|
<a id="lifecycle-lifecycle-customizations"></a>
|
||||||
and apply across all resource types. (See [Meta-Arguments](#meta-arguments) below.)
|
|
||||||
|
|
||||||
### Documentation for Resource Types
|
### `lifecycle`
|
||||||
|
|
||||||
Every Terraform provider has its own documentation, describing its resource
|
This information has moved to
|
||||||
types and their arguments.
|
[`lifecycle`](/docs/configuration/meta-arguments/lifecycle.html).
|
||||||
|
|
||||||
Most publicly available providers are distributed on the
|
<a id="provisioner-and-connection-resource-provisioners"></a>
|
||||||
[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
|
### Provisioners
|
||||||
[the providers section of the Terraform Registry](https://registry.terraform.io/browse/providers).
|
|
||||||
|
|
||||||
-> **Note:** Provider documentation used to be hosted directly on terraform.io,
|
This information has moved to
|
||||||
as part of Terraform's core documentation. Although some provider documentation
|
[Provisioners](/docs/configuration/blocks/resources/provisioners/index.html).
|
||||||
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.
|
|
||||||
|
|
|
@ -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.
|
correspond either to argument names or to nested block type names.
|
||||||
|
|
||||||
* Where a property corresponds to an argument that accepts
|
* 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
|
property value is mapped to an expression as described under
|
||||||
[_Expression Mapping_](#expression-mapping) below. For arguments that
|
[_Expression Mapping_](#expression-mapping) below. For arguments that
|
||||||
do _not_ accept arbitrary expressions, the interpretation of the property
|
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
|
## Expression Mapping
|
||||||
|
|
||||||
Since JSON grammar is not able to represent all of the Terraform language
|
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:
|
are mapped as follows:
|
||||||
|
|
||||||
| JSON | Terraform Language Interpretation |
|
| JSON | Terraform Language Interpretation |
|
||||||
| ------- | ------------------------------------------------------------------------------------------------------------- |
|
| ------- | ------------------------------------------------------------------------------------------------------------- |
|
||||||
| Boolean | A literal `bool` value. |
|
| Boolean | A literal `bool` value. |
|
||||||
| Number | A literal `number` 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. |
|
| 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. |
|
| Array | Each element is mapped per this table, producing a `tuple(...)` value with suitable element types. |
|
||||||
| Null | A literal `null`. |
|
| 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
|
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.
|
and then it is evaluated to produce the final result.
|
||||||
|
|
||||||
If the given template consists _only_ of a single interpolation sequence,
|
If the given template consists _only_ of a single interpolation sequence,
|
||||||
|
|
|
@ -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
|
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
|
(for example, each resource type has a schema that defines the types of its
|
||||||
arguments), but many arguments accept arbitrary
|
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.
|
either be specified literally or generated from other values programmatically.
|
||||||
|
|
||||||
-> **Note:** Terraform's configuration language is based on a more general
|
-> **Note:** Terraform's configuration language is based on a more general
|
||||||
|
|
|
@ -51,7 +51,7 @@ can be used with your configuration.
|
||||||
If the running version of Terraform doesn't match the constraints specified,
|
If the running version of Terraform doesn't match the constraints specified,
|
||||||
Terraform will produce an error and exit without taking any further actions.
|
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
|
version requirements. The requirements of all modules in the tree must be
|
||||||
satisfied.
|
satisfied.
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ function-like constructs called _type constructors._
|
||||||
represent a type; instead, it represents a _kind_ of similar types.
|
represent a type; instead, it represents a _kind_ of similar types.
|
||||||
|
|
||||||
Type constraints look like other kinds of Terraform
|
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
|
Terraform language, they are only valid in the `type` argument of an
|
||||||
[input variable](./variables.html).
|
[input variable](./variables.html).
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ like the following:
|
||||||
|
|
||||||
The Terraform language has literal expressions for creating tuple and object
|
The Terraform language has literal expressions for creating tuple and object
|
||||||
values, which are described in
|
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.
|
"list/tuple" literals and "map/object" literals, respectively.
|
||||||
|
|
||||||
Terraform does _not_ provide any way to directly represent lists, maps, or sets.
|
Terraform does _not_ provide any way to directly represent lists, maps, or sets.
|
||||||
|
|
|
@ -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
|
When you declare variables in the root module of your configuration, you can
|
||||||
set their values using CLI options and environment variables.
|
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.
|
the calling module should pass values in the `module` block.
|
||||||
|
|
||||||
If you're familiar with traditional programming languages, it can be useful to
|
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
|
variable is being discussed. Other kinds of variables in Terraform include
|
||||||
_environment variables_ (set by the shell where Terraform runs) and _expression
|
_environment variables_ (set by the shell where Terraform runs) and _expression
|
||||||
variables_ (used to indirectly represent a value in an
|
variables_ (used to indirectly represent a value in an
|
||||||
[expression](./expressions.html)).
|
[expression](/docs/configuration/expressions/index.html)).
|
||||||
|
|
||||||
## Declaring an Input Variable
|
## 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`.
|
_except_ the following: `source`, `version`, `providers`, `count`, `for_each`, `lifecycle`, `depends_on`, `locals`.
|
||||||
|
|
||||||
These names are reserved for meta-arguments in
|
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.
|
declared as variable names.
|
||||||
|
|
||||||
## Arguments
|
## Arguments
|
||||||
|
@ -106,7 +106,7 @@ configuration.
|
||||||
[inpage-type]: #type-constraints
|
[inpage-type]: #type-constraints
|
||||||
|
|
||||||
The `type` argument in a `variable` block allows you to restrict the
|
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
|
the value for a variable. If no type constraint is set then a value of any type
|
||||||
is accepted.
|
is accepted.
|
||||||
|
|
||||||
|
@ -302,7 +302,7 @@ random_pet.animal: Creation complete after 0s [id=jae-known-mongoose]
|
||||||
## Using Input Variable Values
|
## Using Input Variable Values
|
||||||
|
|
||||||
Within the module that declared a variable, its value can be accessed from
|
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:
|
where `<NAME>` matches the label given in the declaration block:
|
||||||
|
|
||||||
-> **Note:** Input variables are _created_ by a `variable` block, but you
|
-> **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
|
The following sections describe these options in more detail. This section does
|
||||||
not apply to _child_ modules, where values for input variables are instead
|
not apply to _child_ modules, where values for input variables are instead
|
||||||
assigned in the configuration of their parent module, as described in
|
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
|
### Variables on the Command Line
|
||||||
|
|
||||||
|
@ -411,9 +411,10 @@ and lower case letters as in the above example.
|
||||||
|
|
||||||
### Complex-typed Values
|
### Complex-typed Values
|
||||||
|
|
||||||
When variable values are provided in a variable definitions file, Terraform's
|
When variable values are provided in a variable definitions file, you can use
|
||||||
[usual syntax](./expressions.html#structural-types) can be used to assign
|
Terraform's usual syntax for
|
||||||
complex-typed values, like lists and maps.
|
[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
|
Some special rules apply to the `-var` command line option and to environment
|
||||||
variables. For convenience, Terraform defaults to interpreting `-var` and
|
variables. For convenience, Terraform defaults to interpreting `-var` and
|
||||||
|
|
|
@ -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
|
something, it expects a specially formatted string known as a version
|
||||||
constraint. Version constraints are used when configuring:
|
constraint. Version constraints are used when configuring:
|
||||||
|
|
||||||
- [Modules](./modules.html)
|
- [Modules](/docs/configuration/blocks/modules/index.html)
|
||||||
- [Provider requirements](./provider-requirements.html)
|
- [Provider requirements](./provider-requirements.html)
|
||||||
- [The `required_version` setting](./terraform.html#specifying-a-required-terraform-version) in the `terraform` block.
|
- [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"
|
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.
|
containing one or more conditions, which are separated by commas.
|
||||||
|
|
||||||
Each condition consists of an operator and a version number.
|
Each condition consists of an operator and a version number.
|
||||||
|
|
|
@ -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)
|
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_
|
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
|
and connect them together by passing output values from one to input values
|
||||||
of another.
|
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
|
This section is about _creating_ re-usable modules that other configurations
|
||||||
can include using `module` blocks.
|
can include using `module` blocks.
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ Most commonly, modules use:
|
||||||
the calling module.
|
the calling module.
|
||||||
* [Output values](/docs/configuration/outputs.html) to return results to the
|
* [Output values](/docs/configuration/outputs.html) to return results to the
|
||||||
calling module, which it can then use to populate arguments elsewhere.
|
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.
|
infrastructure objects that the module will manage.
|
||||||
|
|
||||||
To define a module, create a new directory for it and place one or more `.tf`
|
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
|
adding unnecessary complexity. Just use the resource type directly in the
|
||||||
calling module instead.
|
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/
|
|
||||||
│ ├── .../
|
|
||||||
```
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
|
@ -14,7 +14,7 @@ If you've built a module that you intend to be reused, we recommend
|
||||||
your module, generate documentation, and more.
|
your module, generate documentation, and more.
|
||||||
|
|
||||||
Published modules can be easily consumed by Terraform, and users can
|
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
|
for safe and predictable updates. The following example shows how a caller
|
||||||
might use a module from the Terraform Registry:
|
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.
|
their own mechanisms for selecting particular VCS commits, etc.
|
||||||
|
|
||||||
We recommend that modules distributed via other protocols still use the
|
We recommend that modules distributed via other protocols still use the
|
||||||
[standard module structure](./#standard-module-structure) so that it can
|
[standard module structure](/docs/modules/structure.html) so that they can
|
||||||
be used in a similar way to a registry module, or even _become_ a registry
|
be used in a similar way as a registry module or be published on the registry
|
||||||
module at a later time.
|
at a later time.
|
||||||
|
|
|
@ -7,7 +7,7 @@ description: The source argument within a module block specifies the location of
|
||||||
|
|
||||||
# Module Sources
|
# 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.
|
tells Terraform where to find the source code for the desired child module.
|
||||||
|
|
||||||
Terraform uses this during the module installation step of `terraform init`
|
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
|
Registry modules support versioning. You can provide a specific version as shown
|
||||||
in the above examples, or use flexible
|
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
|
You can learn more about the registry at the
|
||||||
[Terraform Registry documentation](/docs/registry/modules/use.html#using-modules).
|
[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
|
-> **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
|
[Modules in Package Sub-directories](#modules-in-package-sub-directories) for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
|
|
@ -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/
|
||||||
|
│ ├── .../
|
||||||
|
```
|
|
@ -42,7 +42,7 @@ to populate the short description of the module. This should be a simple
|
||||||
one sentence description of the module.
|
one sentence description of the module.
|
||||||
|
|
||||||
- **Standard module structure.** The module must adhere to the
|
- **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,
|
This allows the registry to inspect your module and generate documentation,
|
||||||
track resource usage, parse submodules and examples, and more.
|
track resource usage, parse submodules and examples, and more.
|
||||||
|
|
||||||
|
|
|
@ -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.
|
we encourage all modules to follow the full guidelines of semantic versioning.
|
||||||
|
|
||||||
Terraform since version 0.11 will resolve any provided
|
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.
|
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
|
Terraform versions after 0.10.6 but before 0.11 have partial support for the registry
|
||||||
|
|
|
@ -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
|
You can load private modules [directly from version control and other
|
||||||
sources](/docs/modules/sources.html), but those sources don't support [version
|
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
|
marketplace of modules, both of which are important for enabling a
|
||||||
producers-and-consumers content model in a large organization.
|
producers-and-consumers content model in a large organization.
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,36 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
|
@ -216,13 +245,34 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="/docs/configuration/modules.html">Module Blocks</a>
|
<a href="/docs/configuration/blocks/modules/syntax.html">Module Blocks</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="/docs/modules/sources.html">Module Sources</a>
|
<a href="/docs/modules/sources.html">Module Sources</a>
|
||||||
</li>
|
</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>
|
<li>
|
||||||
<a href="#">Module Development</a>
|
<a href="#">Module Development</a>
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
|
@ -230,6 +280,14 @@
|
||||||
<a href="/docs/modules/index.html">Overview</a>
|
<a href="/docs/modules/index.html">Overview</a>
|
||||||
</li>
|
</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>
|
<li>
|
||||||
<a href="/docs/modules/composition.html">Best Practices: Module Composition</a>
|
<a href="/docs/modules/composition.html">Best Practices: Module Composition</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -250,7 +308,39 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
|
|
Loading…
Reference in New Issue