-
Notifications
You must be signed in to change notification settings - Fork 9.5k
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
helper/schema: Allow ResourceDiff.ForceNew on nested fields (avoid crash) #17463
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @radeksimko, the bugfix to ForceNew
looks good and makes sense. 👍
The exposure of ResourceAttrDiff
via the new GetDiffAttributes
function though is something that I have feedback on and I think should be possibly done another way for now, as we currently do not expose the lower level diff via ResourceDiff
.
helper/schema/resource_diff.go
Outdated
@@ -234,6 +236,19 @@ func (d *ResourceDiff) clear(key string) error { | |||
return nil | |||
} | |||
|
|||
// GetDiffAttributes helps to implement resourceDiffer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is just a new function on ResourceDiff
and not necessarily a part of the resourceDiffer
interface (which ResourceData
also implements), right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So by resourceDiffer
here I meant CustomizeDiff
function - I will change the wording to make it a little bit more obvious... :)
helper/schema/resource_diff.go
Outdated
// GetDiffAttributes helps to implement resourceDiffer | ||
// where we need to act on all nested fields | ||
// without calling out each field separately | ||
func (d *ResourceDiff) GetDiffAttributes(prefix string) map[string]*terraform.ResourceAttrDiff { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sets a precedent we haven't really implemented in ResourceDiff
yet which is direct exposure of the lower-level diff. Currently ResourceDiff
is mainly just a higher-level interface to the values within the diff, allowing for control of the diff for computed values by adding a new writer that allows the write of values and temporary alteration of the schema (for ForceNew
operations).
I think my question in asking if such a function is necessary is what is the current issue with the functions that already exist, such as Get
and GetChange
? They should be able to get nested attributes just fine as they access the same readers ResourceData
does.
I think maybe in the example that you are giving, you could probably just either walk the schema itself directly (by accessing it via the standard resource generator function), or hard-code the keys you want to mark as ForceNew
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hard-code the keys you want to mark as
ForceNew
The schema is really deeply nested and long and it is likely to grow in the future:
https://github.com/terraform-providers/terraform-provider-kubernetes/blob/master/kubernetes/schema_volume_source.go#L14
so checking each field seems like a rather tedious approach.
maybe in the example that you are giving, you could probably just either walk the schema itself directly
That means we'd have to take the schema and try to "guess" how does it (or may) translate into keys (indexes) in the diff, which is difficult to do specifically for TypeList/TypeSet/TypeMap. It also seems like that's a logic that should be somewhere in core anyway - the provider IMO shouldn't have to traverse its own schema and know how to translate it to "diff-like format" in order to call d.Get(key)
or d.GetChange(key)
.
However I understand what you're saying and I did have similar feelings when cobbling the PR. It does not feel right to expose the diff like this, so thanks for confirming my thoughts. 😃
I'm playing with two ideas at this point:
func (d *ResourceDiff) ForceNewPrefix(prefix) error
which would basically go through the schema and mark all nested fields (those which have the given prefix in state) asForceNew
func (d *ResourceDiff) GetChangedKeys(prefix) []string
- here we'd be still exposing the diff, but only keys, so the bare minimum we need to (in order to calld.Get()
andd.ForceNew()
on them), not the wholemap[string]*terraform.ResourceAttrDiff
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wanted to chime in here and agree with @vancluever's reservation... we should not expose any terraform
package types in the helper/schema
API because our future grpc-based protocol will not be able to marshal these.
(There is one existing violation of that rule in the schema migration mechanism which we'll be designing a special workaround for, but we should avoid introducing any new dependencies like this here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@radeksimko I like both of those ideas, and almost think GetChangedKeys
would be nice for ResourceData
to have too if it weren't for the fact that the diff reader is not available in Read
.
My one concern for GetChangedKeys
is feature overlap with HasChange
, but that's kind of a gut reaction over a logical one, especially considering you could debate that GetChange
has overlap as well by the same logic. As well, I'm wondering if two versions of GetChangedKeys
would be nice where you didn't have to supply the prefix and you could get the entire set of changes resource-wide, versus having to work with a possibly semantically awkward GetChangedKeys("")
.
But yeah, I think that's a great idea, and barring @apparentlymart saying something otherwise I don't think that exposing just the keys from the diff is risky in regards to any future changes in the API.
a229e83
to
7ebf93a
Compare
🤔 I can't think of a particular use case for I'm open to suggestions around names though. Should we have |
Yeah, I'm not 100% sure either, but I didn't necessarily want to rule out the possibility. After giving it further thought I can't really think of one right now either. I think maybe |
7ebf93a
to
ccf8a31
Compare
@vancluever Good idea. PTAL. |
As some context here, I wanted to share some info about what the workflow might look like with the protocol changes we were discussing. There's an internal design sketch on this which you both have access to, but I'm going to copy some relevant parts here for the benefit of others who might view this PR; of course the details are are, as usual, subject to change as we learn more during implementation. The planned new interface for diffing in the wire protocol (not in the func PlanResourceChange(
typeName string,
oldState object,
proposedNewState object,
) returns (
newState object,
requiresReplace []path,
diagnostics,
) A change compared to the current protocol is that Terraform Core has already done some of the preparation work here and provides a "proposed new state" rather than the configuration directly. This already includes the preserved values from computed fields and has already been type-checked and type-converted to conform to the resource schema. The pseudo-type I think the role of The With all of that said, then: I think we can support something like For The (Please excuse that this screenshot is not a perfect fit for the discussion at hand; I cribbed it from my earlier prototyping results.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! I kind of like anything that adds more test cases before the "big refactor" :D
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. |
I bumped into this when trying to resolve a bug in the K8S provider, where certain fields in the schema become immutable from a certain version of K8S.
The end-developer use-case follows:
Test result before patch