Skip to content
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

Merged
merged 1 commit into from
Feb 19, 2016
Merged

Conversation

krousey
Copy link
Contributor

@krousey krousey commented Jan 29, 2016

Attempt to provide a dynamic API client that can access metadata common to API object and lists, and perform common operations on them.

@krousey krousey added the sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. label Jan 29, 2016
@krousey krousey self-assigned this Jan 29, 2016
@k8s-github-robot
Copy link

Labelling this PR as size/XL

@k8s-github-robot k8s-github-robot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Jan 29, 2016
result := new(List)
err := rc.namespace(rc.cl.Get()).
Resource(rc.resource.Name).
VersionedParams(&opts, api.Scheme). // What to do about VersionedParams converter?
Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

@krousey
Copy link
Contributor Author

krousey commented Jan 29, 2016

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
cc @smarterclayton To spot check how I implemented the codec considering that I don't want it to do any conversion. Did I appropriately ignore defaults and overrides?

@krousey
Copy link
Contributor Author

krousey commented Jan 29, 2016

@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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shallow copy is OK?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

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.

@lavalamp
Copy link
Member

Looks good so far!

@k8s-bot
Copy link

k8s-bot commented Jan 29, 2016

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 {
Copy link
Contributor

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

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Member

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".

Copy link
Contributor

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).


var pCodec runtime.ParameterCodec = parameterCodec{}

func getObjectName(obj *runtime.Unstructured) (string, error) {
Copy link
Contributor Author

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.

Copy link
Contributor

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@krousey
Copy link
Contributor Author

krousey commented Feb 8, 2016

@lavalamp @smarterclayton

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.

@k8s-bot
Copy link

k8s-bot commented Feb 8, 2016

GCE e2e test build/test passed for commit 7bf05ee99cd42391ee7fa715c6cf72b41e4599b6.

@k8s-bot
Copy link

k8s-bot commented Feb 8, 2016

GCE e2e test build/test passed for commit f852aedb1d2f5f05985b433f58f8370077fd8018.

return errors.New("DecodeParameters not implemented on nilParameterCodec")
}

var pCodec runtime.ParameterCodec = parameterCodec{}
Copy link
Contributor

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

@derekwaynecarr
Copy link
Member

Can you add DeleteCollection?

On Friday, January 29, 2016, krousey notifications@github.com wrote:

Attempt to provide a dynamic API client that can access metadata common to

API object and lists, and perform common operations on them.

You can view, comment on, or merge this pull request online at:

#20351
Commit Summary

  • WIP Adding dynamic client

File Changes

Patch Links:


Reply to this email directly or view it on GitHub
#20351.

@krousey
Copy link
Contributor Author

krousey commented Feb 9, 2016

@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.

@derekwaynecarr
Copy link
Member

DeleteCollection should work for all namespaced content except Services,
but that needs to be fixed.

See: #20581

On Tuesday, February 9, 2016, krousey notifications@github.com wrote:

@derekwaynecarr https://github.com/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.


Reply to this email directly or view it on GitHub
#20351 (comment)
.

@derekwaynecarr
Copy link
Member

If it's not supported, it's fine to return the error that comes back from
the API server. So for services, I would expect an error response, but for
all others, it should be fine.

On Tuesday, February 9, 2016, krousey notifications@github.com wrote:

@derekwaynecarr https://github.com/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.


Reply to this email directly or view it on GitHub
#20351 (comment)
.

@krousey
Copy link
Contributor Author

krousey commented Feb 9, 2016

@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?

@derekwaynecarr
Copy link
Member

All of the generated clients support the call.

https://github.com/kubernetes/kubernetes/blob/master/pkg/client/typed/generated/core/unversioned/pod.go#L36

Every registry that uses etcd generic for storage has the server side
support:

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
should be good to go.

On Tuesday, February 9, 2016, krousey notifications@github.com wrote:

@derekwaynecarr https://github.com/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?


Reply to this email directly or view it on GitHub
#20351 (comment)
.

