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
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ the change.
|
|||
Once upgraded the configuration will no longer be compatible with Terraform
|
||||
v0.11 and earlier. When upgrading a shared module that is called from multiple
|
||||
configurations, you may need to
|
||||
[fix existing configurations to a previous version](/docs/configuration/modules.html#module-versions)
|
||||
[fix existing configurations to a previous version](/docs/configuration/blocks/modules/syntax.html#version)
|
||||
to allow for a gradual upgrade. If the module is published via
|
||||
[a Terraform registry](/docs/registry/), assign a new _major_ version number
|
||||
to the upgraded module source to represent the fact that this is a breaking
|
||||
|
|
|
@ -10,14 +10,14 @@ description: |-
|
|||
# Command: console
|
||||
|
||||
The `terraform console` command provides an interactive console for
|
||||
evaluating [expressions](/docs/configuration/expressions.html).
|
||||
evaluating [expressions](/docs/configuration/expressions/index.html).
|
||||
|
||||
## Usage
|
||||
|
||||
Usage: `terraform console [options]`
|
||||
|
||||
This command provides an interactive command-line console for evaluating and
|
||||
experimenting with [expressions](/docs/configuration/expressions.html).
|
||||
experimenting with [expressions](/docs/configuration/expressions/index.html).
|
||||
This is useful for testing interpolations before using them in configurations,
|
||||
and for interacting with any values currently saved in
|
||||
[state](/docs/state/index.html).
|
||||
|
|
|
@ -133,7 +133,7 @@ $ terraform import module.foo.aws_instance.bar i-abcd1234
|
|||
## Example: Import into Resource configured with count
|
||||
|
||||
The example below will import an AWS instance into the first instance of the `aws_instance` resource named `baz` configured with
|
||||
[`count`](/docs/configuration/resources.html#count-multiple-resource-instances-by-count):
|
||||
[`count`](/docs/configuration/meta-arguments/count.html):
|
||||
|
||||
```shell
|
||||
$ terraform import 'aws_instance.baz[0]' i-abcd1234
|
||||
|
@ -142,7 +142,7 @@ $ terraform import 'aws_instance.baz[0]' i-abcd1234
|
|||
## Example: Import into Resource configured with for_each
|
||||
|
||||
The example below will import an AWS instance into the `"example"` instance of the `aws_instance` resource named `baz` configured with
|
||||
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
|
||||
[`for_each`](/docs/configuration/meta-arguments/for_each.html):
|
||||
|
||||
Linux, Mac OS, and UNIX:
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ $ terraform state mv -state-out=other.tfstate 'module.app' 'module.app'
|
|||
## Example: Move a Resource configured with count
|
||||
|
||||
The example below moves the first instance of a `packet_device` resource named `worker` configured with
|
||||
[`count`](/docs/configuration/resources.html#count-multiple-resource-instances-by-count) to
|
||||
[`count`](/docs/configuration/meta-arguments/count.html) to
|
||||
the first instance of a resource named `helper` also configured with `count`:
|
||||
|
||||
```shell
|
||||
|
@ -105,7 +105,7 @@ $ terraform state mv 'packet_device.worker[0]' 'packet_device.helper[0]'
|
|||
## Example: Move a Resource configured with for_each
|
||||
|
||||
The example below moves the `"example123"` instance of a `packet_device` resource named `worker` configured with
|
||||
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
||||
[`for_each`](/docs/configuration/meta-arguments/for_each.html)
|
||||
to the `"example456"` instance of a resource named `helper` also configuring `for_each`:
|
||||
|
||||
Linux, Mac OS, and UNIX:
|
||||
|
|
|
@ -78,7 +78,7 @@ $ terraform state rm 'module.foo.packet_device.worker'
|
|||
## Example: Remove a Resource configured with count
|
||||
|
||||
The example below removes the first instance of a `packet_device` resource named `worker` configured with
|
||||
[`count`](/docs/configuration/resources.html#count-multiple-resource-instances-by-count):
|
||||
[`count`](/docs/configuration/meta-arguments/count.html):
|
||||
|
||||
```shell
|
||||
$ terraform state rm 'packet_device.worker[0]'
|
||||
|
@ -87,7 +87,7 @@ $ terraform state rm 'packet_device.worker[0]'
|
|||
## Example: Remove a Resource configured with for_each
|
||||
|
||||
The example below removes the `"example"` instance of a `packet_device` resource named `worker` configured with
|
||||
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
|
||||
[`for_each`](/docs/configuration/meta-arguments/for_each.html):
|
||||
|
||||
Linux, Mac OS, and UNIX:
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ $ terraform state show 'module.foo.packet_device.worker'
|
|||
## Example: Show a Resource configured with count
|
||||
|
||||
The example below shows the first instance of a `packet_device` resource named `worker` configured with
|
||||
[`count`](/docs/configuration/resources.html#count-multiple-resource-instances-by-count):
|
||||
[`count`](/docs/configuration/meta-arguments/count.html):
|
||||
|
||||
```shell
|
||||
$ terraform state show 'packet_device.worker[0]'
|
||||
|
@ -70,7 +70,7 @@ $ terraform state show 'packet_device.worker[0]'
|
|||
## Example: Show a Resource configured with for_each
|
||||
|
||||
The example below shows the `"example"` instance of a `packet_device` resource named `worker` configured with
|
||||
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
|
||||
[`for_each`](/docs/configuration/meta-arguments/for_each.html):
|
||||
|
||||
Linux, Mac OS, and UNIX:
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ description: |-
|
|||
|
||||
-> **Note:** This page is about Terraform 0.11 and earlier. For Terraform 0.12
|
||||
and later, see
|
||||
[Configuration Language: Expressions](../configuration/expressions.html) and
|
||||
[Configuration Language: Expressions](/docs/configuration/expressions/index.html) and
|
||||
[Configuration Language: Functions](../configuration/functions.html).
|
||||
|
||||
Embedded within strings in Terraform, whether you're using the
|
||||
|
|
|
@ -153,7 +153,7 @@ example = [
|
|||
|
||||
For the arguments that use the attributes-as-blocks usage mode, the above is
|
||||
a better pattern than using
|
||||
[`dynamic` blocks](/docs/configuration/expressions.html#dynamic-blocks)
|
||||
[`dynamic` blocks](/docs/configuration/expressions/dynamic-blocks.html)
|
||||
because the case where the
|
||||
caller provides an empty list will result in explicitly assigning an empty
|
||||
list value, rather than assigning no value at all and thus retaining and
|
||||
|
|
|
@ -48,12 +48,20 @@ module registry for sharing modules internally within your organization.
|
|||
|
||||
## Using Modules
|
||||
|
||||
- [Module Blocks](/docs/configuration/modules.html) documents the syntax for
|
||||
- [Module Blocks](/docs/configuration/blocks/modules/syntax.html) documents the syntax for
|
||||
calling a child module from a parent module, including meta-arguments like
|
||||
`for_each`.
|
||||
|
||||
- [Module Sources](/docs/modules/sources.html) documents what kinds of paths,
|
||||
addresses, and URIs can be used in the `source` argument of a module block.
|
||||
|
||||
- The Meta-Arguments section documents special arguments that can be used with
|
||||
every module, including
|
||||
[`providers`](/docs/configuration/meta-arguments/module-providers.html),
|
||||
[`depends_on`](/docs/configuration/meta-arguments/depends_on.html),
|
||||
[`count`](/docs/configuration/meta-arguments/count.html),
|
||||
and [`for_each`](/docs/configuration/meta-arguments/for_each.html).
|
||||
|
||||
## Developing Modules
|
||||
|
||||
For information about developing reusable modules, see
|
||||
|
|
|
@ -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
|
||||
|
||||
Each provider adds a set of [resource types](/docs/configuration/resources.html)
|
||||
Each provider adds a set of [resource types](/docs/configuration/blocks/resources/index.html)
|
||||
and/or [data sources](/docs/configuration/data-sources.html) that Terraform can
|
||||
manage.
|
||||
|
||||
|
|
|
@ -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 DNS records.
|
||||
|
||||
- [Resource Blocks](/docs/configuration/resources.html) documents how to declare
|
||||
resources, including information about meta-arguments like `for_each`.
|
||||
- [Resource Blocks](/docs/configuration/blocks/resources/syntax.html) documents
|
||||
the syntax for declaring resources.
|
||||
|
||||
- [Resource Behavior](/docs/configuration/resources/behavior.html) explains in
|
||||
more detail how Terraform handles resource declarations when applying a
|
||||
configuration.
|
||||
|
||||
- The Meta-Arguments section documents special arguments that can be used with
|
||||
every resource type, including
|
||||
[`depends_on`](/docs/configuration/meta-arguments/depends_on.html),
|
||||
[`count`](/docs/configuration/meta-arguments/count.html),
|
||||
[`for_each`](/docs/configuration/meta-arguments/for_each.html),
|
||||
[`provider`](/docs/configuration/meta-arguments/resource-provider.html),
|
||||
and [`lifecycle`](/docs/configuration/meta-arguments/lifecycle.html).
|
||||
|
||||
- [Provisioners](/docs/configuration/blocks/resources/provisioners/index.html)
|
||||
documents configuring post-creation actions for a resource using the
|
||||
`provisioner` and `connection` blocks. Since provisioners are non-declarative
|
||||
|
|
|
@ -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.
|
||||
|
||||
Each [provider](./providers.html) may offer data sources
|
||||
alongside its set of [resource types](./resources.html#resource-types-and-arguments).
|
||||
alongside its set of [resource](/docs/configuration/blocks/resources/index.html)
|
||||
types.
|
||||
|
||||
## Using Data Sources
|
||||
|
||||
|
@ -71,7 +72,7 @@ infrastructure platform.
|
|||
|
||||
Most of the items within the body of a `data` block are defined by and
|
||||
specific to the selected data source, and these arguments can make full
|
||||
use of [expressions](./expressions.html) and other dynamic
|
||||
use of [expressions](/docs/configuration/expressions/index.html) and other dynamic
|
||||
Terraform language features.
|
||||
|
||||
However, there are some "meta-arguments" that are defined by Terraform itself
|
||||
|
@ -113,7 +114,7 @@ operation, and is re-calculated each time a new plan is created.
|
|||
## Data Resource Dependencies
|
||||
|
||||
Data resources have the same dependency resolution behavior
|
||||
[as defined for managed resources](./resources.html#resource-dependencies).
|
||||
[as defined for managed resources](/docs/configuration/blocks/resources/behavior.html#resource-dependencies).
|
||||
Setting the `depends_on` meta-argument within `data` blocks defers reading of
|
||||
the data source until after all changes to the dependencies have been applied.
|
||||
|
||||
|
@ -122,8 +123,8 @@ the data source until after all changes to the dependencies have been applied.
|
|||
|
||||
## Multiple Resource Instances
|
||||
|
||||
Data resources support [`count`](./resources.html#count-multiple-resource-instances-by-count)
|
||||
and [`for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
||||
Data resources support [`count`](/docs/configuration/meta-arguments/count.html)
|
||||
and [`for_each`](/docs/configuration/meta-arguments/for_each.html)
|
||||
meta-arguments as defined for managed resources, with the same syntax and behavior.
|
||||
|
||||
As with managed resources, when `count` or `for_each` is present it is important to
|
||||
|
@ -133,7 +134,7 @@ own variant of the constraint arguments, producing an indexed result.
|
|||
|
||||
## Selecting a Non-default Provider Configuration
|
||||
|
||||
Data resources support [the `provider` meta-argument](./resources.html#provider-selecting-a-non-default-provider-configuration)
|
||||
Data resources support [the `provider` meta-argument](/docs/configuration/meta-arguments/resource-provider.html)
|
||||
as defined for managed resources, with the same syntax and behavior.
|
||||
|
||||
## Lifecycle Customizations
|
||||
|
@ -187,13 +188,15 @@ resource "aws_instance" "web" {
|
|||
## Meta-Arguments
|
||||
|
||||
As data sources are essentially a read only subset of resources, they also
|
||||
support the same [meta-arguments](./resources.html#meta-arguments) of resources
|
||||
support the same [meta-arguments](/docs/configuration/blocks/resources/syntax.html#meta-arguments) of resources
|
||||
with the exception of the
|
||||
[`lifecycle` configuration block](./resources.html#lifecycle-lifecycle-customizations).
|
||||
[`lifecycle` configuration block](/docs/configuration/meta-arguments/lifecycle.html).
|
||||
|
||||
### Non-Default Provider Configurations
|
||||
|
||||
Similarly to [resources](./resources.html), when a module has multiple configurations for the same provider you can specify which configuration to use with the `provider` meta-argument:
|
||||
Similarly to [resources](/docs/configuration/blocks/resources/index.html), when
|
||||
a module has multiple configurations for the same provider you can specify which
|
||||
configuration to use with the `provider` meta-argument:
|
||||
|
||||
```hcl
|
||||
data "aws_ami" "web" {
|
||||
|
@ -204,7 +207,7 @@ data "aws_ami" "web" {
|
|||
```
|
||||
|
||||
See
|
||||
[Resources: Selecting a Non-Default Provider Configuration](./resources.html#provider-selecting-a-non-default-provider-configuration)
|
||||
[The Resource `provider` Meta-Argument](/docs/configuration/meta-arguments/resource-provider.html)
|
||||
for more information.
|
||||
|
||||
## Data Source Lifecycle
|
||||
|
|
|
@ -14,9 +14,9 @@ dependency that come from outside of its own codebase:
|
|||
|
||||
* [Providers](./provider-requirements.html), which are plugins for Terraform
|
||||
that extend it with support for interacting with various external systems.
|
||||
* [Modules](./modules.html), which allow splitting out groups of Terraform
|
||||
configuration constructs (written in the Terraform language) into reusable
|
||||
abstractions.
|
||||
* [Modules](/docs/configuration/blocks/modules/index.html), which allow
|
||||
splitting out groups of Terraform configuration constructs (written in the
|
||||
Terraform language) into reusable abstractions.
|
||||
|
||||
Both of these dependency types can be published and updated independently from
|
||||
Terraform itself and from the configurations that depend on them. For that
|
||||
|
@ -168,7 +168,7 @@ block in the dependency lock file.
|
|||
@@ -6,6 +6,26 @@
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
+provider "registry.terraform.io/hashicorp/azurerm" {
|
||||
+ version = "2.30.0"
|
||||
+ constraints = "~> 2.12"
|
||||
|
@ -219,7 +219,7 @@ block to reflect that change.
|
|||
+++ .terraform.lock.hcl 2020-10-07 16:43:42.785665945 -0700
|
||||
@@ -7,22 +7,22 @@
|
||||
}
|
||||
|
||||
|
||||
provider "registry.terraform.io/hashicorp/azurerm" {
|
||||
- version = "2.1.0"
|
||||
- constraints = "~> 2.1.0"
|
||||
|
|
|
@ -1,905 +1,123 @@
|
|||
---
|
||||
layout: "language"
|
||||
page_title: "Expressions - Configuration Language"
|
||||
page_title: "Expressions Landing Page - Configuration Language"
|
||||
sidebar_current: "docs-config-expressions"
|
||||
description: |-
|
||||
The Terraform language allows the use of expressions to access data exported
|
||||
by resources and to transform and combine that data to produce other values.
|
||||
---
|
||||
|
||||
# Expressions
|
||||
# Expressions Landing Page
|
||||
|
||||
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
|
||||
earlier, see
|
||||
[0.11 Configuration Language: Interpolation Syntax](../configuration-0-11/interpolation.html).
|
||||
To improve navigation, we've split the old Expressions page into several smaller
|
||||
pages.
|
||||
|
||||
_Expressions_ are used to refer to or compute values within a configuration.
|
||||
The simplest expressions are just literal values, like `"hello"` or `5`,
|
||||
but the Terraform language also allows more complex expressions such as
|
||||
references to data exported by resources, arithmetic, conditional evaluation,
|
||||
and a number of built-in functions.
|
||||
<a id="types-and-values"></a>
|
||||
<a id="advanced-type-details"></a>
|
||||
<a id="type-conversion"></a>
|
||||
<a id="literal-expressions"></a>
|
||||
<a id="indices-and-attributes"></a>
|
||||
|
||||
Expressions can be used in a number of places in the Terraform language,
|
||||
but some contexts limit which expression constructs are allowed,
|
||||
such as requiring a literal value of a particular type or forbidding
|
||||
[references to resource attributes](/docs/configuration/expressions.html#references-to-resource-attributes).
|
||||
Each language feature's documentation describes any restrictions it places on expressions.
|
||||
## Types and Values, Literal Expressions, Indices and Attributes
|
||||
|
||||
You can experiment with the behavior of Terraform's expressions from
|
||||
the Terraform expression console, by running
|
||||
[the `terraform console` command](/docs/commands/console.html).
|
||||
Terraform's types are `string`, `number`, `bool`, `list`, `tuple`, `map`,
|
||||
`object`, and `null`.
|
||||
|
||||
The rest of this page describes all of the features of Terraform's
|
||||
expression syntax.
|
||||
This information has moved to
|
||||
[Types and Values](/docs/configuration/expressions/types.html).
|
||||
|
||||
## Types and Values
|
||||
<a id="references-to-named-values"></a>
|
||||
<a id="local-named-values"></a>
|
||||
<a id="named-values-and-dependencies"></a>
|
||||
<a id="references-to-resource-attributes"></a>
|
||||
<a id="local-named-values-1"></a>
|
||||
<a id="values-not-yet-known"></a>
|
||||
|
||||
The result of an expression is a _value_. All values have a _type_, which
|
||||
dictates where that value can be used and what transformations can be
|
||||
applied to it.
|
||||
## References to Named Values (Resource Attributes, Variables, etc.)
|
||||
|
||||
The Terraform language uses the following types for its values:
|
||||
You can refer to certain values by name, like `var.some_variable` or
|
||||
`aws_instance.example.ami`.
|
||||
|
||||
* `string`: a sequence of Unicode characters representing some text, like
|
||||
`"hello"`.
|
||||
* `number`: a numeric value. The `number` type can represent both whole
|
||||
numbers like `15` and fractional values like `6.283185`.
|
||||
* `bool`: either `true` or `false`. `bool` values can be used in conditional
|
||||
logic.
|
||||
* `list` (or `tuple`): a sequence of values, like
|
||||
`["us-west-1a", "us-west-1c"]`. Elements in a list or tuple are identified by
|
||||
consecutive whole numbers, starting with zero.
|
||||
* `map` (or `object`): a group of values identified by named labels, like
|
||||
`{name = "Mabel", age = 52}`.
|
||||
This information has moved to
|
||||
[References to Values](/docs/configuration/expressions/references.html).
|
||||
|
||||
Strings, numbers, and bools are sometimes called _primitive types._ Lists/tuples and maps/objects are sometimes called _complex types,_ _structural types,_ or _collection types._
|
||||
|
||||
Finally, there is one special value that has _no_ type:
|
||||
|
||||
* `null`: a value that represents _absence_ or _omission._ If you set an
|
||||
argument of a resource or module to `null`, Terraform behaves as though you
|
||||
had completely omitted it — it will use the argument's default value if it has
|
||||
one, or raise an error if the argument is mandatory. `null` is most useful in
|
||||
conditional expressions, so you can dynamically omit an argument if a
|
||||
condition isn't met.
|
||||
|
||||
### Advanced Type Details
|
||||
|
||||
In most situations, lists and tuples behave identically, as do maps and objects.
|
||||
Whenever the distinction isn't relevant, the Terraform documentation uses each
|
||||
pair of terms interchangeably (with a historical preference for "list" and
|
||||
"map").
|
||||
|
||||
However, module authors and provider developers should understand the
|
||||
differences between these similar types (and the related `set` type), since they
|
||||
offer different ways to restrict the allowed values for input variables and
|
||||
resource arguments.
|
||||
|
||||
For complete details about these types (and an explanation of why the difference
|
||||
usually doesn't matter), see [Type Constraints](./types.html).
|
||||
|
||||
### Type Conversion
|
||||
|
||||
Expressions are most often used to set values for the arguments of resources and
|
||||
child modules. In these cases, the argument has an expected type and the given
|
||||
expression must produce a value of that type.
|
||||
|
||||
Where possible, Terraform automatically converts values from one type to
|
||||
another in order to produce the expected type. If this isn't possible, Terraform
|
||||
will produce a type mismatch error and you must update the configuration with a
|
||||
more suitable expression.
|
||||
|
||||
Terraform automatically converts number and bool values to strings when needed.
|
||||
It also converts strings to numbers or bools, as long as the string contains a
|
||||
valid representation of a number or bool value.
|
||||
|
||||
* `true` converts to `"true"`, and vice-versa
|
||||
* `false` converts to `"false"`, and vice-versa
|
||||
* `15` converts to `"15"`, and vice-versa
|
||||
|
||||
## Literal Expressions
|
||||
|
||||
A _literal expression_ is an expression that directly represents a particular
|
||||
constant value. Terraform has a literal expression syntax for each of the value
|
||||
types described above:
|
||||
|
||||
* Strings are usually represented by a double-quoted sequence of Unicode
|
||||
characters, `"like this"`. There is also a "heredoc" syntax for more complex
|
||||
strings. String literals are the most complex kind of literal expression in
|
||||
Terraform, and have additional documentation on this page:
|
||||
* See [String Literals](#string-literals) below for information about escape
|
||||
sequences and the heredoc syntax.
|
||||
* See [String Templates](#string-templates) below for information about
|
||||
interpolation and template directives.
|
||||
* Numbers are represented by unquoted sequences of digits with or without a
|
||||
decimal point, like `15` or `6.283185`.
|
||||
* Bools are represented by the unquoted symbols `true` and `false`.
|
||||
* The null value is represented by the unquoted symbol `null`.
|
||||
* Lists/tuples are represented by a pair of square brackets containing a
|
||||
comma-separated sequence of values, like `["a", 15, true]`.
|
||||
|
||||
List literals can be split into multiple lines for readability, but always
|
||||
require a comma between values. A comma after the final value is allowed,
|
||||
but not required. Values in a list can be arbitrary expressions.
|
||||
* Maps/objects are represented by a pair of curly braces containing a series of
|
||||
`<KEY> = <VALUE>` pairs:
|
||||
|
||||
```hcl
|
||||
{
|
||||
name = "John"
|
||||
age = 52
|
||||
}
|
||||
```
|
||||
|
||||
Key/value pairs can be separated by either a comma or a line break. Values
|
||||
can be arbitrary expressions. Keys are strings; they can be left unquoted if
|
||||
they are a valid [identifier](./syntax.html#identifiers), but must be quoted
|
||||
otherwise. You can use a non-literal expression as a key by wrapping it in
|
||||
parentheses, like `(var.business_unit_tag_name) = "SRE"`.
|
||||
|
||||
## Indices and Attributes
|
||||
|
||||
[inpage-index]: #indices-and-attributes
|
||||
|
||||
Elements of list/tuple and map/object values can be accessed using
|
||||
the square-bracket index notation, like `local.list[3]`. The expression within
|
||||
the brackets must be a whole number for list and tuple values or a string
|
||||
for map and object values.
|
||||
|
||||
Map/object attributes with names that are valid identifiers can also be accessed
|
||||
using the dot-separated attribute notation, like `local.object.attrname`.
|
||||
In cases where a map might contain arbitrary user-specified keys, we recommend
|
||||
using only the square-bracket index notation (`local.map["keyname"]`).
|
||||
|
||||
## References to Named Values
|
||||
|
||||
Terraform makes several kinds of named values available. Each of these names is
|
||||
an expression that references the associated value; you can use them as
|
||||
standalone expressions, or combine them with other expressions to compute new
|
||||
values.
|
||||
|
||||
The following named values are available:
|
||||
|
||||
* `<RESOURCE TYPE>.<NAME>` is an object representing a
|
||||
[managed resource](./resources.html) of the given type
|
||||
and name. The attributes of the resource can be accessed using
|
||||
[dot or square bracket notation][inpage-index].
|
||||
|
||||
Any named value that does not match another pattern listed below
|
||||
will be interpreted by Terraform as a reference to a managed resource.
|
||||
|
||||
If the resource has the `count` argument set, the value of this expression
|
||||
is a _list_ of objects representing its instances.
|
||||
|
||||
If the resource has the `for_each` argument set, the value of this expression
|
||||
is a _map_ of objects representing its instances.
|
||||
|
||||
For more information, see
|
||||
[references to resource attributes](#references-to-resource-attributes) below.
|
||||
* `var.<NAME>` is the value of the
|
||||
[input variable](./variables.html) of the given name.
|
||||
* `local.<NAME>` is the value of the
|
||||
[local value](./locals.html) of the given name.
|
||||
* `module.<MODULE NAME>.<OUTPUT NAME>` is the value of the specified
|
||||
[output value](./outputs.html) from a
|
||||
[child module](./modules.html) called by the current module.
|
||||
* `data.<DATA TYPE>.<NAME>` is an object representing a
|
||||
[data resource](./data-sources.html) of the given data
|
||||
source type and name. If the resource has the `count` argument set, the value
|
||||
is a list of objects representing its instances. If the resource has the `for_each`
|
||||
argument set, the value is a map of objects representing its instances.
|
||||
* `path.module` is the filesystem path of the module where the expression
|
||||
is placed.
|
||||
* `path.root` is the filesystem path of the root module of the configuration.
|
||||
* `path.cwd` is the filesystem path of the current working directory. In
|
||||
normal use of Terraform this is the same as `path.root`, but some advanced
|
||||
uses of Terraform run it from a directory other than the root module
|
||||
directory, causing these paths to be different.
|
||||
* `terraform.workspace` is the name of the currently selected
|
||||
[workspace](/docs/state/workspaces.html).
|
||||
|
||||
Although many of these names use dot-separated paths that resemble
|
||||
[attribute notation][inpage-index] for elements of object values, they are not
|
||||
implemented as real objects. This means you must use them exactly as written:
|
||||
you cannot use square-bracket notation to replace the dot-separated paths, and
|
||||
you cannot iterate over the "parent object" of a named entity (for example, you
|
||||
cannot use `aws_instance` in a `for` expression).
|
||||
|
||||
### Local Named Values
|
||||
|
||||
Within the bodies of certain expressions, or in some other specific contexts,
|
||||
there are other named values available beyond the global values listed above.
|
||||
These local names are described in the documentation for the specific contexts
|
||||
where they appear. Some of most common local names are:
|
||||
|
||||
- `count.index`, in resources that use
|
||||
[the `count` meta-argument](./resources.html#count-multiple-resource-instances-by-count).
|
||||
- `each.key` / `each.value`, in resources that use
|
||||
[the `for_each` meta-argument](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings).
|
||||
- `self`, in [provisioner](../provisioners/index.html) and
|
||||
[connection](../provisioners/connection.html) blocks.
|
||||
|
||||
-> **Note:** Local names are often referred to as _variables_ or
|
||||
_temporary variables_ in their documentation. These are not [input
|
||||
variables](./variables.html); they are just arbitrary names
|
||||
that temporarily represent a value.
|
||||
|
||||
### Named Values and Dependencies
|
||||
|
||||
Constructs like resources and module calls often use references to named values
|
||||
in their block bodies, and Terraform analyzes these expressions to automatically
|
||||
infer dependencies between objects. For example, an expression in a resource
|
||||
argument that refers to another managed resource creates an implicit dependency
|
||||
between the two resources.
|
||||
|
||||
### References to Resource Attributes
|
||||
|
||||
The most common reference type is a reference to an attribute of a resource
|
||||
which has been declared either with a `resource` or `data` block. Because
|
||||
the contents of such blocks can be quite complicated themselves, expressions
|
||||
referring to these contents can also be complicated.
|
||||
|
||||
Consider the following example resource block:
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "example" {
|
||||
ami = "ami-abc123"
|
||||
instance_type = "t2.micro"
|
||||
|
||||
ebs_block_device {
|
||||
device_name = "sda2"
|
||||
volume_size = 16
|
||||
}
|
||||
ebs_block_device {
|
||||
device_name = "sda3"
|
||||
volume_size = 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The documentation for [`aws_instance`](/docs/providers/aws/r/instance.html)
|
||||
lists all of the arguments and nested blocks supported for this resource type,
|
||||
and also lists a number of attributes that are _exported_ by this resource
|
||||
type. All of these different resource type schema constructs are available
|
||||
for use in references, as follows:
|
||||
|
||||
* The `ami` argument set in the configuration can be used elsewhere with
|
||||
the reference expression `aws_instance.example.ami`.
|
||||
* The `id` attribute exported by this resource type can be read using the
|
||||
same syntax, giving `aws_instance.example.id`.
|
||||
* The arguments of the `ebs_block_device` nested blocks can be accessed using
|
||||
a [splat expression](#splat-expressions). For example, to obtain a list of
|
||||
all of the `device_name` values, use
|
||||
`aws_instance.example.ebs_block_device[*].device_name`.
|
||||
* The nested blocks in this particular resource type do not have any exported
|
||||
attributes, but if `ebs_block_device` were to have a documented `id`
|
||||
attribute then a list of them could be accessed similarly as
|
||||
`aws_instance.example.ebs_block_device[*].id`.
|
||||
* Sometimes nested blocks are defined as taking a logical key to identify each
|
||||
block, which serves a similar purpose as the resource's own name by providing
|
||||
a convenient way to refer to that single block in expressions. If `aws_instance`
|
||||
had a hypothetical nested block type `device` that accepted such a key, it
|
||||
would look like this in configuration:
|
||||
|
||||
```hcl
|
||||
device "foo" {
|
||||
size = 2
|
||||
}
|
||||
device "bar" {
|
||||
size = 4
|
||||
}
|
||||
```
|
||||
|
||||
Arguments inside blocks with _keys_ can be accessed using index syntax, such
|
||||
as `aws_instance.example.device["foo"].size`.
|
||||
|
||||
To obtain a map of values of a particular argument for _labelled_ nested
|
||||
block types, use a [`for` expression](#for-expressions):
|
||||
`{for k, device in aws_instance.example.device : k => device.size}`.
|
||||
|
||||
When a resource has the
|
||||
[`count`](https://www.terraform.io/docs/configuration/resources.html#count-multiple-resource-instances-by-count)
|
||||
argument set, the resource itself becomes a _list_ of instance objects rather than
|
||||
a single object. In that case, access the attributes of the instances using
|
||||
either [splat expressions](#splat-expressions) or index syntax:
|
||||
|
||||
* `aws_instance.example[*].id` returns a list of all of the ids of each of the
|
||||
instances.
|
||||
* `aws_instance.example[0].id` returns just the id of the first instance.
|
||||
|
||||
When a resource has the
|
||||
[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
||||
argument set, the resource itself becomes a _map_ of instance objects rather than
|
||||
a single object, and attributes of instances must be specified by key, or can
|
||||
be accessed using a [`for` expression](#for-expressions).
|
||||
|
||||
* `aws_instance.example["a"].id` returns the id of the "a"-keyed resource.
|
||||
* `[for value in aws_instance.example: value.id]` returns a list of all of the ids
|
||||
of each of the instances.
|
||||
|
||||
Note that unlike `count`, splat expressions are _not_ directly applicable to resources managed with `for_each`, as splat expressions are for lists only. You may apply a splat expression to values in a map like so:
|
||||
|
||||
* `values(aws_instance.example)[*].id`
|
||||
|
||||
### Values Not Yet Known
|
||||
|
||||
When Terraform is planning a set of changes that will apply your configuration,
|
||||
some resource attribute values cannot be populated immediately because their
|
||||
values are decided dynamically by the remote system. For example, if a
|
||||
particular remote object type is assigned a generated unique id on creation,
|
||||
Terraform cannot predict the value of this id until the object has been created.
|
||||
|
||||
To allow expressions to still be evaluated during the plan phase, Terraform
|
||||
uses special "unknown value" placeholders for these results. In most cases you
|
||||
don't need to do anything special to deal with these, since the Terraform
|
||||
language automatically handles unknown values during expressions, so that
|
||||
for example adding a known value to an unknown value automatically produces
|
||||
an unknown value as the result.
|
||||
|
||||
However, there are some situations where unknown values _do_ have a significant
|
||||
effect:
|
||||
|
||||
* The `count` meta-argument for resources cannot be unknown, since it must
|
||||
be evaluated during the plan phase to determine how many instances are to
|
||||
be created.
|
||||
|
||||
* If unknown values are used in the configuration of a data resource, that
|
||||
data resource cannot be read during the plan phase and so it will be deferred
|
||||
until the apply phase. In this case, the results of the data resource will
|
||||
_also_ be unknown values.
|
||||
|
||||
* If an unknown value is assigned to an argument inside a `module` block,
|
||||
any references to the corresponding input variable within the child module
|
||||
will use that unknown value.
|
||||
|
||||
* If an unknown value is used in the `value` argument of an output value,
|
||||
any references to that output value in the parent module will use that
|
||||
unknown value.
|
||||
|
||||
* Terraform will attempt to validate that unknown values are of suitable
|
||||
types where possible, but incorrect use of such values may not be detected
|
||||
until the apply phase, causing the apply to fail.
|
||||
|
||||
Unknown values appear in the `terraform plan` output as `(not yet known)`.
|
||||
<a id="arithmetic-operators"></a>
|
||||
<a id="equality-operators"></a>
|
||||
<a id="comparison-operators"></a>
|
||||
<a id="logical-operators"></a>
|
||||
|
||||
## Arithmetic and Logical Operators
|
||||
|
||||
An _operator_ is a type of expression that transforms or combines one or more
|
||||
other expressions. Operators either combine two values in some way to
|
||||
produce a third result value, or transform a single given value to
|
||||
produce a single result.
|
||||
Operators are expressions that transform other expressions, like adding two
|
||||
numbers (`+`) or comparing two values to get a bool (`==`, `>=`, etc.).
|
||||
|
||||
Operators that work on two values place an operator symbol between the two
|
||||
values, similar to mathematical notation: `1 + 2`. Operators that work on
|
||||
only one value place an operator symbol before that value, like
|
||||
`!true`.
|
||||
|
||||
The Terraform language has a set of operators for both arithmetic and logic,
|
||||
which are similar to operators in programming languages such as JavaScript
|
||||
or Ruby.
|
||||
|
||||
When multiple operators are used together in an expression, they are evaluated
|
||||
in the following order of operations:
|
||||
|
||||
1. `!`, `-` (multiplication by `-1`)
|
||||
1. `*`, `/`, `%`
|
||||
1. `+`, `-` (subtraction)
|
||||
1. `>`, `>=`, `<`, `<=`
|
||||
1. `==`, `!=`
|
||||
1. `&&`
|
||||
1. `||`
|
||||
|
||||
Parentheses can be used to override the default order of operations. Without
|
||||
parentheses, higher levels are evaluated first, so `1 + 2 * 3` is interpreted
|
||||
as `1 + (2 * 3)` and _not_ as `(1 + 2) * 3`.
|
||||
|
||||
The different operators can be gathered into a few different groups with
|
||||
similar behavior, as described below. Each group of operators expects its
|
||||
given values to be of a particular type. Terraform will attempt to convert
|
||||
values to the required type automatically, or will produce an error message
|
||||
if this automatic conversion is not possible.
|
||||
|
||||
### Arithmetic Operators
|
||||
|
||||
The arithmetic operators all expect number values and produce number values
|
||||
as results:
|
||||
|
||||
* `a + b` returns the result of adding `a` and `b` together.
|
||||
* `a - b` returns the result of subtracting `b` from `a`.
|
||||
* `a * b` returns the result of multiplying `a` and `b`.
|
||||
* `a / b` returns the result of dividing `a` by `b`.
|
||||
* `a % b` returns the remainder of dividing `a` by `b`. This operator is
|
||||
generally useful only when used with whole numbers.
|
||||
* `-a` returns the result of multiplying `a` by `-1`.
|
||||
|
||||
### Equality Operators
|
||||
|
||||
The equality operators both take two values of any type and produce boolean
|
||||
values as results.
|
||||
|
||||
* `a == b` returns `true` if `a` and `b` both have the same type and the same
|
||||
value, or `false` otherwise.
|
||||
* `a != b` is the opposite of `a == b`.
|
||||
|
||||
### Comparison Operators
|
||||
|
||||
The comparison operators all expect number values and produce boolean values
|
||||
as results.
|
||||
|
||||
* `a < b` returns `true` if `a` is less than `b`, or `false` otherwise.
|
||||
* `a <= b` returns `true` if `a` is less than or equal to `b`, or `false`
|
||||
otherwise.
|
||||
* `a > b` returns `true` if `a` is greater than `b`, or `false` otherwise.
|
||||
* `a >= b` returns `true` if `a` is greater than or equal to `b`, or `false` otherwise.
|
||||
|
||||
### Logical Operators
|
||||
|
||||
The logical operators all expect bool values and produce bool values as results.
|
||||
|
||||
* `a || b` returns `true` if either `a` or `b` is `true`, or `false` if both are `false`.
|
||||
* `a && b` returns `true` if both `a` and `b` are `true`, or `false` if either one is `false`.
|
||||
* `!a` returns `true` if `a` is `false`, and `false` if `a` is `true`.
|
||||
This information has moved to
|
||||
[Operators](/docs/configuration/expressions/references.html).
|
||||
|
||||
## Conditional Expressions
|
||||
|
||||
A _conditional expression_ uses the value of a bool expression to select one of
|
||||
two values.
|
||||
The `condition ? true_val : false_val` expression chooses between two
|
||||
expressions based on a bool condition.
|
||||
|
||||
The syntax of a conditional expression is as follows:
|
||||
This information has moved to
|
||||
[Conditional Expressions](/docs/configuration/expressions/conditionals.html).
|
||||
|
||||
```hcl
|
||||
condition ? true_val : false_val
|
||||
```
|
||||
|
||||
If `condition` is `true` then the result is `true_val`. If `condition` is
|
||||
`false` then the result is `false_val`.
|
||||
|
||||
A common use of conditional expressions is to define defaults to replace
|
||||
invalid values:
|
||||
|
||||
```
|
||||
var.a != "" ? var.a : "default-a"
|
||||
```
|
||||
|
||||
If `var.a` is an empty string then the result is `"default-a"`, but otherwise
|
||||
it is the actual value of `var.a`.
|
||||
|
||||
Any of the equality, comparison, and logical operators can be used to define
|
||||
the condition. The two result values may be of any type, but they must both
|
||||
be of the _same_ type so that Terraform can determine what type the whole
|
||||
conditional expression will return without knowing the condition value.
|
||||
<a id="expanding-function-arguments"></a>
|
||||
<a id="available-functions"></a>
|
||||
|
||||
## Function Calls
|
||||
|
||||
The Terraform language has a number of
|
||||
[built-in functions](./functions.html) that can be used
|
||||
within expressions as another way to transform and combine values. These
|
||||
are similar to the operators but all follow a common syntax:
|
||||
Terraform's functions can be called like `function_name(arg1, arg2)`.
|
||||
|
||||
```hcl
|
||||
<FUNCTION NAME>(<ARGUMENT 1>, <ARGUMENT 2>)
|
||||
```
|
||||
This information has moved to
|
||||
[Function Calls](/docs/configuration/expressions/function-calls.html).
|
||||
|
||||
The function name specifies which function to call. Each defined function
|
||||
expects a specific number of arguments with specific value types, and returns a
|
||||
specific value type as a result.
|
||||
|
||||
Some functions take an arbitrary number of arguments. For example, the `min`
|
||||
function takes any amount of number arguments and returns the one that is
|
||||
numerically smallest:
|
||||
|
||||
```hcl
|
||||
min(55, 3453, 2)
|
||||
```
|
||||
|
||||
### Expanding Function Arguments
|
||||
|
||||
If the arguments to pass to a function are available in a list or tuple value,
|
||||
that value can be _expanded_ into separate arguments. Provide the list value as
|
||||
an argument and follow it with the `...` symbol:
|
||||
|
||||
```hcl
|
||||
min([55, 2453, 2]...)
|
||||
```
|
||||
|
||||
The expansion symbol is three periods (`...`), not a Unicode ellipsis character
|
||||
(`…`). Expansion is a special syntax that is only available in function calls.
|
||||
|
||||
### Available Functions
|
||||
|
||||
For a full list of available functions, see
|
||||
[the function reference](./functions.html).
|
||||
<a id="for-expressions"></a>
|
||||
|
||||
## `for` Expressions
|
||||
|
||||
A _`for` expression_ creates a complex type value by transforming
|
||||
another complex type value. Each element in the input value
|
||||
can correspond to either one or zero values in the result, and an arbitrary
|
||||
expression can be used to transform each input element into an output element.
|
||||
Expressions like `[for s in var.list : upper(s)]` can transform a complex type
|
||||
value into another complex type value.
|
||||
|
||||
For example, if `var.list` is a list of strings, then the following expression
|
||||
produces a list of strings with all-uppercase letters:
|
||||
This information has moved to
|
||||
[For Expressions](/docs/configuration/expressions/for.html).
|
||||
|
||||
```hcl
|
||||
[for s in var.list : upper(s)]
|
||||
```
|
||||
|
||||
This `for` expression iterates over each element of `var.list`, and then
|
||||
evaluates the expression `upper(s)` with `s` set to each respective element.
|
||||
It then builds a new tuple value with all of the results of executing that
|
||||
expression in the same order.
|
||||
|
||||
The type of brackets around the `for` expression decide what type of result
|
||||
it produces. The above example uses `[` and `]`, which produces a tuple. If
|
||||
`{` and `}` are used instead, the result is an object, and two result
|
||||
expressions must be provided separated by the `=>` symbol:
|
||||
|
||||
```hcl
|
||||
{for s in var.list : s => upper(s)}
|
||||
```
|
||||
|
||||
This expression produces an object whose attributes are the original elements
|
||||
from `var.list` and their corresponding values are the uppercase versions.
|
||||
|
||||
A `for` expression can also include an optional `if` clause to filter elements
|
||||
from the source collection, which can produce a value with fewer elements than
|
||||
the source:
|
||||
|
||||
```
|
||||
[for s in var.list : upper(s) if s != ""]
|
||||
```
|
||||
|
||||
The source value can also be an object or map value, in which case two
|
||||
temporary variable names can be provided to access the keys and values
|
||||
respectively:
|
||||
|
||||
```
|
||||
[for k, v in var.map : length(k) + length(v)]
|
||||
```
|
||||
|
||||
Finally, if the result type is an object (using `{` and `}` delimiters) then
|
||||
the value result expression can be followed by the `...` symbol to group
|
||||
together results that have a common key:
|
||||
|
||||
```
|
||||
{for s in var.list : substr(s, 0, 1) => s... if s != ""}
|
||||
```
|
||||
|
||||
For expressions are particularly useful when combined with other language
|
||||
features to combine collections together in various ways. For example,
|
||||
the following two patterns are commonly used when constructing map values
|
||||
to use with [resource `for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
|
||||
|
||||
* Transform a multi-level nested structure into a flat list by
|
||||
[using nested `for` expressions with the `flatten` function](./functions/flatten.html#flattening-nested-structures-for-for_each).
|
||||
* Produce an exhaustive list of combinations of elements from two or more
|
||||
collections by
|
||||
[using the `setproduct` function inside a `for` expression](./functions/setproduct.html#finding-combinations-for-for_each).
|
||||
<a id="splat-expressions"></a>
|
||||
<a id="legacy-attribute-only-splat-expressions"></a>
|
||||
|
||||
## Splat Expressions
|
||||
|
||||
A _splat expression_ provides a more concise way to express a common
|
||||
operation that could otherwise be performed with a `for` expression.
|
||||
Expressions like `var.list[*].id` can extract simpler collections from complex
|
||||
collections.
|
||||
|
||||
If `var.list` is a list of objects that all have an attribute `id`, then
|
||||
a list of the ids could be produced with the following `for` expression:
|
||||
This information has moved to
|
||||
[Splat Expressions](/docs/configuration/expressions/splat.html).
|
||||
|
||||
```hcl
|
||||
[for o in var.list : o.id]
|
||||
```
|
||||
<a id="dynamic-blocks"></a>
|
||||
<a id="best-practices-for-dynamic-blocks"></a>
|
||||
|
||||
This is equivalent to the following _splat expression:_
|
||||
## `dynamic` Blocks
|
||||
|
||||
```hcl
|
||||
var.list[*].id
|
||||
```
|
||||
The special `dynamic` block type serves the same purpose as a `for` expression,
|
||||
except it creates multiple repeatable nested blocks instead of a complex value.
|
||||
|
||||
The special `[*]` symbol iterates over all of the elements of the list given
|
||||
to its left and accesses from each one the attribute name given on its
|
||||
right. A splat expression can also be used to access attributes and indexes
|
||||
from lists of complex types by extending the sequence of operations to the
|
||||
right of the symbol:
|
||||
This information has moved to
|
||||
[Dynamic Blocks](/docs/configuration/expressions/dynamic-blocks.html).
|
||||
|
||||
```hcl
|
||||
var.list[*].interfaces[0].name
|
||||
```
|
||||
<a id="string-literals"></a>
|
||||
<a id="string-templates"></a>
|
||||
<a id="interpolation"></a>
|
||||
<a id="directives"></a>
|
||||
|
||||
The above expression is equivalent to the following `for` expression:
|
||||
## String Literals and String Templates
|
||||
|
||||
```hcl
|
||||
[for o in var.list : o.interfaces[0].name]
|
||||
```
|
||||
|
||||
Splat expressions are for lists only (and thus cannot be used [to reference resources
|
||||
created with `for_each`](/docs/configuration/resources.html#referring-to-instances-1),
|
||||
which are represented as maps in Terraform). However, if a splat expression is applied
|
||||
to a value that is _not_ a list or tuple then the value is automatically wrapped in
|
||||
a single-element list before processing.
|
||||
|
||||
For example, `var.single_object[*].id` is equivalent to `[var.single_object][*].id`,
|
||||
or effectively `[var.single_object.id]`. This behavior is not interesting in most cases,
|
||||
but it is particularly useful when referring to resources that may or may
|
||||
not have `count` set, and thus may or may not produce a tuple value:
|
||||
|
||||
```hcl
|
||||
aws_instance.example[*].id
|
||||
```
|
||||
|
||||
The above will produce a list of ids whether `aws_instance.example` has
|
||||
`count` set or not, avoiding the need to revise various other expressions
|
||||
in the configuration when a particular resource switches to and from
|
||||
having `count` set.
|
||||
|
||||
### Legacy (Attribute-only) Splat Expressions
|
||||
|
||||
An older variant of the splat expression is available for compatibility with
|
||||
code written in older versions of the Terraform language. This is a less useful
|
||||
version of the splat expression, and should be avoided in new configurations.
|
||||
|
||||
An "attribute-only" splat expression is indicated by the sequence `.*` (instead
|
||||
of `[*]`):
|
||||
|
||||
```
|
||||
var.list.*.interfaces[0].name
|
||||
```
|
||||
|
||||
This form has a subtly different behavior, equivalent to the following
|
||||
`for` expression:
|
||||
|
||||
```
|
||||
[for o in var.list : o.interfaces][0].name
|
||||
```
|
||||
|
||||
Notice that with the attribute-only splat expression the index operation
|
||||
`[0]` is applied to the result of the iteration, rather than as part of
|
||||
the iteration itself.
|
||||
|
||||
## `dynamic` blocks
|
||||
|
||||
Within top-level block constructs like resources, expressions can usually be
|
||||
used only when assigning a value to an argument using the `name = expression`
|
||||
form. This covers many uses, but some resource types include repeatable _nested
|
||||
blocks_ in their arguments, which do not accept expressions:
|
||||
|
||||
```hcl
|
||||
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
|
||||
name = "tf-test-name" # can use expressions here
|
||||
|
||||
setting {
|
||||
# but the "setting" block is always a literal block
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can dynamically construct repeatable nested blocks like `setting` using a
|
||||
special `dynamic` block type, which is supported inside `resource`, `data`,
|
||||
`provider`, and `provisioner` blocks:
|
||||
|
||||
```hcl
|
||||
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
|
||||
name = "tf-test-name"
|
||||
application = "${aws_elastic_beanstalk_application.tftest.name}"
|
||||
solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"
|
||||
|
||||
dynamic "setting" {
|
||||
for_each = var.settings
|
||||
content {
|
||||
namespace = setting.value["namespace"]
|
||||
name = setting.value["name"]
|
||||
value = setting.value["value"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A `dynamic` block acts much like a `for` expression, but produces nested blocks
|
||||
instead of a complex typed value. It iterates over a given complex value, and
|
||||
generates a nested block for each element of that complex value.
|
||||
|
||||
- The label of the dynamic block (`"setting"` in the example above) specifies
|
||||
what kind of nested block to generate.
|
||||
- The `for_each` argument provides the complex value to iterate over.
|
||||
- The `iterator` argument (optional) sets the name of a temporary variable
|
||||
that represents the current element of the complex value. If omitted, the name
|
||||
of the variable defaults to the label of the `dynamic` block (`"setting"` in
|
||||
the example above).
|
||||
- The `labels` argument (optional) is a list of strings that specifies the block
|
||||
labels, in order, to use for each generated block. You can use the temporary
|
||||
iterator variable in this value.
|
||||
- The nested `content` block defines the body of each generated block. You can
|
||||
use the temporary iterator variable inside this block.
|
||||
|
||||
Since the `for_each` argument accepts any collection or structural value,
|
||||
you can use a `for` expression or splat expression to transform an existing
|
||||
collection.
|
||||
|
||||
The iterator object (`setting` in the example above) has two attributes:
|
||||
|
||||
* `key` is the map key or list element index for the current element. If the
|
||||
`for_each` expression produces a _set_ value then `key` is identical to
|
||||
`value` and should not be used.
|
||||
* `value` is the value of the current element.
|
||||
|
||||
A `dynamic` block can only generate arguments that belong to the resource type,
|
||||
data source, provider or provisioner being configured. It is _not_ possible
|
||||
to generate meta-argument blocks such as `lifecycle` and `provisioner`
|
||||
blocks, since Terraform must process these before it is safe to evaluate
|
||||
expressions.
|
||||
|
||||
The `for_each` value must be a map or set with one element per desired
|
||||
nested block. If you need to declare resource instances based on a nested
|
||||
data structure or combinations of elements from multiple data structures you
|
||||
can use Terraform expressions and functions to derive a suitable value.
|
||||
For some common examples of such situations, see the
|
||||
[`flatten`](/docs/configuration/functions/flatten.html)
|
||||
and
|
||||
[`setproduct`](/docs/configuration/functions/setproduct.html)
|
||||
functions.
|
||||
|
||||
### Best Practices for `dynamic` Blocks
|
||||
|
||||
Overuse of `dynamic` blocks can make configuration hard to read and maintain, so
|
||||
we recommend using them only when you need to hide details in order to build a
|
||||
clean user interface for a re-usable module. Always write nested blocks out
|
||||
literally where possible.
|
||||
|
||||
## String Literals
|
||||
|
||||
The Terraform language has two different syntaxes for string literals. The
|
||||
most common is to delimit the string with quote characters (`"`), like
|
||||
`"hello"`. In quoted strings, the backslash character serves as an escape
|
||||
sequence, with the following characters selecting the escape behavior:
|
||||
|
||||
| Sequence | Replacement |
|
||||
| ------------ | ----------------------------------------------------------------------------- |
|
||||
| `\n` | Newline |
|
||||
| `\r` | Carriage Return |
|
||||
| `\t` | Tab |
|
||||
| `\"` | Literal quote (without terminating the string) |
|
||||
| `\\` | Literal backslash |
|
||||
| `\uNNNN` | Unicode character from the basic multilingual plane (NNNN is four hex digits) |
|
||||
| `\UNNNNNNNN` | Unicode character from supplementary planes (NNNNNNNN is eight hex digits) |
|
||||
|
||||
The alternative syntax for string literals is the so-called "heredoc" style,
|
||||
inspired by Unix shell languages. This style allows multi-line strings to
|
||||
be expressed more clearly by using a custom delimiter word on a line of its
|
||||
own to close the string:
|
||||
Strings can be `"double-quoted"` or
|
||||
|
||||
```hcl
|
||||
<<EOT
|
||||
hello
|
||||
world
|
||||
heredocs
|
||||
EOT
|
||||
```
|
||||
|
||||
The `<<` marker followed by any identifier at the end of a line introduces the
|
||||
sequence. Terraform then processes the following lines until it finds one that
|
||||
consists entirely of the identifier given in the introducer. In the above
|
||||
example, `EOT` is the identifier selected. Any identifier is allowed, but
|
||||
conventionally this identifier is in all-uppercase and begins with `EO`, meaning
|
||||
"end of". `EOT` in this case stands for "end of text".
|
||||
Strings can also include escape sequences like `\n`, interpolation sequences
|
||||
(`${ ... }`), and template sequences (`%{ ... }`).
|
||||
|
||||
The "heredoc" form shown above requires that the lines following be flush with
|
||||
the left margin, which can be awkward when an expression is inside an indented
|
||||
block:
|
||||
|
||||
```hcl
|
||||
block {
|
||||
value = <<EOT
|
||||
hello
|
||||
world
|
||||
EOT
|
||||
}
|
||||
```
|
||||
|
||||
To improve on this, Terraform also accepts an _indented_ heredoc string variant
|
||||
that is introduced by the `<<-` sequence:
|
||||
|
||||
```hcl
|
||||
block {
|
||||
value = <<-EOT
|
||||
hello
|
||||
world
|
||||
EOT
|
||||
}
|
||||
```
|
||||
|
||||
In this case, Terraform analyses the lines in the sequence to find the one
|
||||
with the smallest number of leading spaces, and then trims that many spaces
|
||||
from the beginning of all of the lines, leading to the following result:
|
||||
|
||||
```
|
||||
hello
|
||||
world
|
||||
```
|
||||
|
||||
Backslash sequences are not interpreted in a heredoc string expression.
|
||||
Instead, the backslash character is interpreted literally.
|
||||
|
||||
In both quoted and heredoc string expressions, Terraform supports template
|
||||
sequences that begin with `${` and `%{`. These are described in more detail
|
||||
in the following section. To include these sequences _literally_ without
|
||||
beginning a template sequence, double the leading character: `$${` or `%%{`.
|
||||
|
||||
## String Templates
|
||||
|
||||
Within quoted and heredoc string expressions, the sequences `${` and `%{` begin
|
||||
_template sequences_. Templates let you directly embed expressions into a string
|
||||
literal, to dynamically construct strings from other values.
|
||||
|
||||
### Interpolation
|
||||
|
||||
A `${ ... }` sequence is an _interpolation,_ which evaluates the expression
|
||||
given between the markers, converts the result to a string if necessary, and
|
||||
then inserts it into the final string:
|
||||
|
||||
```hcl
|
||||
"Hello, ${var.name}!"
|
||||
```
|
||||
|
||||
In the above example, the named object `var.name` is accessed and its value
|
||||
inserted into the string, producing a result like "Hello, Juan!".
|
||||
|
||||
### Directives
|
||||
|
||||
A `%{ ... }` sequence is a _directive_, which allows for conditional
|
||||
results and iteration over collections, similar to conditional
|
||||
and `for` expressions.
|
||||
|
||||
The following directives are supported:
|
||||
|
||||
* The `if <BOOL>`/`else`/`endif` directive chooses between two templates based
|
||||
on the value of a bool expression:
|
||||
|
||||
```hcl
|
||||
"Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"
|
||||
```
|
||||
|
||||
The `else` portion may be omitted, in which case the result is an empty
|
||||
string if the condition expression returns `false`.
|
||||
|
||||
* The `for <NAME> in <COLLECTION>` / `endfor` directive iterates over the
|
||||
elements of a given collection or structural value and evaluates a given
|
||||
template once for each element, concatenating the results together:
|
||||
|
||||
```hcl
|
||||
<<EOT
|
||||
%{ for ip in aws_instance.example.*.private_ip }
|
||||
server ${ip}
|
||||
%{ endfor }
|
||||
EOT
|
||||
```
|
||||
|
||||
The name given immediately after the `for` keyword is used as a temporary
|
||||
variable name which can then be referenced from the nested template.
|
||||
|
||||
To allow template directives to be formatted for readability without adding
|
||||
unwanted spaces and newlines to the result, all template sequences can include
|
||||
optional _strip markers_ (`~`), immediately after the opening characters or
|
||||
immediately before the end. When a strip marker is present, the template
|
||||
sequence consumes all of the literal whitespace (spaces and newlines) either
|
||||
before the sequence (if the marker appears at the beginning) or after (if the
|
||||
marker appears at the end):
|
||||
|
||||
```hcl
|
||||
<<EOT
|
||||
%{ for ip in aws_instance.example.*.private_ip ~}
|
||||
server ${ip}
|
||||
%{ endfor ~}
|
||||
EOT
|
||||
```
|
||||
|
||||
In the above example, the newline after each of the directives is not included
|
||||
in the output, but the newline after the `server ${ip}` sequence is retained,
|
||||
causing only one line to be generated for each element:
|
||||
|
||||
```
|
||||
server 10.1.16.154
|
||||
server 10.1.16.1
|
||||
server 10.1.16.34
|
||||
```
|
||||
|
||||
When using template directives, we recommend always using the "heredoc" string
|
||||
literal form and then formatting the template over multiple lines for
|
||||
readability. Quoted string literals should usually include only interpolation
|
||||
sequences.
|
||||
This information has moved to
|
||||
[Strings and Templates](/docs/configuration/expressions/strings.html).
|
||||
|
|
|
@ -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,
|
||||
such as requiring a literal value of a particular type or forbidding
|
||||
[references to resource attributes](/docs/configuration/expressions/references.html#references-to-resource-attributes).
|
||||
Each language feature's documentation describes any restrictions it places on expressions.
|
||||
Each language feature's documentation describes any restrictions it places on
|
||||
expressions.
|
||||
|
||||
You can experiment with the behavior of Terraform's expressions from
|
||||
the Terraform expression console, by running
|
||||
|
@ -23,3 +24,44 @@ the Terraform expression console, by running
|
|||
|
||||
The other pages in this section describe the features of Terraform's
|
||||
expression syntax.
|
||||
|
||||
- [Types and Values](/docs/configuration/expressions/types.html)
|
||||
documents the data types that Terraform expressions can resolve to, and the
|
||||
literal syntaxes for values of those types.
|
||||
|
||||
- [Strings and Templates](/docs/configuration/expressions/strings.html)
|
||||
documents the syntaxes for string literals, including interpolation sequences
|
||||
and template directives.
|
||||
|
||||
- [References to Values](/docs/configuration/expressions/references.html)
|
||||
documents how to refer to named values like variables and resource attributes.
|
||||
|
||||
- [Operators](/docs/configuration/expressions/references.html)
|
||||
documents the arithmetic, comparison, and logical operators.
|
||||
|
||||
- [Function Calls](/docs/configuration/expressions/function-calls.html)
|
||||
documents the syntax for calling Terraform's built-in functions.
|
||||
|
||||
- [Conditional Expressions](/docs/configuration/expressions/conditionals.html)
|
||||
documents the `<CONDITION> ? <TRUE VAL> : <FALSE VAL>` expression, which
|
||||
chooses between two values based on a bool condition.
|
||||
|
||||
- [For Expressions](/docs/configuration/expressions/for.html)
|
||||
documents expressions like `[for s in var.list : upper(s)]`, which can
|
||||
transform a complex type value into another complex type value.
|
||||
|
||||
- [Splat Expressions](/docs/configuration/expressions/splat.html)
|
||||
documents expressions like `var.list[*].id`, which can extract simpler
|
||||
collections from more complicated expressions.
|
||||
|
||||
- [Dynamic Blocks](/docs/configuration/expressions/dynamic-blocks.html)
|
||||
documents a way to create multiple repeatable nested blocks within a resource
|
||||
or other construct.
|
||||
|
||||
- [Type Constraints](/docs/configuration/types.html)
|
||||
documents the syntax for referring to a type, rather than a value of that
|
||||
type. Input variables expect this syntax in their `type` argument.
|
||||
|
||||
- [Version Constraints](/docs/configuration/version-constraints.html)
|
||||
documents the syntax of special strings that define a set of allowed software
|
||||
versions. Terraform uses version constraints in several places.
|
||||
|
|
|
@ -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
|
||||
has no effect on the module's behavior.
|
||||
|
||||
A Terraform module can use [module calls](/docs/configuration/modules.html) to
|
||||
A Terraform module can use [module calls](/docs/configuration/blocks/modules/index.html) to
|
||||
explicitly include other modules into the configuration. These child modules can
|
||||
come from local directories (nested in the parent module's directory, or
|
||||
anywhere else on disk), or from external sources like the
|
||||
|
|
|
@ -23,8 +23,8 @@ max(5, 12, 9)
|
|||
```
|
||||
|
||||
For more details on syntax, see
|
||||
[_Function Calls_](./expressions.html#function-calls)
|
||||
on the Expressions page.
|
||||
[_Function Calls_](/docs/configuration/expressions/function-calls.html)
|
||||
in the Expressions section.
|
||||
|
||||
The Terraform language does not support user-defined functions, and so only
|
||||
the functions built in to the language are available for use. The navigation
|
||||
|
|
|
@ -70,7 +70,7 @@ platforms.
|
|||
```
|
||||
|
||||
You can use nested `cidrsubnets` calls with
|
||||
[`for` expressions](/docs/configuration/expressions.html#for-expressions)
|
||||
[`for` expressions](/docs/configuration/expressions/for.html)
|
||||
to concisely allocate groups of network address blocks:
|
||||
|
||||
```
|
||||
|
|
|
@ -46,7 +46,7 @@ number of fields, or this function will produce an error.
|
|||
## Use with the `for_each` meta-argument
|
||||
|
||||
You can use the result of `csvdecode` with
|
||||
[the `for_each` meta-argument](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
||||
[the `for_each` meta-argument](/docs/configuration/meta-arguments/for_each.html)
|
||||
to describe a collection of similar objects whose differences are
|
||||
described by the rows in the given CSV file.
|
||||
|
||||
|
@ -94,7 +94,7 @@ create or destroy associated instances as appropriate.
|
|||
|
||||
If there is no reasonable value you can use as a unique identifier in your CSV
|
||||
then you could instead use
|
||||
[the `count` meta-argument](/docs/configuration/resources.html#count-multiple-resource-instances-by-count)
|
||||
[the `count` meta-argument](/docs/configuration/meta-arguments/count.html)
|
||||
to define an object for each CSV row, with each one identified by its index into
|
||||
the list returned by `csvdecode`. However, in that case any future updates to
|
||||
the CSV may be disruptive if they change the positions of particular objects in
|
||||
|
|
|
@ -69,7 +69,7 @@ before Terraform takes any actions.
|
|||
```
|
||||
|
||||
A common use of `fileset` is to create one resource instance per matched file, using
|
||||
[the `for_each` meta-argument](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings):
|
||||
[the `for_each` meta-argument](/docs/configuration/meta-arguments/for_each.html):
|
||||
|
||||
```hcl
|
||||
resource "example_thing" "example" {
|
||||
|
|
|
@ -35,9 +35,9 @@ Indirectly-nested lists, such as those in maps, are _not_ flattened.
|
|||
## Flattening nested structures for `for_each`
|
||||
|
||||
The
|
||||
[resource `for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
||||
[resource `for_each`](/docs/configuration/meta-arguments/for_each.html)
|
||||
and
|
||||
[`dynamic` block](/docs/configuration/expressions.html#dynamic-blocks)
|
||||
[`dynamic` block](/docs/configuration/expressions/dynamic-blocks.html)
|
||||
language features both require a collection value that has one element for
|
||||
each repetition.
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ of the result of decoding that string.
|
|||
The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
|
||||
|
||||
This function maps JSON values to
|
||||
[Terraform language values](../expressions.html#types-and-values)
|
||||
[Terraform language values](/docs/configuration/expressions/types.html)
|
||||
in the following way:
|
||||
|
||||
| JSON type | Terraform type |
|
||||
|
|
|
@ -17,7 +17,7 @@ earlier, see
|
|||
The JSON encoding is defined in [RFC 7159](https://tools.ietf.org/html/rfc7159).
|
||||
|
||||
This function maps
|
||||
[Terraform language values](../expressions.html#types-and-values)
|
||||
[Terraform language values](/docs/configuration/expressions/types.html)
|
||||
to JSON values in the following way:
|
||||
|
||||
| Terraform type | JSON type |
|
||||
|
|
|
@ -121,9 +121,9 @@ elements all have a consistent type:
|
|||
## Finding combinations for `for_each`
|
||||
|
||||
The
|
||||
[resource `for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
||||
[resource `for_each`](/docs/configuration/meta-arguments/for_each.html)
|
||||
and
|
||||
[`dynamic` block](/docs/configuration/expressions.html#dynamic-blocks)
|
||||
[`dynamic` block](/docs/configuration/expressions/dynamic-blocks.html)
|
||||
language features both require a collection value that has one element for
|
||||
each repetition.
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@ templatefile(path, vars)
|
|||
```
|
||||
|
||||
The template syntax is the same as for
|
||||
[string templates](../expressions.html#string-templates) in the main Terraform
|
||||
language, including interpolation sequences delimited with `${` ... `}`.
|
||||
This function just allows longer template sequences to be factored out
|
||||
into a separate file for readability.
|
||||
[string templates](/docs/configuration/expressions/strings.html#string-templates)
|
||||
in the main Terraform language, including interpolation sequences delimited with
|
||||
`${` ... `}`. This function just allows longer template sequences to be factored
|
||||
out into a separate file for readability.
|
||||
|
||||
The "vars" argument must be a map. Within the template file, each of the keys
|
||||
in the map is available as a variable for interpolation. The template may
|
||||
|
@ -78,8 +78,8 @@ The `templatefile` function renders the template:
|
|||
|
||||
```
|
||||
> templatefile(
|
||||
"${path.module}/backends.tmpl",
|
||||
{
|
||||
"${path.module}/backends.tmpl",
|
||||
{
|
||||
config = {
|
||||
"x" = "y"
|
||||
"foo" = "bar"
|
||||
|
@ -102,7 +102,7 @@ interpolation sequences and directives.
|
|||
Instead, you can write a template that consists only of a single interpolated
|
||||
call to either [`jsonencode`](./jsonencode.html) or
|
||||
[`yamlencode`](./yamlencode.html), specifying the value to encode using
|
||||
[normal Terraform expression syntax](/docs/configuration/expressions.html)
|
||||
[normal Terraform expression syntax](/docs/configuration/expressions/index.html)
|
||||
as in the following examples:
|
||||
|
||||
```
|
||||
|
@ -122,9 +122,9 @@ this will produce a valid JSON or YAML representation of the given data
|
|||
structure, without the need to manually handle escaping or delimiters.
|
||||
In the latest examples above, the repetition based on elements of `ip_addrs` is
|
||||
achieved by using a
|
||||
[`for` expression](/docs/configuration/expressions.html#for-expressions)
|
||||
[`for` expression](/docs/configuration/expressions/for.html)
|
||||
rather than by using
|
||||
[template directives](/docs/configuration/expressions.html#directives).
|
||||
[template directives](/docs/configuration/expressions/strings.html#directives).
|
||||
|
||||
```json
|
||||
{"backends":["10.0.0.1:8080","10.0.0.2:8080"]}
|
||||
|
|
|
@ -24,7 +24,7 @@ The result of this function will change every second, so using this function
|
|||
directly with resource attributes will cause a diff to be detected on every
|
||||
Terraform run. We do not recommend using this function in resource attributes,
|
||||
but in rare cases it can be used in conjunction with
|
||||
[the `ignore_changes` lifecycle meta-argument](../resources.html#ignore_changes)
|
||||
[the `ignore_changes` lifecycle meta-argument](/docs/configuration/meta-arguments/lifecycle.html#ignore_changes)
|
||||
to take the timestamp only on initial creation of the resource. For more stable
|
||||
time handling, see the [Time Provider](https://registry.terraform.io/providers/hashicorp/time/).
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ This function produces a new value each time it is called, and so using it
|
|||
directly in resource arguments will result in spurious diffs. We do not
|
||||
recommend using the `uuid` function in resource configurations, but it can
|
||||
be used with care in conjunction with
|
||||
[the `ignore_changes` lifecycle meta-argument](../resources.html#ignore_changes).
|
||||
[the `ignore_changes` lifecycle meta-argument](/docs/configuration/meta-arguments/lifecycle.html#ignore_changes).
|
||||
|
||||
In most cases we recommend using [the `random` provider](/docs/providers/random/index.html)
|
||||
instead, since it allows the one-time generation of random values that are
|
||||
|
|
|
@ -20,7 +20,7 @@ This function supports a subset of [YAML 1.2](https://yaml.org/spec/1.2/spec.htm
|
|||
as described below.
|
||||
|
||||
This function maps YAML values to
|
||||
[Terraform language values](../expressions.html#types-and-values)
|
||||
[Terraform language values](/docs/configuration/expressions/types.html)
|
||||
in the following way:
|
||||
|
||||
| YAML type | Terraform type |
|
||||
|
|
|
@ -33,7 +33,7 @@ results are also valid YAML because YAML is a JSON superset.
|
|||
-->
|
||||
|
||||
This function maps
|
||||
[Terraform language values](../expressions.html#types-and-values)
|
||||
[Terraform language values](/docs/configuration/expressions/types.html)
|
||||
to YAML tags in the following way:
|
||||
|
||||
| Terraform type | YAML type |
|
||||
|
|
|
@ -19,7 +19,7 @@ heart of the workflow.
|
|||
## About the Terraform Language
|
||||
|
||||
The main purpose of the Terraform language is declaring
|
||||
[resources](./resources.html), which represent infrastructure objects. All other
|
||||
[resources](/docs/configuration/blocks/resources/index.html), which represent infrastructure objects. All other
|
||||
language features exist only to make the definition of resources more flexible
|
||||
and convenient.
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ description: |-
|
|||
earlier, see
|
||||
[0.11 Configuration Language: Local Values](../configuration-0-11/locals.html).
|
||||
|
||||
A local value assigns a name to an [expression](./expressions.html),
|
||||
A local value assigns a name to an [expression](/docs/configuration/expressions/index.html),
|
||||
so you can use it multiple times within a module without repeating
|
||||
it.
|
||||
|
||||
|
@ -61,7 +61,7 @@ locals {
|
|||
## Using Local Values
|
||||
|
||||
Once a local value is declared, you can reference it in
|
||||
[expressions](./expressions.html) as `local.<NAME>`.
|
||||
[expressions](/docs/configuration/expressions/index.html) as `local.<NAME>`.
|
||||
|
||||
-> **Note:** Local values are _created_ by a `locals` block (plural), but you
|
||||
_reference_ them as attributes on an object named `local` (singular). Make sure
|
||||
|
|
|
@ -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"
|
||||
page_title: "Modules - Configuration Language"
|
||||
sidebar_current: "docs-config-modules"
|
||||
description: |-
|
||||
Modules allow multiple resources to be grouped together and encapsulated.
|
||||
page_title: "Modules Landing Page - Configuration Language"
|
||||
---
|
||||
|
||||
# Modules
|
||||
# Modules Landing Page
|
||||
|
||||
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
|
||||
earlier, see
|
||||
[0.11 Configuration Language: Modules](../configuration-0-11/modules.html).
|
||||
To improve navigation, we've split the old Modules page into several smaller
|
||||
pages.
|
||||
|
||||
> **Hands-on:** Try the [Reuse Configuration with Modules](https://learn.hashicorp.com/collections/terraform/modules?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
|
||||
<a id="calling-a-child-module"></a>
|
||||
<a id="accessing-module-output-values"></a>
|
||||
<a id="transferring-resource-state-into-modules"></a>
|
||||
<a id="tainting-resources-within-a-module"></a>
|
||||
<a id="module-versions"></a>
|
||||
<a id="other-meta-arguments"></a>
|
||||
|
||||
A _module_ is a container for multiple resources that are used together.
|
||||
## Syntax and Elements of Module Blocks
|
||||
|
||||
Every Terraform configuration has at least one module, known as its
|
||||
_root module_, which consists of the resources defined in the `.tf` files in
|
||||
the main working directory.
|
||||
This information has moved to
|
||||
[Module Blocks](/docs/configuration/blocks/modules/syntax.html).
|
||||
|
||||
A module can call other modules, which lets you include the child module's
|
||||
resources into the configuration in a concise way. Modules
|
||||
can also be called multiple times, either within the same configuration or
|
||||
in separate configurations, allowing resource configurations to be packaged
|
||||
and re-used.
|
||||
<a id="multiple-instances-of-a-module"></a>
|
||||
|
||||
This page describes how to call one module from another. Other pages in this
|
||||
section of the documentation describe the different elements that make up
|
||||
modules, and there is further information about how modules can be used,
|
||||
created, and published in [the dedicated _Modules_
|
||||
section](/docs/modules/index.html).
|
||||
## Multiple Instances with `count` and `for_each`
|
||||
|
||||
## Calling a Child Module
|
||||
This information has moved to
|
||||
[`count`](/docs/configuration/meta-arguments/count.html) and
|
||||
[`for_each`](/docs/configuration/meta-arguments/for_each.html).
|
||||
|
||||
To _call_ a module means to include the contents of that module into the
|
||||
configuration with specific values for its
|
||||
[input variables](./variables.html). Modules are called
|
||||
from within other modules using `module` blocks:
|
||||
<a id="providers-within-modules"></a>
|
||||
<a id="provider-version-constraints-in-modules"></a>
|
||||
<a id="implicit-provider-inheritance"></a>
|
||||
<a id="passing-providers-explicitly"></a>
|
||||
<a id="proxy-configuration-blocks"></a>
|
||||
<a id="legacy-shared-modules-with-provider-configurations"></a>
|
||||
|
||||
```hcl
|
||||
module "servers" {
|
||||
source = "./app-cluster"
|
||||
## Handling Provider Configurations in Re-usable Modules
|
||||
|
||||
servers = 5
|
||||
}
|
||||
```
|
||||
|
||||
A module that includes a `module` block like this is the _calling module_ of the
|
||||
child module.
|
||||
|
||||
The label immediately after the `module` keyword is a local name, which the
|
||||
calling module can use to refer to this instance of the module.
|
||||
|
||||
Within the block body (between `{` and `}`) are the arguments for the module.
|
||||
Most of the arguments correspond to [input variables](./variables.html)
|
||||
defined by the module, including the `servers` argument in the above example.
|
||||
Terraform also defines a few meta-arguments that are reserved by Terraform
|
||||
and used for its own purposes; we will discuss those throughout the rest of
|
||||
this section.
|
||||
|
||||
All modules require a `source` argument, which is a meta-argument defined by
|
||||
Terraform. Its value is either the path to a local directory containing the
|
||||
module's configuration files, or a remote module source that Terraform should
|
||||
download and use. This value must be a literal string with no template
|
||||
sequences; arbitrary expressions are not allowed. For more information on
|
||||
possible values for this argument, see [Module Sources](/docs/modules/sources.html).
|
||||
|
||||
The same source address can be specified in multiple `module` blocks to create
|
||||
multiple copies of the resources defined within, possibly with different
|
||||
variable values.
|
||||
|
||||
After adding, removing, or modifying `module` blocks, you must re-run
|
||||
`terraform init` to allow Terraform the opportunity to adjust the installed
|
||||
modules. By default this command will not upgrade an already-installed module;
|
||||
use the `-upgrade` option to instead upgrade to the newest available version.
|
||||
|
||||
## Accessing Module Output Values
|
||||
|
||||
The resources defined in a module are encapsulated, so the calling module
|
||||
cannot access their attributes directly. However, the child module can
|
||||
declare [output values](./outputs.html) to selectively
|
||||
export certain values to be accessed by the calling module.
|
||||
|
||||
For example, if the `./app-cluster` module referenced in the example above
|
||||
exported an output value named `instance_ids` then the calling module
|
||||
can reference that result using the expression `module.servers.instance_ids`:
|
||||
|
||||
```hcl
|
||||
resource "aws_elb" "example" {
|
||||
# ...
|
||||
|
||||
instances = module.servers.instance_ids
|
||||
}
|
||||
```
|
||||
|
||||
For more information about referring to named values, see
|
||||
[Expressions](./expressions.html).
|
||||
|
||||
## Transferring Resource State Into Modules
|
||||
|
||||
When refactoring an existing configuration to split code into child modules,
|
||||
moving resource blocks between modules causes Terraform to see the new location
|
||||
as an entirely different resource from the old. Always check the execution plan
|
||||
after moving code across modules to ensure that no resources are deleted by
|
||||
surprise.
|
||||
|
||||
If you want to make sure an existing resource is preserved, use
|
||||
[the `terraform state mv` command](/docs/commands/state/mv.html) to inform
|
||||
Terraform that it has moved to a different module.
|
||||
|
||||
When passing resource addresses to `terraform state mv`, resources within child
|
||||
modules must be prefixed with `module.<MODULE NAME>.`. If a module was called
|
||||
with `count` or `for_each` ([see below][inpage-multiple]), its resource
|
||||
addresses must be prefixed with `module.<MODULE NAME>[<INDEX>].` instead, where
|
||||
`<INDEX>` matches the `count.index` or `each.key` value of a particular module
|
||||
instance.
|
||||
|
||||
Full resource addresses for module contents are used within the UI and on the
|
||||
command line, but cannot be used within a Terraform configuration. Only
|
||||
[outputs](./outputs.html) from a module can be referenced from
|
||||
elsewhere in your configuration.
|
||||
|
||||
## Other Meta-arguments
|
||||
|
||||
Along with the `source` meta-argument described above, module blocks have
|
||||
some optional meta-arguments that have special meaning across all modules,
|
||||
described in more detail below:
|
||||
|
||||
- `version` - A [version constraint string](./version-constraints.html)
|
||||
that specifies acceptable versions of the module. Described in detail under
|
||||
[Module Versions][inpage-versions] below.
|
||||
|
||||
- `count` and `for_each` - Both of these arguments create multiple instances of a
|
||||
module from a single `module` block. Described in detail under
|
||||
[Multiple Instances of a Module][inpage-multiple] below.
|
||||
|
||||
- `providers` - A map whose keys are provider configuration names
|
||||
that are expected by child module and whose values are the corresponding
|
||||
provider configurations in the calling module. This allows
|
||||
[provider configurations to be passed explicitly to child modules](#passing-providers-explicitly).
|
||||
If not specified, the child module inherits all of the default (un-aliased)
|
||||
provider configurations from the calling module. Described in detail under
|
||||
[Providers Within Modules][inpage-providers]
|
||||
|
||||
- `depends_on` - Creates explicit dependencies between the entire
|
||||
module and the listed targets. This will delay the final evaluation of the
|
||||
module, and any sub-modules, until after the dependencies have been applied.
|
||||
Modules have the same dependency resolution behavior
|
||||
[as defined for managed resources](./resources.html#resource-dependencies).
|
||||
|
||||
In addition to the above, the `lifecycle` argument is not currently used by
|
||||
Terraform but is reserved for planned future features.
|
||||
|
||||
Since modules are a complex feature in their own right, further detail
|
||||
about how modules can be used, created, and published is included in
|
||||
[the dedicated section on modules](/docs/modules/index.html).
|
||||
|
||||
## Module Versions
|
||||
|
||||
[inpage-versions]: #module-versions
|
||||
|
||||
When using modules installed from a module registry, we recommend explicitly
|
||||
constraining the acceptable version numbers to avoid unexpected or unwanted
|
||||
changes.
|
||||
|
||||
Use the `version` attribute in the `module` block to specify versions:
|
||||
|
||||
```shell
|
||||
module "consul" {
|
||||
source = "hashicorp/consul/aws"
|
||||
version = "0.0.5"
|
||||
|
||||
servers = 3
|
||||
}
|
||||
```
|
||||
|
||||
The `version` attribute accepts a [version constraint string](./version-constraints.html).
|
||||
Terraform will use the newest installed version of the module that meets the
|
||||
constraint; if no acceptable versions are installed, it will download the newest
|
||||
version that meets the constraint.
|
||||
|
||||
Version constraints are supported only for modules installed from a module
|
||||
registry, such as the public [Terraform Registry](https://registry.terraform.io/)
|
||||
or [Terraform Cloud's private module registry](/docs/cloud/registry/index.html).
|
||||
Other module sources can provide their own versioning mechanisms within the
|
||||
source string itself, or might not support versions at all. In particular,
|
||||
modules sourced from local file paths do not support `version`; since
|
||||
they're loaded from the same source repository, they always share the same
|
||||
version as their caller.
|
||||
|
||||
## Multiple Instances of a Module
|
||||
|
||||
[inpage-multiple]: #multiple-instances-of-a-module
|
||||
|
||||
-> **Note:** Module support for the `for_each` and `count` meta-arguments was
|
||||
added in Terraform 0.13. Previous versions can only use these arguments with
|
||||
individual resources.
|
||||
|
||||
Use the `for_each` or the `count` argument to create multiple instances of a
|
||||
module from a single `module` block. These arguments have the same syntax and
|
||||
type constraints as
|
||||
[`for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
|
||||
and
|
||||
[`count`](./resources.html#count-multiple-resource-instances-by-count)
|
||||
when used with resources.
|
||||
|
||||
```hcl
|
||||
# my_buckets.tf
|
||||
module "bucket" {
|
||||
for_each = toset(["assets", "media"])
|
||||
source = "./publish_bucket"
|
||||
name = "${each.key}_bucket"
|
||||
}
|
||||
```
|
||||
|
||||
```hcl
|
||||
# publish_bucket/bucket-and-cloudfront.tf
|
||||
variable "name" {} # this is the input parameter of the module
|
||||
|
||||
resource "aws_s3_bucket" "example" {
|
||||
# Because var.name includes each.key in the calling
|
||||
# module block, its value will be different for
|
||||
# each instance of this module.
|
||||
bucket = var.name
|
||||
|
||||
# ...
|
||||
}
|
||||
|
||||
resource "aws_iam_user" "deploy_user" {
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
This example defines a local child module in the `./publish_bucket`
|
||||
subdirectory. That module has configuration to create an S3 bucket. The module
|
||||
wraps the bucket and all the other implementation details required to configure
|
||||
a bucket.
|
||||
|
||||
We declare multiple module instances by using the `for_each` attribute,
|
||||
which accepts a map (with string keys) or a set of strings as its value. Additionally,
|
||||
we use the special `each.key` value in our module block, because the
|
||||
[`each`](/docs/configuration/resources.html#the-each-object) object is available when
|
||||
we have declared `for_each` on the module block. When using the `count` argument, the
|
||||
[`count`](/docs/configuration/resources.html#the-count-object) object is available.
|
||||
|
||||
Resources from child modules are prefixed with `module.module_name[module index]`
|
||||
when displayed in plan output and elsewhere in the UI. For a module without
|
||||
`count` or `for_each`, the address will not contain the module index as the module's
|
||||
name suffices to reference the module.
|
||||
|
||||
In our example, the `./publish_bucket` module contains `aws_s3_bucket.example`, and so the two
|
||||
instances of this module produce S3 bucket resources with [resource addresses](/docs/internals/resource-addressing.html) of `module.bucket["assets"].aws_s3_bucket.example`
|
||||
and `module.bucket["media"].aws_s3_bucket.example` respectively.
|
||||
|
||||
## Providers Within Modules
|
||||
|
||||
[inpage-providers]: #providers-within-modules
|
||||
|
||||
In a configuration with multiple modules, there are some special considerations
|
||||
for how resources are associated with provider configurations.
|
||||
|
||||
Each resource in the configuration must be associated with one provider
|
||||
configuration. Provider configurations, unlike most other concepts in
|
||||
Terraform, are global to an entire Terraform configuration and can be shared
|
||||
across module boundaries. Provider configurations can be defined only in a
|
||||
root Terraform module.
|
||||
|
||||
Providers can be passed down to descendent modules in two ways: either
|
||||
_implicitly_ through inheritance, or _explicitly_ via the `providers` argument
|
||||
within a `module` block. These two options are discussed in more detail in the
|
||||
following sections.
|
||||
|
||||
A module intended to be called by one or more other modules must not contain
|
||||
any `provider` blocks, with the exception of the special
|
||||
"proxy provider blocks" discussed under
|
||||
_[Passing Providers Explicitly](#passing-providers-explicitly)_
|
||||
below.
|
||||
|
||||
For backward compatibility with configurations targeting Terraform v0.10 and
|
||||
earlier Terraform does not produce an error for a `provider` block in a shared
|
||||
module if the `module` block only uses features available in Terraform v0.10,
|
||||
but that is a legacy usage pattern that is no longer recommended. A legacy
|
||||
module containing its own provider configurations is not compatible with the
|
||||
`for_each`, `count`, and `depends_on` arguments that were introduced in
|
||||
Terraform v0.13. For more information, see
|
||||
[Legacy Shared Modules with Provider Configurations](#legacy-shared-modules-with-provider-configurations).
|
||||
|
||||
Provider configurations are used for all operations on associated resources,
|
||||
including destroying remote objects and refreshing state. Terraform retains, as
|
||||
part of its state, a reference to the provider configuration that was most
|
||||
recently used to apply changes to each resource. When a `resource` block is
|
||||
removed from the configuration, this record in the state will be used to locate
|
||||
the appropriate configuration because the resource's `provider` argument
|
||||
(if any) will no longer be present in the configuration.
|
||||
|
||||
As a consequence, you must ensure that all resources that belong to a
|
||||
particular provider configuration are destroyed before you can remove that
|
||||
provider configuration's block from your configuration. If Terraform finds
|
||||
a resource instance tracked in the state whose provider configuration block is
|
||||
no longer available then it will return an error during planning, prompting you
|
||||
to reintroduce the provider configuration.
|
||||
|
||||
### Provider Version Constraints in Modules
|
||||
|
||||
Although provider _configurations_ are shared between modules, each module must
|
||||
declare its own [provider requirements](provider-requirements.html), so that
|
||||
Terraform can ensure that there is a single version of the provider that is
|
||||
compatible with all modules in the configuration and to specify the
|
||||
[source address](provider-requirements.html#source-addresses) that serves as
|
||||
the global (module-agnostic) identifier for a provider.
|
||||
|
||||
To declare that a module requires particular versions of a specific provider,
|
||||
use a `required_providers` block inside a `terraform` block:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 2.7.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A provider requirement says, for example, "This module requires version v2.7.0
|
||||
of the provider `hashicorp/aws` and will refer to it as `aws`." It doesn't,
|
||||
however, specify any of the configuration settings that determine what remote
|
||||
endpoints the provider will access, such as an AWS region; configuration
|
||||
settings come from provider _configurations_, and a particular overall Terraform
|
||||
configuration can potentially have
|
||||
[several different configurations for the same provider](providers.html#alias-multiple-provider-instances).
|
||||
|
||||
If you are writing a shared Terraform module, constrain only the minimum
|
||||
required provider version using a `>=` constraint. This should specify the
|
||||
minimum version containing the features your module relies on, and thus allow a
|
||||
user of your module to potentially select a newer provider version if other
|
||||
features are needed by other parts of their overall configuration.
|
||||
|
||||
### Implicit Provider Inheritance
|
||||
|
||||
For convenience in simple configurations, a child module automatically inherits
|
||||
default (un-aliased) provider configurations from its parent. This means that
|
||||
explicit `provider` blocks appear only in the root module, and downstream
|
||||
modules can simply declare resources for that provider and have them
|
||||
automatically associated with the root provider configurations.
|
||||
|
||||
For example, the root module might contain only a `provider` block and a
|
||||
`module` block to instantiate a child module:
|
||||
|
||||
```hcl
|
||||
provider "aws" {
|
||||
region = "us-west-1"
|
||||
}
|
||||
|
||||
module "child" {
|
||||
source = "./child"
|
||||
}
|
||||
```
|
||||
|
||||
The child module can then use any resource from this provider with no further
|
||||
provider configuration required:
|
||||
|
||||
```hcl
|
||||
resource "aws_s3_bucket" "example" {
|
||||
bucket = "provider-inherit-example"
|
||||
}
|
||||
```
|
||||
|
||||
We recommend using this approach when a single configuration for each provider
|
||||
is sufficient for an entire configuration.
|
||||
|
||||
~> **Note:** Only provider configurations are inherited by child modules, not provider source or version requirements. Each module must [declare its own provider requirements](provider-requirements.html). This is especially important for non-HashiCorp providers.
|
||||
|
||||
In more complex situations there may be
|
||||
[multiple provider configurations](/docs/configuration/providers.html#alias-multiple-provider-configurations),
|
||||
or a child module may need to use different provider settings than
|
||||
its parent. For such situations, you must pass providers explicitly.
|
||||
|
||||
### Passing Providers Explicitly
|
||||
|
||||
When child modules each need a different configuration of a particular
|
||||
provider, or where the child module requires a different provider configuration
|
||||
than its parent, you can use the `providers` argument within a `module` block
|
||||
to explicitly define which provider configurations are available to the
|
||||
child module. For example:
|
||||
|
||||
```hcl
|
||||
# The default "aws" configuration is used for AWS resources in the root
|
||||
# module where no explicit provider instance is selected.
|
||||
provider "aws" {
|
||||
region = "us-west-1"
|
||||
}
|
||||
|
||||
# An alternate configuration is also defined for a different
|
||||
# region, using the alias "usw2".
|
||||
provider "aws" {
|
||||
alias = "usw2"
|
||||
region = "us-west-2"
|
||||
}
|
||||
|
||||
# An example child module is instantiated with the alternate configuration,
|
||||
# so any AWS resources it defines will use the us-west-2 region.
|
||||
module "example" {
|
||||
source = "./example"
|
||||
providers = {
|
||||
aws = aws.usw2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `providers` argument within a `module` block is similar to
|
||||
[the `provider` argument](resources.html#provider-selecting-a-non-default-provider-configuration)
|
||||
within a resource, but is a map rather than a single string because a module may
|
||||
contain resources from many different providers.
|
||||
|
||||
The keys of the `providers` map are provider configuration names as expected by
|
||||
the child module, and the values are the names of corresponding configurations
|
||||
in the _current_ module.
|
||||
|
||||
Once the `providers` argument is used in a `module` block, it overrides all of
|
||||
the default inheritance behavior, so it is necessary to enumerate mappings
|
||||
for _all_ of the required providers. This is to avoid confusion and surprises
|
||||
that may result when mixing both implicit and explicit provider passing.
|
||||
|
||||
Additional provider configurations (those with the `alias` argument set) are
|
||||
_never_ inherited automatically by child modules, and so must always be passed
|
||||
explicitly using the `providers` map. For example, a module
|
||||
that configures connectivity between networks in two AWS regions is likely
|
||||
to need both a source and a destination region. In that case, the root module
|
||||
may look something like this:
|
||||
|
||||
```hcl
|
||||
provider "aws" {
|
||||
alias = "usw1"
|
||||
region = "us-west-1"
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
alias = "usw2"
|
||||
region = "us-west-2"
|
||||
}
|
||||
|
||||
module "tunnel" {
|
||||
source = "./tunnel"
|
||||
providers = {
|
||||
aws.src = aws.usw1
|
||||
aws.dst = aws.usw2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The subdirectory `./tunnel` must then contain _proxy configuration blocks_ like
|
||||
the following, to declare that it requires its calling module to pass
|
||||
configurations with these names in its `providers` argument:
|
||||
|
||||
```hcl
|
||||
provider "aws" {
|
||||
alias = "src"
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
alias = "dst"
|
||||
}
|
||||
```
|
||||
|
||||
Each resource should then have its own `provider` attribute set to either
|
||||
`aws.src` or `aws.dst` to choose which of the two provider configurations to
|
||||
use.
|
||||
|
||||
### Proxy Configuration Blocks
|
||||
|
||||
A proxy configuration block is one that contains only the `alias` argument. It
|
||||
serves as a placeholder for provider configurations passed between modules, and
|
||||
declares that a module expects to be explicitly passed an additional (aliased)
|
||||
provider configuration.
|
||||
|
||||
-> **Note:** Although a completely empty proxy configuration block is also
|
||||
valid, it is not necessary: proxy configuration blocks are needed only to
|
||||
establish which _aliased_ provider configurations a child module expects.
|
||||
Don't use a proxy configuration block if a module only needs a single default
|
||||
provider configuration, and don't use proxy configuration blocks only to imply
|
||||
[provider requirements](./provider-requirements.html).
|
||||
|
||||
## Legacy Shared Modules with Provider Configurations
|
||||
|
||||
In Terraform v0.10 and earlier there was no explicit way to use different
|
||||
configurations of a provider in different modules in the same configuration,
|
||||
and so module authors commonly worked around this by writing `provider` blocks
|
||||
directly inside their modules, making the module have its own separate
|
||||
provider configurations separate from those declared in the root module.
|
||||
|
||||
However, that pattern had a significant drawback: because a provider
|
||||
configuration is required to destroy the remote object associated with a
|
||||
resource instance as well as to create or update it, a provider configuration
|
||||
must always stay present in the overall Terraform configuration for longer
|
||||
than all of the resources it manages. If a particular module includes
|
||||
both resources and the provider configurations for those resources then
|
||||
removing the module from its caller would violate that constraint: both the
|
||||
resources and their associated providers would, in effect, be removed
|
||||
simultaneously.
|
||||
|
||||
Terraform v0.11 introduced the mechanisms described in earlier sections to
|
||||
allow passing provider configurations between modules in a structured way, and
|
||||
thus we explicitly recommended against writing a child module with its own
|
||||
provider configuration blocks. However, that legacy pattern continued to work
|
||||
for compatibility purposes -- though with the same drawback -- until Terraform
|
||||
v0.13.
|
||||
|
||||
Terraform v0.13 introduced the possibility for a module itself to use the
|
||||
`for_each`, `count`, and `depends_on` arguments, but the implementation of
|
||||
those unfortunately conflicted with the support for the legacy pattern.
|
||||
|
||||
To retain the backward compatibility as much as possible, Terraform v0.13
|
||||
continues to support the legacy pattern for module blocks that do not use these
|
||||
new features, but a module with its own provider configurations is not
|
||||
compatible with `for_each`, `count`, or `depends_on`. Terraform will produce an
|
||||
error if you attempt to combine these features. For example:
|
||||
|
||||
```
|
||||
Error: Module does not support count
|
||||
|
||||
on main.tf line 15, in module "child":
|
||||
15: count = 2
|
||||
|
||||
Module "child" cannot be used with count because it contains a nested provider
|
||||
configuration for "aws", at child/main.tf:2,10-15.
|
||||
|
||||
This module can be made compatible with count by changing it to receive all of
|
||||
its provider configurations from the calling module, by using the "providers"
|
||||
argument in the calling module block.
|
||||
```
|
||||
|
||||
To make a module compatible with the new features, you must either remove all
|
||||
of the `provider` blocks from its definition or, if you need multiple
|
||||
configurations for the same provider, replace them with
|
||||
_proxy configuration blocks_ as described in
|
||||
[Passing Providers Explicitly](#passing-providers-explicitly).
|
||||
|
||||
If the new version of the module uses proxy configuration blocks, or if the
|
||||
calling module needs the child module to use different provider configurations
|
||||
than its own default provider configurations, the calling module must then
|
||||
include an explicit `providers` argument to describe which provider
|
||||
configurations the child module will use:
|
||||
|
||||
```hcl
|
||||
provider "aws" {
|
||||
region = "us-west-1"
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
alias = "east"
|
||||
}
|
||||
|
||||
module "child" {
|
||||
count = 2
|
||||
providers = {
|
||||
# By default, the child module would use the
|
||||
# default (unaliased) AWS provider configuration
|
||||
# using us-west-1, but this will override it
|
||||
# to use the additional "east" configuration
|
||||
# for its resources instead.
|
||||
aws = aws.east
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Since the association between resources and provider configurations is
|
||||
static, module calls using `for_each` or `count` cannot pass different
|
||||
provider configurations to different instances. If you need different
|
||||
instances of your module to use different provider configurations then you
|
||||
must use a separate `module` block for each distinct set of provider
|
||||
configurations:
|
||||
|
||||
```hcl
|
||||
provider "aws" {
|
||||
alias = "usw1"
|
||||
region = "us-west-1"
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
alias = "usw2"
|
||||
region = "us-west-2"
|
||||
}
|
||||
|
||||
provider "google" {
|
||||
alias = "usw1"
|
||||
credentials = "${file("account.json")}"
|
||||
project = "my-project-id"
|
||||
region = "us-west1"
|
||||
zone = "us-west1-a"
|
||||
}
|
||||
|
||||
provider "google" {
|
||||
alias = "usw2"
|
||||
credentials = "${file("account.json")}"
|
||||
project = "my-project-id"
|
||||
region = "us-west2"
|
||||
zone = "us-west2-a"
|
||||
}
|
||||
|
||||
module "bucket_w1" {
|
||||
source = "./publish_bucket"
|
||||
providers = {
|
||||
aws.src = aws.usw1
|
||||
google.src = google.usw2
|
||||
}
|
||||
}
|
||||
|
||||
module "bucket_w2" {
|
||||
source = "./publish_bucket"
|
||||
providers = {
|
||||
aws.src = aws.usw2
|
||||
google.src = google.usw2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tainting resources within a module
|
||||
|
||||
The [taint command](/docs/commands/taint.html) can be used to _taint_ specific
|
||||
resources within a module:
|
||||
|
||||
```shell
|
||||
$ terraform taint module.salt_master.aws_instance.salt_master
|
||||
```
|
||||
|
||||
It is not possible to taint an entire module. Instead, each resource within
|
||||
the module must be tainted separately.
|
||||
This information has moved to
|
||||
[The `providers` Meta-Argument](/docs/configuration/meta-arguments/module-providers.html)
|
||||
(for users of re-usable modules) and
|
||||
[Providers Within Modules](/docs/modules/providers.html)
|
||||
(for module developers).
|
||||
|
|
|
@ -46,7 +46,7 @@ valid [identifier](./syntax.html#identifiers). In a root module, this name is
|
|||
displayed to the user; in a child module, it can be used to access the output's
|
||||
value.
|
||||
|
||||
The `value` argument takes an [expression](./expressions.html)
|
||||
The `value` argument takes an [expression](/docs/configuration/expressions/index.html)
|
||||
whose result is to be returned to the user. In this example, the expression
|
||||
refers to the `private_ip` attribute exposed by an `aws_instance` resource
|
||||
defined elsewhere in this module (not shown). Any valid expression is allowed
|
||||
|
@ -98,7 +98,7 @@ output "db_password" {
|
|||
}
|
||||
```
|
||||
|
||||
Setting an output value as sensitive prevents Terraform from showing its value
|
||||
Setting an output value as sensitive prevents Terraform from showing its value
|
||||
in `plan` and `apply`. In the following scenario, our root module has an output declared as sensitive
|
||||
and a module call with a sensitive output, which we then use in a resource attribute.
|
||||
|
||||
|
@ -163,7 +163,7 @@ correctly determine the dependencies between resources defined in different
|
|||
modules.
|
||||
|
||||
Just as with
|
||||
[resource dependencies](./resources.html#resource-dependencies),
|
||||
[resource dependencies](/docs/configuration/blocks/resources/behavior.html#resource-dependencies),
|
||||
Terraform analyzes the `value` expression for an output value and automatically
|
||||
determines a set of dependencies, but in less-common cases there are
|
||||
dependencies that cannot be recognized implicitly. In these rare cases, the
|
||||
|
|
|
@ -28,7 +28,8 @@ configuration (like endpoint URLs or cloud regions) before they can be used.
|
|||
Provider configurations belong in the root module of a Terraform configuration.
|
||||
(Child modules receive their provider configurations from the root module; for
|
||||
more information, see
|
||||
[Providers Within Modules](./modules.html#providers-within-modules).)
|
||||
[The Module `providers` Meta-Argument](/docs/configuration/meta-arguments/module-providers.html)
|
||||
and [Module Development: Providers Within Modules](/docs/modules/providers.html).)
|
||||
|
||||
A provider configuration is created using a `provider` block:
|
||||
|
||||
|
@ -49,7 +50,7 @@ the provider. Most arguments in this section are defined by the provider itself;
|
|||
in this example both `project` and `region` are specific to the `google`
|
||||
provider.
|
||||
|
||||
You can use [expressions](./expressions.html) in the values of these
|
||||
You can use [expressions](/docs/configuration/expressions/index.html) in the values of these
|
||||
configuration arguments, but can only reference values that are known before the
|
||||
configuration is applied. This means you can safely reference input variables,
|
||||
but not attributes exported by resources (with an exception for resource
|
||||
|
@ -160,7 +161,7 @@ module "aws_vpc" {
|
|||
```
|
||||
|
||||
Modules have some special requirements when passing in providers; see
|
||||
[Providers Within Modules](./modules.html#providers-within-modules)
|
||||
[The Module `providers` Meta-Argument](/docs/configuration/meta-arguments/module-providers.html)
|
||||
for more details. In most cases, only _root modules_ should define provider
|
||||
configurations, with all child modules obtaining their provider configurations
|
||||
from their parents.
|
||||
|
@ -177,7 +178,7 @@ works the same way as the `version` argument in a
|
|||
constraint in a provider configuration is only used if `required_providers`
|
||||
does not include one for that provider.
|
||||
|
||||
**The `version` argument in provider configurations is deprecated.**
|
||||
**The `version` argument in provider configurations is deprecated.**
|
||||
In Terraform 0.13 and later, version constraints should always be declared in
|
||||
[the `required_providers` block](./provider-requirements.html). The `version`
|
||||
argument will be removed in a future version of Terraform.
|
||||
|
|
|
@ -1,764 +1,86 @@
|
|||
---
|
||||
layout: "language"
|
||||
page_title: "Resources - Configuration Language"
|
||||
sidebar_current: "docs-config-resources"
|
||||
description: |-
|
||||
Resources are the most important element in a Terraform configuration.
|
||||
Each resource corresponds to an infrastructure object, such as a virtual
|
||||
network or compute instance.
|
||||
page_title: "Resources Landing Page - Configuration Language"
|
||||
---
|
||||
|
||||
# Resources
|
||||
# Resources Landing Page
|
||||
|
||||
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
|
||||
earlier, see
|
||||
[0.11 Configuration Language: Resources](../configuration-0-11/resources.html).
|
||||
To improve navigation, we've split the old Resources page into several smaller
|
||||
pages.
|
||||
|
||||
> **Hands-on:** Try the [Terraform: Get Started](https://learn.hashicorp.com/collections/terraform/aws-get-started?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
|
||||
<a id="resource-syntax"></a>
|
||||
<a id="resource-types"></a>
|
||||
<a id="providers"></a>
|
||||
<a id="resource-arguments"></a>
|
||||
<a id="documentation-for-resource-types"></a>
|
||||
<a id="meta-arguments"></a>
|
||||
<a id="operation-timeouts"></a>
|
||||
|
||||
_Resources_ are the most important element in the Terraform language.
|
||||
Each resource block describes one or more infrastructure objects, such
|
||||
as virtual networks, compute instances, or higher-level components such
|
||||
as DNS records.
|
||||
## Syntax and Elements of Resource Blocks
|
||||
|
||||
## Resource Syntax
|
||||
This information has moved to
|
||||
[Resource Blocks](/docs/configuration/blocks/resources/syntax.html).
|
||||
|
||||
Resource declarations can include a number of advanced features, but only
|
||||
a small subset are required for initial use. More advanced syntax features,
|
||||
such as single resource declarations that produce multiple similar remote
|
||||
objects, are described later in this page.
|
||||
<a id="resource-behavior"></a>
|
||||
<a id="accessing-resource-attributes"></a>
|
||||
<a id="resource-dependencies"></a>
|
||||
<a id="local-only-resources"></a>
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "web" {
|
||||
ami = "ami-a1b2c3d4"
|
||||
instance_type = "t2.micro"
|
||||
}
|
||||
```
|
||||
## Details of Resource Behavior
|
||||
|
||||
A `resource` block declares a resource of a given type ("aws_instance")
|
||||
with a given local name ("web"). The name is used to refer to this resource
|
||||
from elsewhere in the same Terraform module, but has no significance outside
|
||||
that module's scope.
|
||||
This information has moved to
|
||||
[Resource Behavior](/docs/configuration/blocks/resources/behavior.html).
|
||||
|
||||
The resource type and name together serve as an identifier for a given
|
||||
resource and so must be unique within a module.
|
||||
## Resource Meta-Arguments
|
||||
|
||||
Within the block body (between `{` and `}`) are the configuration arguments
|
||||
for the resource itself. Most arguments in this section depend on the
|
||||
resource type, and indeed in this example both `ami` and `instance_type` are
|
||||
arguments defined specifically for [the `aws_instance` resource type](/docs/providers/aws/r/instance.html).
|
||||
Each resource meta-argument has moved to its own page.
|
||||
|
||||
-> **Note:** Resource names must start with a letter or underscore, and may
|
||||
contain only letters, digits, underscores, and dashes.
|
||||
<a id="depends_on-explicit-resource-dependencies"></a>
|
||||
|
||||
## Resource Types
|
||||
### `depends_on`
|
||||
|
||||
Each resource is associated with a single _resource type_, which determines
|
||||
the kind of infrastructure object it manages and what arguments and other
|
||||
attributes the resource supports.
|
||||
This information has moved to
|
||||
[`depends_on`](/docs/configuration/meta-arguments/depends_on.html).
|
||||
|
||||
### Providers
|
||||
<a id="count-multiple-resource-instances-by-count"></a>
|
||||
<a id="the-count-object"></a>
|
||||
<a id="referring-to-instances"></a>
|
||||
<a id="using-expressions-in-count"></a>
|
||||
<a id="when-to-use-for_each-instead-of-count"></a>
|
||||
|
||||
Each resource type is implemented by a [provider](./provider-requirements.html),
|
||||
which is a plugin for Terraform that offers a collection of resource types. A
|
||||
provider usually provides resources to manage a single cloud or on-premises
|
||||
infrastructure platform. Providers are distributed separately from Terraform
|
||||
itself, but Terraform can automatically install most providers when initializing
|
||||
a working directory.
|
||||
### `count`
|
||||
|
||||
In order to manage resources, a Terraform module must specify which providers it
|
||||
requires. Additionally, most providers need some configuration in order to
|
||||
access their remote APIs, and the root module must provide that configuration.
|
||||
This information has moved to
|
||||
[`count`](/docs/configuration/meta-arguments/count.html).
|
||||
|
||||
For more information, see:
|
||||
<a id="for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings"></a>
|
||||
<a id="the-each-object"></a>
|
||||
<a id="using-expressions-in-for_each"></a>
|
||||
<a id="referring-to-instances-1"></a>
|
||||
<a id="using-sets"></a>
|
||||
|
||||
- [Provider Requirements](./provider-requirements.html), for declaring which
|
||||
providers a module uses.
|
||||
- [Provider Configuration](./providers.html), for configuring provider settings.
|
||||
### `for_each`
|
||||
|
||||
Terraform usually automatically determines which provider to use based on a
|
||||
resource type's name. (By convention, resource type names start with their
|
||||
provider's preferred local name.) When using multiple configurations of a
|
||||
provider (or non-preferred local provider names), you must use the `provider`
|
||||
meta-argument to manually choose an alternate provider configuration. See
|
||||
[the section on `provider` below][inpage-provider] for more details.
|
||||
This information has moved to
|
||||
[`for_each`](/docs/configuration/meta-arguments/for_each.html).
|
||||
|
||||
### Resource Arguments
|
||||
<a id="provider-selecting-a-non-default-provider-configuration"></a>
|
||||
|
||||
Most of the arguments within the body of a `resource` block are specific to the
|
||||
selected resource type. The resource type's documentation lists which arguments
|
||||
are available and how their values should be formatted.
|
||||
### `provider`
|
||||
|
||||
The values for resource arguments can make full use of
|
||||
[expressions](./expressions.html) and other dynamic Terraform
|
||||
language features.
|
||||
This information has moved to
|
||||
[`provider`](/docs/configuration/meta-arguments/resource-provider.html).
|
||||
|
||||
There are also some _meta-arguments_ that are defined by Terraform itself
|
||||
and apply across all resource types. (See [Meta-Arguments](#meta-arguments) below.)
|
||||
<a id="lifecycle-lifecycle-customizations"></a>
|
||||
|
||||
### Documentation for Resource Types
|
||||
### `lifecycle`
|
||||
|
||||
Every Terraform provider has its own documentation, describing its resource
|
||||
types and their arguments.
|
||||
This information has moved to
|
||||
[`lifecycle`](/docs/configuration/meta-arguments/lifecycle.html).
|
||||
|
||||
Most publicly available providers are distributed on the
|
||||
[Terraform Registry](https://registry.terraform.io/browse/providers), which also
|
||||
hosts their documentation. When viewing a provider's page on the Terraform
|
||||
Registry, you can click the "Documentation" link in the header to browse its
|
||||
documentation. Provider documentation on the registry is versioned, and you can
|
||||
use the dropdown version menu in the header to switch which version's
|
||||
documentation you are viewing.
|
||||
<a id="provisioner-and-connection-resource-provisioners"></a>
|
||||
|
||||
To browse the publicly available providers and their documentation, see
|
||||
[the providers section of the Terraform Registry](https://registry.terraform.io/browse/providers).
|
||||
### Provisioners
|
||||
|
||||
-> **Note:** Provider documentation used to be hosted directly on terraform.io,
|
||||
as part of Terraform's core documentation. Although some provider documentation
|
||||
might still be hosted here, the Terraform Registry is now the main home for all
|
||||
public provider docs. (The exception is the built-in
|
||||
[`terraform` provider](/docs/providers/terraform/index.html) for reading state
|
||||
data, since it is not available on the Terraform Registry.)
|
||||
|
||||
## Resource Behavior
|
||||
|
||||
A `resource` block declares that you want a particular infrastructure object
|
||||
to exist with the given settings. If you are writing a new configuration for
|
||||
the first time, the resources it defines will exist _only_ in the configuration,
|
||||
and will not yet represent real infrastructure objects in the target platform.
|
||||
|
||||
_Applying_ a Terraform configuration is the process of creating, updating,
|
||||
and destroying real infrastructure objects in order to make their settings
|
||||
match the configuration.
|
||||
|
||||
When Terraform creates a new infrastructure object represented by a `resource`
|
||||
block, the identifier for that real object is saved in Terraform's
|
||||
[state](/docs/state/index.html), allowing it to be updated and destroyed
|
||||
in response to future changes. For resource blocks that already have an
|
||||
associated infrastructure object in the state, Terraform compares the
|
||||
actual configuration of the object with the arguments given in the
|
||||
configuration and, if necessary, updates the object to match the configuration.
|
||||
|
||||
This general behavior applies for all resources, regardless of type. The
|
||||
details of what it means to create, update, or destroy a resource are different
|
||||
for each resource type, but this standard set of verbs is common across them
|
||||
all.
|
||||
|
||||
The meta-arguments within `resource` blocks, documented in the
|
||||
sections below, allow some details of this standard resource behavior to be
|
||||
customized on a per-resource basis.
|
||||
|
||||
### Accessing Resource Attributes
|
||||
|
||||
[Expressions](./expressions.html) within a Terraform module can access
|
||||
information about resources in the same module, and you can use that information
|
||||
to help configure other resources. Use the `<RESOURCE TYPE>.<NAME>.<ATTRIBUTE>`
|
||||
syntax to reference a resource attribute in an expression.
|
||||
|
||||
In addition to arguments specified in the configuration, resources often provide
|
||||
read-only attributes with information obtained from the remote API; this often
|
||||
includes things that can't be known until the resource is created, like the
|
||||
resource's unique random ID.
|
||||
|
||||
Many providers also include [data sources](./data-sources.html), which are a
|
||||
special type of resource used only for looking up information.
|
||||
|
||||
For a list of the attributes a resource or data source type provides, consult
|
||||
its documentation; these are generally included in a second list below its list
|
||||
of configurable arguments.
|
||||
|
||||
For more information about referencing resource attributes in expressions, see
|
||||
[Expressions: References to Resource Attributes](./expressions.html#references-to-resource-attributes).
|
||||
|
||||
### Resource Dependencies
|
||||
|
||||
Most resources in a configuration don't have any particular relationship, and
|
||||
Terraform can make changes to several unrelated resources in parallel.
|
||||
|
||||
However, some resources must be processed after other specific resources;
|
||||
sometimes this is because of how the resource works, and sometimes the
|
||||
resource's configuration just requires information generated by another
|
||||
resource.
|
||||
|
||||
Most resource dependencies are handled automatically. Terraform analyses any
|
||||
[expressions](./expressions.html) within a `resource` block to find references
|
||||
to other objects, and treats those references as implicit ordering requirements
|
||||
when creating, updating, or destroying resources. Since most resources with
|
||||
behavioral dependencies on other resources also refer to those resources' data,
|
||||
it's usually not necessary to manually specify dependencies between resources.
|
||||
|
||||
However, some dependencies cannot be recognized implicitly in configuration. For
|
||||
example, if Terraform must manage access control policies _and_ take actions
|
||||
that require those policies to be present, there is a hidden dependency between
|
||||
the access policy and a resource whose creation depends on it. In these rare
|
||||
cases, [the `depends_on` meta-argument][inpage-depend] can explicitly specify a
|
||||
dependency.
|
||||
|
||||
## Meta-Arguments
|
||||
|
||||
Terraform CLI defines the following meta-arguments, which can be used with
|
||||
any resource type to change the behavior of resources:
|
||||
|
||||
- [`depends_on`, for specifying hidden dependencies][inpage-depend]
|
||||
- [`count`, for creating multiple resource instances according to a count][inpage-count]
|
||||
- [`for_each`, to create multiple instances according to a map, or set of strings][inpage-for_each]
|
||||
- [`provider`, for selecting a non-default provider configuration][inpage-provider]
|
||||
- [`lifecycle`, for lifecycle customizations][inpage-lifecycle]
|
||||
- [`provisioner` and `connection`, for taking extra actions after resource creation][inpage-provisioner]
|
||||
|
||||
These arguments often have additional restrictions on what language features can
|
||||
be used with them, which are described in each
|
||||
|
||||
### `depends_on`: Explicit Resource Dependencies
|
||||
|
||||
[inpage-depend]: #depends_on-explicit-resource-dependencies
|
||||
|
||||
Use the `depends_on` meta-argument to handle hidden resource dependencies that
|
||||
Terraform can't automatically infer.
|
||||
|
||||
Explicitly specifying a dependency is only necessary when a resource relies on
|
||||
some other resource's behavior but _doesn't_ access any of that resource's data
|
||||
in its arguments.
|
||||
|
||||
This argument is available in all `resource` blocks, regardless of resource
|
||||
type. For example:
|
||||
|
||||
```hcl
|
||||
resource "aws_iam_role" "example" {
|
||||
name = "example"
|
||||
|
||||
# assume_role_policy is omitted for brevity in this example. See the
|
||||
# documentation for aws_iam_role for a complete example.
|
||||
assume_role_policy = "..."
|
||||
}
|
||||
|
||||
resource "aws_iam_instance_profile" "example" {
|
||||
# Because this expression refers to the role, Terraform can infer
|
||||
# automatically that the role must be created first.
|
||||
role = aws_iam_role.example.name
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "example" {
|
||||
name = "example"
|
||||
role = aws_iam_role.example.name
|
||||
policy = jsonencode({
|
||||
"Statement" = [{
|
||||
# This policy allows software running on the EC2 instance to
|
||||
# access the S3 API.
|
||||
"Action" = "s3:*",
|
||||
"Effect" = "Allow",
|
||||
}],
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_instance" "example" {
|
||||
ami = "ami-a1b2c3d4"
|
||||
instance_type = "t2.micro"
|
||||
|
||||
# Terraform can infer from this that the instance profile must
|
||||
# be created before the EC2 instance.
|
||||
iam_instance_profile = aws_iam_instance_profile.example
|
||||
|
||||
# However, if software running in this EC2 instance needs access
|
||||
# to the S3 API in order to boot properly, there is also a "hidden"
|
||||
# dependency on the aws_iam_role_policy that Terraform cannot
|
||||
# automatically infer, so it must be declared explicitly:
|
||||
depends_on = [
|
||||
aws_iam_role_policy.example,
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `depends_on` meta-argument, if present, must be a list of references
|
||||
to other resources in the same module. Arbitrary expressions are not allowed
|
||||
in the `depends_on` argument value, because its value must be known before
|
||||
Terraform knows resource relationships and thus before it can safely
|
||||
evaluate expressions.
|
||||
|
||||
The `depends_on` argument should be used only as a last resort. When using it,
|
||||
always include a comment explaining why it is being used, to help future
|
||||
maintainers understand the purpose of the additional dependency.
|
||||
|
||||
### `count`: Multiple Resource Instances By Count
|
||||
|
||||
[inpage-count]: #count-multiple-resource-instances-by-count
|
||||
|
||||
-> **Note:** A given resource block cannot use both `count` and `for_each`.
|
||||
|
||||
By default, a `resource` block configures one real infrastructure object.
|
||||
However, sometimes you want to manage several similar objects, such as a fixed
|
||||
pool of compute instances. Terraform has two ways to do this:
|
||||
`count` and [`for_each`][inpage-for_each].
|
||||
|
||||
> **Hands-on:** Try the [Manage Similar Resources With Count](https://learn.hashicorp.com/tutorials/terraform/count?in=terraform/0-13&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn.
|
||||
|
||||
The `count` meta-argument accepts a whole number, and creates that many
|
||||
instances of the resource. Each instance has a distinct infrastructure object
|
||||
associated with it (as described above in
|
||||
[Resource Behavior](#resource-behavior)), and each is separately created,
|
||||
updated, or destroyed when the configuration is applied.
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "server" {
|
||||
count = 4 # create four similar EC2 instances
|
||||
|
||||
ami = "ami-a1b2c3d4"
|
||||
instance_type = "t2.micro"
|
||||
|
||||
tags = {
|
||||
Name = "Server ${count.index}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### The `count` Object
|
||||
|
||||
In resource blocks where `count` is set, an additional `count` object is
|
||||
available in expressions, so you can modify the configuration of each instance.
|
||||
This object has one attribute:
|
||||
|
||||
- `count.index` — The distinct index number (starting with `0`) corresponding
|
||||
to this instance.
|
||||
|
||||
#### Referring to Instances
|
||||
|
||||
When `count` is set, Terraform distinguishes between the resource block itself
|
||||
and the multiple _resource instances_ associated with it. Instances are
|
||||
identified by an index number, starting with `0`.
|
||||
|
||||
- `<TYPE>.<NAME>` (for example, `aws_instance.server`) refers to the resource block.
|
||||
- `<TYPE>.<NAME>[<INDEX>]` (for example, `aws_instance.server[0]`,
|
||||
`aws_instance.server[1]`, etc.) refers to individual instances.
|
||||
|
||||
This is different from resources without `count` or `for_each`, which can be
|
||||
referenced without an index or key.
|
||||
|
||||
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
|
||||
`self` object refers to the current _resource instance,_ not the resource block
|
||||
as a whole.
|
||||
|
||||
#### Using Expressions in `count`
|
||||
|
||||
The `count` meta-argument accepts numeric [expressions](./expressions.html).
|
||||
However, unlike most resource arguments, the `count` value must be known
|
||||
_before_ Terraform performs any remote resource actions. This means `count`
|
||||
can't refer to any resource attributes that aren't known until after a
|
||||
configuration is applied (such as a unique ID generated by the remote API when
|
||||
an object is created).
|
||||
|
||||
#### When to Use `for_each` Instead of `count`
|
||||
|
||||
If your resource instances are almost identical, `count` is appropriate. If some
|
||||
of their arguments need distinct values that can't be directly derived from an
|
||||
integer, it's safer to use `for_each`.
|
||||
|
||||
Before `for_each` was available, it was common to derive `count` from the
|
||||
length of a list and use `count.index` to look up the original list value:
|
||||
|
||||
```hcl
|
||||
variable "subnet_ids" {
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
resource "aws_instance" "server" {
|
||||
# Create one instance for each subnet
|
||||
count = length(var.subnet_ids)
|
||||
|
||||
ami = "ami-a1b2c3d4"
|
||||
instance_type = "t2.micro"
|
||||
subnet_id = var.subnet_ids[count.index]
|
||||
|
||||
tags = {
|
||||
Name = "Server ${count.index}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This was fragile, because the resource instances were still identified by their
|
||||
_index_ instead of the string values in the list. If an element was removed from
|
||||
the middle of the list, every instance _after_ that element would see its
|
||||
`subnet_id` value change, resulting in more remote object changes than intended.
|
||||
Using `for_each` gives the same flexibility without the extra churn.
|
||||
|
||||
### `for_each`: Multiple Resource Instances Defined By a Map, or Set of Strings
|
||||
|
||||
[inpage-for_each]: #for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings
|
||||
|
||||
-> **Version note:** `for_each` was added in Terraform 0.12.6.
|
||||
|
||||
-> **Note:** A given resource block cannot use both `count` and `for_each`.
|
||||
|
||||
By default, a `resource` block configures one real infrastructure object.
|
||||
However, sometimes you want to manage several similar objects, such as a fixed
|
||||
pool of compute instances. Terraform has two ways to do this:
|
||||
[`count`][inpage-count] and `for_each`.
|
||||
|
||||
> **Hands-on:** Try the [Manage Similar Resources With For Each](https://learn.hashicorp.com/tutorials/terraform/for-each?in=terraform/0-13&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn.
|
||||
|
||||
The `for_each` meta-argument accepts a map or a set of strings, and creates an
|
||||
instance for each item in that map or set. Each instance has a distinct
|
||||
infrastructure object associated with it (as described above in
|
||||
[Resource Behavior](#resource-behavior)), and each is separately created,
|
||||
updated, or destroyed when the configuration is applied.
|
||||
|
||||
-> **Note:** The keys of the map (or all the values in the case of a set of strings) must
|
||||
be _known values_, or you will get an error message that `for_each` has dependencies
|
||||
that cannot be determined before apply, and a `-target` may be needed. `for_each` keys
|
||||
cannot be the result (or rely on the result of) of impure functions, including `uuid`, `bcrypt`,
|
||||
or `timestamp`, as their evaluation is deferred resource during evaluation.
|
||||
|
||||
Map:
|
||||
|
||||
```hcl
|
||||
resource "azurerm_resource_group" "rg" {
|
||||
for_each = {
|
||||
a_group = "eastus"
|
||||
another_group = "westus2"
|
||||
}
|
||||
name = each.key
|
||||
location = each.value
|
||||
}
|
||||
```
|
||||
Set of strings:
|
||||
|
||||
```hcl
|
||||
resource "aws_iam_user" "the-accounts" {
|
||||
for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
|
||||
name = each.key
|
||||
}
|
||||
```
|
||||
#### The `each` Object
|
||||
|
||||
In resource blocks where `for_each` is set, an additional `each` object is
|
||||
available in expressions, so you can modify the configuration of each instance.
|
||||
This object has two attributes:
|
||||
|
||||
- `each.key` — The map key (or set member) corresponding to this instance.
|
||||
- `each.value` — The map value corresponding to this instance. (If a set was
|
||||
provided, this is the same as `each.key`.)
|
||||
|
||||
#### Using Expressions in `for_each`
|
||||
|
||||
The `for_each` meta-argument accepts map or set [expressions](./expressions.html).
|
||||
However, unlike most resource arguments, the `for_each` value must be known
|
||||
_before_ Terraform performs any remote resource actions. This means `for_each`
|
||||
can't refer to any resource attributes that aren't known until after a
|
||||
configuration is applied (such as a unique ID generated by the remote API when
|
||||
an object is created).
|
||||
|
||||
The `for_each` value must be a map or set with one element per desired
|
||||
resource instance. When providing a set, you must use an expression that
|
||||
explicitly returns a set value, like the [`toset`](/docs/configuration/functions/toset.html)
|
||||
function; to prevent unwanted surprises during conversion, the `for_each`
|
||||
argument does not implicitly convert lists or tuples to sets.
|
||||
If you need to declare resource instances based on a nested
|
||||
data structure or combinations of elements from multiple data structures you
|
||||
can use Terraform expressions and functions to derive a suitable value.
|
||||
For example:
|
||||
|
||||
* Transform a multi-level nested structure into a flat list by
|
||||
[using nested `for` expressions with the `flatten` function](./functions/flatten.html#flattening-nested-structures-for-for_each).
|
||||
* Produce an exhaustive list of combinations of elements from two or more
|
||||
collections by
|
||||
[using the `setproduct` function inside a `for` expression](./functions/setproduct.html#finding-combinations-for-for_each).
|
||||
|
||||
#### Referring to Instances
|
||||
|
||||
When `for_each` is set, Terraform distinguishes between the resource block itself
|
||||
and the multiple _resource instances_ associated with it. Instances are
|
||||
identified by a map key (or set member) from the value provided to `for_each`.
|
||||
|
||||
- `<TYPE>.<NAME>` (for example, `azurerm_resource_group.rg`) refers to the resource block.
|
||||
- `<TYPE>.<NAME>[<KEY>]` (for example, `azurerm_resource_group.rg["a_group"]`,
|
||||
`azurerm_resource_group.rg["another_group"]`, etc.) refers to individual instances.
|
||||
|
||||
This is different from resources without `count` or `for_each`, which can be
|
||||
referenced without an index or key.
|
||||
|
||||
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
|
||||
`self` object refers to the current _resource instance,_ not the resource block
|
||||
as a whole.
|
||||
|
||||
#### Using Sets
|
||||
|
||||
The Terraform language doesn't have a literal syntax for
|
||||
[set values](./types.html#collection-types), but you can use the `toset`
|
||||
function to explicitly convert a list of strings to a set:
|
||||
|
||||
```hcl
|
||||
locals {
|
||||
subnet_ids = toset([
|
||||
"subnet-abcdef",
|
||||
"subnet-012345",
|
||||
])
|
||||
}
|
||||
|
||||
resource "aws_instance" "server" {
|
||||
for_each = local.subnet_ids
|
||||
|
||||
ami = "ami-a1b2c3d4"
|
||||
instance_type = "t2.micro"
|
||||
subnet_id = each.key # note: each.key and each.value are the same for a set
|
||||
|
||||
tags = {
|
||||
Name = "Server ${each.key}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Conversion from list to set discards the ordering of the items in the list and
|
||||
removes any duplicate elements. `toset(["b", "a", "b"])` will produce a set
|
||||
containing only `"a"` and `"b"` in no particular order; the second `"b"` is
|
||||
discarded.
|
||||
|
||||
If you are writing a module with an [input variable](./variables.html) that
|
||||
will be used as a set of strings for `for_each`, you can set its type to
|
||||
`set(string)` to avoid the need for an explicit type conversion:
|
||||
|
||||
```
|
||||
variable "subnet_ids" {
|
||||
type = set(string)
|
||||
}
|
||||
|
||||
resource "aws_instance" "server" {
|
||||
for_each = var.subnet_ids
|
||||
|
||||
# (and the other arguments as above)
|
||||
}
|
||||
```
|
||||
|
||||
### `provider`: Selecting a Non-default Provider Configuration
|
||||
|
||||
[inpage-provider]: #provider-selecting-a-non-default-provider-configuration
|
||||
|
||||
The `provider` meta-argument specifies which provider configuration to use,
|
||||
overriding Terraform's default behavior of selecting one based on the resource
|
||||
type name. Its value should be an unquoted `<PROVIDER>.<ALIAS>` reference.
|
||||
|
||||
As described in [Provider Configuration](./providers.html), you can optionally
|
||||
create multiple configurations for a single provider (usually to manage
|
||||
resources in different regions of multi-region services). Each provider can have
|
||||
one default configuration, and any number of alternate configurations that
|
||||
include an extra name segment (or "alias").
|
||||
|
||||
By default, Terraform interprets the initial word in the resource type name
|
||||
(separated by underscores) as the local name of a provider, and uses that
|
||||
provider's default configuration. For example, the resource type
|
||||
`google_compute_instance` is associated automatically with the default
|
||||
configuration for the provider named `google`.
|
||||
|
||||
By using the `provider` meta-argument, you can select an alternate provider
|
||||
configuration for a resource:
|
||||
|
||||
```hcl
|
||||
# default configuration
|
||||
provider "google" {
|
||||
region = "us-central1"
|
||||
}
|
||||
|
||||
# alternate configuration, whose alias is "europe"
|
||||
provider "google" {
|
||||
alias = "europe"
|
||||
region = "europe-west1"
|
||||
}
|
||||
|
||||
resource "google_compute_instance" "example" {
|
||||
# This "provider" meta-argument selects the google provider
|
||||
# configuration whose alias is "europe", rather than the
|
||||
# default configuration.
|
||||
provider = google.europe
|
||||
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
A resource always has an implicit dependency on its associated provider, to
|
||||
ensure that the provider is fully configured before any resource actions
|
||||
are taken.
|
||||
|
||||
The `provider` meta-argument expects
|
||||
[a `<PROVIDER>.<ALIAS>` reference](./providers.html#referring-to-alternate-providers),
|
||||
which does not need to be quoted. Arbitrary expressions are not permitted for
|
||||
`provider` because it must be resolved while Terraform is constructing the
|
||||
dependency graph, before it is safe to evaluate expressions.
|
||||
|
||||
### `lifecycle`: Lifecycle Customizations
|
||||
|
||||
[inpage-lifecycle]: #lifecycle-lifecycle-customizations
|
||||
|
||||
The general lifecycle for resources is described above in the
|
||||
[Resource Behavior](#resource-behavior) section. Some details of that behavior
|
||||
can be customized using the special nested `lifecycle` block within a resource
|
||||
block body:
|
||||
|
||||
```
|
||||
resource "azurerm_resource_group" "example" {
|
||||
# ...
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `lifecycle` block and its contents are meta-arguments, available
|
||||
for all `resource` blocks regardless of type. The following lifecycle
|
||||
meta-arguments are supported:
|
||||
|
||||
* `create_before_destroy` (bool) - By default, when Terraform must make a
|
||||
change to a resource argument that cannot be updated in-place due to
|
||||
remote API limitations, Terraform will instead destroy the existing object
|
||||
and then create a new replacement object with the new configured arguments.
|
||||
|
||||
The `create_before_destroy` meta-argument changes this behavior so that
|
||||
the new replacement object is created _first,_ and then the prior object
|
||||
is destroyed only once the replacement is created.
|
||||
|
||||
This is an opt-in behavior because many remote object types have unique
|
||||
name requirements or other constraints that must be accommodated for
|
||||
both a new and an old object to exist concurrently. Some resource types
|
||||
offer special options to append a random suffix onto each object name to
|
||||
avoid collisions, for example. Terraform CLI cannot automatically activate
|
||||
such features, so you must understand the constraints for each resource
|
||||
type before using `create_before_destroy` with it.
|
||||
|
||||
* `prevent_destroy` (bool) - This meta-argument, when set to `true`, will
|
||||
cause Terraform to reject with an error any plan that would destroy the
|
||||
infrastructure object associated with the resource, as long as the argument
|
||||
remains present in the configuration.
|
||||
|
||||
This can be used as a measure of safety against the accidental replacement
|
||||
of objects that may be costly to reproduce, such as database instances.
|
||||
However, it will make certain configuration changes impossible to apply,
|
||||
and will prevent the use of the `terraform destroy` command once such
|
||||
objects are created, and so this option should be used sparingly.
|
||||
|
||||
Since this argument must be present in configuration for the protection to
|
||||
apply, note that this setting does not prevent the remote object from
|
||||
being destroyed if the `resource` block were removed from configuration
|
||||
entirely: in that case, the `prevent_destroy` setting is removed along
|
||||
with it, and so Terraform will allow the destroy operation to succeed.
|
||||
|
||||
* `ignore_changes` (list of attribute names) - By default, Terraform detects
|
||||
any difference in the current settings of a real infrastructure object
|
||||
and plans to update the remote object to match configuration.
|
||||
|
||||
The `ignore_changes` feature is intended to be used when a resource is
|
||||
created with references to data that may change in the future, but should
|
||||
not effect said resource after its creation. In some rare cases, settings
|
||||
of a remote object are modified by processes outside of Terraform, which
|
||||
Terraform would then attempt to "fix" on the next run. In order to make
|
||||
Terraform share management responsibilities of a single object with a
|
||||
separate process, the `ignore_changes` meta-argument specifies resource
|
||||
attributes that Terraform should ignore when planning updates to the
|
||||
associated remote object.
|
||||
|
||||
The arguments corresponding to the given attribute names are considered
|
||||
when planning a _create_ operation, but are ignored when planning an
|
||||
_update_. The arguments are the relative address of the attributes in the
|
||||
resource. Map and list elements can be referenced using index notation,
|
||||
like `tags["Name"]` and `list[0]` respectively.
|
||||
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "example" {
|
||||
# ...
|
||||
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
# Ignore changes to tags, e.g. because a management agent
|
||||
# updates these based on some ruleset managed elsewhere.
|
||||
tags,
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Instead of a list, the special keyword `all` may be used to instruct
|
||||
Terraform to ignore _all_ attributes, which means that Terraform can
|
||||
create and destroy the remote object but will never propose updates to it.
|
||||
|
||||
Only attributes defined by the resource type can be ignored.
|
||||
`ignore_changes` cannot be applied to itself or to any other meta-arguments.
|
||||
|
||||
The `lifecycle` settings all effect how Terraform constructs and traverses
|
||||
the dependency graph. As a result, only literal values can be used because
|
||||
the processing happens too early for arbitrary expression evaluation.
|
||||
|
||||
### `provisioner` and `connection`: Resource Provisioners
|
||||
|
||||
[inpage-provisioner]: #provisioner-and-connection-resource-provisioners
|
||||
|
||||
> **Hands-on:** To learn about more declarative ways to handle provisioning actions, try the [Provision Infrastructure Deployed with Terraform](https://learn.hashicorp.com/collections/terraform/provision?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn.
|
||||
|
||||
Some infrastructure objects require some special actions to be taken after they
|
||||
are created before they can become fully functional. For example, compute
|
||||
instances may require configuration to be uploaded or a configuration management
|
||||
program to be run before they can begin their intended operation.
|
||||
|
||||
Create-time actions like these can be described using _resource provisioners_.
|
||||
A provisioner is another type of plugin supported by Terraform, and each
|
||||
provisioner takes a different kind of action in the context of a resource
|
||||
being created.
|
||||
|
||||
Provisioning steps should be used sparingly, since they represent
|
||||
non-declarative actions taken during the creation of a resource and so
|
||||
Terraform is not able to model changes to them as it can for the declarative
|
||||
portions of the Terraform language.
|
||||
|
||||
Provisioners can also be defined to run when a resource is _destroyed_, with
|
||||
certain limitations.
|
||||
|
||||
The `provisioner` and `connection` block types within `resource` blocks are
|
||||
meta-arguments available across all resource types. Provisioners and their
|
||||
usage are described in more detail in
|
||||
[the Provisioners section](/docs/provisioners/index.html).
|
||||
|
||||
## Local-only Resources
|
||||
|
||||
While most resource types correspond to an infrastructure object type that
|
||||
is managed via a remote network API, there are certain specialized resource
|
||||
types that operate only within Terraform itself, calculating some results and
|
||||
saving those results in the state for future use.
|
||||
|
||||
For example, local-only resource types exist for
|
||||
[generating private keys](/docs/providers/tls/r/private_key.html),
|
||||
[issuing self-signed TLS certificates](/docs/providers/tls/r/self_signed_cert.html),
|
||||
and even [generating random ids](/docs/providers/random/r/id.html).
|
||||
While these resource types often have a more marginal purpose than those
|
||||
managing "real" infrastructure objects, they can be useful as glue to help
|
||||
connect together other resources.
|
||||
|
||||
The behavior of local-only resources is the same as all other resources, but
|
||||
their result data exists only within the Terraform state. "Destroying" such
|
||||
a resource means only to remove it from the state, discarding its data.
|
||||
|
||||
## Operation Timeouts
|
||||
|
||||
Some resource types provide a special `timeouts` nested block argument that
|
||||
allows you to customize how long certain operations are allowed to take
|
||||
before being considered to have failed.
|
||||
For example, [`aws_db_instance`](/docs/providers/aws/r/db_instance.html)
|
||||
allows configurable timeouts for `create`, `update` and `delete` operations.
|
||||
|
||||
Timeouts are handled entirely by the resource type implementation in the
|
||||
provider, but resource types offering these features follow the convention
|
||||
of defining a child block called `timeouts` that has a nested argument
|
||||
named after each operation that has a configurable timeout value.
|
||||
Each of these arguments takes a string representation of a duration, such
|
||||
as `"60m"` for 60 minutes, `"10s"` for ten seconds, or `"2h"` for two hours.
|
||||
|
||||
```hcl
|
||||
resource "aws_db_instance" "example" {
|
||||
# ...
|
||||
|
||||
timeouts {
|
||||
create = "60m"
|
||||
delete = "2h"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The set of configurable operations is chosen by each resource type. Most
|
||||
resource types do not support the `timeouts` block at all. Consult the
|
||||
documentation for each resource type to see which operations it offers
|
||||
for configuration, if any.
|
||||
This information has moved to
|
||||
[Provisioners](/docs/configuration/blocks/resources/provisioners/index.html).
|
||||
|
|
|
@ -99,7 +99,7 @@ different (see the [block-type-specific exceptions](#block-type-specific-excepti
|
|||
correspond either to argument names or to nested block type names.
|
||||
|
||||
* Where a property corresponds to an argument that accepts
|
||||
[arbitrary expressions](./expressions.html) in the native syntax, the
|
||||
[arbitrary expressions](/docs/configuration/expressions/index.html) in the native syntax, the
|
||||
property value is mapped to an expression as described under
|
||||
[_Expression Mapping_](#expression-mapping) below. For arguments that
|
||||
do _not_ accept arbitrary expressions, the interpretation of the property
|
||||
|
@ -116,20 +116,22 @@ different (see the [block-type-specific exceptions](#block-type-specific-excepti
|
|||
## Expression Mapping
|
||||
|
||||
Since JSON grammar is not able to represent all of the Terraform language
|
||||
[expression syntax](./expressions.html), JSON values interpreted as expressions
|
||||
[expression syntax](/docs/configuration/expressions/index.html), JSON values interpreted as expressions
|
||||
are mapped as follows:
|
||||
|
||||
| JSON | Terraform Language Interpretation |
|
||||
| ------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| Boolean | A literal `bool` value. |
|
||||
| Number | A literal `number` value. |
|
||||
| String | Parsed as a [string template](./expressions.html#string-templates) and then evaluated as described below. |
|
||||
| String | Parsed as a [string template][] and then evaluated as described below. |
|
||||
| Object | Each property value is mapped per this table, producing an `object(...)` value with suitable attribute types. |
|
||||
| Array | Each element is mapped per this table, producing a `tuple(...)` value with suitable element types. |
|
||||
| Null | A literal `null`. |
|
||||
|
||||
[string template]: /docs/configuration/expressions/strings.html#string-templates
|
||||
|
||||
When a JSON string is encountered in a location where arbitrary expressions are
|
||||
expected, its value is first parsed as a [string template](./expressions.html#string-templates)
|
||||
expected, its value is first parsed as a [string template][]
|
||||
and then it is evaluated to produce the final result.
|
||||
|
||||
If the given template consists _only_ of a single interpolation sequence,
|
||||
|
|
|
@ -53,7 +53,7 @@ after the equals sign is the argument's value.
|
|||
The context where the argument appears determines what value types are valid
|
||||
(for example, each resource type has a schema that defines the types of its
|
||||
arguments), but many arguments accept arbitrary
|
||||
[expressions](./expressions.html), which allow the value to
|
||||
[expressions](/docs/configuration/expressions/index.html), which allow the value to
|
||||
either be specified literally or generated from other values programmatically.
|
||||
|
||||
-> **Note:** Terraform's configuration language is based on a more general
|
||||
|
|
|
@ -51,7 +51,7 @@ can be used with your configuration.
|
|||
If the running version of Terraform doesn't match the constraints specified,
|
||||
Terraform will produce an error and exit without taking any further actions.
|
||||
|
||||
When you use [child modules](./modules.html), each module can specify its own
|
||||
When you use [child modules](/docs/configuration/blocks/modules/index.html), each module can specify its own
|
||||
version requirements. The requirements of all modules in the tree must be
|
||||
satisfied.
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ function-like constructs called _type constructors._
|
|||
represent a type; instead, it represents a _kind_ of similar types.
|
||||
|
||||
Type constraints look like other kinds of Terraform
|
||||
[expressions](./expressions.html), but are a special syntax. Within the
|
||||
[expressions](/docs/configuration/expressions/index.html), but are a special syntax. Within the
|
||||
Terraform language, they are only valid in the `type` argument of an
|
||||
[input variable](./variables.html).
|
||||
|
||||
|
@ -160,7 +160,7 @@ like the following:
|
|||
|
||||
The Terraform language has literal expressions for creating tuple and object
|
||||
values, which are described in
|
||||
[Expressions: Literal Expressions](./expressions.html#literal-expressions) as
|
||||
[Expressions: Literal Expressions](/docs/configuration/expressions/types.html#literal-expressions) as
|
||||
"list/tuple" literals and "map/object" literals, respectively.
|
||||
|
||||
Terraform does _not_ provide any way to directly represent lists, maps, or sets.
|
||||
|
|
|
@ -21,7 +21,7 @@ and allowing modules to be shared between different configurations.
|
|||
|
||||
When you declare variables in the root module of your configuration, you can
|
||||
set their values using CLI options and environment variables.
|
||||
When you declare them in [child modules](./modules.html),
|
||||
When you declare them in [child modules](/docs/configuration/blocks/modules/index.html),
|
||||
the calling module should pass values in the `module` block.
|
||||
|
||||
If you're familiar with traditional programming languages, it can be useful to
|
||||
|
@ -36,7 +36,7 @@ compare Terraform modules to function definitions:
|
|||
variable is being discussed. Other kinds of variables in Terraform include
|
||||
_environment variables_ (set by the shell where Terraform runs) and _expression
|
||||
variables_ (used to indirectly represent a value in an
|
||||
[expression](./expressions.html)).
|
||||
[expression](/docs/configuration/expressions/index.html)).
|
||||
|
||||
## Declaring an Input Variable
|
||||
|
||||
|
@ -78,7 +78,7 @@ The name of a variable can be any valid [identifier](./syntax.html#identifiers)
|
|||
_except_ the following: `source`, `version`, `providers`, `count`, `for_each`, `lifecycle`, `depends_on`, `locals`.
|
||||
|
||||
These names are reserved for meta-arguments in
|
||||
[module configuration blocks](./modules.html), and cannot be
|
||||
[module configuration blocks](/docs/configuration/blocks/modules/syntax.html), and cannot be
|
||||
declared as variable names.
|
||||
|
||||
## Arguments
|
||||
|
@ -106,7 +106,7 @@ configuration.
|
|||
[inpage-type]: #type-constraints
|
||||
|
||||
The `type` argument in a `variable` block allows you to restrict the
|
||||
[type of value](./expressions.html#types-and-values) that will be accepted as
|
||||
[type of value](/docs/configuration/expressions/types.html) that will be accepted as
|
||||
the value for a variable. If no type constraint is set then a value of any type
|
||||
is accepted.
|
||||
|
||||
|
@ -302,7 +302,7 @@ random_pet.animal: Creation complete after 0s [id=jae-known-mongoose]
|
|||
## Using Input Variable Values
|
||||
|
||||
Within the module that declared a variable, its value can be accessed from
|
||||
within [expressions](./expressions.html) as `var.<NAME>`,
|
||||
within [expressions](/docs/configuration/expressions/index.html) as `var.<NAME>`,
|
||||
where `<NAME>` matches the label given in the declaration block:
|
||||
|
||||
-> **Note:** Input variables are _created_ by a `variable` block, but you
|
||||
|
@ -332,7 +332,7 @@ can be set in a number of ways:
|
|||
The following sections describe these options in more detail. This section does
|
||||
not apply to _child_ modules, where values for input variables are instead
|
||||
assigned in the configuration of their parent module, as described in
|
||||
[_Modules_](./modules.html).
|
||||
[_Modules_](/docs/configuration/blocks/modules/index.html).
|
||||
|
||||
### Variables on the Command Line
|
||||
|
||||
|
@ -411,9 +411,10 @@ and lower case letters as in the above example.
|
|||
|
||||
### Complex-typed Values
|
||||
|
||||
When variable values are provided in a variable definitions file, Terraform's
|
||||
[usual syntax](./expressions.html#structural-types) can be used to assign
|
||||
complex-typed values, like lists and maps.
|
||||
When variable values are provided in a variable definitions file, you can use
|
||||
Terraform's usual syntax for
|
||||
[literal expressions](/docs/configuration/expressions/types.html#literal-expressions)
|
||||
to assign complex-typed values, like lists and maps.
|
||||
|
||||
Some special rules apply to the `-var` command line option and to environment
|
||||
variables. For convenience, Terraform defaults to interpreting `-var` and
|
||||
|
|
|
@ -9,7 +9,7 @@ Anywhere that Terraform lets you specify a range of acceptable versions for
|
|||
something, it expects a specially formatted string known as a version
|
||||
constraint. Version constraints are used when configuring:
|
||||
|
||||
- [Modules](./modules.html)
|
||||
- [Modules](/docs/configuration/blocks/modules/index.html)
|
||||
- [Provider requirements](./provider-requirements.html)
|
||||
- [The `required_version` setting](./terraform.html#specifying-a-required-terraform-version) in the `terraform` block.
|
||||
|
||||
|
@ -22,7 +22,7 @@ other dependency management systems like Bundler and NPM.
|
|||
version = ">= 1.2.0, < 2.0.0"
|
||||
```
|
||||
|
||||
A version constraint is a [string literal](./expressions.html#string-literals)
|
||||
A version constraint is a [string literal](/docs/configuration/expressions/strings.html)
|
||||
containing one or more conditions, which are separated by commas.
|
||||
|
||||
Each condition consists of an operator and a version number.
|
||||
|
|
|
@ -17,11 +17,11 @@ directly in terms of physical objects.
|
|||
|
||||
The `.tf` files in your working directory when you run [`terraform plan`](/docs/commands/plan.html)
|
||||
or [`terraform apply`](/docs/commands/apply.html) together form the _root_
|
||||
module. That module may [call other modules](/docs/configuration/modules.html#calling-a-child-module)
|
||||
module. That module may [call other modules](/docs/configuration/blocks/modules/syntax.html#calling-a-child-module)
|
||||
and connect them together by passing output values from one to input values
|
||||
of another.
|
||||
|
||||
To learn how to _use_ modules, see [the Modules configuration section](/docs/configuration/modules.html).
|
||||
To learn how to _use_ modules, see [the Modules configuration section](/docs/configuration/blocks/modules/index.html).
|
||||
This section is about _creating_ re-usable modules that other configurations
|
||||
can include using `module` blocks.
|
||||
|
||||
|
@ -35,7 +35,7 @@ Most commonly, modules use:
|
|||
the calling module.
|
||||
* [Output values](/docs/configuration/outputs.html) to return results to the
|
||||
calling module, which it can then use to populate arguments elsewhere.
|
||||
* [Resources](/docs/configuration/resources.html) to define one or more
|
||||
* [Resources](/docs/configuration/blocks/resources/index.html) to define one or more
|
||||
infrastructure objects that the module will manage.
|
||||
|
||||
To define a module, create a new directory for it and place one or more `.tf`
|
||||
|
@ -71,126 +71,3 @@ your module is not creating any new abstraction and so the module is
|
|||
adding unnecessary complexity. Just use the resource type directly in the
|
||||
calling module instead.
|
||||
|
||||
## Standard Module Structure
|
||||
|
||||
The standard module structure is a file and directory layout we recommend for
|
||||
reusable modules distributed in separate repositories. Terraform tooling is
|
||||
built to understand the standard module structure and use that structure to
|
||||
generate documentation, index modules for the module registry, and more.
|
||||
|
||||
The standard module structure expects the layout documented below. The list may
|
||||
appear long, but everything is optional except for the root module. Most modules
|
||||
don't need to do any extra work to follow the standard structure.
|
||||
|
||||
* **Root module**. This is the **only required element** for the standard
|
||||
module structure. Terraform files must exist in the root directory of
|
||||
the repository. This should be the primary entrypoint for the module and is
|
||||
expected to be opinionated. For the
|
||||
[Consul module](https://registry.terraform.io/modules/hashicorp/consul)
|
||||
the root module sets up a complete Consul cluster. It makes a lot of assumptions
|
||||
however, and we expect that advanced users will use specific _nested modules_
|
||||
to more carefully control what they want.
|
||||
|
||||
* **README**. The root module and any nested modules should have README
|
||||
files. This file should be named `README` or `README.md`. The latter will
|
||||
be treated as markdown. There should be a description of the module and
|
||||
what it should be used for. If you want to include an example for how this
|
||||
module can be used in combination with other resources, put it in an [examples
|
||||
directory like this](https://github.com/hashicorp/terraform-aws-consul/tree/master/examples).
|
||||
Consider including a visual diagram depicting the infrastructure resources
|
||||
the module may create and their relationship.
|
||||
|
||||
The README doesn't need to document inputs or outputs of the module because
|
||||
tooling will automatically generate this. If you are linking to a file or
|
||||
embedding an image contained in the repository itself, use a commit-specific
|
||||
absolute URL so the link won't point to the wrong version of a resource in the
|
||||
future.
|
||||
|
||||
* **LICENSE**. The license under which this module is available. If you are
|
||||
publishing a module publicly, many organizations will not adopt a module
|
||||
unless a clear license is present. We recommend always having a license
|
||||
file, even if it is not an open source license.
|
||||
|
||||
* **`main.tf`, `variables.tf`, `outputs.tf`**. These are the recommended filenames for
|
||||
a minimal module, even if they're empty. `main.tf` should be the primary
|
||||
entrypoint. For a simple module, this may be where all the resources are
|
||||
created. For a complex module, resource creation may be split into multiple
|
||||
files but any nested module calls should be in the main file. `variables.tf`
|
||||
and `outputs.tf` should contain the declarations for variables and outputs,
|
||||
respectively.
|
||||
|
||||
* **Variables and outputs should have descriptions.** All variables and
|
||||
outputs should have one or two sentence descriptions that explain their
|
||||
purpose. This is used for documentation. See the documentation for
|
||||
[variable configuration](/docs/configuration/variables.html) and
|
||||
[output configuration](/docs/configuration/outputs.html) for more details.
|
||||
|
||||
* **Nested modules**. Nested modules should exist under the `modules/`
|
||||
subdirectory. Any nested module with a `README.md` is considered usable
|
||||
by an external user. If a README doesn't exist, it is considered for internal
|
||||
use only. These are purely advisory; Terraform will not actively deny usage
|
||||
of internal modules. Nested modules should be used to split complex behavior
|
||||
into multiple small modules that advanced users can carefully pick and
|
||||
choose. For example, the
|
||||
[Consul module](https://registry.terraform.io/modules/hashicorp/consul)
|
||||
has a nested module for creating the Cluster that is separate from the
|
||||
module to setup necessary IAM policies. This allows a user to bring in their
|
||||
own IAM policy choices.
|
||||
|
||||
If the root module includes calls to nested modules, they should use relative
|
||||
paths like `./modules/consul-cluster` so that Terraform will consider them
|
||||
to be part of the same repository or package, rather than downloading them
|
||||
again separately.
|
||||
|
||||
If a repository or package contains multiple nested modules, they should
|
||||
ideally be [composable](./composition.html) by the caller, rather than
|
||||
calling directly to each other and creating a deeply-nested tree of modules.
|
||||
|
||||
* **Examples**. Examples of using the module should exist under the
|
||||
`examples/` subdirectory at the root of the repository. Each example may have
|
||||
a README to explain the goal and usage of the example. Examples for
|
||||
submodules should also be placed in the root `examples/` directory.
|
||||
|
||||
Because examples will often be copied into other repositories for
|
||||
customization, any `module` blocks should have their `source` set to the
|
||||
address an external caller would use, not to a relative path.
|
||||
|
||||
A minimal recommended module following the standard structure is shown below.
|
||||
While the root module is the only required element, we recommend the structure
|
||||
below as the minimum:
|
||||
|
||||
```sh
|
||||
$ tree minimal-module/
|
||||
.
|
||||
├── README.md
|
||||
├── main.tf
|
||||
├── variables.tf
|
||||
├── outputs.tf
|
||||
```
|
||||
|
||||
A complete example of a module following the standard structure is shown below.
|
||||
This example includes all optional elements and is therefore the most
|
||||
complex a module can become:
|
||||
|
||||
```sh
|
||||
$ tree complete-module/
|
||||
.
|
||||
├── README.md
|
||||
├── main.tf
|
||||
├── variables.tf
|
||||
├── outputs.tf
|
||||
├── ...
|
||||
├── modules/
|
||||
│ ├── nestedA/
|
||||
│ │ ├── README.md
|
||||
│ │ ├── variables.tf
|
||||
│ │ ├── main.tf
|
||||
│ │ ├── outputs.tf
|
||||
│ ├── nestedB/
|
||||
│ ├── .../
|
||||
├── examples/
|
||||
│ ├── exampleA/
|
||||
│ │ ├── main.tf
|
||||
│ ├── exampleB/
|
||||
│ ├── .../
|
||||
```
|
||||
|
|
|
@ -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.
|
||||
|
||||
Published modules can be easily consumed by Terraform, and users can
|
||||
[constrain module versions](/docs/configuration/modules.html#module-versions)
|
||||
[constrain module versions](/docs/configuration/blocks/modules/syntax.html#version)
|
||||
for safe and predictable updates. The following example shows how a caller
|
||||
might use a module from the Terraform Registry:
|
||||
|
||||
|
@ -37,6 +37,6 @@ do not support the first-class versioning mechanism, but some sources have
|
|||
their own mechanisms for selecting particular VCS commits, etc.
|
||||
|
||||
We recommend that modules distributed via other protocols still use the
|
||||
[standard module structure](./#standard-module-structure) so that it can
|
||||
be used in a similar way to a registry module, or even _become_ a registry
|
||||
module at a later time.
|
||||
[standard module structure](/docs/modules/structure.html) so that they can
|
||||
be used in a similar way as a registry module or be published on the registry
|
||||
at a later time.
|
||||
|
|
|
@ -7,7 +7,7 @@ description: The source argument within a module block specifies the location of
|
|||
|
||||
# Module Sources
|
||||
|
||||
The `source` argument in [a `module` block](/docs/configuration/modules.html)
|
||||
The `source` argument in [a `module` block](/docs/configuration/blocks/modules/syntax.html)
|
||||
tells Terraform where to find the source code for the desired child module.
|
||||
|
||||
Terraform uses this during the module installation step of `terraform init`
|
||||
|
@ -122,7 +122,7 @@ access the Terraform Cloud application.
|
|||
|
||||
Registry modules support versioning. You can provide a specific version as shown
|
||||
in the above examples, or use flexible
|
||||
[version constraints](/docs/configuration/modules.html#module-versions).
|
||||
[version constraints](/docs/configuration/blocks/modules/syntax.html#version).
|
||||
|
||||
You can learn more about the registry at the
|
||||
[Terraform Registry documentation](/docs/registry/modules/use.html#using-modules).
|
||||
|
@ -349,7 +349,7 @@ module "vpc" {
|
|||
```
|
||||
|
||||
-> **Note:** If the content of the archive file is a directory, you will need to
|
||||
include that directory in the module source. Read the section on
|
||||
include that directory in the module source. Read the section on
|
||||
[Modules in Package Sub-directories](#modules-in-package-sub-directories) for more
|
||||
information.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
- **Standard module structure.** The module must adhere to the
|
||||
[standard module structure](/docs/modules/index.html#standard-module-structure).
|
||||
[standard module structure](/docs/modules/structure.html).
|
||||
This allows the registry to inspect your module and generate documentation,
|
||||
track resource usage, parse submodules and examples, and more.
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ follow [semantic versioning](http://semver.org/). In addition to pure syntax,
|
|||
we encourage all modules to follow the full guidelines of semantic versioning.
|
||||
|
||||
Terraform since version 0.11 will resolve any provided
|
||||
[module version constraints](/docs/configuration/modules.html#module-versions) and
|
||||
[module version constraints](/docs/configuration/blocks/modules/syntax.html#version) and
|
||||
using them is highly recommended to avoid pulling in breaking changes.
|
||||
|
||||
Terraform versions after 0.10.6 but before 0.11 have partial support for the registry
|
||||
|
|
|
@ -14,7 +14,7 @@ can't, shouldn't, or don't need to be public.
|
|||
|
||||
You can load private modules [directly from version control and other
|
||||
sources](/docs/modules/sources.html), but those sources don't support [version
|
||||
constraints](/docs/configuration/modules.html#module-versions) or a browsable
|
||||
constraints](/docs/configuration/blocks/modules/syntax.html#version) or a browsable
|
||||
marketplace of modules, both of which are important for enabling a
|
||||
producers-and-consumers content model in a large organization.
|
||||
|
||||
|
|
|
@ -50,7 +50,36 @@
|
|||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/resources.html">Resource Blocks</a>
|
||||
<a href="/docs/configuration/blocks/resources/syntax.html">Resource Blocks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/blocks/resources/behavior.html">Resource Behavior</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#">Meta-Arguments</a>
|
||||
<ul class="nav nav-auto-expand">
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/depends_on.html"><code>depends_on</code></a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/count.html"><code>count</code></a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/for_each.html"><code>for_each</code></a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/resource-provider.html"><code>provider</code></a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/lifecycle.html"><code>lifecycle</code></a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
@ -216,13 +245,34 @@
|
|||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/modules.html">Module Blocks</a>
|
||||
<a href="/docs/configuration/blocks/modules/syntax.html">Module Blocks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/modules/sources.html">Module Sources</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#">Meta-Arguments</a>
|
||||
<ul class="nav nav-auto-expand">
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/module-providers.html"><code>providers</code></a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/depends_on.html"><code>depends_on</code></a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/count.html"><code>count</code></a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/meta-arguments/for_each.html"><code>for_each</code></a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#">Module Development</a>
|
||||
<ul class="nav">
|
||||
|
@ -230,6 +280,14 @@
|
|||
<a href="/docs/modules/index.html">Overview</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/modules/structure.html">Standard Module Structure</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/modules/providers.html">Providers Within Modules</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/modules/composition.html">Best Practices: Module Composition</a>
|
||||
</li>
|
||||
|
@ -250,7 +308,39 @@
|
|||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions.html">Standard Expressions</a>
|
||||
<a href="/docs/configuration/expressions/types.html">Types and Values</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions/strings.html">Strings and Templates</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions/references.html">References to Values</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions/operators.html">Operators</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions/function-calls.html">Function Calls</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions/conditionals.html">Conditional Expressions</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions/for.html">For Expressions</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions/splat.html">Splat Expressions</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/expressions/dynamic-blocks.html">Dynamic Blocks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
|
Loading…
Reference in New Issue