Terraform
- Plugin Framework
- v1.16.x (latest)
- No versions of this document exist before v1.15.x. Click below to redirect to the version homepage.
- v1.15.x
- v1.14.x
- v1.13.x
- v1.12.x
- v1.11.x
- v1.10.x
- v1.9.x
- v1.8.x
- v1.7.x
- v1.6.x
- v1.5.x
- v1.4.x
- v1.3.x
- v1.2.x
- v1.1.x
- v1.0.x
- v0.16.x
- v0.15.x
- v0.14.x
- v0.13.x
- v0.12.x
- v0.11.x
- v0.10.x
- v0.9.x
- v0.8.x
- v0.7.x
Writing State
Note: The Plugin Framework is in beta.
One of the primary jobs of a Terraform provider is to manage the provider's resources and data sources in the Terraform state. Writing values to state is something that provider developers will do frequently.
The state that a provider developer wants to update is usually stored in a response object:
func (r ThingResource) Create(ctx context.Context,
    req resource.CreateRequest, resp *resource.CreateResponse)
In this example, resp holds the state that the provider developer should
update.
Replace the Entire State
One way to set the state is to replace all the state values for a resource or data source all at once. You need to define a type to contain the values. The benefit is that this allows the compiler to check all code that sets values on state, and only the final call to persist state can return an error.
Use the Set method to store the entire state data.
type ThingResourceModel struct {
    Address    types.Object `tfsdk:"address"`
    Age        types.Int64  `tfsdk:"age"`
    Name       types.String `tfsdk:"name"`
    Pets       types.List   `tfsdk:"pets"`
    Registered types.Bool   `tfsdk:"registered"`
    Tags       types.Map    `tfsdk:"tags"`
}
func (r ThingResource) Create(ctx context.Context,
    req resource.CreateRequest, resp *resource.CreateResponse) {
    var newState ThingResourceModel
    // ...
    // update newState by modifying each property as usual for Go values
    newState.Name = types.StringValue("J. Doe")
    // persist the values to state
    diags := resp.State.Set(ctx, &newState)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }
}
The state information is represented as an object, and gets persisted like an object. Refer to the conversion rules for an explanation on how objects get persisted and what Go types are valid for persisting as an object.
Set a Single Attribute or Block Value
Use the SetAttribute method to set an individual attribute or block value.
The value must not be an untyped nil. Use a typed nil or types package null value function instead. For example with a types.StringType attribute, use (*string)(nil) or types.StringNull().
func (r ThingResource) Read(ctx context.Context,
    req resource.ReadRequest, resp *resource.ReadResponse) {
    // ...
    diags := resp.State.SetAttribute(ctx, path.Root("age"), 7)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }
}
Refer to the conversion rules for more information about supported Go types.
Conversion Rules
The following is a list of schema types and the Go types they know how to
accept in Set and SetAttribute.
String
Strings can be automatically created from Go's string type (or any aliases of
it, like type MyString string).
Number
Numbers can be automatically created from the following numeric types (or any
aliases of them, like type MyNumber int):
- int,- int8,- int16,- int32,- int64
- uint,- uint8,- uint16,- uint32,- uint64
- float32,- float64
- *big.Int,- *big.Float
Boolean
Booleans can be automatically created from Go's bool type (or any aliases of
it, like type MyBoolean bool).
List
Lists can be automatically created from any Go slice type (or alias of a Go
slice type, like type MyList []string), with the elements either being
attr.Value implementations or being converted according to these rules.
Map
Maps can be automatically created from any Go map type with string keys (or any
alias of a Go map type with string keys, like type MyMap map[string]int),
with the elements either being attr.Value implementations or being converted
according to these rules.
Object
Objects can be automatically created from any Go struct type with that follows these constraints:
- Every property on the struct must have a tfsdkstruct tag.
- The tfsdkstruct tag must name an attribute in the object that it is being mapped to or be set to-to explicitly declare it does not map to an attribute in the object.
- Every attribute in the object must have a corresponding struct tag.
These rules help prevent typos and human error from unwittingly discarding information by failing as early, consistently, and loudly as possible.
Properties can either be attr.Value implementations or will be converted
according to these rules.
Pointers
A nil pointer will be treated as a null value. Otherwise, the rules for the type the pointer is referencing apply.
Detected Interfaces
Set detects and utilizes the following interfaces, if the target implements
them.
ValueCreator
If a value is set on a Go type that implements the tftypes.ValueCreator
interface,
that interface will be delegated to to handle the conversion.
Unknownable
If a value is set on a Go type that fills the Unknownable interface:
type Unknownable interface {
    SetUnknown(context.Context, bool) error
    SetValue(context.Context, interface{}) error
    GetUnknown(context.Context) bool
    GetValue(context.Context) interface{}
}
It will be used to convert the value. The interface{} being passed and
retrieved will be of a type that can be passed to
tftypes.NewValue.
Nullable
If a value is set on a Go type that fills the Nullable interface:
type Nullable interface {
    SetNull(context.Context, bool) error
    SetValue(context.Context, interface{}) error
    GetNull(context.Context) bool
    GetValue(context.Context) interface{}
}
It will be used to convert the value. The interface{} being passed and
retrieved will be of a type that can be passed to
tftypes.NewValue.