@krousey
Copy link
Contributor Author

krousey commented Feb 17, 2016

@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?

@derekwaynecarr
Copy link
Member

@krousey - I will push an example for the namespace controller using this for where it causes the problem.

@derekwaynecarr
Copy link
Member

@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:
0fab678#diff-2aa9cfe6a01016c1679752b0fcfc9244R248

The issue is that at this point, it has no notion of the group version to use, so the call fails:

Failed to create client: GroupVersion is required when initializing a RESTClient

Later, I do some discovery, and know the set of resources I plan to delete, and will call delete collection here:
0fab678#diff-f86a8dd1c06d1f9578423999f8094cc7R138

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 Resource() call.

Make sense?

@derekwaynecarr
Copy link
Member

I want to avoid passing a *client.Config into the namespace controller as it makes testing the controller really difficult versus passing in a mock client implementation.

@derekwaynecarr
Copy link
Member

After discussion on Slack, we agreed to put an interface in front of dynamic.Client in a separate PR that will maintain a cache of clients per group version. The namespace controller will use that.

@derekwaynecarr derekwaynecarr added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 17, 2016
@krousey
Copy link
Contributor Author

krousey commented Feb 17, 2016

@k8s-bot e2e test this issue: #21257

@k8s-bot
Copy link

k8s-bot commented Feb 17, 2016

GCE e2e test build/test passed for commit 4c58302.

@krmayankk
Copy link

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-github-robot
Copy link

@k8s-bot test this [submit-queue is verifying that this PR is safe to merge]

@k8s-bot
Copy link

k8s-bot commented Feb 18, 2016

GCE e2e test build/test passed for commit 4c58302.

@k8s-github-robot
Copy link

@k8s-bot test this [submit-queue is verifying that this PR is safe to merge]

@k8s-bot
Copy link

k8s-bot commented Feb 18, 2016

GCE e2e build/test failed for commit 4c58302.

@krousey
Copy link
Contributor Author

krousey commented Feb 18, 2016

@k8s-bot e2e test this issue: #21257

@krmayankk
Copy link

@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 ?

@krousey
Copy link
Contributor Author

krousey commented Feb 18, 2016

@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.

@k8s-bot
Copy link

k8s-bot commented Feb 18, 2016

GCE e2e build/test failed for commit 4c58302.

@krousey
Copy link
Contributor Author

krousey commented Feb 18, 2016

@k8s-bot e2e test this issue: #21138

@lavalamp
Copy link
Member

@krmayankk we will work on reducing the import tree next. First we're
trying to get the client into the right shape at all...

On Thu, Feb 18, 2016 at 10:05 AM, krousey notifications@github.com wrote:

@k8s-bot https://github.com/k8s-bot e2e test this issue: #21138
#21138


Reply to this email directly or view it on GitHub
#20351 (comment)
.

@k8s-bot
Copy link

k8s-bot commented Feb 18, 2016

GCE e2e build/test failed for commit 4c58302.

@krousey
Copy link
Contributor Author

krousey commented Feb 18, 2016

@k8s-bot e2e test this issue: #21463

@k8s-bot
Copy link

k8s-bot commented Feb 18, 2016

GCE e2e test build/test passed for commit 4c58302.

@k8s-github-robot
Copy link

@k8s-bot test this [submit-queue is verifying that this PR is safe to merge]

@k8s-bot
Copy link

k8s-bot commented Feb 19, 2016

GCE e2e build/test failed for commit 4c58302.

@krousey
Copy link
Contributor Author

krousey commented Feb 19, 2016

I'm adding the e2e-not-required label since e2e is flaky and this code in no way affects the e2e suite.

@k8s-github-robot
Copy link

Automatic merge from submit-queue

k8s-github-robot pushed a commit that referenced this pull request Feb 19, 2016
@k8s-github-robot k8s-github-robot merged commit c3a962b into kubernetes:master Feb 19, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm "Looks good to me", indicates that a PR is ready to be merged. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants