diff --git a/cmd/kube-controller-manager/app/controllermanager.go b/cmd/kube-controller-manager/app/controllermanager.go index 03cb8969e31..f7022ccf146 100644 --- a/cmd/kube-controller-manager/app/controllermanager.go +++ b/cmd/kube-controller-manager/app/controllermanager.go @@ -36,6 +36,7 @@ import ( "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/apis/batch" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned" @@ -311,9 +312,12 @@ func StartControllers(s *options.CMServer, kubeconfig *restclient.Config, stop < glog.Fatalf("Failed to get supported resources from server: %v", err) } + // TODO: should use a dynamic RESTMapper built from the discovery results. + restMapper := registered.RESTMapper() + // Find the list of namespaced resources via discovery that the namespace controller must manage namespaceKubeClient := client("namespace-controller") - namespaceClientPool := dynamic.NewClientPool(restclient.AddUserAgent(kubeconfig, "namespace-controller"), dynamic.LegacyAPIPathResolverFunc) + namespaceClientPool := dynamic.NewClientPool(restclient.AddUserAgent(kubeconfig, "namespace-controller"), restMapper, dynamic.LegacyAPIPathResolverFunc) groupVersionResources, err := namespaceKubeClient.Discovery().ServerPreferredNamespacedResources() if err != nil { glog.Fatalf("Failed to get supported resources from server: %v", err) @@ -519,12 +523,13 @@ func StartControllers(s *options.CMServer, kubeconfig *restclient.Config, stop < if err != nil { glog.Fatalf("Failed to get supported resources from server: %v", err) } + config := restclient.AddUserAgent(kubeconfig, "generic-garbage-collector") config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()} - metaOnlyClientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) + metaOnlyClientPool := dynamic.NewClientPool(config, restMapper, dynamic.LegacyAPIPathResolverFunc) config.ContentConfig.NegotiatedSerializer = nil - clientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) - garbageCollector, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, groupVersionResources) + clientPool := dynamic.NewClientPool(config, restMapper, dynamic.LegacyAPIPathResolverFunc) + garbageCollector, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, restMapper, groupVersionResources) if err != nil { glog.Errorf("Failed to start the generic garbage collector: %v", err) } else { diff --git a/contrib/mesos/pkg/controllermanager/controllermanager.go b/contrib/mesos/pkg/controllermanager/controllermanager.go index cee71cb1759..29e235bda9d 100644 --- a/contrib/mesos/pkg/controllermanager/controllermanager.go +++ b/contrib/mesos/pkg/controllermanager/controllermanager.go @@ -30,6 +30,7 @@ import ( "k8s.io/kubernetes/contrib/mesos/pkg/node" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apimachinery/registered" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/typed/dynamic" @@ -234,7 +235,7 @@ func (s *CMServer) Run(_ []string) error { // Find the list of namespaced resources via discovery that the namespace controller must manage namespaceKubeClient := clientset.NewForConfigOrDie(restclient.AddUserAgent(kubeconfig, "namespace-controller")) - namespaceClientPool := dynamic.NewClientPool(restclient.AddUserAgent(kubeconfig, "namespace-controller"), dynamic.LegacyAPIPathResolverFunc) + namespaceClientPool := dynamic.NewClientPool(restclient.AddUserAgent(kubeconfig, "namespace-controller"), registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) groupVersionResources, err := namespaceKubeClient.Discovery().ServerPreferredNamespacedResources() if err != nil { glog.Fatalf("Failed to get supported resources from server: %v", err) diff --git a/pkg/api/meta/interfaces.go b/pkg/api/meta/interfaces.go index 80dab0b7fdd..488f78d3720 100644 --- a/pkg/api/meta/interfaces.go +++ b/pkg/api/meta/interfaces.go @@ -160,8 +160,7 @@ type RESTMapping struct { // to API groups. In other words, kinds and resources should not be assumed to be // unique across groups. // -// TODO(caesarxuchao): Add proper multi-group support so that kinds & resources are -// scoped to groups. See http://issues.k8s.io/12413 and http://issues.k8s.io/10009. +// TODO: split into sub-interfaces type RESTMapper interface { // KindFor takes a partial resource and returns the single match. Returns an error if there are multiple matches KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) diff --git a/pkg/client/typed/dynamic/client_pool.go b/pkg/client/typed/dynamic/client_pool.go index 66a50e0bbd6..e7ba944dc8b 100644 --- a/pkg/client/typed/dynamic/client_pool.go +++ b/pkg/client/typed/dynamic/client_pool.go @@ -20,6 +20,7 @@ import ( "sync" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/runtime" @@ -28,46 +29,72 @@ import ( // ClientPool manages a pool of dynamic clients. type ClientPool interface { - // ClientForGroupVersion returns a client configured for the specified groupVersion. - ClientForGroupVersion(groupVersion unversioned.GroupVersion) (*Client, error) + // ClientForGroupVersionKind returns a client configured for the specified groupVersionResource. + // Resource may be empty. + ClientForGroupVersionResource(resource unversioned.GroupVersionResource) (*Client, error) + // ClientForGroupVersionKind returns a client configured for the specified groupVersionKind. + // Kind may be empty. + ClientForGroupVersionKind(kind unversioned.GroupVersionKind) (*Client, error) } -// APIPathResolverFunc knows how to convert a groupVersion to its API path. -type APIPathResolverFunc func(groupVersion unversioned.GroupVersion) string +// APIPathResolverFunc knows how to convert a groupVersion to its API path. The Kind field is +// optional. +type APIPathResolverFunc func(kind unversioned.GroupVersionKind) string // LegacyAPIPathResolverFunc can resolve paths properly with the legacy API. -func LegacyAPIPathResolverFunc(groupVersion unversioned.GroupVersion) string { - if len(groupVersion.Group) == 0 { +func LegacyAPIPathResolverFunc(kind unversioned.GroupVersionKind) string { + if len(kind.Group) == 0 { return "/api" } return "/apis" } -// clientPoolImpl implements Factory +// clientPoolImpl implements ClientPool and caches clients for the resource group versions +// is asked to retrieve. This type is thread safe. type clientPoolImpl struct { lock sync.RWMutex config *restclient.Config clients map[unversioned.GroupVersion]*Client apiPathResolverFunc APIPathResolverFunc + mapper meta.RESTMapper } -// NewClientPool returns a ClientPool from the specified config -func NewClientPool(config *restclient.Config, apiPathResolverFunc APIPathResolverFunc) ClientPool { +// NewClientPool returns a ClientPool from the specified config. It reuses clients for the the same +// group version. It is expected this type may be wrapped by specific logic that special cases certain +// resources or groups. +func NewClientPool(config *restclient.Config, mapper meta.RESTMapper, apiPathResolverFunc APIPathResolverFunc) ClientPool { confCopy := *config return &clientPoolImpl{ config: &confCopy, clients: map[unversioned.GroupVersion]*Client{}, apiPathResolverFunc: apiPathResolverFunc, + mapper: mapper, } } -// ClientForGroupVersion returns a client for the specified groupVersion, creates one if none exists -func (c *clientPoolImpl) ClientForGroupVersion(groupVersion unversioned.GroupVersion) (*Client, error) { +// ClientForGroupVersionResource uses the provided RESTMapper to identify the appropriate resource. Resource may +// be empty. If no matching kind is found the underlying client for that group is still returned. +func (c *clientPoolImpl) ClientForGroupVersionResource(resource unversioned.GroupVersionResource) (*Client, error) { + kinds, err := c.mapper.KindsFor(resource) + if err != nil { + if meta.IsNoMatchError(err) { + return c.ClientForGroupVersionKind(unversioned.GroupVersionKind{Group: resource.Group, Version: resource.Version}) + } + return nil, err + } + return c.ClientForGroupVersionKind(kinds[0]) +} + +// ClientForGroupVersion returns a client for the specified groupVersion, creates one if none exists. Kind +// in the GroupVersionKind may be empty. +func (c *clientPoolImpl) ClientForGroupVersionKind(kind unversioned.GroupVersionKind) (*Client, error) { c.lock.Lock() defer c.lock.Unlock() + gv := kind.GroupVersion() + // do we have a client already configured? - if existingClient, found := c.clients[groupVersion]; found { + if existingClient, found := c.clients[gv]; found { return existingClient, nil } @@ -76,10 +103,10 @@ func (c *clientPoolImpl) ClientForGroupVersion(groupVersion unversioned.GroupVer conf := &confCopy // we need to set the api path based on group version, if no group, default to legacy path - conf.APIPath = c.apiPathResolverFunc(groupVersion) + conf.APIPath = c.apiPathResolverFunc(kind) // we need to make a client - conf.GroupVersion = &groupVersion + conf.GroupVersion = &gv if conf.NegotiatedSerializer == nil { streamingInfo, _ := api.Codecs.StreamingSerializerForMediaType("application/json;stream=watch", nil) @@ -90,6 +117,6 @@ func (c *clientPoolImpl) ClientForGroupVersion(groupVersion unversioned.GroupVer if err != nil { return nil, err } - c.clients[groupVersion] = dynamicClient + c.clients[gv] = dynamicClient return dynamicClient, nil } diff --git a/pkg/controller/garbagecollector/garbagecollector.go b/pkg/controller/garbagecollector/garbagecollector.go index d69d3e3a7f1..a4018a7842e 100644 --- a/pkg/controller/garbagecollector/garbagecollector.go +++ b/pkg/controller/garbagecollector/garbagecollector.go @@ -29,7 +29,6 @@ import ( "k8s.io/kubernetes/pkg/api/meta/metatypes" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/v1" - "k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/client/typed/dynamic" "k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly" @@ -478,7 +477,7 @@ func (gc *GarbageCollector) monitorFor(resource unversioned.GroupVersionResource // TODO: consider store in one storage. glog.V(6).Infof("create storage for resource %s", resource) var monitor monitor - client, err := gc.metaOnlyClientPool.ClientForGroupVersion(resource.GroupVersion()) + client, err := gc.metaOnlyClientPool.ClientForGroupVersionKind(kind) if err != nil { return monitor, err } @@ -537,12 +536,11 @@ var ignoredResources = map[unversioned.GroupVersionResource]struct{}{ unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "localsubjectaccessreviews"}: {}, } -func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) { +func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, mapper meta.RESTMapper, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) { gc := &GarbageCollector{ - metaOnlyClientPool: metaOnlyClientPool, - clientPool: clientPool, - // TODO: should use a dynamic RESTMapper built from the discovery results. - restMapper: registered.RESTMapper(), + metaOnlyClientPool: metaOnlyClientPool, + clientPool: clientPool, + restMapper: mapper, clock: clock.RealClock{}, dirtyQueue: workqueue.NewTimedWorkQueue(), orphanQueue: workqueue.NewTimedWorkQueue(), @@ -611,7 +609,7 @@ func (gc *GarbageCollector) apiResource(apiVersion, kind string, namespaced bool func (gc *GarbageCollector) deleteObject(item objectReference) error { fqKind := unversioned.FromAPIVersionAndKind(item.APIVersion, item.Kind) - client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion()) + client, err := gc.clientPool.ClientForGroupVersionKind(fqKind) gc.registeredRateLimiter.registerIfNotPresent(fqKind.GroupVersion(), client, "garbage_collector_operation") resource, err := gc.apiResource(item.APIVersion, item.Kind, len(item.Namespace) != 0) if err != nil { @@ -625,7 +623,7 @@ func (gc *GarbageCollector) deleteObject(item objectReference) error { func (gc *GarbageCollector) getObject(item objectReference) (*runtime.Unstructured, error) { fqKind := unversioned.FromAPIVersionAndKind(item.APIVersion, item.Kind) - client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion()) + client, err := gc.clientPool.ClientForGroupVersionKind(fqKind) gc.registeredRateLimiter.registerIfNotPresent(fqKind.GroupVersion(), client, "garbage_collector_operation") resource, err := gc.apiResource(item.APIVersion, item.Kind, len(item.Namespace) != 0) if err != nil { @@ -636,7 +634,7 @@ func (gc *GarbageCollector) getObject(item objectReference) (*runtime.Unstructur func (gc *GarbageCollector) updateObject(item objectReference, obj *runtime.Unstructured) (*runtime.Unstructured, error) { fqKind := unversioned.FromAPIVersionAndKind(item.APIVersion, item.Kind) - client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion()) + client, err := gc.clientPool.ClientForGroupVersionKind(fqKind) gc.registeredRateLimiter.registerIfNotPresent(fqKind.GroupVersion(), client, "garbage_collector_operation") resource, err := gc.apiResource(item.APIVersion, item.Kind, len(item.Namespace) != 0) if err != nil { @@ -647,7 +645,7 @@ func (gc *GarbageCollector) updateObject(item objectReference, obj *runtime.Unst func (gc *GarbageCollector) patchObject(item objectReference, patch []byte) (*runtime.Unstructured, error) { fqKind := unversioned.FromAPIVersionAndKind(item.APIVersion, item.Kind) - client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion()) + client, err := gc.clientPool.ClientForGroupVersionKind(fqKind) gc.registeredRateLimiter.registerIfNotPresent(fqKind.GroupVersion(), client, "garbage_collector_operation") resource, err := gc.apiResource(item.APIVersion, item.Kind, len(item.Namespace) != 0) if err != nil { @@ -728,7 +726,7 @@ func (gc *GarbageCollector) processItem(item *node) error { // prevent objects having references to an old resource from being // deleted during a cluster upgrade. fqKind := unversioned.FromAPIVersionAndKind(reference.APIVersion, reference.Kind) - client, err := gc.clientPool.ClientForGroupVersion(fqKind.GroupVersion()) + client, err := gc.clientPool.ClientForGroupVersionKind(fqKind) if err != nil { return err } diff --git a/pkg/controller/garbagecollector/garbagecollector_test.go b/pkg/controller/garbagecollector/garbagecollector_test.go index be1c900e629..78b2864e4a7 100644 --- a/pkg/controller/garbagecollector/garbagecollector_test.go +++ b/pkg/controller/garbagecollector/garbagecollector_test.go @@ -23,17 +23,19 @@ import ( "sync" "testing" - _ "k8s.io/kubernetes/pkg/api/install" - "k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly" - "k8s.io/kubernetes/pkg/runtime/serializer" - "github.com/stretchr/testify/assert" + + _ "k8s.io/kubernetes/pkg/api/install" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/meta/metatypes" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/typed/dynamic" + "k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly" + "k8s.io/kubernetes/pkg/runtime/serializer" "k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/util/clock" "k8s.io/kubernetes/pkg/util/json" @@ -44,11 +46,11 @@ import ( func TestNewGarbageCollector(t *testing.T) { config := &restclient.Config{} config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()} - metaOnlyClientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) + metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) config.ContentConfig.NegotiatedSerializer = nil - clientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) + clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) podResource := []unversioned.GroupVersionResource{{Version: "v1", Resource: "pods"}} - gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, podResource) + gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), podResource) if err != nil { t.Fatal(err) } @@ -107,11 +109,11 @@ func testServerAndClientConfig(handler func(http.ResponseWriter, *http.Request)) func setupGC(t *testing.T, config *restclient.Config) *GarbageCollector { config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()} - metaOnlyClientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) + metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) config.ContentConfig.NegotiatedSerializer = nil - clientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) + clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) podResource := []unversioned.GroupVersionResource{{Version: "v1", Resource: "pods"}} - gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, podResource) + gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), podResource) if err != nil { t.Fatal(err) } @@ -340,9 +342,9 @@ func TestGCListWatcher(t *testing.T) { testHandler := &fakeActionHandler{} srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP) defer srv.Close() - clientPool := dynamic.NewClientPool(clientConfig, dynamic.LegacyAPIPathResolverFunc) + clientPool := dynamic.NewClientPool(clientConfig, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) podResource := unversioned.GroupVersionResource{Version: "v1", Resource: "pods"} - client, err := clientPool.ClientForGroupVersion(podResource.GroupVersion()) + client, err := clientPool.ClientForGroupVersionResource(podResource) if err != nil { t.Fatal(err) } diff --git a/pkg/controller/namespace/namespace_controller_test.go b/pkg/controller/namespace/namespace_controller_test.go index dcee9a696e3..0bfb071eacd 100644 --- a/pkg/controller/namespace/namespace_controller_test.go +++ b/pkg/controller/namespace/namespace_controller_test.go @@ -28,6 +28,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apimachinery/registered" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/restclient" @@ -113,7 +114,7 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, versions *unversioned.APIV groupVersionResources := testGroupVersionResources() for _, groupVersionResource := range groupVersionResources { urlPath := path.Join([]string{ - dynamic.LegacyAPIPathResolverFunc(groupVersionResource.GroupVersion()), + dynamic.LegacyAPIPathResolverFunc(unversioned.GroupVersionKind{Group: groupVersionResource.Group, Version: groupVersionResource.Version}), groupVersionResource.Group, groupVersionResource.Version, "namespaces", @@ -155,7 +156,7 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, versions *unversioned.APIV defer srv.Close() mockClient := fake.NewSimpleClientset(testInput.testNamespace) - clientPool := dynamic.NewClientPool(clientConfig, dynamic.LegacyAPIPathResolverFunc) + clientPool := dynamic.NewClientPool(clientConfig, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) err := syncNamespace(mockClient, clientPool, operationNotSupportedCache{}, groupVersionResources, testInput.testNamespace, api.FinalizerKubernetes) if err != nil { diff --git a/pkg/controller/namespace/namespace_controller_utils.go b/pkg/controller/namespace/namespace_controller_utils.go index 287e2e8b813..a5748a73c97 100644 --- a/pkg/controller/namespace/namespace_controller_utils.go +++ b/pkg/controller/namespace/namespace_controller_utils.go @@ -274,7 +274,7 @@ func deleteAllContentForGroupVersionResource( glog.V(5).Infof("namespace controller - deleteAllContentForGroupVersionResource - estimate - namespace: %s, gvr: %v, estimate: %v", namespace, gvr, estimate) // get a client for this group version... - dynamicClient, err := clientPool.ClientForGroupVersion(gvr.GroupVersion()) + dynamicClient, err := clientPool.ClientForGroupVersionResource(gvr) if err != nil { glog.V(5).Infof("namespace controller - deleteAllContentForGroupVersionResource - unable to get client - namespace: %s, gvr: %v, err: %v", namespace, gvr, err) return estimate, err diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index dca066f4921..2d8c71a1777 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -34,6 +34,7 @@ import ( apierrs "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/typed/dynamic" @@ -197,7 +198,7 @@ func (f *Framework) BeforeEach() { clientRepoConfig := getClientRepoConfig(config) f.StagingClient, err = staging.NewForConfig(clientRepoConfig) Expect(err).NotTo(HaveOccurred()) - f.ClientPool = dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) + f.ClientPool = dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) } if f.federated { diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index c342bf06b7c..e087e541256 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -437,7 +437,7 @@ func SkipUnlessFederated(c *client.Client) { } func SkipIfMissingResource(clientPool dynamic.ClientPool, gvr unversioned.GroupVersionResource, namespace string) { - dynamicClient, err := clientPool.ClientForGroupVersion(gvr.GroupVersion()) + dynamicClient, err := clientPool.ClientForGroupVersionResource(gvr) if err != nil { Failf("Unexpected error getting dynamic client for %v: %v", gvr.GroupVersion(), err) } @@ -1230,7 +1230,7 @@ func hasRemainingContent(c *client.Client, clientPool dynamic.ClientPool, namesp // dump how many of resource type is on the server in a log. for _, gvr := range groupVersionResources { // get a client for this group version... - dynamicClient, err := clientPool.ClientForGroupVersion(gvr.GroupVersion()) + dynamicClient, err := clientPool.ClientForGroupVersionResource(gvr) if err != nil { // not all resource types support list, so some errors here are normal depending on the resource type. Logf("namespace: %s, unable to get client - gvr: %v, error: %v", namespace, gvr, err) diff --git a/test/e2e_node/services/namespace_controller.go b/test/e2e_node/services/namespace_controller.go index 90cf20b3fd1..e4282edba93 100644 --- a/test/e2e_node/services/namespace_controller.go +++ b/test/e2e_node/services/namespace_controller.go @@ -20,6 +20,7 @@ import ( "time" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apimachinery/registered" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/typed/dynamic" @@ -54,7 +55,7 @@ func (n *NamespaceController) Start() error { if err != nil { return err } - clientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) + clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) resources, err := client.Discovery().ServerPreferredNamespacedResources() if err != nil { return err diff --git a/test/integration/garbagecollector/garbage_collector_test.go b/test/integration/garbagecollector/garbage_collector_test.go index 8691d549eae..3f1e54d3a7b 100644 --- a/test/integration/garbagecollector/garbage_collector_test.go +++ b/test/integration/garbagecollector/garbage_collector_test.go @@ -33,6 +33,7 @@ import ( "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/apimachinery/registered" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_3" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/typed/dynamic" @@ -133,10 +134,10 @@ func setup(t *testing.T) (*httptest.Server, *garbagecollector.GarbageCollector, } config := &restclient.Config{Host: s.URL} config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()} - metaOnlyClientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) + metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) config.ContentConfig.NegotiatedSerializer = nil - clientPool := dynamic.NewClientPool(config, dynamic.LegacyAPIPathResolverFunc) - gc, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, groupVersionResources) + clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) + gc, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), groupVersionResources) if err != nil { t.Fatalf("Failed to create garbage collector") }