diff --git a/website/docs/cli/code/index.html.md b/website/docs/cli/code/index.html.md index ba05a8940571..3c72083c4636 100644 --- a/website/docs/cli/code/index.html.md +++ b/website/docs/cli/code/index.html.md @@ -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. diff --git a/website/docs/commands/0.12upgrade.html.markdown b/website/docs/commands/0.12upgrade.html.markdown index 1136599b7711..0499e5eec4c4 100644 --- a/website/docs/commands/0.12upgrade.html.markdown +++ b/website/docs/commands/0.12upgrade.html.markdown @@ -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 diff --git a/website/docs/commands/console.html.markdown b/website/docs/commands/console.html.markdown index 511f8516462a..5e146c79181e 100644 --- a/website/docs/commands/console.html.markdown +++ b/website/docs/commands/console.html.markdown @@ -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). diff --git a/website/docs/commands/import.html.md b/website/docs/commands/import.html.md index 7ae3568181b4..c29fa90e2b3c 100644 --- a/website/docs/commands/import.html.md +++ b/website/docs/commands/import.html.md @@ -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: diff --git a/website/docs/commands/state/mv.html.md b/website/docs/commands/state/mv.html.md index 41118ed0f11b..ce5f7449c3c7 100644 --- a/website/docs/commands/state/mv.html.md +++ b/website/docs/commands/state/mv.html.md @@ -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: diff --git a/website/docs/commands/state/rm.html.md b/website/docs/commands/state/rm.html.md index f153320e6ca3..3930821dbc62 100644 --- a/website/docs/commands/state/rm.html.md +++ b/website/docs/commands/state/rm.html.md @@ -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: diff --git a/website/docs/commands/state/show.html.md b/website/docs/commands/state/show.html.md index da95b3822662..85f53d95ce75 100644 --- a/website/docs/commands/state/show.html.md +++ b/website/docs/commands/state/show.html.md @@ -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: diff --git a/website/docs/configuration-0-11/interpolation.html.md b/website/docs/configuration-0-11/interpolation.html.md index 8da16e154a8a..7178cd215e3a 100644 --- a/website/docs/configuration-0-11/interpolation.html.md +++ b/website/docs/configuration-0-11/interpolation.html.md @@ -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 diff --git a/website/docs/configuration/attr-as-blocks.html.md b/website/docs/configuration/attr-as-blocks.html.md index d9b95deacaa5..de4778675240 100644 --- a/website/docs/configuration/attr-as-blocks.html.md +++ b/website/docs/configuration/attr-as-blocks.html.md @@ -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 diff --git a/website/docs/configuration/blocks/modules/index.html.md b/website/docs/configuration/blocks/modules/index.html.md index bdb1a317beaa..e5f756102a30 100644 --- a/website/docs/configuration/blocks/modules/index.html.md +++ b/website/docs/configuration/blocks/modules/index.html.md @@ -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 diff --git a/website/docs/configuration/blocks/modules/syntax.html.md b/website/docs/configuration/blocks/modules/syntax.html.md new file mode 100644 index 000000000000..04d05b84ca71 --- /dev/null +++ b/website/docs/configuration/blocks/modules/syntax.html.md @@ -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..`. 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.[].` +instead, where `` 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. diff --git a/website/docs/configuration/blocks/providers/index.html.md b/website/docs/configuration/blocks/providers/index.html.md index a6790044a5dc..81ef9f094101 100644 --- a/website/docs/configuration/blocks/providers/index.html.md +++ b/website/docs/configuration/blocks/providers/index.html.md @@ -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. diff --git a/website/docs/configuration/blocks/resources/behavior.html.md b/website/docs/configuration/blocks/resources/behavior.html.md new file mode 100644 index 000000000000..d405c18dcf19 --- /dev/null +++ b/website/docs/configuration/blocks/resources/behavior.html.md @@ -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 `..` +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. + diff --git a/website/docs/configuration/blocks/resources/index.html.md b/website/docs/configuration/blocks/resources/index.html.md index f29d327e0074..a570b0da64de 100644 --- a/website/docs/configuration/blocks/resources/index.html.md +++ b/website/docs/configuration/blocks/resources/index.html.md @@ -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 diff --git a/website/docs/configuration/blocks/resources/syntax.html.md b/website/docs/configuration/blocks/resources/syntax.html.md new file mode 100644 index 000000000000..a9b369a03677 --- /dev/null +++ b/website/docs/configuration/blocks/resources/syntax.html.md @@ -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. diff --git a/website/docs/configuration/data-sources.html.md b/website/docs/configuration/data-sources.html.md index ec5185666373..7d8597b27c49 100644 --- a/website/docs/configuration/data-sources.html.md +++ b/website/docs/configuration/data-sources.html.md @@ -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 diff --git a/website/docs/configuration/dependency-lock.html.md b/website/docs/configuration/dependency-lock.html.md index 37c95068c44c..c65902ba167e 100644 --- a/website/docs/configuration/dependency-lock.html.md +++ b/website/docs/configuration/dependency-lock.html.md @@ -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" diff --git a/website/docs/configuration/expressions.html.md b/website/docs/configuration/expressions.html.md index c7f9a4000129..560b5c014293 100644 --- a/website/docs/configuration/expressions.html.md +++ b/website/docs/configuration/expressions.html.md @@ -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). - -_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. - -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. - -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). - -The rest of this page describes all of the features of Terraform's -expression syntax. - -## 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. - -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`: 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. - -### 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 - ` = ` 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: - -* `.` 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.` is the value of the - [input variable](./variables.html) of the given name. -* `local.` is the value of the - [local value](./locals.html) of the given name. -* `module..` is the value of the specified - [output value](./outputs.html) from a - [child module](./modules.html) called by the current module. -* `data..` 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: +To improve navigation, we've split the old Expressions page into several smaller +pages. -```hcl -resource "aws_instance" "example" { - ami = "ami-abc123" - instance_type = "t2.micro" - - ebs_block_device { - device_name = "sda2" - volume_size = 16 - } - ebs_block_device { - device_name = "sda3" - volume_size = 20 - } -} -``` - -The documentation for [`aws_instance`](/docs/providers/aws/r/instance.html) -lists all of the arguments and nested blocks supported for this resource type, -and also lists a number of attributes that are _exported_ by this resource -type. All of these different resource type schema constructs are available -for use in references, as follows: - -* The `ami` argument set in the configuration can be used elsewhere with - the reference expression `aws_instance.example.ami`. -* The `id` attribute exported by this resource type can be read using the - same syntax, giving `aws_instance.example.id`. -* The arguments of the `ebs_block_device` nested blocks can be accessed using - a [splat expression](#splat-expressions). For example, to obtain a list of - all of the `device_name` values, use - `aws_instance.example.ebs_block_device[*].device_name`. -* The nested blocks in this particular resource type do not have any exported - attributes, but if `ebs_block_device` were to have a documented `id` - attribute then a list of them could be accessed similarly as - `aws_instance.example.ebs_block_device[*].id`. -* Sometimes nested blocks are defined as taking a logical key to identify each - block, which serves a similar purpose as the resource's own name by providing - a convenient way to refer to that single block in expressions. If `aws_instance` - had a hypothetical nested block type `device` that accepted such a key, it - would look like this in configuration: - - ```hcl - device "foo" { - size = 2 - } - device "bar" { - size = 4 - } - ``` - - Arguments inside blocks with _keys_ can be accessed using index syntax, such - as `aws_instance.example.device["foo"].size`. - - To obtain a map of values of a particular argument for _labelled_ nested - block types, use a [`for` expression](#for-expressions): - `{for k, device in aws_instance.example.device : k => device.size}`. - -When a resource has the -[`count`](https://www.terraform.io/docs/configuration/resources.html#count-multiple-resource-instances-by-count) -argument set, the resource itself becomes a _list_ of instance objects rather than -a single object. In that case, access the attributes of the instances using -either [splat expressions](#splat-expressions) or index syntax: - -* `aws_instance.example[*].id` returns a list of all of the ids of each of the - instances. -* `aws_instance.example[0].id` returns just the id of the first instance. - -When a resource has the -[`for_each`](/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings) -argument set, the resource itself becomes a _map_ of instance objects rather than -a single object, and attributes of instances must be specified by key, or can -be accessed using a [`for` expression](#for-expressions). - -* `aws_instance.example["a"].id` returns the id of the "a"-keyed resource. -* `[for value in aws_instance.example: value.id]` returns a list of all of the ids - of each of the instances. - -Note that unlike `count`, splat expressions are _not_ directly applicable to resources managed with `for_each`, as splat expressions are for lists only. You may apply a splat expression to values in a map like so: - -* `values(aws_instance.example)[*].id` - -### Values Not Yet Known - -When Terraform is planning a set of changes that will apply your configuration, -some resource attribute values cannot be populated immediately because their -values are decided dynamically by the remote system. For example, if a -particular remote object type is assigned a generated unique id on creation, -Terraform cannot predict the value of this id until the object has been created. - -To allow expressions to still be evaluated during the plan phase, Terraform -uses special "unknown value" placeholders for these results. In most cases you -don't need to do anything special to deal with these, since the Terraform -language automatically handles unknown values during expressions, so that -for example adding a known value to an unknown value automatically produces -an unknown value as the result. - -However, there are some situations where unknown values _do_ have a significant -effect: - -* The `count` meta-argument for resources cannot be unknown, since it must - be evaluated during the plan phase to determine how many instances are to - be created. - -* If unknown values are used in the configuration of a data resource, that - data resource cannot be read during the plan phase and so it will be deferred - until the apply phase. In this case, the results of the data resource will - _also_ be unknown values. - -* If an unknown value is assigned to an argument inside a `module` block, - any references to the corresponding input variable within the child module - will use that unknown value. - -* If an unknown value is used in the `value` argument of an output value, - any references to that output value in the parent module will use that - unknown value. - -* Terraform will attempt to validate that unknown values are of suitable - types where possible, but incorrect use of such values may not be detected - until the apply phase, causing the apply to fail. - -Unknown values appear in the `terraform plan` output as `(not yet known)`. - -## Arithmetic and Logical Operators - -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. `||` +## Types and Values, Literal Expressions, Indices and Attributes -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`. +Terraform's types are `string`, `number`, `bool`, `list`, `tuple`, `map`, +`object`, and `null`. -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. +This information has moved to +[Types and Values](/docs/configuration/expressions/types.html). -### Arithmetic Operators + + + + + + -The arithmetic operators all expect number values and produce number values -as results: +## References to Named Values (Resource Attributes, Variables, etc.) -* `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`. +You can refer to certain values by name, like `var.some_variable` or +`aws_instance.example.ami`. -### Equality Operators +This information has moved to +[References to Values](/docs/configuration/expressions/references.html). -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 +## Arithmetic and Logical Operators -The logical operators all expect bool values and produce bool values as results. +Operators are expressions that transform other expressions, like adding two +numbers (`+`) or comparing two values to get a bool (`==`, `>=`, etc.). -* `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 syntax of a conditional expression is as follows: - -```hcl -condition ? true_val : false_val -``` +The `condition ? true_val : false_val` expression chooses between two +expressions based on a bool condition. -If `condition` is `true` then the result is `true_val`. If `condition` is -`false` then the result is `false_val`. +This information has moved to +[Conditional Expressions](/docs/configuration/expressions/conditionals.html). -A common use of conditional expressions is to define defaults to replace -invalid values: - -``` -var.a != "" ? var.a : "default-a" -``` - -If `var.a` is an empty string then the result is `"default-a"`, but otherwise -it is the actual value of `var.a`. - -Any of the equality, comparison, and logical operators can be used to define -the condition. The two result values may be of any type, but they must both -be of the _same_ type so that Terraform can determine what type the whole -conditional expression will return without knowing the condition value. + + ## Function Calls -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: - -```hcl -(, ) -``` - -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. +Terraform's functions can be called like `function_name(arg1, arg2)`. -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]...) -``` +This information has moved to +[Function Calls](/docs/configuration/expressions/function-calls.html). -The expansion symbol is three periods (`...`), not a Unicode ellipsis character -(`…`). Expansion is a special syntax that is only available in function calls. - -### Available Functions - -For a full list of available functions, see -[the function reference](./functions.html). + ## `for` Expressions -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: +Expressions like `[for s in var.list : upper(s)]` can transform a complex type +value into another complex type value. -``` -[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: +This information has moved to +[For Expressions](/docs/configuration/expressions/for.html). -``` -{for s in var.list : substr(s, 0, 1) => s... if s != ""} -``` - -For expressions are particularly useful when combined with other language -features to combine collections together in various ways. For example, -the following two patterns are commonly used when constructing map values -to use with [resource `for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings): - -* Transform a multi-level nested structure into a flat list by - [using nested `for` expressions with the `flatten` function](./functions/flatten.html#flattening-nested-structures-for-for_each). -* Produce an exhaustive list of combinations of elements from two or more - collections by - [using the `setproduct` function inside a `for` expression](./functions/setproduct.html#finding-combinations-for-for_each). + + ## Splat Expressions -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] -``` + + -This is equivalent to the following _splat expression:_ +## `dynamic` Blocks -```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 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 above expression is equivalent to the following `for` expression: +This information has moved to +[Dynamic Blocks](/docs/configuration/expressions/dynamic-blocks.html). -```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. +## String Literals and String Templates -For example, `var.single_object[*].id` is equivalent to `[var.single_object][*].id`, -or effectively `[var.single_object.id]`. This behavior is not interesting in most cases, -but it is particularly useful when referring to resources that may or may -not have `count` set, and thus may or may not produce a tuple value: - -```hcl -aws_instance.example[*].id -``` - -The above will produce a list of ids whether `aws_instance.example` has -`count` set or not, avoiding the need to revise various other expressions -in the configuration when a particular resource switches to and from -having `count` set. - -### Legacy (Attribute-only) Splat Expressions - -An older variant of the splat expression is available for compatibility with -code written in older versions of the Terraform language. This is a less useful -version of the splat expression, and should be avoided in new configurations. - -An "attribute-only" splat expression is indicated by the sequence `.*` (instead -of `[*]`): - -``` -var.list.*.interfaces[0].name -``` - -This form has a subtly different behavior, equivalent to the following -`for` expression: - -``` -[for o in var.list : o.interfaces][0].name -``` - -Notice that with the attribute-only splat expression the index operation -`[0]` is applied to the result of the iteration, rather than as part of -the iteration itself. - -## `dynamic` blocks - -Within top-level block constructs like resources, expressions can usually be -used only when assigning a value to an argument using the `name = expression` -form. This covers many uses, but some resource types include repeatable _nested -blocks_ in their arguments, which do not accept expressions: - -```hcl -resource "aws_elastic_beanstalk_environment" "tfenvtest" { - name = "tf-test-name" # can use expressions here - - setting { - # but the "setting" block is always a literal block - } -} -``` - -You can dynamically construct repeatable nested blocks like `setting` using a -special `dynamic` block type, which is supported inside `resource`, `data`, -`provider`, and `provisioner` blocks: - -```hcl -resource "aws_elastic_beanstalk_environment" "tfenvtest" { - name = "tf-test-name" - application = "${aws_elastic_beanstalk_application.tftest.name}" - solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6" - - dynamic "setting" { - for_each = var.settings - content { - namespace = setting.value["namespace"] - name = setting.value["name"] - value = setting.value["value"] - } - } -} -``` - -A `dynamic` block acts much like a `for` expression, but produces nested blocks -instead of a complex typed value. It iterates over a given complex value, and -generates a nested block for each element of that complex value. - -- The label of the dynamic block (`"setting"` in the example above) specifies - what kind of nested block to generate. -- The `for_each` argument provides the complex value to iterate over. -- The `iterator` argument (optional) sets the name of a temporary variable - that represents the current element of the complex value. If omitted, the name - of the variable defaults to the label of the `dynamic` block (`"setting"` in - the example above). -- The `labels` argument (optional) is a list of strings that specifies the block - labels, in order, to use for each generated block. You can use the temporary - iterator variable in this value. -- The nested `content` block defines the body of each generated block. You can - use the temporary iterator variable inside this block. - -Since the `for_each` argument accepts any collection or structural value, -you can use a `for` expression or splat expression to transform an existing -collection. - -The iterator object (`setting` in the example above) has two attributes: - -* `key` is the map key or list element index for the current element. If the - `for_each` expression produces a _set_ value then `key` is identical to - `value` and should not be used. -* `value` is the value of the current element. - -A `dynamic` block can only generate arguments that belong to the resource type, -data source, provider or provisioner being configured. It is _not_ possible -to generate meta-argument blocks such as `lifecycle` and `provisioner` -blocks, since Terraform must process these before it is safe to evaluate -expressions. - -The `for_each` value must be a map or set with one element per desired -nested block. If you need to declare resource instances based on a nested -data structure or combinations of elements from multiple data structures you -can use Terraform expressions and functions to derive a suitable value. -For some common examples of such situations, see the -[`flatten`](/docs/configuration/functions/flatten.html) -and -[`setproduct`](/docs/configuration/functions/setproduct.html) -functions. - -### Best Practices for `dynamic` Blocks - -Overuse of `dynamic` blocks can make configuration hard to read and maintain, so -we recommend using them only when you need to hide details in order to build a -clean user interface for a re-usable module. Always write nested blocks out -literally where possible. - -## String Literals - -The Terraform language has two different syntaxes for string literals. The -most common is to delimit the string with quote characters (`"`), like -`"hello"`. In quoted strings, the backslash character serves as an escape -sequence, with the following characters selecting the escape behavior: - -| Sequence | Replacement | -| ------------ | ----------------------------------------------------------------------------- | -| `\n` | Newline | -| `\r` | Carriage Return | -| `\t` | Tab | -| `\"` | Literal quote (without terminating the string) | -| `\\` | Literal backslash | -| `\uNNNN` | Unicode character from the basic multilingual plane (NNNN is four hex digits) | -| `\UNNNNNNNN` | Unicode character from supplementary planes (NNNNNNNN is eight hex digits) | - -The alternative syntax for string literals is the so-called "heredoc" style, -inspired by Unix shell languages. This style allows multi-line strings to -be expressed more clearly by using a custom delimiter word on a line of its -own to close the string: - -```hcl -<`/`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 in ` / `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 - <` 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). diff --git a/website/docs/configuration/expressions/function-calls.html.md b/website/docs/configuration/expressions/function-calls.html.md new file mode 100644 index 000000000000..771b75f72420 --- /dev/null +++ b/website/docs/configuration/expressions/function-calls.html.md @@ -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 +(, ) +``` + +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). + diff --git a/website/docs/configuration/expressions/index.html.md b/website/docs/configuration/expressions/index.html.md index 9bfb15e28999..0de96564c615 100644 --- a/website/docs/configuration/expressions/index.html.md +++ b/website/docs/configuration/expressions/index.html.md @@ -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 ` ? : ` 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. diff --git a/website/docs/configuration/expressions/operators.html.md b/website/docs/configuration/expressions/operators.html.md new file mode 100644 index 000000000000..37906831c217 --- /dev/null +++ b/website/docs/configuration/expressions/operators.html.md @@ -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`. diff --git a/website/docs/configuration/expressions/references.html.md b/website/docs/configuration/expressions/references.html.md new file mode 100644 index 000000000000..a1cb91781033 --- /dev/null +++ b/website/docs/configuration/expressions/references.html.md @@ -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 + +`.` 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.` is the value of the [input variable](/docs/configuration/variables.html) of the given name. + +### Local Values + +`local.` is the value of the [local value](/docs/configuration/locals.html) of the given name. + +### Child Module Outputs + +* `module..` 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..` 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)`. diff --git a/website/docs/configuration/expressions/splat.html.md b/website/docs/configuration/expressions/splat.html.md new file mode 100644 index 000000000000..d0fa27f0856e --- /dev/null +++ b/website/docs/configuration/expressions/splat.html.md @@ -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. diff --git a/website/docs/configuration/expressions/strings.html.md b/website/docs/configuration/expressions/strings.html.md new file mode 100644 index 000000000000..4841a39e78cd --- /dev/null +++ b/website/docs/configuration/expressions/strings.html.md @@ -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 +<}`/`%{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 in }` / `%{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 + < = ` 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 + diff --git a/website/docs/configuration/files/index.html.md b/website/docs/configuration/files/index.html.md index 93b664771f33..9051f8705dbd 100644 --- a/website/docs/configuration/files/index.html.md +++ b/website/docs/configuration/files/index.html.md @@ -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 diff --git a/website/docs/configuration/functions.html.md b/website/docs/configuration/functions.html.md index edfa0d44cea9..6ba460c622e2 100644 --- a/website/docs/configuration/functions.html.md +++ b/website/docs/configuration/functions.html.md @@ -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 diff --git a/website/docs/configuration/functions/cidrsubnets.html.md b/website/docs/configuration/functions/cidrsubnets.html.md index 37f665446c27..66268f8ffead 100644 --- a/website/docs/configuration/functions/cidrsubnets.html.md +++ b/website/docs/configuration/functions/cidrsubnets.html.md @@ -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: ``` diff --git a/website/docs/configuration/functions/csvdecode.html.md b/website/docs/configuration/functions/csvdecode.html.md index 2f36238616c8..acd0e50a6ee8 100644 --- a/website/docs/configuration/functions/csvdecode.html.md +++ b/website/docs/configuration/functions/csvdecode.html.md @@ -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 diff --git a/website/docs/configuration/functions/fileset.html.md b/website/docs/configuration/functions/fileset.html.md index 46d167445aba..82ac4773da9e 100644 --- a/website/docs/configuration/functions/fileset.html.md +++ b/website/docs/configuration/functions/fileset.html.md @@ -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" { diff --git a/website/docs/configuration/functions/flatten.html.md b/website/docs/configuration/functions/flatten.html.md index 80ba1166b6d1..90da0079c922 100644 --- a/website/docs/configuration/functions/flatten.html.md +++ b/website/docs/configuration/functions/flatten.html.md @@ -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. diff --git a/website/docs/configuration/functions/jsondecode.html.md b/website/docs/configuration/functions/jsondecode.html.md index c3e7ffe4e4ff..b09f42cbb6d7 100644 --- a/website/docs/configuration/functions/jsondecode.html.md +++ b/website/docs/configuration/functions/jsondecode.html.md @@ -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 | diff --git a/website/docs/configuration/functions/jsonencode.html.md b/website/docs/configuration/functions/jsonencode.html.md index 2056f521a764..90896acf1826 100644 --- a/website/docs/configuration/functions/jsonencode.html.md +++ b/website/docs/configuration/functions/jsonencode.html.md @@ -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 | diff --git a/website/docs/configuration/functions/setproduct.html.md b/website/docs/configuration/functions/setproduct.html.md index 73822c8a46fa..f5d60faac551 100644 --- a/website/docs/configuration/functions/setproduct.html.md +++ b/website/docs/configuration/functions/setproduct.html.md @@ -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. diff --git a/website/docs/configuration/functions/templatefile.html.md b/website/docs/configuration/functions/templatefile.html.md index 1bc70350bfc6..44a4b9e79f67 100644 --- a/website/docs/configuration/functions/templatefile.html.md +++ b/website/docs/configuration/functions/templatefile.html.md @@ -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"]} diff --git a/website/docs/configuration/functions/timestamp.html.md b/website/docs/configuration/functions/timestamp.html.md index d4b75e7130b6..c17527ae2642 100644 --- a/website/docs/configuration/functions/timestamp.html.md +++ b/website/docs/configuration/functions/timestamp.html.md @@ -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/). diff --git a/website/docs/configuration/functions/uuid.html.md b/website/docs/configuration/functions/uuid.html.md index 0b481e0368b1..40ef135d9829 100644 --- a/website/docs/configuration/functions/uuid.html.md +++ b/website/docs/configuration/functions/uuid.html.md @@ -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 diff --git a/website/docs/configuration/functions/yamldecode.html.md b/website/docs/configuration/functions/yamldecode.html.md index 6e5c72745140..600c6312ec80 100644 --- a/website/docs/configuration/functions/yamldecode.html.md +++ b/website/docs/configuration/functions/yamldecode.html.md @@ -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 | diff --git a/website/docs/configuration/functions/yamlencode.html.md b/website/docs/configuration/functions/yamlencode.html.md index fe5532e1b3b2..aa128ea22219 100644 --- a/website/docs/configuration/functions/yamlencode.html.md +++ b/website/docs/configuration/functions/yamlencode.html.md @@ -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 | diff --git a/website/docs/configuration/index.html.md b/website/docs/configuration/index.html.md index 50d0148a5eea..1f60b96a25b2 100644 --- a/website/docs/configuration/index.html.md +++ b/website/docs/configuration/index.html.md @@ -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. diff --git a/website/docs/configuration/locals.html.md b/website/docs/configuration/locals.html.md index b6b876a31a99..5dd39e8de691 100644 --- a/website/docs/configuration/locals.html.md +++ b/website/docs/configuration/locals.html.md @@ -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.`. +[expressions](/docs/configuration/expressions/index.html) as `local.`. -> **Note:** Local values are _created_ by a `locals` block (plural), but you _reference_ them as attributes on an object named `local` (singular). Make sure diff --git a/website/docs/configuration/meta-arguments/count.html.md b/website/docs/configuration/meta-arguments/count.html.md new file mode 100644 index 000000000000..fa2125325676 --- /dev/null +++ b/website/docs/configuration/meta-arguments/count.html.md @@ -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`. + +- `.` or `module.` (for example, `aws_instance.server`) refers to the resource block. +- `.[]` or `module.[]` (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.[]` 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. diff --git a/website/docs/configuration/meta-arguments/depends_on.html.md b/website/docs/configuration/meta-arguments/depends_on.html.md new file mode 100644 index 000000000000..fb8a35cc68a0 --- /dev/null +++ b/website/docs/configuration/meta-arguments/depends_on.html.md @@ -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. + diff --git a/website/docs/configuration/meta-arguments/for_each.html.md b/website/docs/configuration/meta-arguments/for_each.html.md new file mode 100644 index 000000000000..a65cc7f4f9c8 --- /dev/null +++ b/website/docs/configuration/meta-arguments/for_each.html.md @@ -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`. + +- `.` or `module.` (for example, `azurerm_resource_group.rg`) refers to the block. +- `.[]` or `module.[]` (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.[]` 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) +} +``` diff --git a/website/docs/configuration/meta-arguments/lifecycle.html.md b/website/docs/configuration/meta-arguments/lifecycle.html.md new file mode 100644 index 000000000000..6c9be168c78b --- /dev/null +++ b/website/docs/configuration/meta-arguments/lifecycle.html.md @@ -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. diff --git a/website/docs/configuration/meta-arguments/module-providers.html.md b/website/docs/configuration/meta-arguments/module-providers.html.md new file mode 100644 index 000000000000..b5b1faca6e86 --- /dev/null +++ b/website/docs/configuration/meta-arguments/module-providers.html.md @@ -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 `.` 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). diff --git a/website/docs/configuration/meta-arguments/resource-provider.html.md b/website/docs/configuration/meta-arguments/resource-provider.html.md new file mode 100644 index 000000000000..37a84e8d66f5 --- /dev/null +++ b/website/docs/configuration/meta-arguments/resource-provider.html.md @@ -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 `.` 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 `.` 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. + diff --git a/website/docs/configuration/modules.html.md b/website/docs/configuration/modules.html.md index 767b211c6d36..4af54dcc7eb9 100644 --- a/website/docs/configuration/modules.html.md +++ b/website/docs/configuration/modules.html.md @@ -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 _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. + -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: + + + + + + -```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..`. If a module was called -with `count` or `for_each` ([see below][inpage-multiple]), its resource -addresses must be prefixed with `module.[].` instead, where -`` 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 with 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). diff --git a/website/docs/configuration/outputs.html.md b/website/docs/configuration/outputs.html.md index f4711b08d129..8e06bfa17c6a 100644 --- a/website/docs/configuration/outputs.html.md +++ b/website/docs/configuration/outputs.html.md @@ -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 diff --git a/website/docs/configuration/providers.html.md b/website/docs/configuration/providers.html.md index 87740a205039..30a5c3cea47c 100644 --- a/website/docs/configuration/providers.html.md +++ b/website/docs/configuration/providers.html.md @@ -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. diff --git a/website/docs/configuration/resources.html.md b/website/docs/configuration/resources.html.md index e66b12fdf127..4c3942c5c7ea 100644 --- a/website/docs/configuration/resources.html.md +++ b/website/docs/configuration/resources.html.md @@ -1,760 +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. + + + + + + + -_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. + + + + -```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. + -## 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 + + + + + -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: + + + + + -- [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 + -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.) + -### 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. + -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 `..` -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`. - -- `.` (for example, `aws_instance.server`) refers to the resource block. -- `.[]` (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. 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`. - -- `.` (for example, `azurerm_resource_group.rg`) refers to the resource block. -- `.[]` (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 `.` 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 `.` 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). diff --git a/website/docs/configuration/syntax-json.html.md b/website/docs/configuration/syntax-json.html.md index ec5cb4700f2a..787c232f1346 100644 --- a/website/docs/configuration/syntax-json.html.md +++ b/website/docs/configuration/syntax-json.html.md @@ -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, diff --git a/website/docs/configuration/syntax.html.md b/website/docs/configuration/syntax.html.md index a9f9fba6970c..eed3769e110f 100644 --- a/website/docs/configuration/syntax.html.md +++ b/website/docs/configuration/syntax.html.md @@ -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 diff --git a/website/docs/configuration/terraform.html.md b/website/docs/configuration/terraform.html.md index 75e532f33618..b6f1ffd1dc46 100644 --- a/website/docs/configuration/terraform.html.md +++ b/website/docs/configuration/terraform.html.md @@ -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. diff --git a/website/docs/configuration/types.html.md b/website/docs/configuration/types.html.md index 8cc42e8d3ede..441cdc6fbf82 100644 --- a/website/docs/configuration/types.html.md +++ b/website/docs/configuration/types.html.md @@ -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. diff --git a/website/docs/configuration/variables.html.md b/website/docs/configuration/variables.html.md index 5acb4b49d809..6e95c03ac9fd 100644 --- a/website/docs/configuration/variables.html.md +++ b/website/docs/configuration/variables.html.md @@ -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.`, +within [expressions](/docs/configuration/expressions/index.html) as `var.`, where `` 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 diff --git a/website/docs/configuration/version-constraints.html.md b/website/docs/configuration/version-constraints.html.md index 6178fd960b92..0c4ff6edd4c5 100644 --- a/website/docs/configuration/version-constraints.html.md +++ b/website/docs/configuration/version-constraints.html.md @@ -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. diff --git a/website/docs/modules/index.html.markdown b/website/docs/modules/index.html.markdown index 306d533693bb..af6d608bf257 100644 --- a/website/docs/modules/index.html.markdown +++ b/website/docs/modules/index.html.markdown @@ -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/ -│   ├── .../ -``` diff --git a/website/docs/modules/providers.html.md b/website/docs/modules/providers.html.md new file mode 100644 index 000000000000..dee5d76429ca --- /dev/null +++ b/website/docs/modules/providers.html.md @@ -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 + } +} +``` diff --git a/website/docs/modules/publish.html.markdown b/website/docs/modules/publish.html.markdown index 116b863d57ef..b0eebf367eb7 100644 --- a/website/docs/modules/publish.html.markdown +++ b/website/docs/modules/publish.html.markdown @@ -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. diff --git a/website/docs/modules/sources.html.markdown b/website/docs/modules/sources.html.markdown index dace869bfd8d..528d5f83ee51 100644 --- a/website/docs/modules/sources.html.markdown +++ b/website/docs/modules/sources.html.markdown @@ -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. diff --git a/website/docs/modules/structure.html.md b/website/docs/modules/structure.html.md new file mode 100644 index 000000000000..e3b0225b00fa --- /dev/null +++ b/website/docs/modules/structure.html.md @@ -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/ +│   ├── .../ +``` diff --git a/website/docs/registry/modules/publish.html.md b/website/docs/registry/modules/publish.html.md index 9c343284e28a..7b997feca06c 100644 --- a/website/docs/registry/modules/publish.html.md +++ b/website/docs/registry/modules/publish.html.md @@ -45,7 +45,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. diff --git a/website/docs/registry/modules/use.html.md b/website/docs/registry/modules/use.html.md index dcd60211273c..89d48d83ccf6 100644 --- a/website/docs/registry/modules/use.html.md +++ b/website/docs/registry/modules/use.html.md @@ -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 diff --git a/website/docs/registry/private.html.md b/website/docs/registry/private.html.md index 80a8b7502a09..65504f101bc4 100644 --- a/website/docs/registry/private.html.md +++ b/website/docs/registry/private.html.md @@ -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. diff --git a/website/layouts/language.erb b/website/layouts/language.erb index 19660645412d..85d09b9026a5 100644 --- a/website/layouts/language.erb +++ b/website/layouts/language.erb @@ -50,7 +50,36 @@
  • - Resource Blocks + Resource Blocks +
  • + +
  • + Resource Behavior +
  • + +
  • + Meta-Arguments +
  • @@ -216,13 +245,34 @@
  • - Module Blocks + Module Blocks
  • Module Sources
  • +
  • + Meta-Arguments + +
  • +
  • Module Development