2014-07-28 19:43:00 +02:00
|
|
|
|
---
|
|
|
|
|
layout: "docs"
|
2018-12-20 05:34:34 +01:00
|
|
|
|
page_title: "Resources - Configuration Language"
|
2014-07-28 19:43:00 +02:00
|
|
|
|
sidebar_current: "docs-config-resources"
|
2014-10-22 05:21:56 +02:00
|
|
|
|
description: |-
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
---
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
# Resources
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2019-01-17 01:30:43 +01:00
|
|
|
|
-> **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).
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
_Resources_ are the most important element in the Terraform language.
|
2018-12-11 01:14:33 +01:00
|
|
|
|
Each resource block describes one or more infrastructure objects, such
|
2018-05-05 23:00:31 +02:00
|
|
|
|
as virtual networks, compute instances, or higher-level components such
|
|
|
|
|
as DNS records.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
## Resource Syntax
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2017-04-05 17:29:27 +02:00
|
|
|
|
```hcl
|
2014-07-28 19:43:00 +02:00
|
|
|
|
resource "aws_instance" "web" {
|
2018-05-05 23:00:31 +02:00
|
|
|
|
ami = "ami-a1b2c3d4"
|
|
|
|
|
instance_type = "t2.micro"
|
2014-07-28 19:43:00 +02:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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
|
|
|
|
|
of the scope of a module.
|
|
|
|
|
|
|
|
|
|
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).
|
|
|
|
|
|
2019-03-01 21:30:51 +01:00
|
|
|
|
-> **Note:** Resource names must start with a letter or underscore, and may
|
|
|
|
|
contain only letters, digits, underscores, and dashes.
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
## Resource Types and Arguments
|
|
|
|
|
|
|
|
|
|
Each resource is associated with a single _resource type_, which determines
|
|
|
|
|
the kind of infrastructure object it manages and what arguments and other
|
2018-12-11 01:14:33 +01:00
|
|
|
|
attributes the resource supports.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
Each resource type in turn belongs to a [provider](./providers.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.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
Most of the items within the body of a `resource` block are specific to the
|
|
|
|
|
selected resource type. These arguments can make full use of
|
|
|
|
|
[expressions](./expressions.html) and other dynamic Terraform
|
|
|
|
|
language features.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
[Terraform's provider documentation][providers] is the primary place to
|
|
|
|
|
learn which resource types are available and which arguments to use for each
|
|
|
|
|
resource type. Once you understand Terraform's basic syntax, the provider
|
|
|
|
|
documentation will be where you spend the majority of your time on this website.
|
|
|
|
|
|
|
|
|
|
The "[Providers][]" link at the top level of the navigation sidebar will take
|
|
|
|
|
you to an alphabetical list of all of the providers distributed by HashiCorp.
|
|
|
|
|
You can find a specific provider in this master list, or choose a category from
|
|
|
|
|
the navigation sidebar to browse a more focused list of providers.
|
|
|
|
|
|
|
|
|
|
You can also search GitHub or other sources for third-party providers, which can
|
|
|
|
|
be installed as plugins to enable an even broader selection of resource types.
|
|
|
|
|
|
|
|
|
|
[providers]: /docs/providers/index.html
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
|
|
|
|
## Resource Behavior
|
|
|
|
|
|
|
|
|
|
A `resource` block describes your intent for 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.
|
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
The meta-arguments within `resource` blocks, documented in the
|
|
|
|
|
sections below, allow some details of this standard resource behavior to be
|
2018-05-05 23:00:31 +02:00
|
|
|
|
customized on a per-resource basis.
|
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
### 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.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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
|
2019-03-22 23:08:55 +01:00
|
|
|
|
cases, [the `depends_on` meta-argument][inpage-depend] can explicitly specify a
|
|
|
|
|
dependency.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
## Meta-Arguments
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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]
|
2019-06-12 17:07:32 +02:00
|
|
|
|
- [`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]
|
2018-12-11 01:14:33 +01:00
|
|
|
|
- [`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
|
|
|
|
|
|
2019-03-22 23:08:55 +01:00
|
|
|
|
### `depends_on`: Explicit Resource Dependencies
|
2018-12-11 01:14:33 +01:00
|
|
|
|
|
2019-03-22 23:08:55 +01:00
|
|
|
|
[inpage-depend]: #depends_on-explicit-resource-dependencies
|
2018-12-11 01:14:33 +01:00
|
|
|
|
|
|
|
|
|
Use the `depends_on` meta-argument to handle hidden resource dependencies that
|
2019-03-22 23:08:55 +01:00
|
|
|
|
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.
|
2018-12-11 01:14:33 +01:00
|
|
|
|
|
|
|
|
|
This argument is available in all `resource` blocks, regardless of resource
|
|
|
|
|
type. For example:
|
2017-03-02 18:07:49 +01:00
|
|
|
|
|
2017-04-05 17:29:27 +02:00
|
|
|
|
```hcl
|
2018-05-05 23:00:31 +02:00
|
|
|
|
resource "aws_iam_role" "example" {
|
|
|
|
|
name = "example"
|
2017-03-02 18:07:49 +01:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
# assume_role_policy is omitted for brevity in this example. See the
|
|
|
|
|
# documentation for aws_iam_role for a complete example.
|
|
|
|
|
assume_role_policy = "..."
|
2017-03-02 18:07:49 +01:00
|
|
|
|
}
|
2016-11-12 17:41:18 +01:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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
|
|
|
|
|
}
|
2016-11-12 17:41:18 +01:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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",
|
|
|
|
|
}],
|
|
|
|
|
})
|
|
|
|
|
}
|
2016-11-12 17:41:18 +01:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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,
|
|
|
|
|
]
|
2016-11-12 17:41:18 +01:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-05-06 04:53:38 +02:00
|
|
|
|
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.
|
|
|
|
|
|
2019-06-12 17:07:32 +02:00
|
|
|
|
### `count`: Multiple Resource Instances By Count
|
2018-12-11 01:14:33 +01:00
|
|
|
|
|
2019-06-12 17:07:32 +02:00
|
|
|
|
[inpage-count]: #count-multiple-resource-instances-by-count
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
-> **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].
|
|
|
|
|
|
|
|
|
|
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.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
```hcl
|
|
|
|
|
resource "aws_instance" "server" {
|
|
|
|
|
count = 4 # create four similar EC2 instances
|
2015-01-25 01:25:04 +01:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
ami = "ami-a1b2c3d4"
|
|
|
|
|
instance_type = "t2.micro"
|
2015-01-25 01:25:04 +01:00
|
|
|
|
|
2019-10-24 17:23:17 +02:00
|
|
|
|
tags = {
|
2018-05-05 23:00:31 +02:00
|
|
|
|
Name = "Server ${count.index}"
|
2015-01-25 01:25:04 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
#### 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.
|
|
|
|
|
|
2019-08-20 01:33:33 +02:00
|
|
|
|
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
|
|
|
|
|
`self` object refers to the current _resource instance,_ not the resource block
|
|
|
|
|
as a whole.
|
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
#### Using Expressions in `count`
|
2018-12-11 01:14:33 +01:00
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
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).
|
2018-12-11 01:14:33 +01:00
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
#### When to Use `for_each` Instead of `count`
|
2018-12-11 01:14:33 +01:00
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
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`.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
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:
|
2017-12-04 18:43:40 +01:00
|
|
|
|
|
|
|
|
|
```hcl
|
2018-05-05 23:00:31 +02:00
|
|
|
|
variable "subnet_ids" {
|
|
|
|
|
type = list(string)
|
2017-12-04 18:43:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
resource "aws_instance" "server" {
|
|
|
|
|
# Create one instance for each subnet
|
|
|
|
|
count = length(var.subnet_ids)
|
2017-12-04 18:43:40 +01:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
ami = "ami-a1b2c3d4"
|
|
|
|
|
instance_type = "t2.micro"
|
|
|
|
|
subnet_id = var.subnet_ids[count.index]
|
2017-12-04 18:43:40 +01:00
|
|
|
|
|
2019-10-24 17:23:17 +02:00
|
|
|
|
tags = {
|
2018-05-05 23:00:31 +02:00
|
|
|
|
Name = "Server ${count.index}"
|
|
|
|
|
}
|
2017-12-04 18:43:40 +01:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
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.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2019-06-12 17:07:32 +02:00
|
|
|
|
### `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
|
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
-> **Version note:** `for_each` was added in Terraform 0.12.6.
|
2019-06-12 17:07:32 +02:00
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
-> **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`.
|
|
|
|
|
|
|
|
|
|
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.
|
2019-06-12 17:07:32 +02:00
|
|
|
|
|
2020-01-30 23:18:16 +01:00
|
|
|
|
-> **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.
|
|
|
|
|
|
2020-05-20 01:03:21 +02:00
|
|
|
|
Map:
|
|
|
|
|
|
2019-06-12 17:07:32 +02:00
|
|
|
|
```hcl
|
|
|
|
|
resource "azurerm_resource_group" "rg" {
|
|
|
|
|
for_each = {
|
|
|
|
|
a_group = "eastus"
|
|
|
|
|
another_group = "westus2"
|
|
|
|
|
}
|
|
|
|
|
name = each.key
|
|
|
|
|
location = each.value
|
|
|
|
|
}
|
|
|
|
|
```
|
2020-05-20 01:03:21 +02:00
|
|
|
|
Set of strings:
|
2019-06-12 17:07:32 +02:00
|
|
|
|
|
2020-05-20 01:03:21 +02:00
|
|
|
|
```hcl
|
|
|
|
|
resource "aws_iam_user" "the-accounts" {
|
|
|
|
|
for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
|
|
|
|
|
name = each.key
|
|
|
|
|
}
|
|
|
|
|
```
|
2019-08-08 01:47:42 +02:00
|
|
|
|
#### 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`.)
|
|
|
|
|
|
2020-06-01 20:23:56 +02:00
|
|
|
|
#### 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. 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).
|
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
#### Referring to Instances
|
2019-06-12 17:07:32 +02:00
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
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.
|
|
|
|
|
|
2019-08-20 01:33:33 +02:00
|
|
|
|
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
|
|
|
|
|
`self` object refers to the current _resource instance,_ not the resource block
|
|
|
|
|
as a whole.
|
|
|
|
|
|
2019-08-08 01:47:42 +02:00
|
|
|
|
#### Using Sets
|
|
|
|
|
|
|
|
|
|
The Terraform language doesn't have a literal syntax for
|
2020-06-01 20:23:56 +02:00
|
|
|
|
[set values](./types.html#collection-types), but you can use the `toset`
|
|
|
|
|
function to explicitly convert a list of strings to a set:
|
2019-06-12 17:07:32 +02:00
|
|
|
|
|
|
|
|
|
```hcl
|
2020-06-01 20:23:56 +02:00
|
|
|
|
locals {
|
|
|
|
|
subnet_ids = toset([
|
|
|
|
|
"subnet-abcdef",
|
|
|
|
|
"subnet-012345",
|
|
|
|
|
])
|
2019-06-12 17:07:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resource "aws_instance" "server" {
|
2020-06-01 20:23:56 +02:00
|
|
|
|
for_each = local.subnet_ids
|
2019-06-12 17:07:32 +02:00
|
|
|
|
|
|
|
|
|
ami = "ami-a1b2c3d4"
|
|
|
|
|
instance_type = "t2.micro"
|
2019-08-08 01:47:42 +02:00
|
|
|
|
subnet_id = each.key # note: each.key and each.value are the same for a set
|
2019-06-12 17:07:32 +02:00
|
|
|
|
|
2019-10-24 17:23:17 +02:00
|
|
|
|
tags = {
|
2019-06-12 17:07:32 +02:00
|
|
|
|
Name = "Server ${each.key}"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2020-06-01 20:23:56 +02:00
|
|
|
|
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.
|
2019-08-08 01:47:42 +02:00
|
|
|
|
|
2020-06-01 20:23:56 +02:00
|
|
|
|
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:
|
2019-08-08 01:47:42 +02:00
|
|
|
|
|
2020-06-01 20:23:56 +02:00
|
|
|
|
```
|
|
|
|
|
variable "subnet_ids" {
|
|
|
|
|
type = set(string)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resource "aws_instance" "server" {
|
|
|
|
|
for_each = var.subnet_ids
|
|
|
|
|
|
|
|
|
|
# (and the other arguments as above)
|
|
|
|
|
}
|
|
|
|
|
```
|
2019-10-11 21:02:24 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
### `provider`: Selecting a Non-default Provider Configuration
|
|
|
|
|
|
|
|
|
|
[inpage-provider]: #provider-selecting-a-non-default-provider-configuration
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
As described in [the Providers page](./providers.html),
|
2018-05-05 23:00:31 +02:00
|
|
|
|
Terraform optionally allows the definition of multiple alternative ("aliased")
|
|
|
|
|
configurations for a single provider, to allow management of resources
|
|
|
|
|
in different regions in multi-region services, etc.
|
|
|
|
|
The `provider` meta-argument overrides Terraform's default behavior of
|
|
|
|
|
selecting a provider configuration based on the resource type name.
|
|
|
|
|
|
|
|
|
|
By default, Terraform takes the initial word in the resource type name
|
|
|
|
|
(separated by underscores) and selects the default configuration for that
|
|
|
|
|
named provider. 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, an aliased provider configuration
|
|
|
|
|
can be selected:
|
2015-04-21 01:54:56 +02:00
|
|
|
|
|
2017-04-05 17:29:27 +02:00
|
|
|
|
```hcl
|
2018-05-05 23:00:31 +02:00
|
|
|
|
# default configuration
|
|
|
|
|
provider "google" {
|
|
|
|
|
region = "us-central1"
|
|
|
|
|
}
|
2015-04-21 01:54:56 +02:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
# alternative, aliased configuration
|
|
|
|
|
provider "google" {
|
|
|
|
|
alias = "europe"
|
|
|
|
|
region = "europe-west1"
|
2015-04-21 01:54:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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
|
2016-10-24 11:05:25 +02:00
|
|
|
|
|
|
|
|
|
# ...
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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.
|
2015-04-21 01:54:56 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
### `lifecycle`: Lifecycle Customizations
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
[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:
|
2015-04-21 01:54:56 +02:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
```
|
|
|
|
|
resource "azurerm_resource_group" "example" {
|
|
|
|
|
# ...
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
lifecycle {
|
|
|
|
|
create_before_destroy = true
|
|
|
|
|
}
|
2014-07-28 19:43:00 +02:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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
|
2018-12-11 01:14:33 +01:00
|
|
|
|
remote API limitations, Terraform will instead destroy the existing object
|
2018-05-05 23:00:31 +02:00
|
|
|
|
and then create a new replacement object with the new configured arguments.
|
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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
|
2019-03-19 19:26:25 +01:00
|
|
|
|
such features, so you must understand the constraints for each resource
|
2018-12-11 01:14:33 +01:00
|
|
|
|
type before using `create_before_destroy` with it.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
|
|
|
|
* `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.
|
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
|
|
|
|
* `ignore_changes` (list of attribute names) - By default, Terraform detects
|
2018-12-11 01:14:33 +01:00
|
|
|
|
any difference in the current settings of a real infrastructure object
|
2018-05-05 23:00:31 +02:00
|
|
|
|
and plans to update the remote object to match configuration.
|
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
The arguments corresponding to the given attribute names are considered
|
|
|
|
|
when planning a _create_ operation, but are ignored when planning an
|
|
|
|
|
_update_.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
```hcl
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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,
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-11 01:14:33 +01:00
|
|
|
|
```
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2019-06-19 01:03:33 +02:00
|
|
|
|
You can also ignore specific map elements by writing references like
|
|
|
|
|
`tags["Name"]` in the `ignore_changes` list, though with an important
|
|
|
|
|
caveat: the ignoring applies only to in-place updates to an existing
|
|
|
|
|
key. Adding or removing a key is treated by Terraform as a change to the
|
|
|
|
|
containing map itself rather than to the individual key, and so if you
|
|
|
|
|
wish to ignore changes to a particular tag made by an external system
|
|
|
|
|
you must ensure that the Terraform configuration creates a placeholder
|
|
|
|
|
element for that tag name so that the external system changes will be
|
|
|
|
|
understood as an in-place edit of that key:
|
|
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
|
resource "aws_instance" "example" {
|
|
|
|
|
# ...
|
|
|
|
|
|
|
|
|
|
tags = {
|
|
|
|
|
# Initial value for Name is overridden by our automatic scheduled
|
|
|
|
|
# re-tagging process; changes to this are ignored by ignore_changes
|
|
|
|
|
# below.
|
|
|
|
|
Name = "placeholder"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lifecycle {
|
|
|
|
|
ignore_changes = [
|
|
|
|
|
tags["Name"],
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
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.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
Only attributes defined by the resource type can be ignored.
|
|
|
|
|
`ignore_changes` cannot be applied to itself or to any other meta-arguments.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
|
|
|
|
The `lifecycle` settings all effect how Terraform constructs and traverses
|
|
|
|
|
the dependency graph. As a result, only literal values can be used because
|
2019-04-04 17:21:36 +02:00
|
|
|
|
the processing happens too early for arbitrary expression evaluation.
|
2018-05-05 23:00:31 +02:00
|
|
|
|
|
2018-12-11 01:14:33 +01:00
|
|
|
|
### `provisioner` and `connection`: Resource Provisioners
|
|
|
|
|
|
|
|
|
|
[inpage-provisioner]: #provisioner-and-connection-resource-provisioners
|
|
|
|
|
|
|
|
|
|
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).
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
## 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),
|
2018-12-11 01:14:33 +01:00
|
|
|
|
and even [generating random ids](/docs/providers/random/r/id.html).
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
```hcl
|
|
|
|
|
resource "aws_db_instance" "example" {
|
|
|
|
|
# ...
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
timeouts {
|
|
|
|
|
create = "60m"
|
|
|
|
|
delete = "2h"
|
|
|
|
|
}
|
2014-07-28 19:43:00 +02:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-05-05 23:00:31 +02:00
|
|
|
|
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.
|