-
Notifications
You must be signed in to change notification settings - Fork 9.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Custom Diff Logic in Providers (WIP) #8769
Comments
Did a little prototyping today. Just wanted to capture some assorted notes for future-me before I quit working on this for now:
|
This would be super helpful with Nomad. I am suspect of the current Nomad provider implementation in Terraform: treating the jobspec as a text blob makes for awful diffs. If this idea were implemented in such a way that the Nomad diff response were available, that would be a huge step forward. |
This might be useful in the ACME provider for TOS updates on registrations. Initially, TOS are agreed to automatically, but there are provisions for updating the TOS which may need to be signalled via a diff and an |
Hey @apparentlymart have you started on this yet? I was thinking of taking a crack at it :) I did check and couldn't see anything yet in PR form or branches that mentioned this kind of work. From my own analysis, I was thinking the following:
If anything, this was a nice way to teach myself how diffs really work :) |
Hi @vancluever! Thanks for the deep thought here. It's been a while since I looked at this, so I'm a bit rusty. Back in Sep 2016 when I posted my last comment I'd written some hacky code to explore the problem, but it was never in any shape to be submitted so I ended up discarding it. I think I remember convincing myself that we'd need a new thing that is like With regard to your My recommendation would be to start by trying to reproduce my findings before via your own prototype. That'll help you see how all the machinery fits together here, and what the constraints are. Perhaps also starting with just one use-case would be good... I would suggest maybe starting with: the function can return an error to veto the diff (because that's easy), and it can also provide a placeholder value for a Let me know if you want to bounce any more ideas! 😀 |
Hey @apparentlymart! Check out https://github.com/vancluever/terraform/commit/34c7c54eaaf4beb924515591e93b1e2d634ea450. I think it's a good start! I'm not 100% comfortable with the amount of unexported data I needed to access, but we are in the same package after all. The benefit is a very minimal implementation that leans heavily on existing functionality, hopefully meaning that things will behave as expected when I add tests 😉 I missed the bits in the last paragraph where you mentioned vetoing the diff - but I think that the implementation of Let me know what you think! |
Some more notes - I think now that I understand how field readers and writers work a lot more, I think what I might do is get rid of the "duplicated" This will allow for a number of things:
The only challenge in this that I just thought of now is how to signal to |
I've moved on to tests now for Things are going well, but one thing I'm seeing here that I'm wondering if it will be an issue for the implementation as conceptualized: Removed diffs for computed values do not register. I'm guessing this is maybe because computed values were not thought to be diffable things? The main place this is coming up now is in a diff of a complex set. Ultimately what is happening is the diff is showing no old removed values at all, just a change of the count (in the event that these have changed) along with the new values. Not too sure of the implications that would have with |
@apparentlymart - |
Got some basic tests for the wired in customization behaviour now, will be committing/pushing soon Just thought I'd paste this little bit here :)
😁 |
A more evolved version of this was merged in #14887. It will take some time to update existing resources to make use of this mechanism, but the |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. |
Currently the
Diff
step for all existing resources is implemented inside thehelper/schema
logic, focusing only on diffing the config against the state. There is currently no possibility for the provider's own code to do any of the following:This idea is in the general theme of "Terraform should detect as much as possible during plan". Making Terraform more trustworthy and robust requires us to be able to detect problems and conflicts while producing the plan, rather than bailing out while we're halfway through applying.
Use-cases
Vetoing particular changes in the diff
Some AWS operations (not the RDS ones, notably) support a "dry run" flag which allows a client to verify that the given credentials have suitable access and the arguments are syntactically valid. If we gave resources veto power over their diffs, they could potentially do a dry run of certain operations to catch some problems during the plan phase.
Amazon RDS imposes some restrictions on what changes are possible to the allocated storage on database instances, and these restrictions depend on the storage engine in use.
For example, at the time of writing the size value for all of the storage engines must either remain constant or be at least 10% larger than the present value, except Microsoft SQL server which does not permit changes at all. If the
aws_db_instance
resource were to have "veto" power on the diff then it could check these constraints during plan.(This RDS use-case could potentially be thought of as another example for the following section, if we were to decide that asking RDS to make the storage smaller should act as if
ForceNew
were set.)Customizing the diff
Sometimes changing one attribute causes others to change. For example, updating an
aws_s3_bucket_object
when versioning is enabled will causeversion_id
to get updated.Neither Terraform core nor
helper/schema
have enough information to infer this automatically. We have previously discussed aComputedWhen
attribute that can declare simplistic dependencies between attributes, but we can handle this more robustly across more cases by allowing a resource implementation to directly modify a diff produced byhelper/schema
, where it could add additional attribute diffs to represent changes it knows about due to its specific knowledge of a particular service.Replacing the diff behavior altogether
Nomad has first-class support for diffing the existing state against a new configuration, and then safely applying that update without race conditions. Terraform does not yet have Nomad support, but once it does it would be awesome if Terraform could interact with Nomad's own plan/run actions to enable stronger guarantees that a plan will succeed. (As strong as Nomad can guarantee, which isn't 100% but is better than what Terraform can offer with its limited context on the Nomad cluster state.)
In this case,
helper/schema
would skip its own diffing logic altogether (or disregard what it created, at least) and instead call into the provider. The provider would call into the Nomad API's/job/{id}/plan
endpoint to obtain theDiff
andJobModifyIndex
properties, which it can then translate into a Terraform-friendly diff.When later asked to apply that diff, the provider's
Update
function can provide theJobModifyIndex
argument when callingPOST /v1/job/{id}
to ensure that it will make exactly the change that was reflected in the plan, and thus it can ignore all of the other diff elements. (They're only included in the diff so they're shown in the plan output for the user's benefit.)Potential Design
To support the above,
helper/schema
could support a new callbackDiffFunc
that takes the "default diff" produced byhelper/schema
and returns a new diff. The new diff might be either a mutation of the one given or an entirely fresh one, discarding whathelper/schema
came up with itself.DiffFunc
may also return an error, effectively vetoing the diff.This interface supports all of the above use-cases with a single function.
Rather than exposing the
*terraform.Diff
directly to this function, it's likely that we'd want some analog toschema.ResourceData
that represents diffs in a first-class way, as opposed to burying them as an implementation detail asResourceData
does.For example:
Not sure yet exactly what
schema.ResourceDiff
would support, but I'd expect it to have helper functions for the steps needed for the use-cases above, like:SetNewComputed(name)
,SetForcesNew(name)
for simple tweaksClear()
andSetDiff(name, oldValue, newValue)
to discard the default diff and build an entirely new one based on an upstream API callThe text was updated successfully, but these errors were encountered: