terraform/website/docs/configuration/resources.html.md

465 lines
19 KiB
Markdown

---
layout: "docs"
page_title: "Configuring Resources"
sidebar_current: "docs-config-resources"
description: |-
Resources are the most important element in a Terraform configuration.
Each resource corresponds to an infrastructure object, such as a virtual
network or compute instance.
---
# Resources
_Resources_ are the most important element in the Terraform language.
Each resource block describes one ore 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
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).
## 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
attributes are supported for each resource.
Each resource type in turn belongs to a [provider](/docs/configuration/providers.html),
which is a plugin for Terraform that offers a collection of resource types that
most often belong to a single cloud or on-premises infrastructure platform.
Most of the items within the body of a `resource` block are defined by and
specific to the selected resource type, and these arguments can make full
use of [expressions](/docs/configuration/expressions.html) and other dynamic
Terraform language features.
However, there are some "meta-arguments" that are defined by Terraform itself
and apply across all resource types. These arguments often have additional
restrictions on what language features can be used with them, and are described
in more detail in the following sections.
## 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.
The "meta-arguments" within `resource` blocks, defined in the following
sections, allow some details of this standard resource behavior to be
customized on a per-resource basis.
## Resource Dependencies
As with other elements in the Terraform language, Terraform analyses any
[expressions](/docs/configuration/expressions.html) within a `resource`
block to find references to other objects, and infers from this a correct
dependency ordering for creating, updating, or destroying each resource.
Because of this, in most cases it is not necessary to mention explicitly
any dependencies between resources.
However, in some less-common situations there are dependencies between
resources that cannot be recognized implicitly in configuration. For example,
if Terraform is being used to both manage access control policies _and_ take
actions that require those policies to be present, there may be a hidden
dependency between the access policy and a resource whose creation depends
on it.
In these rare cases, the `depends_on` meta-argument can be used to explicitly
specify a dependency. 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.
## Multiple Resource Instances
By default, a single `resource` block corresponds to only one real
infrastructure object. Sometimes it is desirable to instead manage a set
of _similar_ objects of the same type, such as a fixed pool of compute
instances. You can achieve this by using the `count` meta-argument,
which is allowed in all `resource` blocks:
```hcl
resource "aws_instance" "server" {
count = 4 # create four similar EC2 instances
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
tags {
Name = "Server ${count.index}"
}
}
```
When the `count` meta-argument is present, a distinction exists between
the resource block itself -- identified as `aws_instance.server` --
and the multiple _resource instances_ associated with it, identified
as `aws_instance.server[0]`, `aws_instance.server[1]`, etc. When `count`
is _not_ present, a resource block has only a single resource instance,
which has no associated index.
For resource blocks where `count` is set, an additional `count` object
is available for use in expressions, which has an attribute `count.index`
that provides the distinct index for each instance.
The _Resource Behavior_ section above described how each resource corresponds
to a real infrastructure object. It is in fact resource _instances_ that
correspond to infrastructure objects, and so when `count` is used a particular
resource block has a distinct infrastructure object associated with each of its
instances, and each is separtely created, updated, or destroyed when the
configuration is applied.
The `count` meta argument accepts [expressions](/docs/configuration/expressions.html)
in its value, similar to the resource-type-specific arguments for a resource.
However, Terraform must interpret the `count` argument _before_ any actions
are taken from remote resources, and so (unlike the resource-type-specifc arguments)
the `count` expressions may not refer to any resource attributes that are
not known until after a configuration is applied, such as a unique id
generated by the remote API when an object is created.
For example, `count` can be used with an input variable that carries a list
value, to create one instance for each element of the list:
```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}"
}
}
```
Note that the separate resource instances created by `count` are still
identified by their _index_, and not by the string values in the given
list. This means that if an element is removed from the middle of the list,
all of the indexed instances _after_ it will see their `subnet_id` values
change, which will cause more remote object changes than were probably
intended. The practice of generating multiple instances from lists should
be used sparingly, and with due care given to what will happen if the list is
changed later.
## Selecting a Non-default Provider Configuration
As described in [the _providers_ guide](/docs/configuration/providers.html),
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:
```hcl
# default configuration
provider "google" {
region = "us-central1"
}
# alternative, aliased configuration
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 value must always be a literal provider name
followed by an alias name separated by a dot. 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 Customizations
The general lifecycle for resources is described above in the section
_Resource Behavior_. Some details of that behavior can be customized
using the special nested block `lifecycle` 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 Core cannot automatically activate
such features, so you must understand the constrants 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 between the current settings of a real infrastructure object
and plans to update the remote object to match configuration.
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_.
```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 to early for arbitrary expression evaluation.
## 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](https://www.terraform.io/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.
## 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).