Terraform tracks the state of provisioned resources in its state file, and compares the user-passed configuration against that state. When Terraform detects a discrepancy, it presents the user with the differences between the configuration and the state.
Sometimes determining the differences between state and configuration requires special handling, which can be managed with the CustomizeDiff function.
CustomizeDiff is passed a *schema.ResourceDiff. This is a structure similar to schema.ResourceData — it lacks most write functions (like Set), but adds some functions for working with the difference, such as SetNew, SetNewComputed, and ForceNew.
NOTE:CustomizeDiff does not currently support computed/"known after apply" values from other resource attributes.
Any function can be provided for difference customization. For the majority of simple cases, we recommend that you first try to compose the behavior using the customdiff helper package, which allows for a more declarative configuration. However, for highly custom requirements, a custom-made function is usually easier and more maintainable than working around the helper's limitations.
package example
import("fmt""github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff""github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema")funcresourceExampleInstance()*schema.Resource {return&schema.Resource{
Create: resourceExampleInstanceCreate,
Read: resourceExampleInstanceRead,
Update: resourceExampleInstanceUpdate,
Delete: resourceExampleInstanceDelete,
Schema:map[string]*schema.Schema{"size":{
Type: schema.TypeInt,
Required:true,},},
CustomizeDiff: customdiff.All(
customdiff.ValidateChange("size",func(ctx context.Context, old,new, meta any)error{// If we are increasing "size" then the new value must be// a multiple of the old value.ifnew.(int)<= old.(int){returnnil}if(new.(int)% old.(int))!=0{return fmt.Errorf("new size value must be an integer multiple of old value %d", old.(int))}returnnil}),
customdiff.ForceNewIfChange("size",func(ctx context.Context, old,new, meta any)bool{// "size" can only increase in-place, so we must create a new resource// if it is decreased.returnnew.(int)< old.(int)}),),}}
package example
import("fmt""github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff""github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema")funcresourceExampleInstance()*schema.Resource {return&schema.Resource{ Create: resourceExampleInstanceCreate, Read: resourceExampleInstanceRead, Update: resourceExampleInstanceUpdate, Delete: resourceExampleInstanceDelete, Schema:map[string]*schema.Schema{"size":{ Type: schema.TypeInt, Required:true,},}, CustomizeDiff: customdiff.All( customdiff.ValidateChange("size",func(ctx context.Context, old,new, meta any)error{// If we are increasing "size" then the new value must be// a multiple of the old value.ifnew.(int)<= old.(int){returnnil}if(new.(int)% old.(int))!=0{return fmt.Errorf("new size value must be an integer multiple of old value %d", old.(int))}returnnil}), customdiff.ForceNewIfChange("size",func(ctx context.Context, old,new, meta any)bool{// "size" can only increase in-place, so we must create a new resource// if it is decreased.returnnew.(int)< old.(int)}),),}}
In this example we use the helpers to ensure the size can only be increased to multiples of the original size, and that if it is ever decreased it forces a new resource. The customdiff.All helper will run all the customization functions, collecting any errors as a multierror. To have the functions short-circuit on error, please use customdiff.Sequence.