mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Apply suggestions from PR review
This commit is contained in:
parent
686dbcdb8d
commit
ba3bb5ad5d
@ -39,159 +39,10 @@ The condition can be any expression that resolves to a boolean value. This will
|
||||
usually be an expression that uses the equality, comparison, or logical
|
||||
operators.
|
||||
|
||||
The following language features are particularly useful when writing condition expressions.
|
||||
### Custom Condition Checks
|
||||
|
||||
### `contains` Function
|
||||
You can create conditions that produce custom error messages for several types of objects in a configuration. For example, you can add a condition to an input variable that checks whether incoming image IDs are formatted properly.
|
||||
|
||||
Use the built-in function `contains` to test whether a given value is one of a set of predefined valid values.
|
||||
Custom conditions can help capture assumptions, helping future maintainers understand the configuration design and intent. They also return useful information about errors earlier and in context, helping consumers more easily diagnose issues in their configurations.
|
||||
|
||||
```hcl
|
||||
condition = contains(["STAGE", "PROD"], var.environment)
|
||||
```
|
||||
|
||||
### Boolean Operators
|
||||
|
||||
Use the boolean operators `&&` (AND), `||` (OR), and `!` (NOT) to combine multiple conditions together.
|
||||
|
||||
```hcl
|
||||
condition = var.name != "" && lower(var.name) == var.name
|
||||
```
|
||||
|
||||
### `length` Function
|
||||
|
||||
Require a non-empty list or map by testing the collection's length.
|
||||
|
||||
```hcl
|
||||
condition = length(var.items) != 0
|
||||
```
|
||||
This is a better approach than directly comparing with another collection using `==` or `!=`. This is because the comparison operators can only return `true` if both operands have exactly the same type, which is often ambiguous for empty collections.
|
||||
|
||||
### `for` Expressions
|
||||
|
||||
Use `for` expressions in conjunction with the functions `alltrue` and `anytrue` to test whether a condition holds for all or for any elements of a collection.
|
||||
|
||||
```hcl
|
||||
condition = alltrue([
|
||||
for v in var.instances : contains(["t2.micro", "m3.medium"], v.type)
|
||||
])
|
||||
```
|
||||
|
||||
### `can` Function
|
||||
|
||||
Use the `can` function to concisely use the validity of an expression as a condition. It returns `true` if its given expression evaluates successfully and `false` if it returns any error, so you can use various other functions that typically return errors as a part of your condition expressions.
|
||||
|
||||
For example, you can use `can` with `regex` to test if a string matches a particular pattern because `regex` returns an error when given a non-matching string.
|
||||
|
||||
```hcl
|
||||
condition = can(regex("^[a-z]+$", var.name)
|
||||
```
|
||||
|
||||
You can also use `can` with the type conversion functions to test whether a value is convertible to a type or type constraint.
|
||||
|
||||
```hcl
|
||||
# This remote output value must have a value that can
|
||||
# be used as a string, which includes strings themselves
|
||||
# but also allows numbers and boolean values.
|
||||
condition = can(tostring(data.terraform_remote_state.example.outputs["name"]))
|
||||
```
|
||||
|
||||
```hcl
|
||||
# This remote output value must be convertible to a list
|
||||
# type of with element type.
|
||||
condition = can(tolist(data.terraform_remote_state.example.outputs["items"]))
|
||||
```
|
||||
|
||||
You can also use `can` with attribute access or index operators to test whether a collection or structural value has a particular element or index.
|
||||
|
||||
```hcl
|
||||
# var.example must have an attribute named "foo"
|
||||
condition = can(var.example.foo) ```
|
||||
|
||||
```hcl
|
||||
# var.example must be a sequence with at least one element
|
||||
condition = can(var.example[0])
|
||||
# (although it would typically be clearer to write this as a
|
||||
# test like length(var.example) > 0 to better represent the
|
||||
# intent of the condition.)
|
||||
```
|
||||
|
||||
### `self` Object
|
||||
|
||||
Use the `self` object in postcondition blocks to refer to attributes of the instance under evaluation.
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "example" {
|
||||
instance_type = "t2.micro"
|
||||
ami = "ami-abc123"
|
||||
|
||||
lifecycle {
|
||||
postcondition {
|
||||
condition = self.instance_state == "running"
|
||||
error_message = "EC2 instance must be running."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `each` and `count` Objects
|
||||
|
||||
In blocks where `for_each` or `count` are set, use `each` and `count` objects to refer to other resources that are expanded in a chain.
|
||||
|
||||
```hcl
|
||||
variable "vpc_cidrs" {
|
||||
type = set(string)
|
||||
}
|
||||
|
||||
data "aws_vpc" "example" {
|
||||
for_each = var.vpc_cidrs
|
||||
|
||||
filter {
|
||||
name = "cidr"
|
||||
values = [each.key]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "example" {
|
||||
for_each = aws_vpc.example
|
||||
vpc_id = each.value.id
|
||||
|
||||
lifecycle {
|
||||
precondition {
|
||||
condition = aws_vpc.example[each.key].state == "available"
|
||||
error_message = "VPC ${each.key} must be available."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Result Types
|
||||
|
||||
The two result values may be of any type, but they must both
|
||||
be of the _same_ type so that Terraform can determine what type the whole
|
||||
conditional expression will return without knowing the condition value.
|
||||
|
||||
If the two result expressions don't produce the same type then Terraform will
|
||||
attempt to find a type that they can both convert to, and make those
|
||||
conversions automatically if so.
|
||||
|
||||
For example, the following expression is valid and will always return a string,
|
||||
because in Terraform all numbers can convert automatically to a string using
|
||||
decimal digits:
|
||||
|
||||
```hcl
|
||||
var.example ? 12 : "hello"
|
||||
```
|
||||
|
||||
Relying on this automatic conversion behavior can be confusing for those who
|
||||
are not familiar with Terraform's conversion rules though, so we recommend
|
||||
being explicit using type conversion functions in any situation where there may
|
||||
be some uncertainty about the expected result type.
|
||||
|
||||
The following example is contrived because it would be easier to write the
|
||||
constant `"12"` instead of the type conversion in this case, but shows how to
|
||||
use [`tostring`](/language/functions/tostring) to explicitly convert a number to
|
||||
a string.
|
||||
|
||||
```hcl
|
||||
var.example ? tostring(12) : "hello"
|
||||
```
|
||||
Refer to [Custom Condition Checks](/language/expressions/custom-conditions#input-variable-validation) for details.
|
||||
|
@ -185,7 +185,164 @@ You should also consider the following factors.
|
||||
Input variable validation, preconditions, and postconditions all require a `condition` argument. This is a boolean expression that should return `true` if the intended assumption or guarantee is fulfilled or `false` if it does not.
|
||||
|
||||
You can use any of Terraform's built-in functions or language operators
|
||||
in a condition as long as the expression is valid and returns a boolean result. Refer to [Conditional Expressions](/language/expressions/conditionals#conditions) for more details and examples.
|
||||
in a condition as long as the expression is valid and returns a boolean result.
|
||||
|
||||
The following language features are particularly useful when writing condition expressions.
|
||||
|
||||
### `contains` Function
|
||||
|
||||
Use the built-in function `contains` to test whether a given value is one of a set of predefined valid values.
|
||||
|
||||
```hcl
|
||||
condition = contains(["STAGE", "PROD"], var.environment)
|
||||
```
|
||||
|
||||
### Boolean Operators
|
||||
|
||||
Use the boolean operators `&&` (AND), `||` (OR), and `!` (NOT) to combine multiple conditions together.
|
||||
|
||||
```hcl
|
||||
condition = var.name != "" && lower(var.name) == var.name
|
||||
```
|
||||
|
||||
### `length` Function
|
||||
|
||||
Require a non-empty list or map by testing the collection's length.
|
||||
|
||||
```hcl
|
||||
condition = length(var.items) != 0
|
||||
```
|
||||
This is a better approach than directly comparing with another collection using `==` or `!=`. This is because the comparison operators can only return `true` if both operands have exactly the same type, which is often ambiguous for empty collections.
|
||||
|
||||
### `for` Expressions
|
||||
|
||||
Use `for` expressions in conjunction with the functions `alltrue` and `anytrue` to test whether a condition holds for all or for any elements of a collection.
|
||||
|
||||
```hcl
|
||||
condition = alltrue([
|
||||
for v in var.instances : contains(["t2.micro", "m3.medium"], v.type)
|
||||
])
|
||||
```
|
||||
|
||||
### `can` Function
|
||||
|
||||
Use the `can` function to concisely use the validity of an expression as a condition. It returns `true` if its given expression evaluates successfully and `false` if it returns any error, so you can use various other functions that typically return errors as a part of your condition expressions.
|
||||
|
||||
For example, you can use `can` with `regex` to test if a string matches a particular pattern because `regex` returns an error when given a non-matching string.
|
||||
|
||||
```hcl
|
||||
condition = can(regex("^[a-z]+$", var.name)
|
||||
```
|
||||
|
||||
You can also use `can` with the type conversion functions to test whether a value is convertible to a type or type constraint.
|
||||
|
||||
```hcl
|
||||
# This remote output value must have a value that can
|
||||
# be used as a string, which includes strings themselves
|
||||
# but also allows numbers and boolean values.
|
||||
condition = can(tostring(data.terraform_remote_state.example.outputs["name"]))
|
||||
```
|
||||
|
||||
```hcl
|
||||
# This remote output value must be convertible to a list
|
||||
# type of with element type.
|
||||
condition = can(tolist(data.terraform_remote_state.example.outputs["items"]))
|
||||
```
|
||||
|
||||
You can also use `can` with attribute access or index operators to test whether a collection or structural value has a particular element or index.
|
||||
|
||||
```hcl
|
||||
# var.example must have an attribute named "foo"
|
||||
condition = can(var.example.foo) ```
|
||||
|
||||
```hcl
|
||||
# var.example must be a sequence with at least one element
|
||||
condition = can(var.example[0])
|
||||
# (although it would typically be clearer to write this as a
|
||||
# test like length(var.example) > 0 to better represent the
|
||||
# intent of the condition.)
|
||||
```
|
||||
|
||||
### `self` Object
|
||||
|
||||
Use the `self` object in postcondition blocks to refer to attributes of the instance under evaluation.
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "example" {
|
||||
instance_type = "t2.micro"
|
||||
ami = "ami-abc123"
|
||||
|
||||
lifecycle {
|
||||
postcondition {
|
||||
condition = self.instance_state == "running"
|
||||
error_message = "EC2 instance must be running."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `each` and `count` Objects
|
||||
|
||||
In blocks where `for_each` or `count` are set, use `each` and `count` objects to refer to other resources that are expanded in a chain.
|
||||
|
||||
```hcl
|
||||
variable "vpc_cidrs" {
|
||||
type = set(string)
|
||||
}
|
||||
|
||||
data "aws_vpc" "example" {
|
||||
for_each = var.vpc_cidrs
|
||||
|
||||
filter {
|
||||
name = "cidr"
|
||||
values = [each.key]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "example" {
|
||||
for_each = aws_vpc.example
|
||||
vpc_id = each.value.id
|
||||
|
||||
lifecycle {
|
||||
precondition {
|
||||
condition = aws_vpc.example[each.key].state == "available"
|
||||
error_message = "VPC ${each.key} must be available."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Result Types
|
||||
|
||||
The two result values may be of any type, but they must both
|
||||
be of the _same_ type so that Terraform can determine what type the whole
|
||||
conditional expression will return without knowing the condition value.
|
||||
|
||||
If the two result expressions don't produce the same type then Terraform will
|
||||
attempt to find a type that they can both convert to, and make those
|
||||
conversions automatically if so.
|
||||
|
||||
For example, the following expression is valid and will always return a string,
|
||||
because in Terraform all numbers can convert automatically to a string using
|
||||
decimal digits:
|
||||
|
||||
```hcl
|
||||
var.example ? 12 : "hello"
|
||||
```
|
||||
|
||||
Relying on this automatic conversion behavior can be confusing for those who
|
||||
are not familiar with Terraform's conversion rules though, so we recommend
|
||||
being explicit using type conversion functions in any situation where there may
|
||||
be some uncertainty about the expected result type.
|
||||
|
||||
The following example is contrived because it would be easier to write the
|
||||
constant `"12"` instead of the type conversion in this case, but shows how to
|
||||
use [`tostring`](/language/functions/tostring) to explicitly convert a number to
|
||||
a string.
|
||||
|
||||
```hcl
|
||||
var.example ? tostring(12) : "hello"
|
||||
```
|
||||
|
||||
## Error Messages
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user