A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://developer.hashicorp.com/terraform/plugin/framework/migrating/resources/plan-modification below:

Plan modification | Terraform | HashiCorp Developer

Your provider can modify the Terraform plan to match the expected end state. This can include replacing unknown values with expected known values or marking a resource that must be replaced. Refer to Plan Modification in the framework documentation for more details about implementing plan modifiers.

This page explains how to migrate resource CustomizeDiff functions in SDKv2 to PlanModifiers in the plugin framework.

In SDKv2, plan modification is implemented with the CustomizeDiff field on the schema.Resource struct.

In the framework, you implement the ResourceWithImportState interface on your resource.Resource type to allow users to import a given resource. To use this interface, your type must implement an ImportState function.

In the framework, either implement the ResourceWithModifyPlan interface on your resource.Resource type or implement *PlanModifiers() functions on individual attributes. Refer to Attributes - Force New in this guide for more information on how to implement a plan modifier on an attribute.

The following code shows a basic implementation of plan modification with SDKv2.

SDKv2

func resourceExample() *schema.Resource {
    return &schema.Resource{
        CustomizeDiff: CustomizeDiffFunc,
        /* ... */

The following code shows how you ensure that your resource satisfies the resource.ResourceWithModifyPlan interface with the framework.

Framework

var (
    _ resource.Resource                = &resourceExample{}
    _ resource.ResourceWithModifyPlan  = &resourceExample{}
)

The following code shows how you can implement the ModifyPlan function in the framework.

Framework

func (r *resourceExample) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
    /* ... */
}
Migration Notes

Remember the following differences between SDKv2 and the framework when completing the migration.

Examples

Many existing CustomizeDiff implementations would be better suited to migration to attribute plan modifiers in the framework.

Synchronize attributes

The following example shows one way to implement CustomizeDiff in SDKv2 and PlanModifiers in the framework so that two attributes contain the same value.

In SDKv2, the CustomizeDiff field on the schema.Resource struct refers to a function or set of functions that implement plan modification.

SDKv2

func resourcePassword() *schema.Resource {
    /* ... */
    customizeDiffFuncs = append(customizeDiffFuncs, planSyncIfChange("attribute_one", "attribute_two"))
    customizeDiffFuncs = append(customizeDiffFuncs, planSyncIfChange("attribute_two", "attribute_one"))

    return &schema.Resource{
        /* ... */
        CustomizeDiff: customdiff.All(
            customizeDiffFuncs...,
        ),
    }
}

The following example shows the implementation of the planSyncIfChange function in an SDKv2 provider.

SDKv2

func planSyncIfChange(key, keyToSync string) func(context.Context, *schema.ResourceDiff, interface{}) error {
    return customdiff.IfValueChange(
        key,
        func(ctx context.Context, oldValue, newValue, meta interface{}) bool {
            return oldValue != newValue
        },
        func(_ context.Context, d *schema.ResourceDiff, _ interface{}) error {
            return d.SetNew(keyToSync, d.Get(key))
        },
    )
}

The following code shows the implementation using attribute plan modifiers with the framework.

Framework

func exampleSchema() schema.Schema {
    return schema.Schema{
        /* ... */
        Attributes: map[string]schema.Attribute{
            /* ... */
            "attribute_one": schema.BoolAttribute{
                /* ... */
                PlanModifiers: []planmodifier.Bool{
                    planmodifiers.SyncAttributePlanModifier(),
                    /* ... */
                },
            },

            "attribute_two": schema.BoolAttribute{
                /* ... */
                PlanModifiers: []planmodifier.Bool{
                    planmodifiers.SyncAttributePlanModifier(),
                    /* ... */
                },
            },

The following shows an implementation of SyncAttributePlanModifier in the framework.

Framework

func SyncAttributePlanModifier() planmodifier.Bool {
    return &syncAttributePlanModifier{}
}

type syncAttributePlanModifier struct {
}

func (d *syncAttributePlanModifier) Description(ctx context.Context) string {
    return "Ensures that attribute_one and attribute_two attributes are kept synchronised."
}

func (d *syncAttributePlanModifier) MarkdownDescription(ctx context.Context) string {
    return d.Description(ctx)
}

func (d *syncAttributePlanModifier) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) {
    var attributeOne types.Bool
    diags := req.Plan.GetAttribute(ctx, path.Root("attribute_one"), &attributeOne)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    var attributeTwo types.Bool
    req.Plan.GetAttribute(ctx, path.Root("attribute_two"), &attributeTwo)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    if !attributeOne.IsNull() && !attributeTwo.IsNull() && (attributeOne.ValueBool() != attributeTwo.ValueBool()) {
        resp.Diagnostics.AddError(
            "attribute_one and attribute_two are both configured with different values",
            "attribute_one is deprecated, use attribute_two instead",
        )
        return
    }

    // Default to true for both attribute_one and attribute_two when both are null.
    if attributeOne.IsNull() && attributeTwo.IsNull() {
        resp.PlanValue = types.BoolValue(true)
        return
    }

    // Default to using value for attribute_two if attribute_one is null
    if attributeOne.IsNull() && !attributeTwo.IsNull() {
        resp.PlanValue = numericConfig
        return
    }

    // Default to using value for attribute_one if attribute_two is null
    if !attributeOne.IsNull() && attributeTwo.IsNull() {
        resp.PlanValue = numberConfig
        return
    }
}

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4