diff --git a/website/docs/configuration/data-sources.html.md b/website/docs/configuration/data-sources.html.md index 874fb1a78..6feec8697 100644 --- a/website/docs/configuration/data-sources.html.md +++ b/website/docs/configuration/data-sources.html.md @@ -13,8 +13,8 @@ in Terraform configuration. Use of data sources allows a Terraform configuration to make use of information defined outside of Terraform, or defined by another separate Terraform configuration. -Each [provider](/docs/configuration/providers.html) make offer data sources -alongside its set of [resource types](/docs/configuration/resources.html#resource-types-and-arguments). +Each [provider](./providers.html) may offer data sources +alongside its set of [resource types](./resources.html#resource-types-and-arguments). ## Using Data Sources @@ -60,14 +60,14 @@ Each data resource is associated with a single data source, which determines the kind of object (or objects) it reads and what query constraint arguments are available. -Each data source in turn belongs to a [provider](/docs/configuration/providers.html), +Each data source in turn belongs to a [provider](./providers.html), which is a plugin for Terraform that offers a collection of resource types and data sources that most often belong to a single cloud or on-premises 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](/docs/configuration/expressions.html) and other dynamic +use of [expressions](./expressions.html) and other dynamic Terraform language features. However, there are some "meta-arguments" that are defined by Terraform itself @@ -109,7 +109,7 @@ operation, and is re-calulated each time a new plan is created. ## Data Resource Dependencies Data resources have the same dependency resolution behavior -[as defined for managed resources](/docs/configuration/resources.html#resource-dependencies). +[as defined for managed resources](./resources.html#resource-dependencies). In particular, the `depends_on` meta-argument is also available within `data` blocks, with the same meaning and syntax as in `resource` blocks. @@ -125,7 +125,7 @@ resources. ## Multiple Resource Instances -Data resources support [the `count` meta-argument](/docs/configuration/resources.html#multiple-resource-instances) +Data resources support [the `count` meta-argument](./resources.html#count-multiple-resource-instances) as defined for managed resources, with the same syntax and behavior. As with managed resources, when `count` is present it is important to @@ -135,7 +135,7 @@ own variant of the constraint arguments, producing an indexed result. ## Selecting a Non-default Provider Configuration -Data resources support [the `providers` meta-argument](/docs/configuration/resources.html#selecting-a-non-default-provider-configuration) +Data resources support [the `providers` meta-argument](./resources.html#provider-selecting-a-non-default-provider-configuration) as defined for managed resources, with the same syntax and behavior. ## Lifecycle Customizations @@ -167,8 +167,8 @@ data "aws_ami" "web" { ## Description -The `data` block creates a data instance of the given `TYPE` (first -parameter) and `NAME` (second parameter). The combination of the type +The `data` block creates a data instance of the given _type_ (first +block label) and _name_ (second block label). The combination of the type and name must be unique. Within the block (the `{ }`) is configuration for the data instance. The @@ -176,24 +176,27 @@ configuration is dependent on the type, and is documented for each data source in the [providers section](/docs/providers/index.html). Each data instance will export one or more attributes, which can be -interpolated into other resources using variables of the form -`data.TYPE.NAME.ATTR`. For example: +used in other resources as reference expressions of the form +`data...`. For example: ```hcl resource "aws_instance" "web" { - ami = "${data.aws_ami.web.id}" + ami = data.aws_ami.web.id instance_type = "t1.micro" } ``` -### Meta-parameters +## Meta-Arguments -As data sources are essentially a read only subset of resources they also support the same [meta-parameters](https://www.terraform.io/docs/configuration/resources.html#meta-parameters) of resources except for the [`lifecycle` configuration block](https://www.terraform.io/docs/configuration/resources.html#lifecycle). +As data sources are essentially a read only subset of resources, they also +support the same [meta-arguments](./resources.html#meta-arguments) of resources +with the exception of the +[`lifecycle` configuration block](./resources.html#lifecycle-lifecycle-customizations). -## Multiple Provider Instances +### Multiple Provider Instances -Similarly to [resources](/docs/configuration/resources.html), the -`provider` meta-parameter can be used where a configuration has +Similarly to [resources](./resources.html), the +`provider` meta-argument can be used where a configuration has multiple aliased instances of the same provider: ```hcl @@ -204,10 +207,10 @@ data "aws_ami" "web" { } ``` -See the ["Multiple Provider Instances"](/docs/configuration/resources.html#multiple-provider-instances) documentation for resources +See [Resources: Multiple Provider Instances](./resources.html#provider-selecting-a-non-default-provider-configuration) for more information. -## Data Source Lifecycle +### Data Source Lifecycle If the arguments of a data instance contain no references to computed values, such as attributes of resources that have not yet been created, then the diff --git a/website/docs/configuration/expressions.html.md b/website/docs/configuration/expressions.html.md index 15c880443..55465f8fc 100644 --- a/website/docs/configuration/expressions.html.md +++ b/website/docs/configuration/expressions.html.md @@ -16,14 +16,17 @@ 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 place restrictions on which expression constructs are allowed, -such as requiring a literal value of a particular type, or forbidding -references to resource attributes. The other pages in this section describe -the contexts where expressions may be used and which expression features -are allowed in each case. +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. Each language feature's documentation +describes any restrictions it places on expressions. -The following sections describe all of the features of the configuration -syntax. +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 @@ -31,180 +34,186 @@ 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. -A _literal expression_ is an expression that directly represents a particular -constant value. - -Expressions are most commonly used to set the values of arguments to resources -and to child modules. In these cases, the argument itself has an expected -type and so the given expression must produce a value of that type. Where -possible, Terraform will automatically convert 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. - -This section describes all of the value types in the Terraform language, and -the literal expression syntax that can be used to create values of each -type. - -### Primitive Types - -A _primitive_ type is a simple type that isn't made from any other types. -The available primitive types in the Terraform language are: - -* `string`: a sequence of Unicode characters representing some text, such - as `"hello"`. +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 such as `6.283185`. - + 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}`. -The Terraform language will automatically convert `number` and `bool` values -to `string` values when needed, and vice-versa as long as the string contains -a valid representation of a number of boolean value. +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 -### Collection Types +## Literal Expressions -A _collection_ type allows multiple values of another type to be grouped -together as a single value. The type of value _within_ a collection is called -its _element type_, and all collection types must have an element type. +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: -For example, the type `list(string)` means "list of strings", which is a -different type than `list(number)`, a list of numbers. All elements of a -collection must always be of the same type. +* 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]`. -The three _collection type kinds_ in the Terraform language are: + 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: -* `list(...)`: a sequence of values identified by consecutive whole numbers - starting with zero. -* `map(...)`: a collection of values where each is identified by a string label. -* `set(...)`: a collection of unique values that do not have any secondary - identifiers or ordering. + ```hcl + { + name = "John" + age = 52 + } + ``` -There is no direct syntax for creating collection type values, but the -Terraform language can automatically convert a structural type value (as -defined in the next section) to a similar collection type as long as all -of its elements can be converted to the required element type. + 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"`. -### Structural Types +## Indices and Attributes -A _structural_ type is another way to combine multiple values into a single -value, but structural types allow each value to be of a distinct type. +[inpage-index]: #indices-and-attributes -The two _structural type kinds_ in the Terraform language are: +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. -* `object(...)`: has named attributes that each have their own type. -* `tuple(...)`: has a sequence of elements identified by consecutive whole - numbers starting with zero, where each element has its own type. +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"]`). -An object type value can be created using an object expression: +## References to Named Values -```hcl -{ - name = "John" - age = 52 -} -``` +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 type of the object value created by this expression is -`object({name=string,age=number})`. In most cases it is not important to know -the exact type of an object value, since the Terraform language automatically -checks and converts object types when needed. +The following named values are available: -Similarly, a tuple type value can be created using a tuple expression: +* `.` 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]. -```hcl -["a", 15, true] -``` - -The type of the tuple value created by this expression is -`tuple([string, number, bool])`. Tuple values are rarely used directly in -the Terraform language, and are instead usually converted immediately to -list values by converting all of the elements to the same type. - -Terraform will automatically convert object values to map values when required, -so usually object and map values can be used interchangably as long as their -contained values are of suitable types. - -Likewise, Terraform will automatically convert tuple values to list values -when required, and so tuple and list values can be used interchangably in -most cases too. - -Because of these automatic conversions, it is common to not make a strong -distinction between object and map or tuple and list in everyday discussion -of the Terraform language. The Terraform documentation usually discusses the -object and tuple types only in rare cases where it is important to distinguish -them from the map and list types. - -## References to Named Objects - -A number of different named objects can be accessed from Terraform expressions. -For example, resources are available in expressions as named objects that have -an object value corresponding to the schema of their resource type, accessed by -a dot-separated sequence of names like `aws_instance.example`. - -The following named objects are available: - -* `TYPE.NAME` is an object representing a - [managed resource](/docs/configuration/resources.html) of the given type - and name. If the resource has the `count` argument set, the value is - a list of objects representing its instances. Any named object that does - not match one of the other patterns listed below will be interpreted by - Terraform as a reference to a managed resource. - -* `var.NAME` is the value of the - [input variable](/docs/configuration/variables.html) of the given name. - -* `local.NAME` is the value of the - [local value](/docs/configuration/locals.html) of the given name. - -* `module.MOD_NAME.OUTPUT_NAME` is the value of the - [output value](/docs/configuration/outputs.html) of the given name from the - [child module call](/docs/configuration/modules.html) of the given name. - -* `data.SOURCE.NAME` is an object representing a - [data resource](/docs/configuration/data-sources.html) of the given data - source and name. If the resource has the `count` argument set, the value is - a list of objects representing its instances. - -* `path.` is the prefix of a set of named objects that are filesystem - paths of various kinds: - - * `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. + 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. +* `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. +* `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). -Terraform analyses the block bodies of constructs such as resources and module -calls to automatically infer dependencies between objects from the use of -some of these reference types in expressions. For example, an object with an -argument expression that refers to a managed resource creates and implicit -dependency between that object and the resource. +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). -The first name in each of these dot-separated sequence is called a -_variable_, but do not confuse this with the idea of an -[input variable](/docs/configuration/variables.html), which acts as a -customization parameter for a module. Input variables are often referred -to as just "variables" for brevity when the meaning is clear from context, -but due to this other meaning of "variable" in the context of expressions -this documentation page will always refer to input variables by their full -name. +### Named Values and Dependencies -Additional expression variables are available in specific contexts. These are -described in other documentation sections describing those specific features. +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. + +### 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. +(For example, the body of a resource block where `count` is set can use a +special `count.index` value.) These local names are described in the +documentation for the specific contexts where they appear. + +-> **Note:** Local named values 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. ### Values Not Yet Known @@ -247,25 +256,11 @@ effect: Unknown values appear in the `terraform plan` output as `(not yet known)`. -## Indices and Attributes - -Elements of list-, tuple-, map-, and object-typed 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. - -Object attributes with names that are valid identifiers can also be accessed -using the dot-separated attribute notation, like `local.object.attrname`. This -syntax is also allowed for accessing map elements with keys that are valid -identifiers, but we recommend using the square-bracket index notation -(`local.map["keyname"]`) when a map contains arbitrary user-specified keys, as -opposed to an object with a fixed set of attributes defined by a schema. - ## 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 simply transform a single given value 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 @@ -278,16 +273,15 @@ 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 -according to a default order of operations: +in the following order of operations: -| Level | Operators | -| ----- | -------------------- | -| 6 | `*`, `/`, `%` | -| 5 | `+`, `-` | -| 4 | `>`, `>=`, `<`, `<=` | -| 3 | `==`, `!=` | -| 2 | `&&` | -| 1 | `||` | +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 @@ -342,8 +336,8 @@ The logical operators all expect bool values and produce bool values as results. ## Conditional Expressions -A _conditional expression_ allows the selection of one of two values based -on whether another bool expression is `true` or `false`. +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: @@ -372,18 +366,17 @@ conditional expression will return without knowing the condition value. ## Function Calls The Terraform language has a number of -[built-in functions](/docs/configuration/functions.html) that can be used +[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 -function_name(argument1, argument2) +(, ) ``` -The `function_name` specifies which function to call. Each defined function has -a _signature_, which defines how many arguments it expects and what value types -those arguments must have. The signature also defines the type of the result -value for any given set of argument types. +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 @@ -393,26 +386,33 @@ numerically smallest: min(55, 3453, 2) ``` -If the arguments to pass are available in a list or tuple value, that value -can be _expanded_ into separate arguments using the `...` symbol after that -argument: +### 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). +[the function reference](./functions.html). ## `for` Expressions -A _`for` expression_ allows you create a structural type value by transforming -another structural or collection type value. Each element in the input value +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 it can be converted to -a list of strings with all-uppercase letters with the following: +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)] @@ -436,7 +436,8 @@ 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: +from the source collection, which can produce a value with fewer elements than +the source: ``` [for s in var.list: upper(s) if s != ""] @@ -460,19 +461,19 @@ together results that have a common key: ## Splat Expressions -A _splat expressions_ provides a more concise way to express a common +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 obtained using the following `for` expression: +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_: +This is equivalent to the following _splat expression:_ -``` +```hcl var.list[*].id ``` @@ -482,39 +483,16 @@ 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] ``` -A second variant of the _splat expression_ is the "attribute-only" splat -expression, indicated by the sequence `.*`: - -``` -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. - -The standard splat expression `[*]` should be used in most cases, because its -behavior is less surprising. The attribute-only splat expression is supported -only for compatibility with earlier versions of Terraform, and should not be -used in new configurations. - Splat expressions also have another useful effect: if they are applied to a value that is _not_ a list or tuple then the value is automatically wrapped in a single-element list before processing. That is, `var.single_object[*].id` @@ -532,12 +510,36 @@ The above will produce a list of ids whether `aws_instance.example` has 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 -Expressions can usually be used only when assigning a value to an attribute -argument using the `name = expression` form. This covers many uses, but -some resource types include in their arguments _nested blocks_, which -do not accept expressions: +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_security_group" "example" { @@ -549,9 +551,9 @@ resource "aws_security_group" "example" { } ``` -To allow nested blocks like `ingress` to be constructed dynamically, a special -block type `dynamic` is supported inside `resource`, `data`, `provider`, -and `provisioner` blocks: +You can dynamically construct repeatable nested blocks like `ingress` using a +special `dynamic` block type, which is supported inside `resource`, `data`, +`provider`, and `provisioner` blocks: ```hcl resource "aws_security_group" "example" { @@ -568,29 +570,40 @@ resource "aws_security_group" "example" { } ``` -A `dynamic` block iterates over a collection or structural value given in its -`for_each` argument, generating a nested block for each element by evaluating -the nested `content` block. When evaluating the block, a temporary variable -is defined that is by default named after the block type being generated, -or `ingress` in this example. An optional additional argument `iterator` can be -used to override the name of the iterator variable. +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 (`"ingress"` 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 (`"ingress"` 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. -Overuse of `dynamic` blocks can make configuration hard to read and maintain, -so we recommend using this only when a re-usable module is hiding some details. -Avoid creating modules that are just thin wrappers around single resources, -passing through all of the input variables directly to resource arguments. -Always write nested blocks out literally where possible. - 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. +### 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 @@ -665,18 +678,19 @@ Backslash sequences are not interpreted in a heredoc string expression. Instead, the backslash character is interpreted literally. In both quoted and heredoc string expressions, Terraform supports template -sequences introduced by `${` and `%{`. These are described in more detail +sequences that begin with `${` and `%{`. These are described in more detail in the following section. To include these sequences _literally_ without beginning a template sequence, double the leading character: `$${` or `%%{`. ## String Templates -Within quoted and heredoc string expressions, the sequences `${` and `%{` -begin _template sequences_. Templates allow expressions to be embedded directly -into the string sequence, and thus allow strings to be dynamically constructed -from other values in a concise way. +Within quoted and heredoc string expressions, the sequences `${` and `%{` begin +_template sequences_. Templates let you directly embed expressions into a string +literal, to dynamically construct strings from other values. -A `${ ... }` sequence is an _interpolation_, which evaluates the expression +### Interpolation + +A `${ ... }` sequence is an _interpolation,_ which evaluates the expression given between the markers, converts the result to a string if necessary, and then inserts it into the final string: @@ -687,43 +701,46 @@ then inserts it into the final string: In the above example, the named object `var.name` is accessed and its value inserted into the string, producing a result like "Hello, Juan!". +### Directives + A `%{ ... }` sequence is a _directive_, which allows for conditional -results and iteration over collections, similar to conditional and +results and iteration over collections, similar to conditional and `for` expressions. The following directives are supported: -* The `if` directive chooses between two templates based on a conditional - expression: +* The `if `/`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 }!" - ``` + ```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 `else` portion may be omitted, in which case the result is an empty + string if the condition expression returns `false`. -* The `for` directive iterates over each of the elements of a given collection - or structural value and evaluates a given template once for each element, - concatenating the results together: +* 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 - < "" "" { + # Block body + = # Argument +} +``` + +- _Blocks_ are containers for other content and usually represent the + configuration of some kind of object, like a resource. Blocks have a + _block type,_ can have zero or more _labels,_ and have a _body_ that contains + any number of arguments and nested blocks. Most of Terraform's features are + controlled by top-level blocks in a configuration file. +- _Arguments_ assign a value to a name. They appear within blocks. +- _Expressions_ represent a value, either literally or by referencing and + combining other values. They appear as values for arguments, or within other + expressions. + +For full details about Terraform's syntax, see: + +- [Configuration Syntax](./syntax.html) +- [Expressions](./expressions.html) + ## Code Organization The Terraform language uses configuration files that are named with the `.tf` -file extension. There is also [a JSON-based variant of the language](/docs/configuration/syntax-json.html) +file extension. There is also [a JSON-based variant of the language](./syntax-json.html) that is named with the `.tf.json` file extension. Configuration files must always use UTF-8 encoding, and by convention are @@ -53,31 +83,33 @@ or by organizing sets of resources into child modules. ## Configuration Ordering Because Terraform's configuration language is declarative, the ordering of -blocks is generally not significant, except in some specific situations which -are described explicitly elsewhere. +blocks is generally not significant. (The order of `provisioner` blocks within a +resource is the only major feature where block order matters.) Terraform automatically processes resources in the correct order based on relationships defined between them in configuration, and so you can organize resources into source files in whatever way makes sense for your infrastructure. -## Terraform Core vs. Providers +## Terraform CLI vs. Providers -Terraform Core is a general engine for evaluating and applying Terraform -configuations. It defines the Terraform language syntax and overall structure, -and coordinates sequences of changes that must be made to make remote -infrastructure match the given configuration. +The Terraform command line interface (CLI) is a general engine for evaluating +and applying Terraform configuations. It defines the Terraform language syntax +and overall structure, and coordinates sequences of changes that must be made to +make remote infrastructure match the given configuration. -Terraform Core has no knowledge of specific infrastructure object types, though. -Instead, Terraform uses plugins called [providers](/docs/configuration/providers.html) -that each define and know how to manage a set of resource types. Most providers -are associated with a particular cloud or on-premises infrastructure service, -allowing Terraform to manage infrastructure objects within that service. +This general engine has no knowledge about specific types of infrastructure +objects. Instead, Terraform uses plugins called +[providers](./providers.html) that each define and manage a +set of resource types. Most providers are associated with a particular cloud or +on-premises infrastructure service, allowing Terraform to manage infrastructure +objects within that service. -Since each provider has its own resource types with different features, the -exact details of resources can vary between services, but Terraform Core -ensures that the same language constructs and syntax are available across -all services and allows resource types from different services to be combined -as needed. +Terraform doesn't have a concept of platform-independent resource types +— resources are always tied to a provider, since the features of similar +resources can vary greatly from provider to provider. But Terraform CLI's shared +configuration engine ensures that the same language constructs and syntax are +available across all services and allows resource types from different services +to be combined as needed. ## Example @@ -98,6 +130,7 @@ variable "base_cidr_block" { variable "availability_zones" { description = "A list of availability zones in which to create subnets" + type = list(string) } provider "aws" { diff --git a/website/docs/configuration/locals.html.md b/website/docs/configuration/locals.html.md index 61a988234..297237080 100644 --- a/website/docs/configuration/locals.html.md +++ b/website/docs/configuration/locals.html.md @@ -9,15 +9,18 @@ description: |- # Local Values -A local value assigns a name to an [expression](/docs/configuration/expressions.html), -allowing it to then be used multiple times within a module without repeating +A local value assigns a name to an [expression](./expressions.html), +allowing it to be used multiple times within a module without repeating it. -Comparing modules to functions in a traditional programming language, +Comparing modules to functions in a traditional programming language: if [input variables](./variables.html) are analogous to function arguments and -[outputs values](./outputs.html) are analogous to function return values then +[outputs values](./outputs.html) are analogous to function return values, then _local values_ are comparable to a function's local temporary symbols. +-> **Note:** For brevity, local values are often referred to as just "locals" +when the meaning is clear from context. + ## Declaring a Local Value A set of related local values can be delared together in a single `locals` @@ -30,9 +33,6 @@ locals { } ``` -For brevity, local values are often referred to just as "locals", when the -meaning is clear from context. - The expressions assigned to local value names can either be simple constants like the above, allowing these values to be defined only once but used many times, or they can be more complex expressions that transform or combine @@ -54,7 +54,7 @@ locals { ``` As shown above, local values can be referenced from elsewhere in the module -with an expression like `local.common_tags`, and output values can reference +with an expression like `local.common_tags`, and locals can reference each other in order to build more complex values from simpler ones. ``` @@ -67,12 +67,12 @@ resource "aws_instance" "example" { ## When To Use Local Values -Local Values can be helpful to avoid repeating the same values or expressions +Local values can be helpful to avoid repeating the same values or expressions multiple times in a configuration, but if overused they can also make a configuration hard to read by future maintainers by hiding the actual values used. -Use Local Values only in moderation, in situations where a single value or +Use local values only in moderation, in situations where a single value or result is used in many places _and_ that value is likely to be changed in future. The ability to easily change the value in a central place is the key advantage of local values. diff --git a/website/docs/configuration/modules.html.md b/website/docs/configuration/modules.html.md index 8c91288c4..1753fdb64 100644 --- a/website/docs/configuration/modules.html.md +++ b/website/docs/configuration/modules.html.md @@ -9,12 +9,13 @@ description: |- # Modules 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, allowing the suite of resources within the -child module to be included into the configuration in a concise way. Modules +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. @@ -28,7 +29,7 @@ created, and published in [the dedicated _Modules_ section](/docs/modules/index. 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 +[input variables](./variables.html). Modules are called from within other modules using `module` blocks: ```hcl @@ -39,19 +40,22 @@ module "servers" { } ``` -The label immediately after the `module` keyword is a name that will be used -to refer to this instance of the module within the calling module. The -_calling module_ is the one that includes the `module` block shown above. +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](/docs/configuration/variables.html) +Most of the arguments correspond to [input variables](./variables.html) defined by the module, including the `servers` argument in the above example. -The `source` argument is a meta-argument defined and processed by Terraform -itself. Its value is the path to a local directory containing the module's -configuration files, or optionally a remote module source that Terraform should -download and use. For more information on possible values for this argument, -see [_Module Sources_](/docs/modules/sources.html). +All modules require a `source` argument, which is a meta-argument defined by +Terraform CLI. Its value is either the path to a local directory of 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 @@ -61,7 +65,7 @@ variable 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 +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 @@ -76,6 +80,9 @@ resource "aws_elb" "example" { } ``` +For more information about referring to named values, see +[Expressions](./expressions.html). + ## Other Meta-arguments Along with the `source` meta-argument described above, module blocks have diff --git a/website/docs/configuration/outputs.html.md b/website/docs/configuration/outputs.html.md index 24442310a..8029e0ee2 100644 --- a/website/docs/configuration/outputs.html.md +++ b/website/docs/configuration/outputs.html.md @@ -8,15 +8,24 @@ description: |- # Output Values -Output values are like the return values of a Terraform module, allowing -a subset of the resource attributes within a child module to be exposed to -a parent module, or making certain values from a root module visible in the -CLI output after running `terraform apply`. +Output values are like the return values of a Terraform module, and have several +uses: + +- A child module can use outputs to expose a subset of its resource attributes + to a parent module. +- A root module can use outputs to print certain values in the CLI output after + running `terraform apply`. +- When using [remote state](/docs/state/remote.html), root module outputs can be + accessed by other configurations via a + [`terraform_remote_state` data source](/docs/providers/terraform/d/remote_state.html). Resource instances managed by Terraform each export attributes whose values can be used elsewhere in configuration. Output values are a way to expose some of that information to the user of your module. +-> **Note:** For brevity, output values are often referred to as just "outputs" +when the meaning is clear from context. + ## Declaring an Output Value Each output value exported by a module must be declared using an `output` @@ -32,10 +41,7 @@ The label immediately after the `output` keyword is the name that can be used to access this output in the parent module, if any, or the name that will be displayed to the user for output values in the root module. -For brevity, output values are often referred to simply as "outputs", where -the meaning is clear from context. - -The `value` argument takes an [expression](/docs/configuration/expressions.html) +The `value` argument takes an [expression](./expressions.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 @@ -46,9 +52,9 @@ will be described in the following sections. ## Output Value Documentation -Because the output values of a module are part of the user interface of -the module, you may specify a short description of the purpose of each -value using the optional `description` argument: +Because the output values of a module are part of its user interface, you can +briefly describe the purpose of each value using the optional `description` +argument: ```hcl output "instance_ip_addr" { @@ -57,9 +63,9 @@ output "instance_ip_addr" { } ``` -The description for an output value should be a concise description of the -purpose of the variable and what kind of value is expected. This description -string may be included in documentation about the module, and so it should be +The description should concisely explain the +purpose of the output and what kind of value is expected. This description +string might be included in documentation about the module, and so it should be written from the perspective of the user of the module rather than its maintainer. For commentary for module maintainers, use comments. @@ -77,9 +83,9 @@ output "db_password" { ``` Setting an output value in the root module as sensitive prevents Terraform -from showing its value at the end of `terraform apply`. It may still be shown -in the CLI output for other reasons, such as if the value is referenced in -an expression for a resource argument. +from showing its value in the list of outputs at the end of `terraform apply`. +It might still be shown in the CLI output for other reasons, like if the +value is referenced in an expression for a resource argument. Sensitive output values are still recorded in the [state](/docs/state/index.html), and so will be visible to anyone who is able @@ -98,7 +104,7 @@ correctly determine the dependencies between resources defined in different modules. Just as with -[resource dependencies](/docs/configuration/resources.html#resource-dependencies), +[resource dependencies](./resources.html#resource-dependencies), Terraform analyzes the `value` expression for an output value and autmatically 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 2304f1c52..e9b79bc18 100644 --- a/website/docs/configuration/providers.html.md +++ b/website/docs/configuration/providers.html.md @@ -8,7 +8,7 @@ description: |- # Providers -While [resources](/docs/configuration/resources.html) are the primary construct +While [resources](./resources.html) are the primary construct in the Terraform language, the _behaviors_ of resources rely on their associated resource types, and these types are defined by _providers_. @@ -45,11 +45,11 @@ the resource type name `google_compute_instance`. The body of the block (between `{` and `}`) contains configuration arguments for the provider itself. Most arguments in this section are specified by -the provider itself, and indeed in this example both `project` and `region` +the provider itself; in this example both `project` and `region` are specific to the `google` provider. The configuration arguments defined by the provider may be assigned using -[expressions](/docs/configuration/expressions.html), which can for example +[expressions](./expressions.html), which can for example allow them to be parameterized by input variables. However, since provider configurations must be evaluated in order to perform any resource type action, provider configurations may refer only to values that are known before @@ -57,9 +57,11 @@ the configuration is applied. In particular, avoid referring to attributes exported by other resources unless their values are specified directly in the configuration. -A small number of "meta-arguments" are defined by Terraform Core itself and -available for all `provider` blocks. These will be described in the following -sections. +There are also two "meta-arguments" that are defined by Terraform itself +and available for all `provider` blocks: + +- [`version`, for constraining the allowed provider versions][inpage-versions] +- [`alias`, for using the same provider with different configurations for different resources][inpage-alias] Unlike many other objects in the Terraform language, a `provider` block may be omitted if its contents would otherwise be empty. Terraform assumes an @@ -87,7 +89,9 @@ for installation instructions. For more information, see [the `terraform init` command](/docs/commands/init.html). -## Provider Versions +## `version`: Provider Versions + +[inpage-versions]: #version-provider-versions Providers are plugins released on a separate rhythm from Terraform itself, and so they have their own version numbers. For production use, you should @@ -142,12 +146,14 @@ to downloading a new version. To upgrade to the latest acceptable version of each provider, run `terraform init -upgrade`. This command also upgrades to the latest versions of all Terraform modules. -## Multiple Provider Instances +## `alias`: Multiple Provider Instances -You can optionally define multiple configurations for the same provider -to allow managing objects in multiple regions, on multiple hosts, etc. The -primary reason is multiple regions for a cloud platform. Other examples include -targeting multiple Docker hosts, multiple Consul hosts, etc. +[inpage-alias]: #alias-multiple-provider-instances + +You can optionally define multiple configurations for the same provider, and +select which one to use on a per-resource or per-module basis. The primary +reason for this is to support multiple regions for a cloud platform; other +examples include targeting multiple Docker hosts, multiple Consul hosts, etc. To include multiple configurations for a given provider, include multiple `provider` blocks with the same provider name, but set the `alias` meta-argument @@ -172,14 +178,26 @@ configuration. For providers that have no required configuration arguments, the implied _empty_ configuration is considered to be the _default_ provider configuration. -Resources are normally associated with the default provider configuration -inferred from the resource type name. For example, a resource of type -`aws_instance` uses the _default_ (un-aliased) `aws` provider configuration -unless otherwise stated. +### Referring to Alternate Providers -The `provider` meta-argument within any `resource` or `data` block overrides -this default behavior and allows an additional provider configuration to be -selected using its alias: +When Terraform needs the name of a provider configuration, it always expects a +reference of the form `.`. In the example above, +`aws.west` would refer to the provider with the `us-west-2` region. + +These references are special expressions. Like references to other named +entities (for example, `var.image_id`), they aren't strings and don't need to be +quoted. But they are only valid in specific meta-arguments of `resource`, +`data`, and `module` blocks, and can't be used in arbitrary expressions. + +### Selecting Alternate Providers + +By default, resources use a default provider configuration inferred from the +first word of the resource type name. For example, a resource of type +`aws_instance` uses the default (un-aliased) `aws` provider configuration unless +otherwise stated. + +To select an aliased provider for a resource or data source, set its `provider` +meta-argument to a `.` reference: ```hcl resource "aws_instance" "foo" { @@ -189,14 +207,24 @@ resource "aws_instance" "foo" { } ``` -The value of the `provider` meta-argument is always the provider name and an -alias separated by a period, such as `aws.west` above. +To select aliased providers for a child module, use its `providers` +meta-argument to specify which aliased providers should be mapped to which local +provider names inside the module: -Provider configurations may also be passed from a parent module into a -child module, as described in -[_Providers within Modules_](/docs/modules/usage.html#providers-within-modules). -In most cases, only _root modules_ should define provider configurations, with -all child modules obtaining their provider configurations from their parents. +```hcl +module "aws_vpc" { + source = "./aws_vpc" + providers = { + aws = aws.west + } +} +``` + +Modules have some special requirements when passing in providers; see +[Providers within Modules](/docs/modules/usage.html#providers-within-modules) +for more details. In most cases, only _root modules_ should define provider +configurations, with all child modules obtaining their provider configurations +from their parents. ## Third-party Plugins @@ -276,7 +304,7 @@ use of a local directory as a shared plugin cache, which then allows each distinct plugin binary to be downloaded only once. To enable the plugin cache, use the `plugin_cache_dir` setting in -[the CLI configuration file](https://www.terraform.io/docs/commands/cli-config.html). +[the CLI configuration file](/docs/commands/cli-config.html). For example: ```hcl diff --git a/website/docs/configuration/resources.html.md b/website/docs/configuration/resources.html.md index 145bcb771..e7284adfa 100644 --- a/website/docs/configuration/resources.html.md +++ b/website/docs/configuration/resources.html.md @@ -11,7 +11,7 @@ description: |- # Resources _Resources_ are the most important element in the Terraform language. -Each resource block describes one ore more infrastructure objects, such +Each resource block describes one or more infrastructure objects, such as virtual networks, compute instances, or higher-level components such as DNS records. @@ -46,21 +46,37 @@ arguments defined specifically for [the `aws_instance` resource type](/docs/prov Each resource is associated with a single _resource type_, which determines the kind of infrastructure object it manages and what arguments and other -attributes are supported for each resource. +attributes the resource supports. -Each resource type in turn belongs to a [provider](/docs/configuration/providers.html), -which is a plugin for Terraform that offers a collection of resource types that -most often belong to a single cloud or on-premises infrastructure platform. +Each resource type in turn belongs to a [provider](./providers.html), +which is a plugin for Terraform that offers a collection of resource types. A +provider usually provides resources to manage a single cloud or on-premises +infrastructure platform. -Most of the items within the body of a `resource` block are defined by and -specific to the selected resource type, and these arguments can make full -use of [expressions](/docs/configuration/expressions.html) and other dynamic -Terraform language features. +Most of the items within the body of a `resource` block are specific to the +selected resource type. These arguments can make full use of +[expressions](./expressions.html) and other dynamic Terraform +language features. -However, there are some "meta-arguments" that are defined by Terraform itself -and apply across all resource types. These arguments often have additional -restrictions on what language features can be used with them, and are described -in more detail in the following sections. +There are also some _meta-arguments_ that are defined by Terraform itself +and apply across all resource types. (See [Meta-Arguments](#meta-arguments) below.) + +### Documentation for Resource Types + +[Terraform's provider documentation][providers] is the primary place to +learn which resource types are available and which arguments to use for each +resource type. Once you understand Terraform's basic syntax, the provider +documentation will be where you spend the majority of your time on this website. + +The "[Providers][]" link at the top level of the navigation sidebar will take +you to an alphabetical list of all of the providers distributed by HashiCorp. +You can find a specific provider in this master list, or choose a category from +the navigation sidebar to browse a more focused list of providers. + +You can also search GitHub or other sources for third-party providers, which can +be installed as plugins to enable an even broader selection of resource types. + +[providers]: /docs/providers/index.html ## Resource Behavior @@ -86,29 +102,59 @@ details of what it means to create, update, or destroy a resource are different for each resource type, but this standard set of verbs is common across them all. -The "meta-arguments" within `resource` blocks, defined in the following -sections, allow some details of this standard resource behavior to be +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. -## Resource Dependencies +### Resource Dependencies -As with other elements in the Terraform language, Terraform analyses any -[expressions](/docs/configuration/expressions.html) within a `resource` -block to find references to other objects, and infers from this a correct -dependency ordering for creating, updating, or destroying each resource. -Because of this, in most cases it is not necessary to mention explicitly -any dependencies between resources. +Most resources in a configuration don't have any particular relationship, and +Terraform can make changes to several unrelated resources in parallel. -However, in some less-common situations there are dependencies between -resources that cannot be recognized implicitly in configuration. For example, -if Terraform is being used to both manage access control policies _and_ take -actions that require those policies to be present, there may be a hidden -dependency between the access policy and a resource whose creation depends -on it. +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. -In these rare cases, the `depends_on` meta-argument can be used to explicitly -specify a dependency. This argument is available in all `resource` blocks, -regardless of resource type. For example: +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](#depends_on-hidden-resource-dependencies) +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][inpage-count] +- [`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`: Hidden Resource Dependencies + +[inpage-depend]: #depends_on-hidden-resource-dependencies + +Use the `depends_on` meta-argument to handle hidden resource dependencies that +Terraform can't automatically infer. Hidden dependencies happen 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" { @@ -166,7 +212,9 @@ The `depends_on` argument should be used only as a last resort. When using it, always include a comment explaining why it is being used, to help future maintainers understand the purpose of the additional dependency. -## Multiple Resource Instances +### `count`: Multiple Resource Instances + +[inpage-count]: #count-multiple-resource-instances By default, a single `resource` block corresponds to only one real infrastructure object. Sometimes it is desirable to instead manage a set @@ -188,24 +236,22 @@ resource "aws_instance" "server" { ``` When the `count` meta-argument is present, a distinction exists between -the resource block itself -- identified as `aws_instance.server` -- -and the multiple _resource instances_ associated with it, identified -as `aws_instance.server[0]`, `aws_instance.server[1]`, etc. When `count` -is _not_ present, a resource block has only a single resource instance, -which has no associated index. +the resource block itself — identified as `aws_instance.server` — +and the multiple _resource instances_ associated with it, identified as +`aws_instance.server[0]`, `aws_instance.server[1]`, etc. Each instance has a +distinct infrastructure object associated with it (as described above in +[Resource Behavior](#resource-behavior)), and each is separtely created, +updated, or destroyed when the configuration is applied. -For resource blocks where `count` is set, an additional `count` object -is available for use in expressions, which has an attribute `count.index` -that provides the distinct index for each instance. +When `count` is _not_ present, a resource block has only a single resource +instance, which has no associated index. -The _Resource Behavior_ section above described how each resource corresponds -to a real infrastructure object. It is in fact resource _instances_ that -correspond to infrastructure objects, and so when `count` is used a particular -resource block has a distinct infrastructure object associated with each of its -instances, and each is separtely created, updated, or destroyed when the -configuration is applied. +Within resource blocks where `count` is set, an additional `count` object is +available for use in expressions so you can modify the configuration of each +instance. This object has one attribute, `count.index`, which provides the +distinct index number (starting with `0`) for each instance. -The `count` meta argument accepts [expressions](/docs/configuration/expressions.html) +The `count` meta-argument accepts [expressions](./expressions.html) in its value, similar to the resource-type-specific arguments for a resource. However, Terraform must interpret the `count` argument _before_ any actions are taken from remote resources, and so (unlike the resource-type-specifc arguments) @@ -244,9 +290,11 @@ intended. The practice of generating multiple instances from lists should be used sparingly, and with due care given to what will happen if the list is changed later. -## Selecting a Non-default Provider Configuration +### `provider`: Selecting a Non-default Provider Configuration -As described in [the _providers_ guide](/docs/configuration/providers.html), +[inpage-provider]: #provider-selecting-a-non-default-provider-configuration + +As described in [the Providers page](./providers.html), Terraform optionally allows the definition of multiple alternative ("aliased") configurations for a single provider, to allow management of resources in different regions in multi-region services, etc. @@ -288,17 +336,19 @@ A resource always has an implicit dependency on its associated provider, to ensure that the provider is fully configured before any resource actions are taken. -The `provider` meta-argument value must always be a literal provider name -followed by an alias name separated by a dot. Arbitrary expressions are -not permitted for `provider` because it must be resolved while Terraform -is constructing the dependency graph, before it is safe to evaluate -expressions. +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 Customizations +### `lifecycle`: Lifecycle Customizations -The general lifecycle for resources is described above in the section -_Resource Behavior_. Some details of that behavior can be customized -using the special nested block `lifecycle` within a resource block body: +[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" { @@ -316,54 +366,54 @@ 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 + 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. + The `create_before_destroy` meta-argument changes this behavior so that + the new replacement object is created _first,_ and then the prior object + is destroyed only once the replacement is created. - This is an opt-in behavior because many remote object types have unique - name requirements or other constraints that must be accommodated for - both a new and an old object to exist concurrently. Some resource types - offer special options to append a random suffix onto each object name to - avoid collisions, for example. Terraform Core cannot automatically activate - such features, so you must understand the constrants for each resource - type before using `create_before_destroy` with it. + 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 constrants for each resource + type before using `create_before_destroy` with it. * `prevent_destroy` (bool) - This meta-argument, when set to `true`, will cause Terraform to reject with an error any plan that would destroy the infrastructure object associated with the resource, as long as the argument remains present in the configuration. - This can be used as a measure of safety against the accidental replacement - of objects that may be costly to reproduce, such as database instances. - However, it will make certain configuration changes impossible to apply, - and will prevent the use of the `terraform destroy` command once such - objects are created, and so this option should be used sparingly. + 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. + Since this argument must be present in configuration for the protection to + apply, note that this setting does not prevent the remote object from + being destroyed if the `resource` block were removed from configuration + entirely: in that case, the `prevent_destroy` setting is removed along + with it, and so Terraform will allow the destroy operation to succeed. * `ignore_changes` (list of attribute names) - By default, Terraform detects - any difference between the current settings of a real infrastructure object + any difference in the current settings of a real infrastructure object and plans to update the remote object to match configuration. - In some rare cases, settings of a remote object are modified by processes - outside of Terraform, which Terraform would then attempt to "fix" on the - next run. In order to make Terraform share management responsibilities - of a single object with a separate process, the `ignore_changes` - meta-argument specifies resource attributes that Terraform should ignore - when planning updates to the associated remote object. + 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 corresponding to the given attribute names are considered + when planning a _create_ operation, but are ignored when planning an + _update_. - ```hcl + ```hcl resource "aws_instance" "example" { # ... @@ -375,19 +425,46 @@ meta-arguments are supported: ] } } - ``` + ``` - 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. + 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. + Only attributes defined by the resource type can be ignored. + `ignore_changes` cannot be applied to itself or to any other meta-arguments. The `lifecycle` settings all effect how Terraform constructs and traverses the dependency graph. As a result, only literal values can be used because the processing happens to early for arbitrary expression evaluation. +### `provisioner` and `connection`: Resource Provisioners + +[inpage-provisioner]: #provisioner-and-connection-resource-provisioners + +Some infrastructure objects require some special actions to be taken after they +are created before they can become fully functional. For example, compute +instances may require configuration to be uploaded or a configuration management +program to be run before they can begin their intended operation. + +Create-time actions like these can be described using _resource provisioners_. +A provisioner is another type of plugin supported by Terraform, and each +provisioner takes a different kind of action in the context of a resource +being created. + +Provisioning steps should be used sparingly, since they represent +non-declarative actions taken during the creation of a resource and so +Terraform is not able to model changes to them as it can for the declarative +portions of the Terraform language. + +Provisioners can also be defined to run when a resource is _destroyed_, with +certain limitations. + +The `provisioner` and `connection` block types within `resource` blocks are +meta-arguments available across all resource types. Provisioners and their +usage are described in more detail in +[the Provisioners section](/docs/provisioners/index.html). + ## Local-only Resources While most resource types correspond to an infrastructure object type that @@ -398,7 +475,7 @@ saving those results in the state for future use. For example, local-only resource types exist for [generating private keys](/docs/providers/tls/r/private_key.html), [issuing self-signed TLS certificates](/docs/providers/tls/r/self_signed_cert.html), -and even [generating random ids](https://www.terraform.io/docs/providers/random/r/id.html). +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. @@ -438,27 +515,3 @@ resource types do not support the `timeouts` block at all. Consult the documentation for each resource type to see which operations it offers for configuration, if any. -## Resource Provisioners - -Some infrastructure objects require some special actions to be taken after they -are created before they can become fully functional. For example, compute -instances may require configuration to be uploaded or a configuration management -program to be run before they can begin their intended operation. - -Create-time actions like these can be described using _resource provisioners_. -A provisioner is another type of plugin supported by Terraform, and each -provisioner takes a different kind of action in the context of a resource -being created. - -Provisioning steps should be used sparingly, since they represent -non-declarative actions taken during the creation of a resource and so -Terraform is not able to model changes to them as it can for the declarative -portions of the Terraform language. - -Provisioners can also be defined to run when a resource is _destroyed_, with -certain limitations. - -The `provisioner` and `connection` block types within `resource` blocks are -meta-arguments available across all resource types. Provisioners and their -usage are described in more detail in -[the _Provisioners_ section](/docs/provisioners/index.html). diff --git a/website/docs/configuration/style.html.md b/website/docs/configuration/style.html.md new file mode 100644 index 000000000..4b7fefd56 --- /dev/null +++ b/website/docs/configuration/style.html.md @@ -0,0 +1,72 @@ +--- +layout: "docs" +page_title: "Style Conventions" +sidebar_current: "docs-config-style" +description: |- + The Terraform language has some idiomatic style conventions, which we + recommend users always follow for consistency between files and modules + written by different teams. +--- + +# Style Conventions + +The Terraform parser allows you some flexibility in how you lay out the +elements in your configuration files, but the Terraform language also has some +idiomatic style conventions which we recommend users always follow +for consistency between files and modules written by different teams. +Automatic source code formatting tools may apply these conventions +automatically. + +* Indent two spaces for each nesting level. + +* When multiple arguments with single-line values appear on consecutive lines + at the same nesting level, align their equals signs: + + ```hcl + ami = "abc123" + instance_type = "t2.micro" + ``` + +* When both arguments and blocks appear together inside a block body, + place all of the arguments together at the top and then place nested + blocks below them. Use one blank line to separate the arguments from + the blocks. + +* Use empty lines to separate logical groups of arguments within a block. + +* For blocks that contain both arguments and "meta-arguments" (as defined by + the Terraform language semantics), list meta-arguments first + and separate them from other arguments with one blank line. Place + meta-argument blocks _last_ and separate them from other blocks with + one blank line. + + ```hcl + resource "aws_instance" "example" { + count = 2 # meta-argument first + + ami = "abc123" + instance_type = "t2.micro" + + network_interface { + # ... + } + + lifecycle { # meta-argument block last + create_before_destroy = true + } + } + ``` + +* Top-level blocks should always be separated from one another by one + blank line. Nested blocks should also be separated by blank lines, except + when grouping together related blocks of the same type (like multiple + `provisioner` blocks in a resource). + +* Avoid separating multiple blocks of the same type with other blocks of + a different type, unless the block types are defined by semantics to + form a family. + (For example: `root_block_device`, `ebs_block_device` and + `ephemeral_block_device` on `aws_instance` form a family of block types + describing AWS block devices, and can therefore be grouped together and + mixed.) + diff --git a/website/docs/configuration/syntax-json.html.md b/website/docs/configuration/syntax-json.html.md index bb4333344..48ba4cdbd 100644 --- a/website/docs/configuration/syntax-json.html.md +++ b/website/docs/configuration/syntax-json.html.md @@ -88,17 +88,18 @@ resource "aws_instance" "example" { ``` Within each top-level block type the rules for mapping to JSON are slightly -different, but the following general rules apply in most cases: +different (see [Block-type-specific Exceptions][inpage-exceptions] below), but the following general rules apply in most cases: * The JSON object representing the block body contains properties that - correspond either to attribute arguments names or to nested block type names. + correspond either to argument names or to nested block type names. -* Where a property corresponds to an attribute argument that accepts +* Where a property corresponds to an argument that accepts [arbitrary expressions](./expressions.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 - value depends on the argument, as described in [the block-type-specific exceptions](#block-type-specific-exceptions) + value depends on the argument, as described in the + [block-type-specific exceptions](#block-type-specific-exceptions) given later in this page. * Where a property name corresponds to an expected nested block type name, @@ -181,7 +182,7 @@ resource "aws_instance" "example" { ``` When the nested block type requires one or more labels, or when multiple -blocks of the same type must be given, the mapping gets a little more +blocks of the same type can be given, the mapping gets a little more complicated. For example, the `provisioner` nested block type used within `resource` blocks expects a label giving the provisioner to use, and the ordering of provisioner blocks is significant to decide the order @@ -299,6 +300,8 @@ configuration file. This can be useful to note which program created the file. ## Block-type-specific Exceptions +[inpage-block]: #block-type-specific-exceptions + Certain arguments within specific block types are processed in a special way by Terraform, and so their mapping to the JSON syntax does not follow the general rules described above. The following sub-sections describe the special @@ -311,9 +314,9 @@ references to objects, or literal keywords. When represented in JSON, the reference or keyword is given as a JSON string with no additonal surrounding spaces or symbols. -For example, the `provider` meta-argument takes a special compact provider -configuration reference, which appears directly in the native syntax but must -be presented as a string in the JSON syntax: +For example, the `provider` meta-argument takes a `.` reference +to a provider configuration, which appears unquoted in the native syntax but +must be presented as a string in the JSON syntax: ```json { @@ -330,8 +333,8 @@ be presented as a string in the JSON syntax: This special processing applies to the following meta-arguments: * `provider`: a single string, as shown above -* `depends_on`: an array of strings containing object references, like - `["aws_instance.example"]`. +* `depends_on`: an array of strings containing references to named entities, + like `["aws_instance.example"]`. * `ignore_changes` within the `lifecycle` block: if set to `all`, a single string `"all"` must be given. Otherwise, an array of JSON strings containing property references must be used, like `["ami"]`. diff --git a/website/docs/configuration/syntax.html.md b/website/docs/configuration/syntax.html.md index 93921fdd4..66cfb5abc 100644 --- a/website/docs/configuration/syntax.html.md +++ b/website/docs/configuration/syntax.html.md @@ -18,7 +18,7 @@ those constructs are built from. This page describes the _native syntax_ of the Terraform language, which is a rich language designed to be easy for humans to read and write. The constructs in the Terraform language can also be expressed in -[JSON syntax](/docs/configuration/syntax-json.html), which is harder for humans +[JSON syntax](./syntax-json.html), which is harder for humans to read and edit but easier to generate and parse programmatically. This low-level syntax of the Terraform language is defined in terms of a @@ -30,23 +30,39 @@ details. If you are interested, you can find a full definition of HCL syntax in [the HCL native syntax specification](https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md). -## Attributes and Blocks +## Arguments and Blocks The Terraform language syntax is built around two key syntax constructs: -attributes and blocks. +arguments and blocks. -An _attribute_ assigns a value to a particular name: +### Arguments + +An _argument_ assigns a value to a particular name: ```hcl image_id = "abc123" ``` -The identifier before the equals sign is the _attribute name_, and after -the equals sign is the attribute's value. The semantics applied to each -attribute name define what value types are valid, but many attributes -accept arbitrary [expressions](/docs/configuration/expressions.html), -which allow the value to either be specified literally or generated from -other values programmatically. +The identifier before the equals sign is the _argument name_, and the expression +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 +either be specified literally or generated from other values programmatically. + +-> **Note:** Terraform's configuration language is based on a more general +language called HCL, and HCL's documentation usually uses the word "attribute" +instead of "argument." These words are similar enough to be interchangeable in +this context, and experienced Terraform users might use either term in casual +conversation. But because Terraform also interacts with several _other_ things +called "attributes" (in particular, Terraform resources have attributes like +`id` that can be referenced from expressions but can't be assigned values in +configuration), we've chosen to use "argument" in the Terraform documentation +when referring to this syntax construct. + +### Blocks A _block_ is a container for other content: @@ -60,106 +76,41 @@ resource "aws_instance" "example" { } ``` -A block has a _type_ ("resource" in this example). Each block type defines -how many _labels_ must follow the type keyword. The "resource" block type -shown here expects two labels, which are "aws_instance" and "example" -in this case. A particular block type may have any number of required labels, -or it may require none as with the nested "network_interface" block type. +A block has a _type_ (`resource` in this example). Each block type defines +how many _labels_ must follow the type keyword. The `resource` block type +expects two labels, which are `aws_instance` and `example` in the example above. +A particular block type may have any number of required labels, or it may +require none as with the nested `network_interface` block type. After the block type keyword and any labels, the block _body_ is delimited -by the `{` and `}` characters. Within the block body, further attributes +by the `{` and `}` characters. Within the block body, further arguments and blocks may be nested, creating a heirarchy of blocks and their associated -attributes. +arguments. -Unfortunately, the low-level syntax described here uses the noun "attribute" -to mean something slightly different to how it is used by the main -Terraform language. Elsewhere in this documentation, "attribute" usually -refers to a named value exported by an object that can be accessed in an -expression, such as the "id" portion of the expression -`aws_instance.example.id`. To reduce confusion, other documentation uses the -term "argument" to refer to the syntax-level idea of an attribute. - -### Style Conventions - -The Terraform parser allows you some flexibility in how you lay out the -elements in your configuration files, but the Terraform language also has some -idiomatic style conventions which we recommend users should always follow -for consistency between files and modules written by different teams. -Automatic source code formatting tools may apply these conventions -automatically. - -* Indent two spaces for each nesting level. - -* When multiple attributes with single-line values appear on consecutive lines - at the same nesting level, align their equals signs: - - ```hcl - ami = "abc123" - instance_type = "t2.micro" - ``` - -* When both attributes and blocks appear together inside a block body, - place all of the attributes together at the top and then place nested - blocks below them. Use one blank line to separate the attributes from - the blocks. - -* Use empty lines to separate logical groups of attributes within a block. - -* For blocks that contain both arguments and "meta-arguments" (as defined by - the Terraform language semantics), list meta-argument attributes first - and separate them from other attributes with one blank line. Place - meta-argument blocks _last_ and separate them from other blocks with - one blank line. - - ```hcl - resource "aws_instance" "example" { - count = 2 # meta-argument attribute first - - ami = "abc123" - instance_type = "t2.micro" - - network_interface { - # ... - } - - lifecycle { # meta-argument block last - create_before_destroy = true - } - } - ``` - -* Top-level blocks should always be separated from one another by one - blank line. Nested blocks should also be separated by blank lines, except - when grouping together related blocks of the same type. - -* Avoid separating multiple blocks of the same type with other blocks of - a different type, unless the block types are defined by semantics to - form a family. - (For example: `root_block_device`, `ebs_block_device` and - `ephemeral_block_device` on `aws_instance` form a family of block types - describing AWS block devices, and can therefore be grouped together and - mixed.) +The Terraform language uses a limited number of _top-level block types,_ which +are blocks that can appear outside of any other block in a configuration file. +Most of Terraform's features (including resources, input variables, output +values, data sources, etc.) are implemented as top-level blocks. ## Identifiers -Attribute names, block type names, and the names of most Terraform-specific +Argument names, block type names, and the names of most Terraform-specific constructs like resources, input variables, etc. are all _identifiers_. -The Terraform language implements -[the Unicode identifier syntax](http://unicode.org/reports/tr31/), extended -to also include the ASCII hyphen character `-`. -In practice, this means that identifiers can contain letters, digits, -underscores, and hyphens. To avoid ambiguity with literal numbers, the -first character of an identifier must not be a digit. +Identifiers can contain letters, digits, underscores (`_`), and hyphens (`-`). +The first character of an identifier must not be a digit, to avoid ambiguity +with literal numbers. + +For complete identifier rules, Terraform implements +[the Unicode identifier syntax](http://unicode.org/reports/tr31/), extended to +include the ASCII hyphen character `-`. ## Comments The Terraform language supports three different syntaxes for comments: -* `#` begins a single-line comment, ending at the end of the line - +* `#` begins a single-line comment, ending at the end of the line. * `//` also begins a single-line comment, as an alternative to `#`. - * `/*` and `*/` are start and end delimiters for a comment that might span over multiple lines. diff --git a/website/docs/configuration/terraform.html.md b/website/docs/configuration/terraform.html.md index 7141833ab..c14753fe8 100644 --- a/website/docs/configuration/terraform.html.md +++ b/website/docs/configuration/terraform.html.md @@ -56,22 +56,22 @@ More information on backend configuration can be found in ## Specifying a Required Terraform Version The `required_version` setting can be used to constrain which versions of -Terraform Core can be used with your configuration. If the running version of +the Terraform CLI 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](/docs/configuration/modules.html), each module +When you use [child modules](./modules.html), each module can specify its own version requirements. The requirements of all modules in the tree must be satisfied. -Use Terraform Core version constraints in a collaborative environment to +Use Terraform version constraints in a collaborative environment to ensure that everyone is using a spceific Terraform version, or using at least a minimum Terraform version that has behavior expected by the configuration. -The `required_version` setting applies only to the version of Terraform Core. +The `required_version` setting applies only to the version of Terraform CLI. Various behaviors of Terraform are actually implemented by Terraform Providers, -which are released on a cycle independent to Terraform Core and to each other. -Use [provider version constraints](/docs/configuration/providers.html#provider-versions) +which are released on a cycle independent of Terraform CLI and of each other. +Use [provider version constraints](./providers.html#provider-versions) to make similar constraints on which provider versions may be used. The value for `required_version` is a string containing a comma-separated @@ -100,7 +100,7 @@ The `required_providers` setting is a map specifying a version constraint for each provider required by your configuration. This is one of several ways to define -[provider version constraints](/docs/configuration/providers.html#provider-versions), +[provider version constraints](./providers.html#provider-versions), and is particularly suited to re-usable modules that expect a provider configuration to be provided by their caller but still need to impose a minimum version for that provider. diff --git a/website/docs/configuration/types.html.md b/website/docs/configuration/types.html.md new file mode 100644 index 000000000..fd05feb82 --- /dev/null +++ b/website/docs/configuration/types.html.md @@ -0,0 +1,203 @@ +--- +layout: "docs" +page_title: "Type Constraints" +sidebar_current: "docs-config-types" +description: |- + Terraform module authors and provider developers can use detailed type + constraints to validate the inputs of their modules and resources. +--- + +# Type Constraints + +Terraform module authors and provider developers can use detailed type +constraints to validate user-provided values for their input variables and +resource arguments. This requires some additional knowledge about Terraform's +type system, but allows you to build a more resilient user interface for your +modules and resources. + +## Type Keywords and Constructors + +Type constraints are expressed using a mixture of _type keywords_ and +function-like constructs called _type constructors._ + +* Type keywords are unquoted symbols that represent a static type. +* Type constructors are unquoted symbols followed by a pair of + parentheses, which contain an argument that specifies more information about + the type. Without its argument, a type constructor does not fully + 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 +Terraform language, they are only valid in the `type` argument of an +[input variable](./variables.html). + +## Primitive Types + +A _primitive_ type is a simple type that isn't made from any other types. All +primitive types in Terraform are represented by a type keyword. The available +primitive types are: + +* `string`: a sequence of Unicode characters representing some text, such + as `"hello"`. +* `number`: a numeric value. The `number` type can represent both whole + numbers like `15` and fractional values such as `6.283185`. +* `bool`: either `true` or `false`. `bool` values can be used in conditional + logic. + +### Conversion of Primitive Types + +The Terraform language will automatically convert `number` and `bool` values +to `string` values when needed, and vice-versa as long as the string contains +a valid representation of a number or boolean value. + +* `true` converts to `"true"`, and vice-versa +* `false` converts to `"false"`, and vice-versa +* `15` converts to `"15"`, and vice-versa + +## The "Any" Type + +The type keyword `any` is a special type constraint that accepts any value. + +## Complex Types + +A _complex_ type is a type that groups multiple values into a single value. +Complex types are represented by type constructors, but several of them +also have shorthand keyword versions. + +There are two categories of complex types: collection types (for grouping +similar values), and structural types (for grouping potentially dissimilar +values). + +### Collection Types + +A _collection_ type allows multiple values of _one_ other type to be grouped +together as a single value. The type of value _within_ a collection is called +its _element type._ All collection types must have an element type, which is +provided as the argument to their constructor. + +For example, the type `list(string)` means "list of strings", which is a +different type than `list(number)`, a list of numbers. All elements of a +collection must always be of the same type. + +The three kinds of collection type in the Terraform language are: + +* `list(...)`: a sequence of values identified by consecutive whole numbers + starting with zero. + + The keyword `list` is a shorthand for `list(any)`, which accepts any + element type as long as every element is the same type. This is for + compatibility with older configurations; for new code, we recommend using + the full form. +* `map(...)`: a collection of values where each is identified by a string label. + + The keyword `map` is a shorthand for `map(any)`, which accepts any + element type as long as every element is the same type. This is for + compatibility with older configurations; for new code, we recommend using + the full form. +* `set(...)`: a collection of unique values that do not have any secondary + identifiers or ordering. + +### Structural Types + +A _structural_ type allows multiple values of _several distinct types_ to be +grouped together as a single value. Structural types require a _schema_ as an +argument, to specify which types are allowed for which elements. + +The two kinds of structural type in the Terraform language are: + +* `object(...)`: a collection of named attributes that each have their own type. + + The schema for object types is `{ = , = , ... }` — a + pair of curly braces containing a comma-separated series of ` = ` + pairs. Values that match the object type must contain _all_ of the specified + keys, and the value for each key must match its specified type. (Values with + _additional_ keys can still match an object type, but the extra attributes + are discarded during type conversion.) +* `tuple(...)`: a sequence of elements identified by consecutive whole + numbers starting with zero, where each element has its own type. + + The schema for tuple types is `[, , ...]` — a pair of square + brackets containing a comma-separated series of types. Values that match the + tuple type must have _exactly_ the same number of elements (no more and no + fewer), and the value in each position must match the specified type for + that position. + +For example: an object type of `object({ name=string, age=number })` would match +a value like the following: + +```hcl +{ + name = "John" + age = 52 +} +``` + +Also, an object type of `object({ id=string, cidr_block=string })` would match +the object produced by a reference to an `aws_vpc` resource, like +`aws_vpc.example_vpc`; although the resource has additional attributes, they +would be discarded during type conversion. + +Finally, a tuple type of `tuple([string, number, bool])` would match a value +like the following: + +```hcl +["a", 15, true] +``` + +### Complex Type Literals + +The Terraform language has literal expressions for creating tuple and object +values, which are described in +[Expressions: Literal Expressions](./expressions.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. +However, due to the automatic conversion of complex types (described below), the +difference between similar complex types is almost never relevant to a normal +user, and most of the Terraform documentation conflates lists with tuples and +maps with objects. The distinctions are only useful when restricting input +values for a module or resource. + +### Conversion of Complex Types + +Similar kinds of complex types (list/tuple/set and map/object) can usually be +used interchangeably within the Terraform language, and most of Terraform's +documentation glosses over the differences between the kinds of complex type. +This is due to two conversion behaviors: + +* Whenever possible, Terraform converts values between similar kinds of complex + types if the provided value is not the exact type requested. "Similar kinds" + is defined as follows: + * Objects and maps are similar. + * A map (or a larger object) can be converted to an object if it has + _at least_ the keys required by the object schema. Any additional + attributes are discarded during conversion, which means map -> object + -> map conversions can be lossy. + * Tuples and lists are similar. + * A list can only be converted to a tuple if it has _exactly_ the + required number of elements. + * Sets are _almost_ similar to both tuples and lists: + * When a list or tuple is converted to a set, duplicate values are + discarded and the ordering of elements is lost. + * When a `set` is converted to a list or tuple, the elements will be + in an arbitrary order. If the set's elements were strings, they will + be in lexicographical order; sets of other element types do not + guarantee any particular order of elements. +* Whenever possible, Terraform converts _element values_ within a complex type, + either by converting complex-typed elements recursively or as described above + in [Conversion of Primitive Types](#conversion-of-primitive-types). + +For example: if a module argument requires a value of type `list(string)` and a +user provides the tuple `["a", 15, true]`, Terraform will internally transform +the value to `["a", "15", "true"]` by converting the elements to the required +`string` element type. Later, if the module uses those elements to set different +resource arguments that require a string, a number, and a bool (respectively), +Terraform will automatically convert the second and third strings back to the +required types at that time, since they contain valid representations of a +number and a bool. + +On the other hand, automatic conversion will fail if the provided value +(including any of its element values) is incompatible with the required type. If +an argument requires a type of `map(string)` and a user provides the object +`{name = ["Kristy", "Claudia", "Mary Anne", "Stacey"], age = 12}`, Terraform +will raise a type mismatch error, since a tuple cannot be converted to a string. diff --git a/website/docs/configuration/variables.html.md b/website/docs/configuration/variables.html.md index f68fa2dc7..b3ba9fa38 100644 --- a/website/docs/configuration/variables.html.md +++ b/website/docs/configuration/variables.html.md @@ -10,17 +10,24 @@ description: |- # Input Variables Input variables serve as parameters for a Terraform module, allowing aspects -of the a module to be customized without altering the module's own source code, +of the module to be customized without altering the module's own source code, 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 arguments and environment variables. -When you declare them in [_child_ modules](/docs/configuration/modules.html), -you can use the to pass values from parent to child. +set their values using CLI options and environment variables. +When you declare them in [child modules](./modules.html), +the calling module should pass values in the `module` block. Input variable usage is introduced in the Getting Started guide section [_Input Variables_](/intro/getting-started/variables.html). +-> **Note:** For brevity, input variables are often referred to as just +"variables" or "Terraform variables" when it is clear from context what sort of +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)). + ## Declaring an Input Variable Each input variable accepted by a module must be declared using a `variable` @@ -37,35 +44,40 @@ variable "availability_zone_names" { } ``` -For brevity, input variables are often referred to as just "variables" for -short, where it is clear from context what sort of variable is being discussed. - The label after the `variable` keyword is a name for the variable, which must -be unique between all variables in the same module. This name is used to +be unique among all variables in the same module. This name is used to assign a value to the variable from outside and to reference the variable's value from within the module. -The name of a variable can be any valid identifier. However, due to the -interpretation of [module configuration blocks](/docs/configuration/modules.html), -the names `source`, `version`, `providers`, `count`, `for_each`, and `lifecycle` -are reserved for Terraform's own use and may not be declared as variable names. +The name of a variable can be any valid [identifier](./syntax.html#identifiers) +_except_ the following: -The variable declaration may optionally include a `type` argument, which -describes what value types are accepted for the variable, as described +- `source` +- `version` +- `providers` +- `count` +- `for_each` +- `lifecycle` + +These names are reserved for meta-arguments in +[module configuration blocks](./modules.html), and cannot be +declared as variable names. + +The variable declaration can optionally include a `type` argument to +specify what value types are accepted for the variable, as described in the following section. -The variable declaration may also include a `default` argument. If present, +The variable declaration can also include a `default` argument. If present, the variable is considered to be _optional_ and the default value will be used -if no overridden value is set when calling the module. The `default` argument -requires a literal value and cannot reference other objects in the +if no value is set when calling the module or running Terraform. The `default` +argument requires a literal value and cannot reference other objects in the configuration. ## Using Input Variable Values Within the module that declared a variable, its value can be accessed from -within [expressions](/docs/configuration/expressions.html) using an expression -like `var.image_id`, where the name after the period corresponds to the label -given in the declaration block: +within [expressions](./expressions.html) as `var.`, +where `` matches the label given in the declaration block: ```hcl resource "aws_instance" "example" { @@ -79,42 +91,44 @@ the module where it was declared. ## Type Constraints -The `type` argument in a `variable` block allows you to restrict the type of -value that will be accepted as the value for a variable. If no type constraint -is set then a value of any type is accepted. +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 +the value for a variable. If no type constraint is set then a value of any type +is accepted. -While type constraints are optional, we recommend specifying them because it -serves as helpful additional documentation for users of the module and it -allows Terraform to return a helpful error message if the wrong type is used. +While type constraints are optional, we recommend specifying them; they +serve as easy reminders for users of the module, and +allow Terraform to return a helpful error message if the wrong type is used. Type constraints are created from a mixture of type keywords and type -construction functions. The supported type keywords are: +constructors. The supported type keywords are: * `string` * `number` * `bool` -The type construction functions allow you to specify complex types such as +The type constructors allow you to specify complex types such as collections: -* `list()` -* `set()` -* `map()` -* `object({attr_name = , ... })` -* `tuple([, ...])` +* `list()` +* `set()` +* `map()` +* `object({ = , ... })` +* `tuple([, ...])` The keyword `any` may be used to indicate that any type is acceptable. For -more information on the meaning and behavior of these different types, -see [the _Expressions_ section](/docs/configuration/expressions.html). +more information on the meaning and behavior of these different types, as well +as detailed information about automatic conversion of complex types, see +[Type Constraints](./types.html). If both the `type` and `default` arguments are specified, the given default -valuable must be convertible to the specified type. +value must be convertible to the specified type. ## Input Variable Documentation -Because the input variables of a module are part of the user interface of -the module, you may specify a short description of the purpose of each -variable using the optional `description` argument: +Because the input variables of a module are part of its user interface, you can +briefly describe the purpose of each variable using the optional +`description` argument: ```hcl variable "image_id" { @@ -123,9 +137,9 @@ variable "image_id" { } ``` -The description for a variable should be a concise description of the purpose +The description should concisely explain the purpose of the variable and what kind of value is expected. This description string -may be included in documentation about the module, and so it should be written +might be included in documentation about the module, and so it should be written from the perspective of the user of the module rather than its maintainer. For commentary for module maintainers, use comments. @@ -134,35 +148,42 @@ commentary for module maintainers, use comments. When variables are declared in the root module of your configuration, they can be set in a number of ways: -* Individual assignments made on the command line. -* Variable definitions files, either specified on the command line or - automatically loaded. -* Environment variables. +* [In a Terraform Enterprise workspace](/docs/enterprise/workspaces/variables.html). +* Individually, with the `-var` command line option. +* In variable definitions (`.tfvars`) files, either specified on the command line + or automatically loaded. +* As environment variables. 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_](/docs/configuration/modules.html). +[_Modules_](./modules.html). ### Variables on the Command Line -To specify individual modules on the command line, use the `-var` argument -that is accepted by the `terraform plan` and `terraform apply` commands: +To specify individual modules on the command line, use the `-var` option +when running the `terraform plan` and `terraform apply` commands: ``` terraform apply -var="image_id=ami-abc123" ``` -### Variable Definitions Files +The `-var` option can be used any number of times in a single command. + +### Variable Definitions (`.tfvars`) Files To set lots of variables, it is more convenient to specify their values in -a _variable definitions file_, with a filename ending in either `.tfvars` -or `.tfvars.json`, and then specify that filename on the command line: +a _variable definitions file_ (with a filename ending in either `.tfvars` +or `.tfvars.json`) and then specify that file on the command line with +`-var-file`: ``` terraform apply -var-file="testing.tfvars" ``` +-> **Note:** This is how Terraform Enterprise passes +[workspace variables](/docs/enterprise/workspaces/variables.html) to Terraform. + A variable definitions file uses the same basic syntax as Terraform language files, but consists only of variable name assignments: @@ -175,10 +196,10 @@ availability_zone_names = [ ``` Terraform also automatically loads a number of variable definitions files -automatically if they are present: +if they are present: * Files named exactly `terraform.tfvars` or `terraform.tfvars.json`. -* Any files with names ending in either `.auto.tfvars` or `.auto.tfvars.json`. +* Any files with names ending in `.auto.tfvars` or `.auto.tfvars.json`. Files whose names end with `.json` are parsed instead as JSON objects, with the root object properties corresponding to variable names: @@ -213,23 +234,23 @@ and lower case letters as in the above example. ### Complex-typed Values -When variable values are provided in a variable definitions file, the usual -syntax can be used to assign complex-typed values, like lists and maps. +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. Some special rules apply to the `-var` command line option and to environment -variables: to allow string values to be set conveniently, by default values -assigned in these ways are interpreted as literal strings, and thus do not -need to be themselves quoted: +variables. For convenience, Terraform defaults to interpreting `-var` and +environment variable values as literal strings, which do not need to be quoted: ``` $ export TF_VAR_image_id=ami-abc123 ``` -However, if a variable in the root module is declared as being of a complex -type (list, set, map, object, or tuple), Terraform will instead attempt to -parse it using the same syntax used within variable definitions files, -which requires cafeful attention to the string escaping rules in your -shell: +However, if a root module variable uses a [type constraint](#type-constraints) +to require a complex value (list, set, map, object, or tuple), Terraform will +instead attempt to parse its value using the same syntax used within variable +definitions files, which requires cafeful attention to the string escaping rules +in your shell: ``` $ export TF_VAR_availability_zone_names='["us-west-1b","us-west-1d"]' @@ -240,13 +261,23 @@ recommend always setting complex variable values via varable definitions files. ### Variable Definition Precedence -The above mechanisms for defining variable values can be used together in -any combination. If the same variable is assigned multiple values, the -processing order is as follows, with the later items in this list taking -precedence over the earlier: +The above mechanisms for setting variables can be used together in any +combination. If the same variable is assigned multiple values, Terraform uses +the _last_ value it finds, overriding any previous values. -* Environment Variables +Terraform loads variables in the following order, with later sources taking +precedence over earlier ones: + +* Environment variables * The `terraform.tfvars` file, if present. * The `terraform.tfvars.json` file, if present. -* Any `-var` and `-var-file` arguments on the command line, in the order they - are provided. +* Any `*.auto.tfvars` or `*.auto.tfvars.json` files, processed in lexical order + of their filenames. +* Any `-var` and `-var-file` options on the command line, in the order they + are provided. (This includes variables set by a Terraform Enterprise + workspace.) + +~> **Important:** In Terraform 0.12 and later, variables with map and object +values behave the same way as other variables: the last value found overrides +the previous values. This is a change from previous versions of Terraform, which +would _merge_ map values instead of overriding them. diff --git a/website/layouts/docs.erb b/website/layouts/docs.erb index c9d6a757a..478fa8af2 100644 --- a/website/layouts/docs.erb +++ b/website/layouts/docs.erb @@ -2,7 +2,7 @@ <% content_for :sidebar do %>