-
Notifications
You must be signed in to change notification settings - Fork 39.8k
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
Fix original object mutation on patch retry #43871
Conversation
115546c
to
e06a37d
Compare
Removing label |
Tagging for cherry-pick since this was a regression in 1.6 |
Looks like this was failed communication: here is another one: #43902, basically the same thing. We can choose one. |
The patch map also gets mutated. This fixed and tests that issue as well |
I think this does what it sets out to do, but the code in this area is really sticky to read. |
@@ -86,21 +86,21 @@ func strategicPatchObject( | |||
patchJS []byte, | |||
objToUpdate runtime.Object, | |||
versionedObj runtime.Object, | |||
) (originalObjMap map[string]interface{}, patchMap map[string]interface{}, retErr error) { | |||
originalObjMap = make(map[string]interface{}) | |||
) error { |
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 just removed the return values here since they are unsuitable for use after having used them to apply the patch
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.
Yeah - that sounds good.
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.
Sorry for long delay - I added some comment to a test.
@@ -86,21 +86,21 @@ func strategicPatchObject( | |||
patchJS []byte, | |||
objToUpdate runtime.Object, | |||
versionedObj runtime.Object, | |||
) (originalObjMap map[string]interface{}, patchMap map[string]interface{}, retErr error) { | |||
originalObjMap = make(map[string]interface{}) | |||
) error { |
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.
Yeah - that sounds good.
} | ||
wg.Wait() | ||
|
||
if successes < handlers.MaxRetryWhenPatchConflicts { |
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 I don't understand this. We have 2N concurrent goroutines trying to do a patch. Why at least N of them has to succeed? Can you explain it (and add comment about it)?
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.
https://github.com/kubernetes/kubernetes/pull/43902/files#diff-a98175d31a994ac0386ef984acfe13f5R111
@liggitt wants to copy that into his patch. Took some time to get the reasoning there.
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.
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 can rename the function here as well. That one doesn't address the patch map mutation issue
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 see. But the test is still passing with the other PR, which means it's not really testing everything, right?
Anyway - I'm fine with proceeding with this one too - just want to understand it.
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.
the test is still passing with the other PR
the test in the other PR doesn't include the patch directives... the test in this PR would fail against the fix in the other PR
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.
OK - sorry for confusion then.
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.
Can you then please add a comment (similar than the one from the other PR) and I will lgtm this PR.
added comment at https://github.com/kubernetes/kubernetes/pull/43871/files#diff-a98175d31a994ac0386ef984acfe13f5R60 I added a mutation warning to the StrategicMergePatch godoc for now, rather than rename |
That's fine. Thanks. /lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: liggitt, wojtek-t
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
@k8s-bot kops aws e2e test this |
Automatic merge from submit-queue (batch tested with PRs 43871, 44053) |
Commit found in the "release-1.6" branch appears to be this PR. Removing the "cherrypick-candidate" label. If this is an error find help to get your PR picked. |
…k-of-#43871-upstream-release-1.6 Automatic merge from submit-queue Automated cherry pick of kubernetes#43871 Cherry pick of kubernetes#43871 on release-1.6. kubernetes#43871: Fix original object mutation on patch retry ```release-note Fix incorrect conflict errors applying strategic merge patches to resources. ```
When applying a patch, the original state of the object and patch are captured so that retries can determine if an overlapping update was made to the object, and the patch API call should abort with a conflict.
However, the
strategicPatchObject -> applyPatchToObject -> StrategicMergeMapPatch -> mergeMap
call mutates both the original object map and the patch map, making them unsuitable for reusing for subsequent calls.We saw this in a downstream test that exercises patch conflict retries, where the data being submitted in a patch was showing up in the original object data map.
Since mergeMap also mutates the patch map passed in (deletes patch directives as it encounters them), we also cannot reuse the patch map in
applyPatchToObject
once it has been used.This PR:
originalObjMap
separate from the initial patch application for later use in conflict detectionoriginalPatchMap
to a helper that returns a fresh map from original sources$patch
directives