You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, the primary method of handling normalization from remote APIs in terraform-plugin-framework is type-based, using a custom type that implements semantic equality. This is a reasonable place to handle semantic equality, especially for data like JSON strings that need to ignore whitespace or IPv6 addresses that have multiple representations of equivalent data.
Semantic equality logic is used to compare a "prior value" to a "proposed new value", and if the two are determined to be "semantically equal", then the prior value can be kept. This logic is executed at the following points:
During ApplyResourceChange, after the Create method is called. Prior value is PlannedState, proposed new value is NewState returned by the Create method.
During ApplyResourceChange, after the Update method is called. Prior value is PlannedState, proposed new value is NewState returned by the Update method.
During ReadResource, after the Read method is called. Prior value is CurrentState, proposed new value is NewState returned by the Read method.
Problem
There are some edge cases where using a custom type for semantic equality is not preferred. For example, in the case of the AWS provider, custom types are heavily used to facilitate their reflection flex package with data handling (mapping from TF to AWS APIs):
In situations where generic custom types like this are already being used for data handling, if semantic equality logic is also needed, it becomes more difficult to introduce logic on a per-attribute-basis to solve unwanted drift issues like these:
As with all semantic equality/drift/normalization problems, it's possible for providers to implement the logic manually in the Create/Update/Read methods
In the case of using a custom type, it's possible to statically define the *SemanticEquals method, then optionally pass a function when defining the custom type:
Passing this function along from the type to the value:
func (vExampleCustomValue) StringSemanticEquals(ctx context.Context, value basetypes.StringValuable) (bool, diag.Diagnostics) {
ifv.SemanticEqualityFunc!=nil {
returnv.SemanticEqualityFunc(ctx, v.StringValue, value)
}
// No logic defined, so the values can't be semantically equal.returnfalse, nil
}
While this workaround will achieve the equivalent of something like attribute-based semantic equality it's certainly not a straightforward implementation.
Proposal
TBD on possible SDK design
In addition to type-based semantic equality, which would still be the preferred route, we could also implement attribute-based semantic equality, to allow defining equivalent semantic equality logic directly on the attributes in resource/schema and datasource/schema. This was originally considered during #70, but was abandoned due to the increased complexity, lack of concrete use-cases, and the confusion of implementing multiple competing ways to solve the problem.
Considerations
There are some internal refactoring hurdles that we'll need to clear if we want to support both, notably, all of our semantic equality logic is written based off the value itself, and refactoring that logic to be similar to plan modification/validation will be non-trivial, see comment.
We'll need to determine how nested/collection value type semantic equality logic will interact with nested attribute/collection attribute logic (order, precedence, etc.)
Documentation will also need to be updated, possibly splitting semantic equality into it's own page so we can properly describe both approaches and which to prefer (type-based should always be preferred to attribute-based).
Attribute-based expressions of semantic equality behavior sound pretty interesting to me as a provider developer. I don't have any use cases in mind, but expect I'd find 'em if it were available.
Module version
Background
Currently, the primary method of handling normalization from remote APIs in
terraform-plugin-framework
is type-based, using a custom type that implements semantic equality. This is a reasonable place to handle semantic equality, especially for data like JSON strings that need to ignore whitespace or IPv6 addresses that have multiple representations of equivalent data.Semantic equality logic is used to compare a "prior value" to a "proposed new value", and if the two are determined to be "semantically equal", then the prior value can be kept. This logic is executed at the following points:
ApplyResourceChange
, after theCreate
method is called. Prior value isPlannedState
, proposed new value isNewState
returned by theCreate
method.ApplyResourceChange
, after theUpdate
method is called. Prior value isPlannedState
, proposed new value isNewState
returned by theUpdate
method.ReadResource
, after theRead
method is called. Prior value isCurrentState
, proposed new value isNewState
returned by theRead
method.Problem
There are some edge cases where using a custom type for semantic equality is not preferred. For example, in the case of the AWS provider, custom types are heavily used to facilitate their reflection
flex
package with data handling (mapping from TF to AWS APIs):In situations where generic custom types like this are already being used for data handling, if semantic equality logic is also needed, it becomes more difficult to introduce logic on a per-attribute-basis to solve unwanted drift issues like these:
confirmation_setting
produces diffs forprompt_attempts_specification
terraform-provider-aws#35346Workarounds
Create
/Update
/Read
methods*SemanticEquals
method, then optionally pass a function when defining the custom type:Passing this function along from the type to the value:
While this workaround will achieve the equivalent of something like attribute-based semantic equality it's certainly not a straightforward implementation.
Proposal
In addition to type-based semantic equality, which would still be the preferred route, we could also implement attribute-based semantic equality, to allow defining equivalent semantic equality logic directly on the attributes in
resource/schema
anddatasource/schema
. This was originally considered during #70, but was abandoned due to the increased complexity, lack of concrete use-cases, and the confusion of implementing multiple competing ways to solve the problem.Considerations
There are some internal refactoring hurdles that we'll need to clear if we want to support both, notably, all of our semantic equality logic is written based off the value itself, and refactoring that logic to be similar to plan modification/validation will be non-trivial, see comment.
Documentation will also need to be updated, possibly splitting semantic equality into it's own page so we can properly describe both approaches and which to prefer (type-based should always be preferred to attribute-based).
Refs
The text was updated successfully, but these errors were encountered: