-
Notifications
You must be signed in to change notification settings - Fork 38.7k
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
Add DecodeParametersInto method to Codec. #17163
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -147,7 +147,20 @@ func getRequestOptions(req *restful.Request, scope RequestScope, kind string, su | |
newQuery[subpathKey] = []string{req.PathParameter("path")} | ||
query = newQuery | ||
} | ||
return queryToObject(query, scope, kind) | ||
versioned, err := scope.Creater.New(scope.ServerAPIVersion, kind) | ||
if err != nil { | ||
// programmer error | ||
return nil, err | ||
} | ||
if err := scope.Codec.DecodeParametersInto(query, versioned); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of curiosity, why do we need to decode the query to a versioned object and then convert it to unversioned? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are sending versioned object serialized into url params over the network. But internally we are looking internal version - this is how everything works, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Sorry my question is not clear. I'm thinking because I recall there is a discussion on that Codec should only do deserialization and convertor should be explicitly called to do the conversion. Is that why you are doing desserialization and conversion here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see the code is copied from queryToObject. I'll take a look if it's necessary to deserialize to the ServerVersion first. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, it is correct to do the deserialization and conversion separately. This is because the conversion is to a format that the infrastructure needs; therefore that logic should be locate with the infrastructure. We should continue to mutate things until the versioned object is passed into the REST.List() method (if it's not already). If we do deserialization and conversion at the same time, then we'll have to do two deserializations, one for the infrastructure code and one for the strategy code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, also, as @liggitt says, query parameters do not contain their own type and therefore can't be auto-converted. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But at some point we should probably be able to encode those so that different API groups can do something reasonable with them instead of just asking "are you my mother?" to every possible target. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We do not ask that, at least not in the server. We should have a (The client does that sort of thing, which I agree is totally broken.) |
||
return nil, errors.NewBadRequest(err.Error()) | ||
} | ||
out, err := scope.Convertor.ConvertToVersion(versioned, "") | ||
if err != nil { | ||
// programmer error | ||
return nil, err | ||
} | ||
return out, nil | ||
} | ||
|
||
// ConnectResource returns a function that handles a connect request on a rest.Storage object. | ||
|
@@ -226,15 +239,23 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope RequestScope, forceWatch | |
ctx := scope.ContextFunc(req) | ||
ctx = api.WithNamespace(ctx, namespace) | ||
|
||
out, err := queryToObject(req.Request.URL.Query(), scope, "ListOptions") | ||
versioned, err := scope.Creater.New(scope.ServerAPIVersion, "ListOptions") | ||
if err != nil { | ||
errorJSON(err, scope.Codec, w) | ||
return | ||
} | ||
opts := *out.(*api.ListOptions) | ||
if err := scope.Codec.DecodeParametersInto(req.Request.URL.Query(), versioned); err != nil { | ||
errorJSON(err, scope.Codec, w) | ||
return | ||
} | ||
opts := api.ListOptions{} | ||
if err := scope.Convertor.Convert(versioned, &opts); err != nil { | ||
errorJSON(err, scope.Codec, w) | ||
return | ||
} | ||
|
||
// transform fields | ||
// TODO: queryToObject should do this. | ||
// TODO: Should this be done as part of convertion? | ||
fn := func(label, value string) (newLabel, newValue string, err error) { | ||
return scope.Convertor.ConvertFieldLabel(scope.APIVersion, scope.Kind, label, value) | ||
} | ||
|
@@ -679,27 +700,6 @@ func DeleteResource(r rest.GracefulDeleter, checkBody bool, scope RequestScope, | |
} | ||
} | ||
|
||
// queryToObject converts query parameters into a structured internal object by | ||
// kind. The caller must cast the returned object to the matching internal Kind | ||
// to use it. | ||
// TODO: add appropriate structured error responses | ||
func queryToObject(query url.Values, scope RequestScope, kind string) (runtime.Object, error) { | ||
versioned, err := scope.Creater.New(scope.ServerAPIVersion, kind) | ||
if err != nil { | ||
// programmer error | ||
return nil, err | ||
} | ||
if err := scope.Convertor.Convert(&query, versioned); err != nil { | ||
return nil, errors.NewBadRequest(err.Error()) | ||
} | ||
out, err := scope.Convertor.ConvertToVersion(versioned, "") | ||
if err != nil { | ||
// programmer error | ||
return nil, err | ||
} | ||
return out, nil | ||
} | ||
|
||
// resultFunc is a function that returns a rest result and can be run in a goroutine | ||
type resultFunc func() (runtime.Object, 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.
Can we hold on using ServerAPIVersion in more places? I don't think it is correct to have multiple groups using "v1" types…
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 one is just move from the other place in this file - I will keep that in mind when touching ServerAPIVersion again.
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'd actually like to have an explicit dependency expressed upon the internal types accepted by the API. That means plumbing down Sets of types (or group,version,kind), then using the scheme to see whether the incoming object can be coerced to the expected type.
ServerAPIVersion
isn't sufficient for the task and tends to operate a silent dependency on an external type.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.
@deads2k I agree we need to not hard code stuff. But baby steps. This isn't making the problem worse.