Terraform
Schema Behaviors
Schema fields that can have an effect at plan or apply time are collectively
referred to as "Behavioral fields", or an element's behaviors. These fields are
often combined in several ways to create different behaviors, depending on the
need of the element in question, typically customized to match the behavior of a
cloud service API. For example, at time of writing, AWS Launch Configurations
cannot be updated through the AWS API. As a result, all of the schema elements in
the corresponding Terraform Provider resource aws_launch_configuration
are
marked as ForceNew: true
. This behavior instructs Terraform to first destroy
and then recreate the resource if any of the attributes change in the
configuration, as opposed to trying to update the existing resource.
Primitive Behaviors
Note: The primitive behavior fields cannot be set to false
. You can opt out of a behavior by omitting it.
Optional
Data structure: bool
Values: true
Restrictions:
- Cannot be used if
Required
istrue
- Must be set if
Required
is omitted and element is notComputed
Indicates that this element is optional to include in the configuration. Note
that Optional
does not itself establish a default value. See Default
below.
Schema example:
"encrypted": {
Type: schema.TypeBool,
Optional: true,
},
Configuration example:
resource "example_volume" "ex" {
encrypted = true
}
Required
Data structure: bool
Values: true
Restrictions:
- Cannot be used if
Optional
istrue
- Cannot be used if
Computed
istrue
- Must be set if
Optional
is omitted and element is notComputed
Indicates that this element must be provided in the configuration. Omitting this attribute from configuration, or later removing it, will result in a plan-time error.
Schema example:
"name": {
Type: schema.TypeString,
Required: true,
},
Configuration example:
resource "example_volume" "ex" {
name = "swap volume"
}
Default
Data structure: interface
Value: any value of an elements Type
for primitive types, or the type
defined by Elem
for complex types.
Restrictions:
- Cannot be used if
Required
istrue
- Cannot be used with
DefaultFunc
If Default
is specified, Terraform will use that value when this item is not set in
the configuration.
Schema example:
"encrypted": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
Configuration example (specified):
resource "example_volume" "ex" {
name = "swap volume"
encrypted = true
}
Configuration example (omitted):
resource "example_volume" "ex" {
name = "swap volume"
# encrypted receives its default value, false
}
Computed
Data structure: bool
Value: true
Restrictions:
- Cannot be used when
Required
istrue
- Cannot be used when
Default
isspecified
- Cannot be used with
DefaultFunc
Computed
is often used to represent values that are not user configurable or
can not be known at time of terraform plan
or apply
, such as date of
creation or a service specific UUID. Computed
can be combined with other
attributes to achieve specific behaviors, and can be used as output for
interpolation into other resources
Schema example:
"uuid": {
Type: schema.TypeString,
Computed: true,
},
Configuration example:
resource "example_volume" "ex" {
name = "swap volume"
encrypted = true
}
output "volume_uuid" {
value = "${example_volume.ex.uuid}"
}
ForceNew
Data structure: bool
Value: true
ForceNew
indicates that any change in this field requires the resource to be
destroyed and recreated.
Schema example:
"base_image": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
Configuration example:
resource "example_instance" "ex" {
name = "bastion host"
base_image = "ubuntu_17.10"
}
Function Behaviors
DiffSuppressFunc
Data structure: SchemaDiffSuppressFunc
When provided DiffSuppressFunc
will be used by Terraform to calculate the diff
of this field. Common use cases are capitalization differences in string names,
or logical equivalences in JSON values.
Schema example:
"base_image": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
// Suppress the diff shown if the base_image name are equal when both compared in lower case.
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
if strings.ToLower(old) == strings.ToLower(new) {
return true
}
return false
},
},
Configuration example:
Here we assume the service API accepts capitalizations of the base_image
name
and converts it to a lowercase string. The API then returns the lower case value
in its responses.
resource "example_instance" "ex" {
name = "bastion host"
base_image = "UBunTu_17.10"
}
DefaultFunc
Data structure: SchemaDefaultFunc
Restrictions:
- Cannot be used if
Default
is specified
When provided DefaultFunc
will be used to compute a dynamic default for this element.
The return value of this function should be "stable", such that it is uncommon
to return different values in subsequent plans without any other changes being
made, to avoid unnecessary diffs in terraform plan
.
DefaultFunc
is most commonly used in Provider schemas to allow elements to have
defaults that are read from the environment.
Schema example:
In this example, Terraform will attempt to read region
from the environment if
it is omitted from configuration. If it’s not found in the environment, a
default value of us-west
is given.
"region": {
Type: schema.TypeString,
Required: true,
DefaultFunc: func() (any, error) {
if v := os.Getenv("PROVIDER_REGION"); v != "" {
return v, nil
}
return "us-west", nil
},
},
Configuration example (provided):
provider "example" {
api_key = "somesecretkey"
region = "us-east"
}
Configuration example (default func with PROVIDER_REGION
set to us-east
in
the environment):
provider "example" {
api_key = "somesecretkey"
# region is "us-east"
}
Configuration example (default func with PROVIDER_REGION
unset in the
environment):
provider "example" {
api_key = "somesecretkey"
# region is "us-west"
}
StateFunc
Data structure: SchemaStateFunc
StateFunc
is a function used to convert the value of this element to a string to be stored in the state.
Schema example:
In this example, the StateFunc
converts a string value to all lower case.
"name": &schema.Schema{
Type: schema.TypeString,
ForceNew: true,
Required: true,
StateFunc: func(val any) string {
return strings.ToLower(val.(string))
},
},
Configuration example (provided):
resource "example" "ex_instance" {
name = "SomeValueCASEinsensitive"
}
Value in statefile:
"name": "somevaluecaseinsensitive"
ValidateFunc
Deprecated: Use ValidateDiagFunc
instead.
Data structure: SchemaValidateFunc
Restrictions:
- Only works with primitive types
ValidateFunc
is a function used to validate the value of a primitive type. Common use cases include ensuring an integer falls within a range or a string value is present in a list of valid options. The function returns two slices; the first for warnings, the second for errors which can be used to catch multiple invalid cases. Terraform will only halt execution if an error is returned. Returning warnings will warn the user but the data provided is considered valid.
Terraform includes a number of validators for use in plugins in the validation package. A full list can be found here: https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/helper/validation
Schema example:
In this example, the ValidateFunc
ensures the integer provided is a value between 0 and 10.
"amount": &schema.Schema{
Type: schema.TypeInt,
Required: true,
ValidateFunc: func(val any, key string) (warns []string, errs []error) {
v := val.(int)
if v < 0 || v > 10 {
errs = append(errs, fmt.Errorf("%q must be between 0 and 10 inclusive, got: %d", key, v))
}
return
},
},
Configuration example:
resource "example" "ex_instance" {
amount = "-1"
}
ValidateDiagFunc
Data structure: SchemaValidateDiagFunc
Restrictions:
- Only works with primitive types
ValidateDiagFunc
is a function used to validate the value of a primitive type. Common use cases include ensuring an integer falls within a range or a string value is present in a list of valid options. The function returns a collection of Diagnostics. Developers should append and build the list of diagnostics up until a fatal error is reached, at which point they should return the Diagnostics. Terraform will only halt execution if an error is returned. Warnings will display a warning message to the practitioner, but continue execution.
The SDK includes some basic validators in the helper/validation
package.
Schema example:
In this example, the ValidateDiagFunc
ensures the string is abc
.
"sample": &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: func(v any, p cty.Path) diag.Diagnostics {
value := v.(string)
expected := "abc"
var diags diag.Diagnostics
if value != expected {
diag := diag.Diagnostic{
Severity: diag.Error,
Summary: "wrong value",
Detail: fmt.Sprintf("%q is not %q", value, expected),
}
diags = append(diags, diag)
}
return diags
},
},
Configuration example:
resource "example" "ex_instance" {
sample = "efg"
}