-
Notifications
You must be signed in to change notification settings - Fork 40k
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
Avoid double decoding all client responses #36001
Avoid double decoding all client responses #36001
Conversation
@kubernetes/sig-api-machinery @wojtek-t this doubles client read performance (even versioned clients). |
I added a release note that describes how error handling has changed - all calls to |
Jenkins GCE e2e failed for commit 88ef1a8b5bd2fbe229aee818cc2addcbab084b8e. Full PR test history. The magic incantation to run this job again is |
Jenkins GCI GCE e2e failed for commit 88ef1a8b5bd2fbe229aee818cc2addcbab084b8e. Full PR test history. The magic incantation to run this job again is |
88ef1a8
to
4836d5e
Compare
Jenkins unit/integration failed for commit 4836d5ed3baa2edf979b113a7803444f929944b5. Full PR test history. The magic incantation to run this job again is |
// See the Request.Do() comment for what errors you might get. | ||
func (r Result) Error() error { | ||
// if we have received an unexpected server error, and we have a body and decoder, we can try to extract | ||
// a Status object. | ||
if r.err == nil || !errors.IsUnexpectedServerError(r.err) || len(r.body) == 0 || r.decoder == nil { |
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.
Why IsUnexpectedServerError
? I think we should just check if r.err
implements APIStatus interface.
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.
No, the error in this case is set by the thing that creates Result (which calls newGeneric...Error, which is UnexpectedServerError).
UnexpectedServerError literally means - we got an error from the server but we couldn't / didn't decode the body. So this code is looking for errors where before we didn't try to decode it, and try to decode 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.
Ok, the logic is correct. The name UnexpectedServerError
is misleading IMO, the name makes sense for the "couldn't decode the body" case, but doesn't make sense for the "didn't decode the body" case.
}, | ||
}, | ||
{ | ||
// successful status is ignored |
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.
When will this happen in real life?
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.
Delete returns a status object, as do a few others.
LGTM. @deads2k if you want to take another look. |
Found a bug - authorization didn't register Status. Is authorization new for 1.5 or did we also fail to register it in 1.4? |
Was in 1.4 |
I'm going to fix it in 1.5 but that means 1.4 clients can't get Status messages from subject access review. Was it alpha? |
4836d5e
to
40220c9
Compare
Ok, that was fun.
Ready for re-review. No backwards compatibility impact now. |
Jenkins GCE Node e2e failed for commit 40220c917efec57c4384f4c4850d6f76b666bd5c. Full PR test history. The magic incantation to run this job again is |
Jenkins verification failed for commit 40220c917efec57c4384f4c4850d6f76b666bd5c. Full PR test history. The magic incantation to run this job again is |
restclient must be able to deal with multiple types of servers. Alter the behavior of restclient.Result#Raw() to not process the body on error, but instead to return the generic error (which still matches the error checking cases in api/error like IsBadRequest). If the caller uses .Error(), .Into(), or .Get(), try decoding the body as a Status. For older servers, continue to default apiVersion "v1" when calling restclient.Result#Error(). This was only for 1.1 servers and the extensions group, which we have since fixed. This removes a double decode of very large objects (like LIST).
Status is exposed as v1 in the current schema (so all groups are returning v1.Status). However, if you give a codec only "mygroup" "myversion", it will fail to convert Status to v1. For now, unversioned types should be allowed to be projected into all group versions, and when we add the server group we'll rip out the unversioned concept entirely.
40220c9
to
0513826
Compare
@@ -279,6 +290,7 @@ func init() { | |||
Rbac = Groups[rbac.GroupName] | |||
Storage = Groups[storage.GroupName] | |||
ImagePolicy = Groups[imagepolicy.GroupName] | |||
Authorization = Groups[authorization.GroupName] |
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.
If nobody uses this, don't add it. We want less code to touch for each group you add, not more.
@@ -258,6 +260,15 @@ func init() { | |||
externalTypes: api.Scheme.KnownTypes(externalGroupVersion), | |||
} | |||
} | |||
if _, ok := Groups[authorization.GroupName]; !ok { |
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.
It'd be nice to have a unit test somewhere that makes sure this parallel registration stays in sync.
nits, lgtm. |
I need it to properly test authorization implements ExportOptions, which is On Wed, Nov 2, 2016 at 7:53 AM, David Eads notifications@github.com wrote:
|
I agree. Do you have an issue that covers your concerns with testapi that On Wed, Nov 2, 2016 at 7:54 AM, David Eads notifications@github.com wrote:
|
As per comments /lgtm On Wed, Nov 2, 2016 at 11:48 AM, Clayton Coleman ccoleman@redhat.com
|
Old PR trying to remove the package entirely: #34644 . I'm still not sure that I'm convinced of the value it adds. I thought new groups would be able to ignore the package, so I didn't press on it. |
Can you add ExportOptions to this line to test it's registered in all groups? |
Sorry, I saw you did that :) |
Fix #27886. |
Automatic merge from submit-queue |
Fixes #35982
The linked issue uncovered that we were always double decoding the response in restclient for get, list, update, create, and patch. That's fairly expensive, most especially for list. This PR refines the behavior of the rest client to avoid double decoding, and does so while minimizing the changes to rest client consumers.
restclient must be able to deal with multiple types of servers. Alter the behavior of restclient.Result#Raw() to not process the body on error, but instead to return the generic error (which still matches the error checking cases in api/error like IsBadRequest). If the caller uses
.Error(), .Into(), or .Get(), try decoding the body as a Status.
For older servers, continue to default apiVersion "v1" when calling restclient.Result#Error(). This was only for 1.1 servers and the extensions group, which we have since fixed.
This removes a double decode of very large objects (like LIST) - we were trying to DecodeInto status, but that ends up decoding the entire result and then throwing it away. This makes the decode behavior specific to the type of action the user wants.
This change is