Terraform
State upgraders
This page explains how to migrate resource StateUpgraders in SDKv2 to
UpgradeState in the plugin framework.
Background
When you update a resource's implementation in your provider, some changes may not be compatible with old versions. You can implement state upgraders in your provider to automatically migrate resources provisioned with old schema configurations. Refer to State Upgrade in the framework documentation for details about implementing state upgraders.
Migrating state upgraders
In SDKv2, state upgraders are defined by populating the StateUpgraders field
on the schema.Resource struct. Refer to State
Migration in the SDKv2
documentation for details.
In the framework, you implement the
ResourceWithUpgradeState
interface on your resource to upgrade your resource's state when required.
The following code shows a basic implementation of the stateUpgraders field in
SDKv2.
SDKv2
func resourceExample() *schema.Resource {
    return &schema.Resource{
        StateUpgraders: []schema.StateUpgrader{
            {
                Version: int,
                Type:    cty.Type,
                Upgrade: StateUpgradeFunc,
            },
            /* ... */
The following code shows how you ensure that your resource satisfies the
resource.ResourceWithUpgradeState interface with the framework.
Framework
var (
    _ resource.Resource                 = &resourceExample{}
    _ resource.ResourceWithUpgradeState = &resourceExample{}
)
The following code shows how you define an UpgradeState function with the
framework.
Framework
func (r *resourceExample) UpgradeState(context.Context) map[int64]resource.StateUpgrader {
    return map[int64]resource.StateUpgrader{
        0: {
            PriorSchema:   *schema.Schema,
            StateUpgrader: func(context.Context, UpgradeStateRequest, *UpgradeStateResponse),
        },
        /* ... */
The UpgradeState function returns a map from state versions to structs that
implement state upgrade from the given version to the latest version.
Migration Notes
Remember the following differences between SDKv2 and the framework when completing the migration.
- In SDKv2, you implement state upgraders populating the StateUpgradersfield on theschema.Resourcestruct. In the framework, you ensure that your resource implements theResourceWithUpgradeStateinterface, and then define anUpgradeState()function on the resource.
- In SDKv2, state upgraders apply each state upgrader in turn. For example,
version 0 => version 1, version 1 => version 2. In the framework, each
StateUpgraderfunction is required to perform all of the necessary transformations in a single step. For example, version 0 => version 2, version 1 => version 2.
Examples
Migrating state upgraders
In SDKv2 the schema.Resource struct has a StateUpgraders field that holds
[]schema.StateUpgrader struct(s).
In the framework, ensure your resource type implements the
ResourceWithUpgradeState interface, and add an UpgradeState() function to
upgrade your resource state.
The following example from the shows the state upgrade functions for the
example_resource resource with SDKv2.
SDKv2
func exampleResource() *schema.Resource {
    return &schema.Resource{
        Schema:        exampleSchemaV2(),
        SchemaVersion: 2,
        StateUpgraders: []schema.StateUpgrader{
            {
                Version: 0,
                Type:    exampleResourceV0().CoreConfigSchema().ImpliedType(),
                Upgrade: exampleResourceStateUpgradeV0,
            },
            {
                Version: 1,
                Type:    exampleResourceV1().CoreConfigSchema().ImpliedType(),
                Upgrade: exampleResourceStateUpgradeV1,
            },
        },
        /* ... */
The following example shows the implementation of the
exampleResourceStateUpgradeV0 function with SDKv2.
SDKv2
func exampleResourceStateUpgradeV0(_ context.Context, rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
    if rawState == nil {
        return nil, fmt.Errorf("example resource state upgrade failed, state is nil")
    }
    rawState["example_attribute"] = "value"
    return rawState, nil
}
The following shows the same section of provider code after the migration.
This code implements the ResourceWithUpgradeState interface on the
exampleResource type by defining an UpgradeState function. The
UpgradeState function returns a map from each state version (int64) to a
ResourceStateUpgrader struct.
Framework
func (r *exampleResource) UpgradeState(context.Context) map[int64]resource.StateUpgrader {
    schemaV0 := exampleSchemaV0()
    schemaV1 := exampleSchemaV1()
    return map[int64]resource.StateUpgrader{
        0: {
            PriorSchema:   &schemaV0,
            StateUpgrader: upgradeExampleResourceStateV0toV2,
        },
        1: {
            PriorSchema:   &schemaV1,
            StateUpgrader: upgradeExampleResourceStateV1toV2,
        },
    }
}
The following code implements the upgradeExampleResourceStateV0toV2 state
upgrade function.
Framework
func upgradeExampleResourceStateV0toV2(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
    type modelV0 struct {
        ID    types.String `tfsdk:"id"`
    }
    var exampleDataV0 modelV0
    resp.Diagnostics.Append(req.State.Get(ctx, &exampleDataV0)...)
    if resp.Diagnostics.HasError() {
        return
    }
    exampleDataV2 := exampleModelV2{
        ID:    exampleDataV0.ID,
    }
    exampleDataV2.ExampleAttribute = types.StringValue("value")
    diags := resp.State.Set(ctx, exampleDataV2)
    resp.Diagnostics.Append(diags...)