-
Notifications
You must be signed in to change notification settings - Fork 38.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
Allow update without resource version #10074
Conversation
// Pass an EtcdUpdateFunc to EtcdHelper.GuaranteedUpdate to make an etcd update that is guaranteed to succeed. | ||
// See the comment for GuaranteedUpdate for more detail. | ||
type EtcdUpdateFunc func(input runtime.Object, res ResponseMeta) (output runtime.Object, ttl *uint64, err error) | ||
type EtcdUpdateFunc func(input runtime.Object, node *etcd.Node) (output runtime.Object, ttl *uint64, err 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.
Replacing ResponseMeta with etcd.Node should be fine as per #8724 (comment)
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.
But we didn't want to do that for coupling reasons....
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.
Dan convinced me it was a bad idea and I agreed
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.
Conversation lost to the mists of github history, but basically: introduces coupling and encourages bad patterns - generic etcd should be generally isolated from exact etcd objects for test ability, and also callers should not be encouraged to accidentally (or intentionally) start using the node value directly
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.
We could add ModifiedIndex to ResponseMeta, then (named ResourceVersion?).
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.
Yes. I can add node.Expiration and node.ModifiedIndex to ResponseMeta and then change e.Helper.Versioner.UpdateObject() to take modified index and expiration instead of the whole node, if this is a concern. Based on that discussion, I thought @smarterclayton had convinced @lavalamp that its fine to pass node, but looks like thats not the case.
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 the other way around. I fought but then conceded because he was right - pass what you need, not what you think you'll want. :)
----- Original Message -----
// Pass an EtcdUpdateFunc to EtcdHelper.GuaranteedUpdate to make an etcd
update that is guaranteed to succeed.
// See the comment for GuaranteedUpdate for more detail.
-type EtcdUpdateFunc func(input runtime.Object, res ResponseMeta) (output
runtime.Object, ttl *uint64, err error)
+type EtcdUpdateFunc func(input runtime.Object, node *etcd.Node) (output
runtime.Object, ttl *uint64, err error)Yes. I can add node.Expiration and node.ModifiedIndex to ResponseMeta and
then change e.Helper.Versioner.UpdateObject() to take modified index and
expiration instead of the whole node, if this is a concern. Based on that
discussion, I thought @smarterclayton had convinced @lavalamp that its fine
to pass node, but looks like thats not the case.
Reply to this email directly or view it on GitHub:
https://github.com/GoogleCloudPlatform/kubernetes/pull/10074/files#r32851841
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.
Please keep response meta. You don't need to change this at all, the latest resource version is embedded in the object passed to the SimpleEtcdUpdateFunc.
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.
Reverted that change, so that this still takes a ResponseMeta and not etcd.Node
@@ -271,10 +272,21 @@ func (e *Etcd) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool | |||
if err != nil { | |||
return nil, false, err | |||
} | |||
// If the object specified by the user does not have a resource version, |
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 would want this feature to be optional on a type by type basis - opt in. We have a few objects where I'd want to discourage this pattern.
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 don't think that we ever want to encourage this pattern, but it needs to exist, and I'd prefer that it be implemented in the server rather than via a RMW loop in the client. We could create an UpdateOption, but that would be more work, and then we'd need to generate a better error message for the case where resourceVersion == 0 but no forceUpdate option was specified, and we might still need to do something urgently to mitigate false conflicts with status updates.
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, I meant specifically in generic.Etcd
as an implementor you have to enable this function. Prevents it being enabled by accident on new resources - I'd rather this be a deliberate decision.
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 add a AllowUpdateWithoutResourceVersion() like AllowCreateOnUpdate() (https://github.com/GoogleCloudPlatform/kubernetes/blob/5520386b180d3ddc4fa7b7dfe6f52642cc0c25f3/pkg/api/rest/update.go#L35) in RESTUpdateStrategy?
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, something like that. That allows us to add something to resttest that you indeed fail if that is false.
----- Original Message -----
@@ -271,10 +272,21 @@ func (e *Etcd) Update(ctx api.Context, obj
runtime.Object) (runtime.Object, bool
if err != nil {
return nil, false, err
}
- // If the object specified by the user does not have a resource version,
I can add a AllowUpdateWithoutResourceVersion() like AllowCreateOnUpdate()
(https://github.com/GoogleCloudPlatform/kubernetes/blob/5520386b180d3ddc4fa7b7dfe6f52642cc0c25f3/pkg/api/rest/update.go#L35)
in RESTUpdateStrategy?
Reply to this email directly or view it on GitHub:
https://github.com/GoogleCloudPlatform/kubernetes/pull/10074/files#r32854948
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.
Added an AllowUnconditionalUpdate() and using that here
GCE e2e build/test passed for commit 13ca0cf73f20b926021e370132e84604deed81b6. |
// If the object specified by the user does not have a resource version, | ||
// then populete it with the latest version. | ||
// Else, we check that the version specified by the user matches the version of latest etcd object. | ||
useLatestResourceVersion := false |
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 would call this unsafeUpdate, unconditionalUpdate, forceUpdate, or something like that.
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.
allowUnsafeUpdates?
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.
er, reading more closely-- unconditionalUpdate or clobber might be better.
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.
renamed to allowUnconditionalUpdate
13ca0cf
to
0916d31
Compare
// If AllowUnconditionalUpdate() is true and the object specified by the user does not have a resource version, | ||
// then we populate it with the latest version. | ||
// Else, we check that the version specified by the user matches the version of latest etcd object. | ||
allowUnconditionalUpdate := false |
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.
Suggest:
doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
You're not just allowing it, you're doing 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.
Done
Just a few nits, otherwise looks good. |
e13bafd
to
ed56655
Compare
Updated code as per comments. |
GCE e2e build/test passed for commit ed56655e3a10992b63b4361ead24885c869c2352. |
LGTM |
ed56655
to
5aeb1bc
Compare
Thanks! Added a test case for unconditional update to pkg/registry/generic/etcd/etcd_test.go. |
GCE e2e build/test passed for commit 5aeb1bc558aaacdb76513b2e81c1815308a6404f. |
A test that was causing Shippable timeouts is disabled at head. Should be green after rebase. |
5aeb1bc
to
221ae4d
Compare
Rebased |
GCE e2e build/test passed for commit 221ae4d. |
Per new merge policy, please add a brief risk assessment. |
Risk assessment: medium-low. |
@brendandburns or @davidopp for another LGTM. |
// Update the object's resource version to match the latest etcd object's resource version. | ||
err = e.Helper.Versioner.UpdateObject(obj, res.Expiration, res.ResourceVersion) | ||
if err != nil { | ||
return nil, nil, err |
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.
is there some reason why you don't return obj, nil, err 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.
oh sorry, never mind, this is an error case.
LGTM |
Allow update without resource version
Thanks. It looks like the API documentation already assumed we were doing this: |
Updating code to populate the user given object with the resource version of the latest etcd object, if the user given object does not have a resource version.