Plan Modification
After validation and before applying configuration changes, Terraform generates a plan that describes the expected values and behaviors of those changes. Resources can then tailor the plan to match the expected end state, prevent errant in-place updates, or return any diagnostics.
Terraform and the framework support multiple types of plan modification on resources:
- Adjusting unknown attribute values, such as providing a known remote default value when a configuration is not present.
- Marking resources that should be replaced, such as when an in-place update is not supported for a change.
- Returning warning or error diagnostics on planned resource creation, update, or deletion.
Plan modification can be added on resource schema attributes or an entire resource. Use resource-based plan modification if access to the configured resource is necessary.
Plan Modification Process
When the provider receives a request to generate the plan for a resource change via the framework, the following occurs:
- Set any attributes with a null configuration value to the default value.
- If the plan differs from the current resource state, the framework marks computed attributes that are null in the configuration as unknown in the plan. This is intended to prevent unexpected Terraform errors. Providers can later enter any values that may be known.
- Run attribute plan modifiers.
- Run resource plan modifiers.
When the Resource
interface Update
method runs to apply a change, all attribute state values must match their associated planned values or Terraform will generate a Provider produced inconsistent result
error. You can mark values as unknown in the plan if the full expected value is not known.
Refer to the Resource Instance Change Lifecycle document for more details about the concepts and processes relevant to the plan and apply workflows.
During the terraform plan
and terraform apply
commands, Terraform calls the provider PlanResourceChange
RPC, in which the framework calls the resource.Resource
interface Schema
method attribute plan modifiers and the ModifyPlan
method on resources that implement the resource.ResourceWithModifyPlan
interface.
Attribute Plan Modification
You can supply the attribute type PlanModifiers
field with a list of plan modifiers for that attribute. For example:
If defined, plan modifiers are applied to the current attribute. If any nested attributes define plan modifiers, then those are applied afterwards. Any plan modifiers that return an error will prevent Terraform from applying further modifiers of that attribute as well as any nested attribute plan modifiers.
Common Use Case Attribute Plan Modifiers
The framework implements some common use case modifiers in the typed packages under resource/schema/
, such as resource/schema/stringplanmodifier
:
RequiresReplace()
: If the value of the attribute changes, in-place update is not possible and instead the resource should be replaced for the change to occur. Refer to the Go documentation for full details on its behavior.RequiresReplaceIf()
: Similar toresource.RequiresReplace()
, however it also accepts provider-defined conditional logic. Refer to the Go documentation for full details on its behavior.RequiresReplaceIfConfigured()
: Similar toresource.RequiresReplace()
, however it also will only trigger if the practitioner has configured a value. Refer to the Go documentation for full details on its behavior.UseStateForUnknown()
: Copies the prior state value, if not null. This is useful for reducing(known after apply)
plan outputs for computed attributes which are known to not change over time.
Creating Attribute Plan Modifiers
To create an attribute plan modifier, you must implement the one of the planmodifier
package interfaces. For example:
Optionally, you may also want to create a helper function to instantiate the plan modifier. For example:
Caveats
Terraform Data Consistency Rules
Terraform core implements data consistency rules between configuration, plan, and state data. For example, if an attribute value is configured, it is never valid to change that value in the plan except being set to null on resource destroy. The framework does not raise its own targeted errors in many situations, so it is the responsibility of the developer to account for these rules when implementing plan modification logic.
Prior State Under Lists and Sets
Attribute plan modifiers under the following must take special consideration if they rely on prior state data:
- List nested attributes
- List nested blocks
- Set nested attributes
- Set nested blocks
These data structures are implemented based on array indexing, which the framework always sends the exact representation given across the protocol. If list/set elements are rearranged or removed, Terraform nor the framework performs any re-alignment of prior state for those elements.
In this example, potentially unexpected prior state may be given to attribute plan modifier request:
- A list nested attribute with two elements in configuration is saved into state
- The configuration for the first element is removed
- The list nested attribute with now one element still receives the prior state of the first element
Checking Resource Change Operations
Plan modifiers execute on all resource change operations: creation, update, and destroy. If the plan modification logic is sensitive to these details, check the request data to determine the current operation.
Implement the following to check whether the resource is being created:
Implement the following to check whether the resource is being destroyed:
Resource Plan Modification
Resources also support plan modification across all attributes. This is helpful when working with logic that applies to the resource as a whole, or in Terraform 1.3 and later, to return diagnostics during resource destruction. Implement the resource.ResourceWithModifyPlan
interface to support resource-level plan modification. For example:
Resource Destroy Plan Diagnostics
Support for handling resource destruction during planning is available in Terraform 1.3 and later.
Implement the ModifyPlan
method by checking if the resource.ModifyPlanRequest
type Plan
field is a null
value:
Ensure the response plan remains entirely null
when the request plan is entirely null
.