-
Notifications
You must be signed in to change notification settings - Fork 101
Description
(I originally wrote up a longer version of this which included a lot more background information and historical context, but then when I submitted it GitHub encountered an error and lost my content. Sadly I don't have time to reproduce what had been 45 minutes of research and writing and so I'm resorting to a more direct description of a problem in the hope that readers will be familiar enough with this problem to realize what I'm talking about without the background information. However, I'm happy to answer any clarifying questions if the context is unclear here.)
An important responsibility of a provider is to classify whether a difference between two values represents drift (a material change in meaning often -- but not always -- caused by edits made outside of Terraform) or normalization (a different way of writing down the same thing).
In the old SDK we had DiffSuppressFunc
as the primary solution to this problem. On a per-attribute basis this function would take two values and return true
if they are functionally equivalent or false
if they are materially different.
Unfortunately, the implementation of DiffSuppressFunc
was applied only during PlanResourceChange
and not during ReadResource
, which sadly only solves half of the problem and thus largely defeats the benefit of the mechanism.
We can see a concrete example of that in hashicorp/terraform#29181, where the provider seems to have classified a reordering of a JSON array as normalization rather than as drift, but because the SDK didn't check DiffSuppressFunc
on the Read
response the normalized value was misclassified as a material change.
Although the recent "Objects have changed outside of Terraform" message has made this sort of incorrect result more visible, note that it's still a potential problem regardless of whether Terraform explicitly reports it because Terraform allows using the value of an argument of one resource to populate an argument of another resource. For example:
resource "happycloud_thingy" "foo" {
name = "Hello"
}
resource "monitorsauce_doodad" "bar" {
title = "Statistics for ${happycloud_thing.foo.name}"
}
If this "HappyCloud" vendor has an API which normalizes thingy names to lowercase, then we'd likely want to classify case changes as normalization vs. drift. If ReadResource
were to set name
to hello
rather than Hello
then a subsequent plan could propose the following, even though PlanResourceChange
for happycloud_thingy
classified the name change as normalization:
# monitorsauce_doodad.bar must be replaced
-/+ resource "monitorsauce_doodad" "bar" {
~ title = "Statistics for Hello" -> "Statistics for hello" (forces replacement)
}
In modern Terraform the "Objects have changed outside of Terraform" message would at least give a clue as to why this happened, but it'd be better if Terraform had just reported no changes needed at all, thus allowing the configuration to properly converge in only one plan/apply run.
As far as I can tell this new framework doesn't yet have a comparable feature to DiffSuppressFunc
at all, and so my purpose in opening this issue is mainly just to capture this background information (albeit a cut down version due to the work loss mentioned earlier) in the hope that it's useful for designing any feature that might meet a similar need.
I'd also assert, though others might disagree, that this normalization vs. drift problem is a crucial enough part of a provider's responsibility to get right that it would be warranted to have first-class framework support for it, such that it can work correctly by default and thus hopefully avoid the risk of individual resource implementations effectively repeating the old SDK's mistake of only solving half of the problem. 😖