-
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
Adding dynamic client #20351
Adding dynamic client #20351
Conversation
Labelling this PR as size/XL |
result := new(List) | ||
err := rc.namespace(rc.cl.Get()). | ||
Resource(rc.resource.Name). | ||
VersionedParams(&opts, api.Scheme). // What to do about VersionedParams converter? |
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 it ok that we use api.Scheme for conversion here? I think the whole idea behind a dynamic client is not needing to know anything (like how to convert) about the underlying structure.
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, I think it's appropriate to take the standard ListOptions here. But maybe from the v1 package and not the unversioned api package?
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 should be using a generic parametercodec created specifically for the "common API" things. It also assumes that the endpoint supports this version of list params - ultimately that means that the client has a certain "level" of list options that the server may not match.
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.
Do you mean api.ParameterCodec
? I've run into a problem with that. It fails to recognize the ListOptions
belonging to an arbitrary GroupVersion
if the GroupVersion
isn't registered. This means the conversion step fails and results in an error.
I was thinking of just writing a parameter codec that doesn't do group conversion and just calls queryparams.Convert
. Is this a bad idea?
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 there is a generic.ParameterCodec that only needs to know about all of the possible list options a server could support. To make progress you could have a big TODO in there "deal with conversion". I think dealing with conversion will require the discovery doc to describe what the common schema is so you can prime generic.ParameterCodec. For now "best effort' is fine.
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'm having trouble finding the ParameterCodec you mention. The only EncodeParameters
implementation is on runtime.parameterCodec
and the only call to runtime.NewParameterCodec
is in pkg/api/register.
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 is no generic codec yet - just giving it that name for convenience
here. dynamic.ParameterCodec
On Wed, Feb 3, 2016 at 1:33 PM, krousey notifications@github.com wrote:
In pkg/client/typed/dynamic/client.go
#20351 (comment)
:+// namespace applies a namespace to the request if the configured
+// resource is a namespaced resource. Otherwise, it just returns the
+// passed in request.
+func (rc *ResourceClient) namespace(req *client.Request) *client.Request {
- if rc.resource.Namespaced {
return req.Namespace(rc.ns)
- }
- return req
+}
+// List returns a list of objects for this resource.
+func (rc _ResourceClient) List(opts api.ListOptions) (_List, error) {
- result := new(List)
- err := rc.namespace(rc.cl.Get()).
Resource(rc.resource.Name).
VersionedParams(&opts, api.Scheme). // What to do about VersionedParams converter?
I'm having trouble finding the ParameterCodec you mention. The only
EncodeParameters implementation is on runtime.parameterCodec and the only
call to runtime.NewParameterCodec is in pkg/api/register.—
Reply to this email directly or view it on GitHub
https://github.com/kubernetes/kubernetes/pull/20351/files#r51765129.
This is still a work in progress. I have more tests to write, as I'm not that confident in Watch yet. There's a couple of open questions I left as comments in the code. I'll go back and comment on them directly. There's also a question about organization. The new types and codec are in this package. Is this OK? Is there a better place for them to live? It didn't make sense to register the codec, since it's not really associated to any version. Open to all comments about how to do this better. cc @lavalamp cc @derekwaynecarr since you expressed interest in the SIG meeting |
@kubernetes/sig-api-machinery |
// codec is ignored, as the dynamic client uses it's own codec. | ||
func NewClient(conf *client.Config) (*Client, error) { | ||
// avoid changing the original config | ||
confCopy := *conf |
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.
Shallow copy is 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.
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 should probably be careful on reviews of client config to ensure that holds true. Probably worth it to add a copy the next time we change client.config.
Looks good so far! |
GCE e2e test build/test passed for commit c6ffca566577bec731ee6d3b12fbb54b247e8e46. |
|
||
// JSONCodec is a runtime.Codec that attempts to dynamically decode | ||
// objects and lists metadata for generic consumption. | ||
type JSONCodec struct { |
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 what UnstructuredCodec was supposed to do
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.
Should I start working on UnstructuredObject
, UnstructuredList
, and moving some of this logic back into the UnstructuredJSONScheme
? Or do you think this should remain separate?
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 former sounds like a good idea to me.
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.
Also I guess now that @smarterclayton's rename has gone in, this should be called a "Serializer" not a "Codec".
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 roll it into to UnstructuredJSONScheme as well - agree this is a Serializer (does not guarantee versioning).
c6ffca5
to
7bf05ee
Compare
|
||
var pCodec runtime.ParameterCodec = parameterCodec{} | ||
|
||
func getObjectName(obj *runtime.Unstructured) (string, 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.
This is what I used instead of including metadata in the unstructured objects.
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.
Leave a TODO that this needs to be centralized
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.
7bf05ee
to
f852aed
Compare
I think I addressed the high level comments you both had. If you guys don't have any more high level ones, I'm going to add more tests and turn this in to a real review. |
GCE e2e test build/test passed for commit 7bf05ee99cd42391ee7fa715c6cf72b41e4599b6. |
GCE e2e test build/test passed for commit f852aedb1d2f5f05985b433f58f8370077fd8018. |
return errors.New("DecodeParameters not implemented on nilParameterCodec") | ||
} | ||
|
||
var pCodec runtime.ParameterCodec = parameterCodec{} |
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 generally don't use this naming style - it should be parameterCodec
or parameterEncoder
Can you add DeleteCollection? On Friday, January 29, 2016, krousey notifications@github.com wrote:
|
@derekwaynecarr From what I can tell, only events support DeleteCollection. What is the expected behavior if this were used with Pods or Services? I was trying to limit this to the common operations. |
DeleteCollection should work for all namespaced content except Services, See: #20581 On Tuesday, February 9, 2016, krousey notifications@github.com wrote:
|
If it's not supported, it's fine to return the error that comes back from On Tuesday, February 9, 2016, krousey notifications@github.com wrote:
|
@derekwaynecarr I only see a client side implementation on events. Can I assume this to be a canonical was to call with with respect to query parameters, body, and HTTP Verb? That is a DELETE verb, list options in the query parameter, delete options in the body? |
All of the generated clients support the call. Every registry that uses etcd generic for storage has the server side https://github.com/kubernetes/kubernetes/blob/master/pkg/registry/generic/etcd/etcd.go#L444 Unfortunately services does not use that registry yet, but all others On Tuesday, February 9, 2016, krousey notifications@github.com wrote:
|
f852aed
to
fb63234
Compare
@derekwaynecarr It's possible, but I would like to understand why this is a problem. How does deferring the creation of the rest client help if the API the client produces is exactly the same? |
@krousey - I will push an example for the namespace controller using this for where it causes the problem. |
@krousey - here is a PR where I tried to start using this: I want to be able to construct a dynamic client in the controllermanager.go here: The issue is that at this point, it has no notion of the group version to use, so the call fails:
Later, I do some discovery, and know the set of resources I plan to delete, and will call delete collection here: At this point, I actually know api resource and preferred group version that I want to use, and so I would prefer the REST client is built in response to the Make sense? |
I want to avoid passing a |
After discussion on Slack, we agreed to put an interface in front of |
GCE e2e test build/test passed for commit 4c58302. |
What does this client provide ? Is this different from unversion go client for kubernetes or is it a layer on top of it ? Does it remove the 70+ dependencies the earlier go client depends on ? |
@k8s-bot test this [submit-queue is verifying that this PR is safe to merge] |
GCE e2e test build/test passed for commit 4c58302. |
@k8s-bot test this [submit-queue is verifying that this PR is safe to merge] |
GCE e2e build/test failed for commit 4c58302. |
@derekwaynecarr What does this client provide ? Is this different from unversioned go client for kubernetes or is it a layer on top of it ? Does it remove the 70+ dependencies the earlier go client depends on ? |
@krmayankk This client provides the ability to minimally interact with resources that weren't necessarily compiled in. The namespace controller (something @derekwaynecarr works on) has a use case to delete all resources under a namespace when the namespace is being deleted. This gives him a generic way to do that. Another use case is to allow eventually allow kubectl to interact with 3rd party API extensions without having to compile them in. Regarding dependencies, no. It might have few dependencies, but that was not an explicit goal for this PR. Also, this client isn't as fully featured as the others. There are other efforts to reduce the dependencies (API restructuring, client generation...), but this is not one of them. |
GCE e2e build/test failed for commit 4c58302. |
@krmayankk we will work on reducing the import tree next. First we're On Thu, Feb 18, 2016 at 10:05 AM, krousey notifications@github.com wrote:
|
GCE e2e build/test failed for commit 4c58302. |
GCE e2e test build/test passed for commit 4c58302. |
@k8s-bot test this [submit-queue is verifying that this PR is safe to merge] |
GCE e2e build/test failed for commit 4c58302. |
I'm adding the e2e-not-required label since e2e is flaky and this code in no way affects the e2e suite. |
Automatic merge from submit-queue |
Auto commit by PR queue bot
Attempt to provide a dynamic API client that can access metadata common to API object and lists, and perform common operations on them.