From eac2049fc9a151a7cbd6652e039506376574e0a9 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Wed, 4 Oct 2017 18:42:54 -0400 Subject: [PATCH 1/8] [client-go] avoid Registry in fake REST client Previously, the fake RESTClient in client-go required a Registry. It used the Registry to fetch the GroupVersion for the fake client. However, the way it did so was dubious in some cases (it hard-coded the default API group in places), and not strictly necssary. This updates the fake client to just recieve the GroupVersion and internal group name directly, instead of requiring a Registry, so that it can be consumed in unit tests where a Registry isn't necessarily readily available (e.g. elsewhere in client-go). --- federation/pkg/kubefed/init/init_test.go | 2 +- federation/pkg/kubefed/join_test.go | 6 +-- federation/pkg/kubefed/unjoin_test.go | 5 +-- pkg/kubectl/cmd/annotate_test.go | 8 ++-- pkg/kubectl/cmd/apply_test.go | 24 +++++----- pkg/kubectl/cmd/attach_test.go | 6 +-- pkg/kubectl/cmd/auth/cani_test.go | 2 +- pkg/kubectl/cmd/cmd_test.go | 16 +++---- .../cmd/create_clusterrolebinding_test.go | 3 +- pkg/kubectl/cmd/create_configmap_test.go | 2 +- pkg/kubectl/cmd/create_deployment_test.go | 5 ++- pkg/kubectl/cmd/create_namespace_test.go | 2 +- pkg/kubectl/cmd/create_pdb_test.go | 3 +- pkg/kubectl/cmd/create_quota_test.go | 2 +- pkg/kubectl/cmd/create_rolebinding_test.go | 3 +- pkg/kubectl/cmd/create_secret_test.go | 4 +- pkg/kubectl/cmd/create_service_test.go | 6 +-- pkg/kubectl/cmd/create_serviceaccount_test.go | 2 +- pkg/kubectl/cmd/create_test.go | 7 +-- pkg/kubectl/cmd/delete_test.go | 28 ++++++------ pkg/kubectl/cmd/describe_test.go | 13 +++--- pkg/kubectl/cmd/drain_test.go | 4 +- pkg/kubectl/cmd/edit_test.go | 3 +- pkg/kubectl/cmd/exec_test.go | 4 +- pkg/kubectl/cmd/expose_test.go | 2 +- pkg/kubectl/cmd/get_test.go | 44 +++++++++---------- pkg/kubectl/cmd/label_test.go | 6 +-- pkg/kubectl/cmd/logs_test.go | 2 +- pkg/kubectl/cmd/patch_test.go | 9 ++-- pkg/kubectl/cmd/portforward_test.go | 2 +- pkg/kubectl/cmd/replace_test.go | 8 ++-- pkg/kubectl/cmd/run_test.go | 6 +-- pkg/kubectl/cmd/set/BUILD | 1 + pkg/kubectl/cmd/set/set_env_test.go | 2 +- pkg/kubectl/cmd/set/set_image_test.go | 2 +- pkg/kubectl/cmd/set/set_resources_test.go | 2 +- pkg/kubectl/cmd/set/set_selector_test.go | 2 +- .../cmd/set/set_serviceaccount_test.go | 8 ++-- pkg/kubectl/cmd/taint_test.go | 3 +- pkg/kubectl/cmd/top_node_test.go | 8 ++-- pkg/kubectl/cmd/top_pod_test.go | 5 ++- pkg/kubectl/resource/builder_test.go | 2 +- pkg/kubectl/resource/helper_test.go | 10 ++--- pkg/kubectl/rolling_updater_test.go | 4 +- staging/src/k8s.io/client-go/rest/fake/BUILD | 1 - .../src/k8s.io/client-go/rest/fake/fake.go | 16 +++---- 46 files changed, 155 insertions(+), 150 deletions(-) diff --git a/federation/pkg/kubefed/init/init_test.go b/federation/pkg/kubefed/init/init_test.go index 73e9e5d81c0..6571d6bae59 100644 --- a/federation/pkg/kubefed/init/init_test.go +++ b/federation/pkg/kubefed/init/init_test.go @@ -1156,7 +1156,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.TmpDir = tmpDirPath tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/federation/pkg/kubefed/join_test.go b/federation/pkg/kubefed/join_test.go index 77705bf1668..0112ec205a4 100644 --- a/federation/pkg/kubefed/join_test.go +++ b/federation/pkg/kubefed/join_test.go @@ -232,7 +232,7 @@ func testJoinFederationFactory(clusterName, secretName, server string, isRBACAPI codec := testapi.Federation.Codec() ns := dynamic.ContentConfig().NegotiatedSerializer tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -366,7 +366,7 @@ func fakeJoinHostFactory(clusterName, clusterCtx, secretName, server, token, dns ns := dynamic.ContentConfig().NegotiatedSerializer tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -527,7 +527,7 @@ func fakeJoinTargetClusterFactory(clusterName, clusterCtx, dnsProvider, tmpDirPa tf.TmpDir = tmpDirPath tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m, r := req.URL.Path, req.Method, isRBACAPIAvailable; { diff --git a/federation/pkg/kubefed/unjoin_test.go b/federation/pkg/kubefed/unjoin_test.go index ae8509b2fd6..3ff19a1de06 100644 --- a/federation/pkg/kubefed/unjoin_test.go +++ b/federation/pkg/kubefed/unjoin_test.go @@ -185,9 +185,8 @@ func testUnjoinFederationFactory(name, server, secret string) cmdutil.Factory { tf.ClientConfig = kubefedtesting.DefaultClientConfig() ns := serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: runtime.NewCodec(f.JSONEncoder(), legacyscheme.Codecs.UniversalDecoder(fedv1beta1.SchemeGroupVersion))}) tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie("federation").GroupVersion, NegotiatedSerializer: ns, - GroupName: "federation", Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { case strings.HasPrefix(p, urlPrefix): @@ -242,7 +241,7 @@ func fakeUnjoinHostFactory(clusterName string) cmdutil.Factory { ns := dynamic.ContentConfig().NegotiatedSerializer tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/annotate_test.go b/pkg/kubectl/cmd/annotate_test.go index 3b9e2aa085d..7396d9a4936 100644 --- a/pkg/kubectl/cmd/annotate_test.go +++ b/pkg/kubectl/cmd/annotate_test.go @@ -452,7 +452,7 @@ func TestAnnotateObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.Method { @@ -503,7 +503,7 @@ func TestAnnotateObjectFromFile(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.Method { @@ -552,7 +552,7 @@ func TestAnnotateObjectFromFile(t *testing.T) { func TestAnnotateLocal(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) @@ -585,7 +585,7 @@ func TestAnnotateMultipleObjects(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.Method { diff --git a/pkg/kubectl/cmd/apply_test.go b/pkg/kubectl/cmd/apply_test.go index 9cceac1a273..fc98f462f9b 100644 --- a/pkg/kubectl/cmd/apply_test.go +++ b/pkg/kubectl/cmd/apply_test.go @@ -302,7 +302,7 @@ func TestRunApplyViewLastApplied(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -358,7 +358,7 @@ func TestApplyObjectWithoutAnnotation(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -403,7 +403,7 @@ func TestApplyObject(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -460,7 +460,7 @@ func TestApplyObjectOutput(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &printers.YAMLPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -505,7 +505,7 @@ func TestApplyRetry(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -559,7 +559,7 @@ func TestApplyNonExistObject(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -610,7 +610,7 @@ func testApplyMultipleObjects(t *testing.T, asList bool) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -688,7 +688,7 @@ func TestApplyNULLPreservation(t *testing.T) { f, tf, _, _ := cmdtesting.NewTestFactory() tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -757,7 +757,7 @@ func TestUnstructuredApply(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -821,7 +821,7 @@ func TestUnstructuredIdempotentApply(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -946,7 +946,7 @@ func TestRunApplySetLastApplied(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -1035,7 +1035,7 @@ func TestForceApply(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/attach_test.go b/pkg/kubectl/cmd/attach_test.go index f406b4fb069..04dcd0aedf2 100644 --- a/pkg/kubectl/cmd/attach_test.go +++ b/pkg/kubectl/cmd/attach_test.go @@ -140,7 +140,7 @@ func TestPodAndContainerAttach(t *testing.T) { for _, test := range tests { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { if test.obj != nil { @@ -217,7 +217,7 @@ func TestAttach(t *testing.T) { for _, test := range tests { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -304,7 +304,7 @@ func TestAttachWarnings(t *testing.T) { for _, test := range tests { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/auth/cani_test.go b/pkg/kubectl/cmd/auth/cani_test.go index 0bc060b4644..5411dafdde9 100644 --- a/pkg/kubectl/cmd/auth/cani_test.go +++ b/pkg/kubectl/cmd/auth/cani_test.go @@ -122,7 +122,7 @@ func TestRunAccessCheck(t *testing.T) { f, tf, _, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { expectPath := "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews" diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go index f46146d5086..d59ea8d64ab 100644 --- a/pkg/kubectl/cmd/cmd_test.go +++ b/pkg/kubectl/cmd/cmd_test.go @@ -163,7 +163,7 @@ func Example_printReplicationControllerWithNamespace() { printersinternal.AddHandlers(p) tf.Printer = p tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: nil, } @@ -216,7 +216,7 @@ func Example_printMultiContainersReplicationControllerWithWide() { printersinternal.AddHandlers(p) tf.Printer = p tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: nil, } @@ -270,7 +270,7 @@ func Example_printReplicationController() { printersinternal.AddHandlers(p) tf.Printer = p tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: nil, } @@ -325,7 +325,7 @@ func Example_printPodWithWideFormat() { printersinternal.AddHandlers(p) tf.Printer = p tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: nil, } @@ -368,7 +368,7 @@ func Example_printPodWithShowLabels() { printersinternal.AddHandlers(p) tf.Printer = p tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: nil, } @@ -505,7 +505,7 @@ func Example_printPodHideTerminated() { printersinternal.AddHandlers(p) tf.Printer = p tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: nil, } @@ -541,7 +541,7 @@ func Example_printPodShowAll() { printersinternal.AddHandlers(p) tf.Printer = p tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: nil, } @@ -570,7 +570,7 @@ func Example_printServiceWithNamespacesAndLabels() { printersinternal.AddHandlers(p) tf.Printer = p tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: nil, } diff --git a/pkg/kubectl/cmd/create_clusterrolebinding_test.go b/pkg/kubectl/cmd/create_clusterrolebinding_test.go index 26eccd1c531..cf43eff2ae8 100644 --- a/pkg/kubectl/cmd/create_clusterrolebinding_test.go +++ b/pkg/kubectl/cmd/create_clusterrolebinding_test.go @@ -30,6 +30,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" ) @@ -77,7 +78,7 @@ func TestCreateClusterRoleBinding(t *testing.T) { tf.Printer = &testPrinter{} tf.Client = &ClusterRoleBindingRESTClient{ RESTClient: &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/create_configmap_test.go b/pkg/kubectl/cmd/create_configmap_test.go index e8c898ad9ca..f0ed75cda73 100644 --- a/pkg/kubectl/cmd/create_configmap_test.go +++ b/pkg/kubectl/cmd/create_configmap_test.go @@ -33,7 +33,7 @@ func TestCreateConfigMap(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/create_deployment_test.go b/pkg/kubectl/cmd/create_deployment_test.go index 348a5ec2a55..59263ffe67e 100644 --- a/pkg/kubectl/cmd/create_deployment_test.go +++ b/pkg/kubectl/cmd/create_deployment_test.go @@ -26,6 +26,7 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/kubectl" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" @@ -76,7 +77,7 @@ func TestCreateDeployment(t *testing.T) { depName := "jonny-dep" f, tf, _, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return &http.Response{ @@ -105,7 +106,7 @@ func TestCreateDeploymentNoImage(t *testing.T) { depName := "jonny-dep" f, tf, _, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return &http.Response{ diff --git a/pkg/kubectl/cmd/create_namespace_test.go b/pkg/kubectl/cmd/create_namespace_test.go index a4bed218391..d16dc2e2ce8 100644 --- a/pkg/kubectl/cmd/create_namespace_test.go +++ b/pkg/kubectl/cmd/create_namespace_test.go @@ -33,7 +33,7 @@ func TestCreateNamespace(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/create_pdb_test.go b/pkg/kubectl/cmd/create_pdb_test.go index 11f1387ece6..ac21f09f72a 100644 --- a/pkg/kubectl/cmd/create_pdb_test.go +++ b/pkg/kubectl/cmd/create_pdb_test.go @@ -24,6 +24,7 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" ) @@ -32,7 +33,7 @@ func TestCreatePdb(t *testing.T) { pdbName := "my-pdb" f, tf, _, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return &http.Response{ diff --git a/pkg/kubectl/cmd/create_quota_test.go b/pkg/kubectl/cmd/create_quota_test.go index 6f34d81f400..0a4e8c900c4 100644 --- a/pkg/kubectl/cmd/create_quota_test.go +++ b/pkg/kubectl/cmd/create_quota_test.go @@ -33,7 +33,7 @@ func TestCreateQuota(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/create_rolebinding_test.go b/pkg/kubectl/cmd/create_rolebinding_test.go index 5586623da9e..bf85e7febb0 100644 --- a/pkg/kubectl/cmd/create_rolebinding_test.go +++ b/pkg/kubectl/cmd/create_rolebinding_test.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/rbac" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" @@ -75,7 +76,7 @@ func TestCreateRoleBinding(t *testing.T) { tf.Printer = &testPrinter{} tf.Client = &RoleBindingRESTClient{ RESTClient: &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/create_secret_test.go b/pkg/kubectl/cmd/create_secret_test.go index 8b25ea0c265..11970790eaf 100644 --- a/pkg/kubectl/cmd/create_secret_test.go +++ b/pkg/kubectl/cmd/create_secret_test.go @@ -38,7 +38,7 @@ func TestCreateSecretGeneric(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -69,7 +69,7 @@ func TestCreateSecretDockerRegistry(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/create_service_test.go b/pkg/kubectl/cmd/create_service_test.go index aa38d11b3c2..810be786f01 100644 --- a/pkg/kubectl/cmd/create_service_test.go +++ b/pkg/kubectl/cmd/create_service_test.go @@ -33,7 +33,7 @@ func TestCreateService(t *testing.T) { f, tf, codec, negSer := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: negSer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -63,7 +63,7 @@ func TestCreateServiceNodePort(t *testing.T) { f, tf, codec, negSer := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: negSer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -93,7 +93,7 @@ func TestCreateServiceExternalName(t *testing.T) { f, tf, codec, negSer := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: negSer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/create_serviceaccount_test.go b/pkg/kubectl/cmd/create_serviceaccount_test.go index 170fe3401cc..64431e3e2b8 100644 --- a/pkg/kubectl/cmd/create_serviceaccount_test.go +++ b/pkg/kubectl/cmd/create_serviceaccount_test.go @@ -33,7 +33,7 @@ func TestCreateServiceAccount(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/create_test.go b/pkg/kubectl/cmd/create_test.go index c21e1f313ed..819d7d35ffb 100644 --- a/pkg/kubectl/cmd/create_test.go +++ b/pkg/kubectl/cmd/create_test.go @@ -22,6 +22,7 @@ import ( "testing" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" ) @@ -46,7 +47,7 @@ func TestCreateObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -80,7 +81,7 @@ func TestCreateMultipleObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -118,7 +119,7 @@ func TestCreateDirectory(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/delete_test.go b/pkg/kubectl/cmd/delete_test.go index b3bb0895db0..e7c82f1e266 100644 --- a/pkg/kubectl/cmd/delete_test.go +++ b/pkg/kubectl/cmd/delete_test.go @@ -58,7 +58,7 @@ func TestDeleteObjectByTuple(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -123,7 +123,7 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) { tf.Printer = &testPrinter{} var expectedOrphanDependents *bool tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m, b := req.URL.Path, req.Method, req.Body; { @@ -172,7 +172,7 @@ func TestDeleteNamedObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -223,7 +223,7 @@ func TestDeleteObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -282,7 +282,7 @@ func TestDeleteObjectGraceZero(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Logf("got request %s %s", req.Method, req.URL.Path) @@ -332,7 +332,7 @@ func TestDeleteObjectNotFound(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -370,7 +370,7 @@ func TestDeleteObjectIgnoreNotFound(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -408,7 +408,7 @@ func TestDeleteAllNotFound(t *testing.T) { tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -458,7 +458,7 @@ func TestDeleteAllIgnoreNotFound(t *testing.T) { tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -495,7 +495,7 @@ func TestDeleteMultipleObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -531,7 +531,7 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -576,7 +576,7 @@ func TestDeleteMultipleResourcesWithTheSameName(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -615,7 +615,7 @@ func TestDeleteDirectory(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -648,7 +648,7 @@ func TestDeleteMultipleSelector(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/describe_test.go b/pkg/kubectl/cmd/describe_test.go index 77076521e66..c40e88bafdf 100644 --- a/pkg/kubectl/cmd/describe_test.go +++ b/pkg/kubectl/cmd/describe_test.go @@ -23,6 +23,7 @@ import ( "testing" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" ) @@ -33,7 +34,7 @@ func TestDescribeUnknownSchemaObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewTestFactory() tf.Describer = d tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))}, } @@ -58,7 +59,7 @@ func TestDescribeUnknownNamespacedSchemaObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewTestFactory() tf.Describer = d tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalNamespacedType("", "", "foo", "non-default"))}, } @@ -83,7 +84,7 @@ func TestDescribeObject(t *testing.T) { d := &testDescriber{Output: "test output"} tf.Describer = d tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -117,7 +118,7 @@ func TestDescribeListObjects(t *testing.T) { d := &testDescriber{Output: "test output"} tf.Describer = d tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, } @@ -138,7 +139,7 @@ func TestDescribeObjectShowEvents(t *testing.T) { d := &testDescriber{Output: "test output"} tf.Describer = d tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, } @@ -160,7 +161,7 @@ func TestDescribeObjectSkipEvents(t *testing.T) { d := &testDescriber{Output: "test output"} tf.Describer = d tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, } diff --git a/pkg/kubectl/cmd/drain_test.go b/pkg/kubectl/cmd/drain_test.go index d701df65667..5d277055f47 100644 --- a/pkg/kubectl/cmd/drain_test.go +++ b/pkg/kubectl/cmd/drain_test.go @@ -154,7 +154,7 @@ func TestCordon(t *testing.T) { new_node := &v1.Node{} updated := false tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { m := &MyReq{req} @@ -597,7 +597,7 @@ func TestDrain(t *testing.T) { evicted := false f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { m := &MyReq{req} diff --git a/pkg/kubectl/cmd/edit_test.go b/pkg/kubectl/cmd/edit_test.go index 04e5520545c..86792766935 100644 --- a/pkg/kubectl/cmd/edit_test.go +++ b/pkg/kubectl/cmd/edit_test.go @@ -36,6 +36,7 @@ import ( "k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" @@ -217,7 +218,7 @@ func TestEdit(t *testing.T) { versionedAPIPath = "/apis/" + mapping.GroupVersionKind.Group + "/" + mapping.GroupVersionKind.Version } return &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, VersionedAPIPath: versionedAPIPath, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(reqResp), diff --git a/pkg/kubectl/cmd/exec_test.go b/pkg/kubectl/cmd/exec_test.go index ec527899413..3eb751167c3 100644 --- a/pkg/kubectl/cmd/exec_test.go +++ b/pkg/kubectl/cmd/exec_test.go @@ -131,7 +131,7 @@ func TestPodAndContainer(t *testing.T) { for _, test := range tests { f, tf, _, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return nil, nil }), } @@ -186,7 +186,7 @@ func TestExec(t *testing.T) { for _, test := range tests { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/expose_test.go b/pkg/kubectl/cmd/expose_test.go index 5bb4a1b101d..e2f62be3d56 100644 --- a/pkg/kubectl/cmd/expose_test.go +++ b/pkg/kubectl/cmd/expose_test.go @@ -463,7 +463,7 @@ func TestRunExposeService(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &printers.JSONPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/get_test.go b/pkg/kubectl/cmd/get_test.go index 44becf96e06..b36aad4337c 100644 --- a/pkg/kubectl/cmd/get_test.go +++ b/pkg/kubectl/cmd/get_test.go @@ -125,7 +125,7 @@ func TestGetUnknownSchemaObject(t *testing.T) { _, _, codec, _ := cmdtesting.NewTestFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", "foo"))}, } @@ -170,7 +170,7 @@ func TestGetSchemaObject(t *testing.T) { codec := testapi.Default.Codec() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})}, } @@ -196,7 +196,7 @@ func TestGetObjectsWithOpenAPIOutputFormatPresent(t *testing.T) { // for Pod type. tf.OpenAPISchemaFunc = testOpenAPISchemaData tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, } @@ -250,7 +250,7 @@ func TestGetObjects(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, } @@ -302,7 +302,7 @@ func TestGetObjectsFiltered(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{GenericPrinter: test.genericPrinter} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, test.resp)}, } @@ -343,7 +343,7 @@ func TestGetObjectIgnoreNotFound(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{GenericPrinter: true} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -396,7 +396,7 @@ func TestGetSortedObjects(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, } @@ -455,7 +455,7 @@ func TestGetObjectsIdentifiedByFile(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{GenericPrinter: true} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, } @@ -482,7 +482,7 @@ func TestGetListObjects(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, } @@ -523,7 +523,7 @@ func TestGetAllListObjects(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, } @@ -553,7 +553,7 @@ func TestGetListComponentStatus(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, statuses)}, } @@ -595,7 +595,7 @@ func TestGetMixedGenericObjects(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{GenericPrinter: true} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { @@ -659,7 +659,7 @@ func TestGetMultipleTypeObjects(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { @@ -698,7 +698,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{GenericPrinter: true} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { @@ -763,7 +763,7 @@ func TestGetMultipleTypeObjectsWithSelector(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { if req.URL.Query().Get(metav1.LabelSelectorQueryParam(legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.String())) != "a=b" { @@ -815,7 +815,7 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { @@ -852,7 +852,7 @@ func TestGetByFormatForcesFlag(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{GenericPrinter: true} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])}, } @@ -953,7 +953,7 @@ func TestWatchSelector(t *testing.T) { }, } tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { if req.URL.Query().Get(metav1.LabelSelectorQueryParam(legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.String())) != "a=b" { @@ -997,7 +997,7 @@ func TestWatchResource(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { @@ -1039,7 +1039,7 @@ func TestWatchResourceIdentifiedByFile(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { @@ -1082,7 +1082,7 @@ func TestWatchOnlyResource(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { @@ -1130,7 +1130,7 @@ func TestWatchOnlyList(t *testing.T) { }, } tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { diff --git a/pkg/kubectl/cmd/label_test.go b/pkg/kubectl/cmd/label_test.go index a2a42fe18b1..ee591d459fc 100644 --- a/pkg/kubectl/cmd/label_test.go +++ b/pkg/kubectl/cmd/label_test.go @@ -358,7 +358,7 @@ func TestLabelForResourceFromFile(t *testing.T) { pods, _, _ := testData() f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.Method { @@ -409,7 +409,7 @@ func TestLabelForResourceFromFile(t *testing.T) { func TestLabelLocal(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) @@ -443,7 +443,7 @@ func TestLabelMultipleObjects(t *testing.T) { pods, _, _ := testData() f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.Method { diff --git a/pkg/kubectl/cmd/logs_test.go b/pkg/kubectl/cmd/logs_test.go index cd237082fa8..65c06bcbdc8 100644 --- a/pkg/kubectl/cmd/logs_test.go +++ b/pkg/kubectl/cmd/logs_test.go @@ -52,7 +52,7 @@ func TestLog(t *testing.T) { logContent := "test log content" f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/patch_test.go b/pkg/kubectl/cmd/patch_test.go index dfa77c271e9..0b46aed160b 100644 --- a/pkg/kubectl/cmd/patch_test.go +++ b/pkg/kubectl/cmd/patch_test.go @@ -23,6 +23,7 @@ import ( "testing" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" "k8s.io/kubernetes/pkg/printers" @@ -33,7 +34,7 @@ func TestPatchObject(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -72,7 +73,7 @@ func TestPatchObjectFromFile(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -107,7 +108,7 @@ func TestPatchNoop(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -153,7 +154,7 @@ func TestPatchObjectFromFileOutput(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &printers.YAMLPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/portforward_test.go b/pkg/kubectl/cmd/portforward_test.go index 4898365f951..dfae45575a0 100644 --- a/pkg/kubectl/cmd/portforward_test.go +++ b/pkg/kubectl/cmd/portforward_test.go @@ -70,7 +70,7 @@ func testPortForward(t *testing.T, flags map[string]string, args []string) { var err error f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/replace_test.go b/pkg/kubectl/cmd/replace_test.go index 8b2eb2ab9d6..86a87e02c9d 100644 --- a/pkg/kubectl/cmd/replace_test.go +++ b/pkg/kubectl/cmd/replace_test.go @@ -35,7 +35,7 @@ func TestReplaceObject(t *testing.T) { tf.Printer = &testPrinter{} deleted := false tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -92,7 +92,7 @@ func TestReplaceMultipleObject(t *testing.T) { redisMasterDeleted := false frontendDeleted := false tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -161,7 +161,7 @@ func TestReplaceDirectory(t *testing.T) { tf.Printer = &testPrinter{} created := map[string]bool{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -217,7 +217,7 @@ func TestForceReplaceObjectNotFound(t *testing.T) { f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.UnstructuredClient = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { diff --git a/pkg/kubectl/cmd/run_test.go b/pkg/kubectl/cmd/run_test.go index c51016dc54e..a9360c744e5 100644 --- a/pkg/kubectl/cmd/run_test.go +++ b/pkg/kubectl/cmd/run_test.go @@ -164,7 +164,7 @@ func TestRunArgsFollowDashRules(t *testing.T) { for _, test := range tests { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { if req.URL.Path == "/namespaces/test/replicationcontrollers" { @@ -288,7 +288,7 @@ func TestGenerateService(t *testing.T) { tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}} tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -429,7 +429,7 @@ func TestRunValidations(t *testing.T) { f, tf, codec, ns := cmdtesting.NewTestFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, cmdtesting.NewInternalType("", "", ""))}, } diff --git a/pkg/kubectl/cmd/set/BUILD b/pkg/kubectl/cmd/set/BUILD index c00e787e457..19d946148b2 100644 --- a/pkg/kubectl/cmd/set/BUILD +++ b/pkg/kubectl/cmd/set/BUILD @@ -74,6 +74,7 @@ go_test( "//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/rest/fake:go_default_library", ], diff --git a/pkg/kubectl/cmd/set/set_env_test.go b/pkg/kubectl/cmd/set/set_env_test.go index 11942947296..ea71128c990 100644 --- a/pkg/kubectl/cmd/set/set_env_test.go +++ b/pkg/kubectl/cmd/set/set_env_test.go @@ -36,7 +36,7 @@ import ( func TestSetEnvLocal(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) diff --git a/pkg/kubectl/cmd/set/set_image_test.go b/pkg/kubectl/cmd/set/set_image_test.go index c445a612fa0..63c15e92f37 100644 --- a/pkg/kubectl/cmd/set/set_image_test.go +++ b/pkg/kubectl/cmd/set/set_image_test.go @@ -35,7 +35,7 @@ import ( func TestImageLocal(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) diff --git a/pkg/kubectl/cmd/set/set_resources_test.go b/pkg/kubectl/cmd/set/set_resources_test.go index e3e9def3e90..5cff6c25a24 100644 --- a/pkg/kubectl/cmd/set/set_resources_test.go +++ b/pkg/kubectl/cmd/set/set_resources_test.go @@ -35,7 +35,7 @@ import ( func TestResourcesLocal(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) diff --git a/pkg/kubectl/cmd/set/set_selector_test.go b/pkg/kubectl/cmd/set/set_selector_test.go index cde6b1d4f9b..3b45e4da2bb 100644 --- a/pkg/kubectl/cmd/set/set_selector_test.go +++ b/pkg/kubectl/cmd/set/set_selector_test.go @@ -318,7 +318,7 @@ func TestGetResourcesAndSelector(t *testing.T) { func TestSelectorTest(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) diff --git a/pkg/kubectl/cmd/set/set_serviceaccount_test.go b/pkg/kubectl/cmd/set/set_serviceaccount_test.go index 7ecdf988144..2330083b844 100644 --- a/pkg/kubectl/cmd/set/set_serviceaccount_test.go +++ b/pkg/kubectl/cmd/set/set_serviceaccount_test.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/rest/fake" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -65,7 +66,7 @@ func TestServiceAccountLocal(t *testing.T) { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) return nil, nil @@ -155,7 +156,7 @@ func TestServiceAccountRemote(t *testing.T) { tf.Namespace = "test" tf.CategoryExpander = resource.LegacyCategoryExpander tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(input.apiGroup).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { resourcePath := testapi.Default.ResourcePath(input.args[0]+"s", tf.Namespace, input.args[1]) @@ -179,7 +180,6 @@ func TestServiceAccountRemote(t *testing.T) { } }), VersionedAPIPath: path.Join(input.apiPrefix, groupVersion.String()), - GroupName: input.apiGroup, } out := new(bytes.Buffer) cmd := NewCmdServiceAccount(f, out, out) @@ -207,7 +207,7 @@ func TestServiceAccountValidation(t *testing.T) { for _, input := range inputs { f, tf, _, _ := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: schema.GroupVersion{Version: "v1"}, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) return nil, nil diff --git a/pkg/kubectl/cmd/taint_test.go b/pkg/kubectl/cmd/taint_test.go index 61fe9c62aa5..cc2b43e7035 100644 --- a/pkg/kubectl/cmd/taint_test.go +++ b/pkg/kubectl/cmd/taint_test.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" @@ -242,7 +243,7 @@ func TestTaint(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { m := &MyReq{req} diff --git a/pkg/kubectl/cmd/top_node_test.go b/pkg/kubectl/cmd/top_node_test.go index 47d6e8f1dd8..b7da9ae493d 100644 --- a/pkg/kubectl/cmd/top_node_test.go +++ b/pkg/kubectl/cmd/top_node_test.go @@ -46,7 +46,7 @@ func TestTopNodeAllMetrics(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -92,7 +92,7 @@ func TestTopNodeAllMetricsCustomDefaults(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -148,7 +148,7 @@ func TestTopNodeWithNameMetrics(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -208,7 +208,7 @@ func TestTopNodeWithLabelSelectorMetrics(t *testing.T) { f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; { diff --git a/pkg/kubectl/cmd/top_pod_test.go b/pkg/kubectl/cmd/top_pod_test.go index 5b24e176205..43d0666855a 100644 --- a/pkg/kubectl/cmd/top_pod_test.go +++ b/pkg/kubectl/cmd/top_pod_test.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" metricsapi "k8s.io/metrics/pkg/apis/metrics/v1alpha1" @@ -118,7 +119,7 @@ func TestTopPod(t *testing.T) { f, tf, _, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; { @@ -254,7 +255,7 @@ func TestTopPodCustomDefaults(t *testing.T) { f, tf, _, ns := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; { diff --git a/pkg/kubectl/resource/builder_test.go b/pkg/kubectl/resource/builder_test.go index 00f7cfc9189..6c258abfd6b 100644 --- a/pkg/kubectl/resource/builder_test.go +++ b/pkg/kubectl/resource/builder_test.go @@ -72,7 +72,7 @@ func fakeClient() ClientMapper { func fakeClientWith(testName string, t *testing.T, data map[string]string) ClientMapper { return ClientMapperFunc(func(*meta.RESTMapping) (RESTClient, error) { return &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { p := req.URL.Path diff --git a/pkg/kubectl/resource/helper_test.go b/pkg/kubectl/resource/helper_test.go index 17428fcd8b2..db3d7d57e92 100644 --- a/pkg/kubectl/resource/helper_test.go +++ b/pkg/kubectl/resource/helper_test.go @@ -104,7 +104,7 @@ func TestHelperDelete(t *testing.T) { } for _, test := range tests { client := &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Resp: test.Resp, Err: test.HttpErr, @@ -195,7 +195,7 @@ func TestHelperCreate(t *testing.T) { } for i, test := range tests { client := &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Resp: test.Resp, Err: test.HttpErr, @@ -276,7 +276,7 @@ func TestHelperGet(t *testing.T) { } for _, test := range tests { client := &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Resp: test.Resp, Err: test.HttpErr, @@ -350,7 +350,7 @@ func TestHelperList(t *testing.T) { } for _, test := range tests { client := &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Resp: test.Resp, Err: test.HttpErr, @@ -484,7 +484,7 @@ func TestHelperReplace(t *testing.T) { } for i, test := range tests { client := &fake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Client: test.HTTPClient, Resp: test.Resp, diff --git a/pkg/kubectl/rolling_updater_test.go b/pkg/kubectl/rolling_updater_test.go index 15d15a8307a..b30c1183403 100644 --- a/pkg/kubectl/rolling_updater_test.go +++ b/pkg/kubectl/rolling_updater_test.go @@ -1469,7 +1469,7 @@ func TestUpdateRcWithRetries(t *testing.T) { {StatusCode: 200, Header: header, Body: objBody(codec, rc)}, } fakeClient := &manualfake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Client: manualfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { @@ -1562,7 +1562,7 @@ func TestAddDeploymentHash(t *testing.T) { seen := sets.String{} updatedRc := false fakeClient := &manualfake.RESTClient{ - APIRegistry: legacyscheme.Registry, + GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), Client: manualfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { header := http.Header{} diff --git a/staging/src/k8s.io/client-go/rest/fake/BUILD b/staging/src/k8s.io/client-go/rest/fake/BUILD index 524701f1ec0..e511b207a6b 100644 --- a/staging/src/k8s.io/client-go/rest/fake/BUILD +++ b/staging/src/k8s.io/client-go/rest/fake/BUILD @@ -10,7 +10,6 @@ go_library( srcs = ["fake.go"], importpath = "k8s.io/client-go/rest/fake", deps = [ - "//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", diff --git a/staging/src/k8s.io/client-go/rest/fake/fake.go b/staging/src/k8s.io/client-go/rest/fake/fake.go index 2e1bc55a985..db2c01c71fd 100644 --- a/staging/src/k8s.io/client-go/rest/fake/fake.go +++ b/staging/src/k8s.io/client-go/rest/fake/fake.go @@ -22,7 +22,6 @@ import ( "net/http" "net/url" - "k8s.io/apimachinery/pkg/apimachinery/registered" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" @@ -46,8 +45,7 @@ func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { type RESTClient struct { Client *http.Client NegotiatedSerializer runtime.NegotiatedSerializer - GroupName string - APIRegistry *registered.APIRegistrationManager + GroupVersion schema.GroupVersion VersionedAPIPath string Req *http.Request @@ -80,7 +78,7 @@ func (c *RESTClient) Verb(verb string) *restclient.Request { } func (c *RESTClient) APIVersion() schema.GroupVersion { - return c.APIRegistry.GroupOrDie("").GroupVersion + return c.GroupVersion } func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter { @@ -89,22 +87,20 @@ func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter { func (c *RESTClient) request(verb string) *restclient.Request { config := restclient.ContentConfig{ - ContentType: runtime.ContentTypeJSON, - // TODO this was hardcoded before, but it doesn't look right - GroupVersion: &c.APIRegistry.GroupOrDie("").GroupVersion, + ContentType: runtime.ContentTypeJSON, + GroupVersion: &c.GroupVersion, NegotiatedSerializer: c.NegotiatedSerializer, } ns := c.NegotiatedSerializer info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON) internalVersion := schema.GroupVersion{ - Group: c.APIRegistry.GroupOrDie(c.GroupName).GroupVersion.Group, + Group: c.GroupVersion.Group, Version: runtime.APIVersionInternal, } - internalVersion.Version = runtime.APIVersionInternal serializers := restclient.Serializers{ // TODO this was hardcoded before, but it doesn't look right - Encoder: ns.EncoderForVersion(info.Serializer, c.APIRegistry.GroupOrDie("").GroupVersion), + Encoder: ns.EncoderForVersion(info.Serializer, c.GroupVersion), Decoder: ns.DecoderToVersion(info.Serializer, internalVersion), } if info.StreamSerializer != nil { From f83a19676c0b53b2c2240d11d58e9d35c31d9ff5 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Wed, 11 Oct 2017 14:21:29 -0400 Subject: [PATCH 2/8] [client-go] fake discovery returns server groups The fake discovery client currently returns `nil, nil` for several methods. Among them is the `ServerGroups` method, which is used by the discovery REST mapper implementations. This updates the fake discovery client to actually return server groups so that the discovery REST mapper can be used in tests. --- .../client-go/discovery/fake/discovery.go | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/staging/src/k8s.io/client-go/discovery/fake/discovery.go b/staging/src/k8s.io/client-go/discovery/fake/discovery.go index 13ccebfa74f..984a0ba1ec6 100644 --- a/staging/src/k8s.io/client-go/discovery/fake/discovery.go +++ b/staging/src/k8s.io/client-go/discovery/fake/discovery.go @@ -68,7 +68,44 @@ func (c *FakeDiscovery) ServerPreferredNamespacedResources() ([]*metav1.APIResou } func (c *FakeDiscovery) ServerGroups() (*metav1.APIGroupList, error) { - return nil, nil + action := testing.ActionImpl{ + Verb: "get", + Resource: schema.GroupVersionResource{Resource: "group"}, + } + c.Invokes(action, nil) + + groups := map[string]*metav1.APIGroup{} + + for _, res := range c.Resources { + gv, err := schema.ParseGroupVersion(res.GroupVersion) + if err != nil { + return nil, err + } + group := groups[gv.Group] + if group == nil { + group = &metav1.APIGroup{ + Name: gv.Group, + PreferredVersion: metav1.GroupVersionForDiscovery{ + GroupVersion: res.GroupVersion, + Version: gv.Version, + }, + } + groups[gv.Group] = group + } + + group.Versions = append(group.Versions, metav1.GroupVersionForDiscovery{ + GroupVersion: res.GroupVersion, + Version: gv.Version, + }) + } + + list := &metav1.APIGroupList{} + for _, apiGroup := range groups { + list.Groups = append(list.Groups, *apiGroup) + } + + return list, nil + } func (c *FakeDiscovery) ServerVersion() (*version.Info, error) { From d61a2d90372c301dd11088df8941acf2bb01c38c Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Wed, 11 Oct 2017 14:23:48 -0400 Subject: [PATCH 3/8] [client-go] Polymorphic Scale Client This introduces a polymorphic scale client capable of operating against scale subresources which return different group-versions of Scale. The scale subresources may be in group-versions different than the scale itself, so that we no longer need a copy of every scalable resource in the extensions API group. To discovery which Scale group-versions go to which subresources, discovery is used. The scale client maintains its own internal versions and conversions to several external versions, with a "hub" version that's a copy of the autoscaling internal version. It currently supports the following group-versions for Scale subresources: - extensions/v1beta1.Scale - autoscaling/v1.Scale --- hack/.golint_failures | 5 + staging/BUILD | 1 + .../src/k8s.io/client-go/Godeps/Godeps.json | 20 ++ .../src/k8s.io/client-go/rest/url_utils.go | 11 +- staging/src/k8s.io/client-go/scale/BUILD | 72 +++++ staging/src/k8s.io/client-go/scale/client.go | 197 ++++++++++++++ .../src/k8s.io/client-go/scale/client_test.go | 246 ++++++++++++++++++ staging/src/k8s.io/client-go/scale/doc.go | 21 ++ .../src/k8s.io/client-go/scale/interfaces.go | 39 +++ .../k8s.io/client-go/scale/roundtrip_test.go | 34 +++ .../src/k8s.io/client-go/scale/scheme/BUILD | 39 +++ .../scale/scheme/autoscalingv1/BUILD | 35 +++ .../scale/scheme/autoscalingv1/conversion.go | 69 +++++ .../scale/scheme/autoscalingv1/doc.go | 20 ++ .../scale/scheme/autoscalingv1/register.go | 45 ++++ .../autoscalingv1/zz_generated.conversion.go | 109 ++++++++ .../src/k8s.io/client-go/scale/scheme/doc.go | 22 ++ .../scale/scheme/extensionsint/BUILD | 31 +++ .../scale/scheme/extensionsint/doc.go | 22 ++ .../scale/scheme/extensionsint/register.go | 53 ++++ .../scale/scheme/extensionsv1beta1/BUILD | 35 +++ .../scheme/extensionsv1beta1/conversion.go | 87 +++++++ .../scale/scheme/extensionsv1beta1/doc.go | 20 ++ .../scheme/extensionsv1beta1/register.go | 45 ++++ .../zz_generated.conversion.go | 110 ++++++++ .../k8s.io/client-go/scale/scheme/register.go | 52 ++++ .../k8s.io/client-go/scale/scheme/types.go | 60 +++++ .../scale/scheme/zz_generated.deepcopy.go | 123 +++++++++ staging/src/k8s.io/client-go/scale/util.go | 159 +++++++++++ 29 files changed, 1780 insertions(+), 2 deletions(-) create mode 100644 staging/src/k8s.io/client-go/scale/BUILD create mode 100644 staging/src/k8s.io/client-go/scale/client.go create mode 100644 staging/src/k8s.io/client-go/scale/client_test.go create mode 100644 staging/src/k8s.io/client-go/scale/doc.go create mode 100644 staging/src/k8s.io/client-go/scale/interfaces.go create mode 100644 staging/src/k8s.io/client-go/scale/roundtrip_test.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/BUILD create mode 100644 staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/BUILD create mode 100644 staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/conversion.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/doc.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/register.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/zz_generated.conversion.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/doc.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/extensionsint/BUILD create mode 100644 staging/src/k8s.io/client-go/scale/scheme/extensionsint/doc.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/extensionsint/register.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/BUILD create mode 100644 staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/conversion.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/doc.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/register.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/zz_generated.conversion.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/register.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/types.go create mode 100644 staging/src/k8s.io/client-go/scale/scheme/zz_generated.deepcopy.go create mode 100644 staging/src/k8s.io/client-go/scale/util.go diff --git a/hack/.golint_failures b/hack/.golint_failures index dd074d20ef6..85c525427a7 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -715,6 +715,11 @@ staging/src/k8s.io/client-go/plugin/pkg/auth/authenticator/token/oidc/testing staging/src/k8s.io/client-go/plugin/pkg/client/auth/oidc staging/src/k8s.io/client-go/rest staging/src/k8s.io/client-go/rest/fake +staging/src/k8s.io/client-go/scale +staging/src/k8s.io/client-go/scale/scheme +staging/src/k8s.io/client-go/scale/scheme/autoscalingv1 +staging/src/k8s.io/client-go/scale/scheme/extensionsint +staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1 staging/src/k8s.io/client-go/testing staging/src/k8s.io/client-go/tools/cache staging/src/k8s.io/client-go/tools/cache/testing diff --git a/staging/BUILD b/staging/BUILD index 7b541e908a5..9e946f763cf 100644 --- a/staging/BUILD +++ b/staging/BUILD @@ -167,6 +167,7 @@ filegroup( "//staging/src/k8s.io/client-go/plugin/pkg/auth/authenticator/token/oidc/testing:all-srcs", "//staging/src/k8s.io/client-go/plugin/pkg/client/auth:all-srcs", "//staging/src/k8s.io/client-go/rest:all-srcs", + "//staging/src/k8s.io/client-go/scale:all-srcs", "//staging/src/k8s.io/client-go/testing:all-srcs", "//staging/src/k8s.io/client-go/third_party/forked/golang/template:all-srcs", "//staging/src/k8s.io/client-go/tools/auth:all-srcs", diff --git a/staging/src/k8s.io/client-go/Godeps/Godeps.json b/staging/src/k8s.io/client-go/Godeps/Godeps.json index 8216e65bdd7..23da5fd2b39 100644 --- a/staging/src/k8s.io/client-go/Godeps/Godeps.json +++ b/staging/src/k8s.io/client-go/Godeps/Godeps.json @@ -490,14 +490,34 @@ "ImportPath": "k8s.io/apimachinery/pkg/api/resource", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/testing", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, { "ImportPath": "k8s.io/apimachinery/pkg/apimachinery", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, { "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer", + "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion", "Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" diff --git a/staging/src/k8s.io/client-go/rest/url_utils.go b/staging/src/k8s.io/client-go/rest/url_utils.go index 14f94650a9e..a56d1838d8f 100644 --- a/staging/src/k8s.io/client-go/rest/url_utils.go +++ b/staging/src/k8s.io/client-go/rest/url_utils.go @@ -56,6 +56,14 @@ func DefaultServerURL(host, apiPath string, groupVersion schema.GroupVersion, de // hostURL.Path should be blank. // // versionedAPIPath, a path relative to baseURL.Path, points to a versioned API base + versionedAPIPath := DefaultVersionedAPIPath(apiPath, groupVersion) + + return hostURL, versionedAPIPath, nil +} + +// DefaultVersionedAPIPathFor constructs the default path for the given group version, assuming the given +// API path, following the standard conventions of the Kubernetes API. +func DefaultVersionedAPIPath(apiPath string, groupVersion schema.GroupVersion) string { versionedAPIPath := path.Join("/", apiPath) // Add the version to the end of the path @@ -64,10 +72,9 @@ func DefaultServerURL(host, apiPath string, groupVersion schema.GroupVersion, de } else { versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Version) - } - return hostURL, versionedAPIPath, nil + return versionedAPIPath } // defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It diff --git a/staging/src/k8s.io/client-go/scale/BUILD b/staging/src/k8s.io/client-go/scale/BUILD new file mode 100644 index 00000000000..ed2bad0b0ee --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/BUILD @@ -0,0 +1,72 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "client.go", + "doc.go", + "interfaces.go", + "util.go", + ], + importpath = "k8s.io/client-go/scale", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/api/autoscaling/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", + "//vendor/k8s.io/client-go/discovery:go_default_library", + "//vendor/k8s.io/client-go/dynamic:go_default_library", + "//vendor/k8s.io/client-go/rest:go_default_library", + "//vendor/k8s.io/client-go/scale/scheme:go_default_library", + "//vendor/k8s.io/client-go/scale/scheme/autoscalingv1:go_default_library", + "//vendor/k8s.io/client-go/scale/scheme/extensionsint:go_default_library", + "//vendor/k8s.io/client-go/scale/scheme/extensionsv1beta1:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = [ + "client_test.go", + "roundtrip_test.go", + ], + importpath = "k8s.io/client-go/scale", + library = ":go_default_library", + deps = [ + "//vendor/github.com/stretchr/testify/assert:go_default_library", + "//vendor/k8s.io/api/apps/v1beta2:go_default_library", + "//vendor/k8s.io/api/autoscaling/v1:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", + "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", + "//vendor/k8s.io/client-go/discovery:go_default_library", + "//vendor/k8s.io/client-go/discovery/fake:go_default_library", + "//vendor/k8s.io/client-go/dynamic:go_default_library", + "//vendor/k8s.io/client-go/rest/fake:go_default_library", + "//vendor/k8s.io/client-go/testing:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/client-go/scale/scheme:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/client-go/scale/client.go b/staging/src/k8s.io/client-go/scale/client.go new file mode 100644 index 00000000000..3f85197a0b6 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/client.go @@ -0,0 +1,197 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scale + +import ( + "fmt" + + autoscaling "k8s.io/api/autoscaling/v1" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/dynamic" + restclient "k8s.io/client-go/rest" +) + +var scaleConverter = NewScaleConverter() +var codecs = serializer.NewCodecFactory(scaleConverter.Scheme()) + +// restInterfaceProvider turns a restclient.Config into a restclient.Interface. +// It's overridable for the purposes of testing. +type restInterfaceProvider func(*restclient.Config) (restclient.Interface, error) + +// scaleClient is an implementation of ScalesGetter +// which makes use of a RESTMapper and a generic REST +// client to support an discoverable resource. +// It behaves somewhat similarly to the dynamic ClientPool, +// but is more specifically scoped to Scale. +type scaleClient struct { + mapper meta.RESTMapper + + apiPathResolverFunc dynamic.APIPathResolverFunc + scaleKindResolver ScaleKindResolver + clientBase restclient.Interface +} + +// NewForConfig creates a new ScalesGetter which resolves kinds +// to resources using the given RESTMapper, and API paths using +// the given dynamic.APIPathResolverFunc. +func NewForConfig(cfg *restclient.Config, mapper meta.RESTMapper, resolver dynamic.APIPathResolverFunc, scaleKindResolver ScaleKindResolver) (ScalesGetter, error) { + // so that the RESTClientFor doesn't complain + cfg.GroupVersion = &schema.GroupVersion{} + + cfg.NegotiatedSerializer = serializer.DirectCodecFactory{ + CodecFactory: codecs, + } + if len(cfg.UserAgent) == 0 { + cfg.UserAgent = restclient.DefaultKubernetesUserAgent() + } + + client, err := restclient.RESTClientFor(cfg) + if err != nil { + return nil, err + } + + return New(client, mapper, resolver, scaleKindResolver), nil +} + +// New creates a new ScalesGetter using the given client to make requests. +// The GroupVersion on the client is ignored. +func New(baseClient restclient.Interface, mapper meta.RESTMapper, resolver dynamic.APIPathResolverFunc, scaleKindResolver ScaleKindResolver) ScalesGetter { + return &scaleClient{ + mapper: mapper, + + apiPathResolverFunc: resolver, + scaleKindResolver: scaleKindResolver, + clientBase: baseClient, + } +} + +// pathAndVersionFor returns the appropriate base path and the associated full GroupVersionResource +// for the given GroupResource +func (c *scaleClient) pathAndVersionFor(resource schema.GroupResource) (string, schema.GroupVersionResource, error) { + gvr, err := c.mapper.ResourceFor(resource.WithVersion("")) + if err != nil { + return "", gvr, fmt.Errorf("unable to get full preferred group-version-resource for %s: %v", resource.String(), err) + } + + groupVer := gvr.GroupVersion() + + // we need to set the API path based on GroupVersion (defaulting to the legacy path if none is set) + // TODO: we "cheat" here since the API path really only depends on group ATM, but this should + // *probably* take GroupVersionResource and not GroupVersionKind. + apiPath := c.apiPathResolverFunc(groupVer.WithKind("")) + if apiPath == "" { + apiPath = "/api" + } + + path := restclient.DefaultVersionedAPIPath(apiPath, groupVer) + + return path, gvr, nil +} + +// namespacedScaleClient is an ScaleInterface for fetching +// Scales in a given namespace. +type namespacedScaleClient struct { + client *scaleClient + namespace string +} + +func (c *scaleClient) Scales(namespace string) ScaleInterface { + return &namespacedScaleClient{ + client: c, + namespace: namespace, + } +} + +func (c *namespacedScaleClient) Get(resource schema.GroupResource, name string) (*autoscaling.Scale, error) { + // Currently, a /scale endpoint can return different scale types. + // Until we have support for the alternative API representations proposal, + // we need to deal with accepting different API versions. + // In practice, this is autoscaling/v1.Scale and extensions/v1beta1.Scale + + path, gvr, err := c.client.pathAndVersionFor(resource) + if err != nil { + return nil, fmt.Errorf("unable to get client for %s: %v", resource.String(), err) + } + + rawObj, err := c.client.clientBase.Get(). + AbsPath(path). + Namespace(c.namespace). + Resource(gvr.Resource). + Name(name). + SubResource("scale"). + Do(). + Get() + + if err != nil { + return nil, err + } + + // convert whatever this is to autoscaling/v1.Scale + scaleObj, err := scaleConverter.ConvertToVersion(rawObj, autoscaling.SchemeGroupVersion) + if err != nil { + return nil, fmt.Errorf("received an object from a /scale endpoint which was not convertible to autoscaling Scale: %v", err) + } + + return scaleObj.(*autoscaling.Scale), nil +} + +func (c *namespacedScaleClient) Update(resource schema.GroupResource, scale *autoscaling.Scale) (*autoscaling.Scale, error) { + path, gvr, err := c.client.pathAndVersionFor(resource) + if err != nil { + return nil, fmt.Errorf("unable to get client for %s: %v", resource.String(), err) + } + + // Currently, a /scale endpoint can receive and return different scale types. + // Until we hvae support for the alternative API representations proposal, + // we need to deal with sending and accepting differnet API versions. + + // figure out what scale we actually need here + desiredGVK, err := c.client.scaleKindResolver.ScaleForResource(gvr) + if err != nil { + return nil, fmt.Errorf("could not find proper group-version for scale subresource of %s: %v", gvr.String(), err) + } + + // convert this to whatever this endpoint wants + scaleUpdate, err := scaleConverter.ConvertToVersion(scale, desiredGVK.GroupVersion()) + if err != nil { + return nil, fmt.Errorf("could not convert scale update to internal Scale: %v", err) + } + + rawObj, err := c.client.clientBase.Put(). + AbsPath(path). + Namespace(c.namespace). + Resource(gvr.Resource). + Name(scale.Name). + SubResource("scale"). + Body(scaleUpdate). + Do(). + Get() + + if err != nil { + return nil, fmt.Errorf("could not fetch the scale for %s %s: %v", resource.String(), scale.Name, err) + } + + // convert whatever this is back to autoscaling/v1.Scale + scaleObj, err := scaleConverter.ConvertToVersion(rawObj, autoscaling.SchemeGroupVersion) + if err != nil { + return nil, fmt.Errorf("received an object from a /scale endpoint which was not convertible to autoscaling Scale: %v", err) + } + + return scaleObj.(*autoscaling.Scale), err +} diff --git a/staging/src/k8s.io/client-go/scale/client_test.go b/staging/src/k8s.io/client-go/scale/client_test.go new file mode 100644 index 00000000000..a10429c0d36 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/client_test.go @@ -0,0 +1,246 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scale + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/discovery" + fakedisco "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/dynamic" + fakerest "k8s.io/client-go/rest/fake" + + "github.com/stretchr/testify/assert" + appsv1beta2 "k8s.io/api/apps/v1beta2" + autoscalingv1 "k8s.io/api/autoscaling/v1" + corev1 "k8s.io/api/core/v1" + extv1beta1 "k8s.io/api/extensions/v1beta1" + apimeta "k8s.io/apimachinery/pkg/api/meta" + coretesting "k8s.io/client-go/testing" +) + +func bytesBody(bodyBytes []byte) io.ReadCloser { + return ioutil.NopCloser(bytes.NewReader(bodyBytes)) +} + +func defaultHeaders() http.Header { + header := http.Header{} + header.Set("Content-Type", runtime.ContentTypeJSON) + return header +} + +func fakeScaleClient(t *testing.T) (ScalesGetter, []schema.GroupResource) { + fakeDiscoveryClient := &fakedisco.FakeDiscovery{Fake: &coretesting.Fake{}} + fakeDiscoveryClient.Resources = []*metav1.APIResourceList{ + { + GroupVersion: corev1.SchemeGroupVersion.String(), + APIResources: []metav1.APIResource{ + {Name: "pods", Namespaced: true, Kind: "Pod"}, + {Name: "replicationcontrollers", Namespaced: true, Kind: "ReplicationController"}, + {Name: "replicationcontrollers/scale", Namespaced: true, Kind: "Scale", Group: "autoscaling", Version: "v1"}, + }, + }, + { + GroupVersion: extv1beta1.SchemeGroupVersion.String(), + APIResources: []metav1.APIResource{ + {Name: "replicasets", Namespaced: true, Kind: "ReplicaSet"}, + {Name: "replicasets/scale", Namespaced: true, Kind: "Scale"}, + }, + }, + { + GroupVersion: appsv1beta2.SchemeGroupVersion.String(), + APIResources: []metav1.APIResource{ + {Name: "deployments", Namespaced: true, Kind: "Deployment"}, + {Name: "deployments/scale", Namespaced: true, Kind: "Scale", Group: "autoscaling", Version: "v1"}, + }, + }, + // test a resource that doesn't exist anywere to make sure we're not accidentally depending + // on a static RESTMapper anywhere. + { + GroupVersion: "cheese.testing.k8s.io/v27alpha15", + APIResources: []metav1.APIResource{ + {Name: "cheddars", Namespaced: true, Kind: "Cheddar"}, + {Name: "cheddars/scale", Namespaced: true, Kind: "Scale", Group: "extensions", Version: "v1beta1"}, + }, + }, + } + + restMapperRes, err := discovery.GetAPIGroupResources(fakeDiscoveryClient) + if err != nil { + t.Fatalf("unexpected error while constructing resource list from fake discovery client: %v") + } + restMapper := discovery.NewRESTMapper(restMapperRes, apimeta.InterfacesForUnstructured) + + autoscalingScale := &autoscalingv1.Scale{ + TypeMeta: metav1.TypeMeta{ + Kind: "Scale", + APIVersion: autoscalingv1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: autoscalingv1.ScaleSpec{Replicas: 10}, + Status: autoscalingv1.ScaleStatus{ + Replicas: 10, + Selector: "foo=bar", + }, + } + extScale := &extv1beta1.Scale{ + TypeMeta: metav1.TypeMeta{ + Kind: "Scale", + APIVersion: extv1beta1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: extv1beta1.ScaleSpec{Replicas: 10}, + Status: extv1beta1.ScaleStatus{ + Replicas: 10, + TargetSelector: "foo=bar", + }, + } + + resourcePaths := map[string]runtime.Object{ + "/api/v1/namespaces/default/replicationcontrollers/foo/scale": autoscalingScale, + "/apis/extensions/v1beta1/namespaces/default/replicasets/foo/scale": extScale, + "/apis/apps/v1beta2/namespaces/default/deployments/foo/scale": autoscalingScale, + "/apis/cheese.testing.k8s.io/v27alpha15/namespaces/default/cheddars/foo/scale": extScale, + } + + fakeReqHandler := func(req *http.Request) (*http.Response, error) { + scale, isScalePath := resourcePaths[req.URL.Path] + if !isScalePath { + return nil, fmt.Errorf("unexpected request for URL %q with method %q", req.URL.String(), req.Method) + } + + switch req.Method { + case "GET": + res, err := json.Marshal(scale) + if err != nil { + return nil, err + } + return &http.Response{StatusCode: 200, Header: defaultHeaders(), Body: bytesBody(res)}, nil + case "PUT": + decoder := codecs.UniversalDeserializer() + body, err := ioutil.ReadAll(req.Body) + if err != nil { + return nil, err + } + newScale, newScaleGVK, err := decoder.Decode(body, nil, nil) + if err != nil { + return nil, fmt.Errorf("unexpected request body: %v", err) + } + if *newScaleGVK != scale.GetObjectKind().GroupVersionKind() { + return nil, fmt.Errorf("unexpected scale API version %s (expected %s)", newScaleGVK.String(), scale.GetObjectKind().GroupVersionKind().String()) + } + res, err := json.Marshal(newScale) + if err != nil { + return nil, err + } + return &http.Response{StatusCode: 200, Header: defaultHeaders(), Body: bytesBody(res)}, nil + default: + return nil, fmt.Errorf("unexpected request for URL %q with method %q", req.URL.String(), req.Method) + } + } + + fakeClient := &fakerest.RESTClient{ + Client: fakerest.CreateHTTPClient(fakeReqHandler), + NegotiatedSerializer: serializer.DirectCodecFactory{ + CodecFactory: codecs, + }, + GroupVersion: schema.GroupVersion{}, + VersionedAPIPath: "/not/a/real/path", + } + + resolver := NewDiscoveryScaleKindResolver(fakeDiscoveryClient) + client := New(fakeClient, restMapper, dynamic.LegacyAPIPathResolverFunc, resolver) + + groupResources := []schema.GroupResource{ + {Group: corev1.GroupName, Resource: "replicationcontroller"}, + {Group: extv1beta1.GroupName, Resource: "replicaset"}, + {Group: appsv1beta2.GroupName, Resource: "deployment"}, + {Group: "cheese.testing.k8s.io", Resource: "cheddar"}, + } + + return client, groupResources +} + +func TestGetScale(t *testing.T) { + scaleClient, groupResources := fakeScaleClient(t) + expectedScale := &autoscalingv1.Scale{ + TypeMeta: metav1.TypeMeta{ + Kind: "Scale", + APIVersion: autoscalingv1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: autoscalingv1.ScaleSpec{Replicas: 10}, + Status: autoscalingv1.ScaleStatus{ + Replicas: 10, + Selector: "foo=bar", + }, + } + + for _, groupResource := range groupResources { + scale, err := scaleClient.Scales("default").Get(groupResource, "foo") + if !assert.NoError(t, err, "should have been able to fetch a scale for %s", groupResource.String()) { + continue + } + assert.NotNil(t, scale, "should have returned a non-nil scale for %s", groupResource.String()) + + assert.Equal(t, expectedScale, scale, "should have returned the expected scale for %s", groupResource.String()) + } +} + +func TestUpdateScale(t *testing.T) { + scaleClient, groupResources := fakeScaleClient(t) + expectedScale := &autoscalingv1.Scale{ + TypeMeta: metav1.TypeMeta{ + Kind: "Scale", + APIVersion: autoscalingv1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: autoscalingv1.ScaleSpec{Replicas: 10}, + Status: autoscalingv1.ScaleStatus{ + Replicas: 10, + Selector: "foo=bar", + }, + } + + for _, groupResource := range groupResources { + scale, err := scaleClient.Scales("default").Update(groupResource, expectedScale) + if !assert.NoError(t, err, "should have been able to fetch a scale for %s", groupResource.String()) { + continue + } + assert.NotNil(t, scale, "should have returned a non-nil scale for %s", groupResource.String()) + + assert.Equal(t, expectedScale, scale, "should have returned the expected scale for %s", groupResource.String()) + } +} diff --git a/staging/src/k8s.io/client-go/scale/doc.go b/staging/src/k8s.io/client-go/scale/doc.go new file mode 100644 index 00000000000..59fd39146ca --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package scale provides a polymorphic scale client capable of fetching +// and updating Scale for any resource which implements the `scale` subresource, +// as long as that subresource operates on a version of scale convertable to +// autoscaling.Scale. +package scale diff --git a/staging/src/k8s.io/client-go/scale/interfaces.go b/staging/src/k8s.io/client-go/scale/interfaces.go new file mode 100644 index 00000000000..4668c7417d1 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/interfaces.go @@ -0,0 +1,39 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scale + +import ( + autoscalingapi "k8s.io/api/autoscaling/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// ScalesGetter can produce a ScaleInterface +// for a particular namespace. +type ScalesGetter interface { + Scales(namespace string) ScaleInterface +} + +// ScaleInterface can fetch and update scales for +// resources in a particular namespace which implement +// the scale subresource. +type ScaleInterface interface { + // Get fetches the scale of the given scalable resource. + Get(resource schema.GroupResource, name string) (*autoscalingapi.Scale, error) + + // Update updates the scale of the the given scalable resource. + Update(resource schema.GroupResource, scale *autoscalingapi.Scale) (*autoscalingapi.Scale, error) +} diff --git a/staging/src/k8s.io/client-go/scale/roundtrip_test.go b/staging/src/k8s.io/client-go/scale/roundtrip_test.go new file mode 100644 index 00000000000..2ea28875700 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/roundtrip_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scale + +import ( + "testing" + + "k8s.io/apimachinery/pkg/api/testing/roundtrip" +) + +// NB: this can't be in the scheme package, because importing' +// scheme/autoscalingv1 from scheme causes a depedency loop from +// conversions + +func TestRoundTrip(t *testing.T) { + scheme := NewScaleConverter().Scheme() + // we don't actually need any custom fuzzer funcs ATM -- the defaults + // will do just fine + roundtrip.RoundTripTestForScheme(t, scheme, nil) +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/BUILD b/staging/src/k8s.io/client-go/scale/scheme/BUILD new file mode 100644 index 00000000000..effa9141927 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/BUILD @@ -0,0 +1,39 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "register.go", + "types.go", + "zz_generated.deepcopy.go", + ], + importpath = "k8s.io/client-go/scale/scheme", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/api/autoscaling/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/client-go/scale/scheme/autoscalingv1:all-srcs", + "//staging/src/k8s.io/client-go/scale/scheme/extensionsint:all-srcs", + "//staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/BUILD b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/BUILD new file mode 100644 index 00000000000..646a6fdf8e7 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/BUILD @@ -0,0 +1,35 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "conversion.go", + "doc.go", + "register.go", + "zz_generated.conversion.go", + ], + importpath = "k8s.io/client-go/scale/scheme/autoscalingv1", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/api/autoscaling/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/client-go/scale/scheme:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/conversion.go b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/conversion.go new file mode 100644 index 00000000000..a775bcc225b --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/conversion.go @@ -0,0 +1,69 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package autoscalingv1 + +import ( + "fmt" + + v1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + scheme "k8s.io/client-go/scale/scheme" +) + +// addConversions registers conversions between the internal version +// of Scale and supported external versions of Scale. +func addConversionFuncs(scheme *runtime.Scheme) error { + err := scheme.AddConversionFuncs( + Convert_scheme_ScaleStatus_To_v1_ScaleStatus, + Convert_v1_ScaleStatus_To_scheme_ScaleStatus, + ) + if err != nil { + return err + } + + return nil +} + +func Convert_scheme_ScaleStatus_To_v1_ScaleStatus(in *scheme.ScaleStatus, out *v1.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + out.Selector = "" + if in.Selector != nil { + selector, err := metav1.LabelSelectorAsSelector(in.Selector) + if err != nil { + return fmt.Errorf("invalid label selector: %v", err) + } + out.Selector = selector.String() + } + + return nil +} + +func Convert_v1_ScaleStatus_To_scheme_ScaleStatus(in *v1.ScaleStatus, out *scheme.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + if in.Selector != "" { + labelSelector, err := metav1.ParseToLabelSelector(in.Selector) + if err != nil { + out.Selector = nil + return fmt.Errorf("failed to parse target selector: %v", err) + } + out.Selector = labelSelector + } + + return nil +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/doc.go b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/doc.go new file mode 100644 index 00000000000..aff53e4c37b --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:conversion-gen=k8s.io/kubernetes/vendor/k8s.io/client-go/scale/scheme +// +k8s:conversion-gen-external-types=../../../../../k8s.io/api/autoscaling/v1 + +package autoscalingv1 // import "k8s.io/client-go/scale/scheme/autoscalingv1" diff --git a/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/register.go b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/register.go new file mode 100644 index 00000000000..b15701c4ff7 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package autoscalingv1 + +import ( + autoscalingapiv1 "k8s.io/api/autoscaling/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = autoscalingapiv1.GroupName + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + localSchemeBuilder = &autoscalingapiv1.SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addConversionFuncs) +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/zz_generated.conversion.go b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/zz_generated.conversion.go new file mode 100644 index 00000000000..1eaa0d18027 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/autoscalingv1/zz_generated.conversion.go @@ -0,0 +1,109 @@ +// +build !ignore_autogenerated + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file was autogenerated by conversion-gen. Do not edit it manually! + +package autoscalingv1 + +import ( + v1 "k8s.io/api/autoscaling/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + scheme "k8s.io/client-go/scale/scheme" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(scheme *runtime.Scheme) error { + return scheme.AddGeneratedConversionFuncs( + Convert_v1_Scale_To_scheme_Scale, + Convert_scheme_Scale_To_v1_Scale, + Convert_v1_ScaleSpec_To_scheme_ScaleSpec, + Convert_scheme_ScaleSpec_To_v1_ScaleSpec, + Convert_v1_ScaleStatus_To_scheme_ScaleStatus, + Convert_scheme_ScaleStatus_To_v1_ScaleStatus, + ) +} + +func autoConvert_v1_Scale_To_scheme_Scale(in *v1.Scale, out *scheme.Scale, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_ScaleSpec_To_scheme_ScaleSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1_ScaleStatus_To_scheme_ScaleStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Scale_To_scheme_Scale is an autogenerated conversion function. +func Convert_v1_Scale_To_scheme_Scale(in *v1.Scale, out *scheme.Scale, s conversion.Scope) error { + return autoConvert_v1_Scale_To_scheme_Scale(in, out, s) +} + +func autoConvert_scheme_Scale_To_v1_Scale(in *scheme.Scale, out *v1.Scale, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_scheme_ScaleSpec_To_v1_ScaleSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_scheme_ScaleStatus_To_v1_ScaleStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_scheme_Scale_To_v1_Scale is an autogenerated conversion function. +func Convert_scheme_Scale_To_v1_Scale(in *scheme.Scale, out *v1.Scale, s conversion.Scope) error { + return autoConvert_scheme_Scale_To_v1_Scale(in, out, s) +} + +func autoConvert_v1_ScaleSpec_To_scheme_ScaleSpec(in *v1.ScaleSpec, out *scheme.ScaleSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + return nil +} + +// Convert_v1_ScaleSpec_To_scheme_ScaleSpec is an autogenerated conversion function. +func Convert_v1_ScaleSpec_To_scheme_ScaleSpec(in *v1.ScaleSpec, out *scheme.ScaleSpec, s conversion.Scope) error { + return autoConvert_v1_ScaleSpec_To_scheme_ScaleSpec(in, out, s) +} + +func autoConvert_scheme_ScaleSpec_To_v1_ScaleSpec(in *scheme.ScaleSpec, out *v1.ScaleSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + return nil +} + +// Convert_scheme_ScaleSpec_To_v1_ScaleSpec is an autogenerated conversion function. +func Convert_scheme_ScaleSpec_To_v1_ScaleSpec(in *scheme.ScaleSpec, out *v1.ScaleSpec, s conversion.Scope) error { + return autoConvert_scheme_ScaleSpec_To_v1_ScaleSpec(in, out, s) +} + +func autoConvert_v1_ScaleStatus_To_scheme_ScaleStatus(in *v1.ScaleStatus, out *scheme.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + // WARNING: in.Selector requires manual conversion: inconvertible types (string vs *k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector) + return nil +} + +func autoConvert_scheme_ScaleStatus_To_v1_ScaleStatus(in *scheme.ScaleStatus, out *v1.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + // WARNING: in.Selector requires manual conversion: inconvertible types (*k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector vs string) + return nil +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/doc.go b/staging/src/k8s.io/client-go/scale/scheme/doc.go new file mode 100644 index 00000000000..8a050ce47b4 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package,register + +// Package scheme contains a runtime.Scheme to be used for serializing +// and deserializing different versions of Scale, and for converting +// in between them. +package scheme diff --git a/staging/src/k8s.io/client-go/scale/scheme/extensionsint/BUILD b/staging/src/k8s.io/client-go/scale/scheme/extensionsint/BUILD new file mode 100644 index 00000000000..6174a88b145 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/extensionsint/BUILD @@ -0,0 +1,31 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "register.go", + ], + importpath = "k8s.io/client-go/scale/scheme/extensionsint", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/client-go/scale/scheme:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/client-go/scale/scheme/extensionsint/doc.go b/staging/src/k8s.io/client-go/scale/scheme/extensionsint/doc.go new file mode 100644 index 00000000000..cc92bf18824 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/extensionsint/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package extensionsint contains the necessary scaffolding of the +// internal version of extensions as required by conversion logic. +// It doesn't have any of its own types -- it's just necessary to +// get the expected behavoir out of runtime.Scheme.ConvertToVersion +// and associated methods. +package extensionsint diff --git a/staging/src/k8s.io/client-go/scale/scheme/extensionsint/register.go b/staging/src/k8s.io/client-go/scale/scheme/extensionsint/register.go new file mode 100644 index 00000000000..5a96ac56140 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/extensionsint/register.go @@ -0,0 +1,53 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package extensionsint + +import ( + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + scalescheme "k8s.io/client-go/scale/scheme" +) + +// GroupName is the group name use in this package +const GroupName = extensionsv1beta1.GroupName + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &scalescheme.Scale{}, + ) + return nil +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/BUILD b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/BUILD new file mode 100644 index 00000000000..4c992c7d113 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/BUILD @@ -0,0 +1,35 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "conversion.go", + "doc.go", + "register.go", + "zz_generated.conversion.go", + ], + importpath = "k8s.io/client-go/scale/scheme/extensionsv1beta1", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/client-go/scale/scheme:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/conversion.go b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/conversion.go new file mode 100644 index 00000000000..1b6b9e61037 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/conversion.go @@ -0,0 +1,87 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package extensionsv1beta1 + +import ( + "fmt" + + v1beta1 "k8s.io/api/extensions/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + scheme "k8s.io/client-go/scale/scheme" +) + +// addConversions registers conversions between the internal version +// of Scale and supported external versions of Scale. +func addConversionFuncs(scheme *runtime.Scheme) error { + err := scheme.AddConversionFuncs( + Convert_scheme_ScaleStatus_To_v1beta1_ScaleStatus, + Convert_v1beta1_ScaleStatus_To_scheme_ScaleStatus, + ) + if err != nil { + return err + } + + return nil +} +func Convert_scheme_ScaleStatus_To_v1beta1_ScaleStatus(in *scheme.ScaleStatus, out *v1beta1.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + out.Selector = nil + out.TargetSelector = "" + if in.Selector != nil { + if in.Selector.MatchExpressions == nil || len(in.Selector.MatchExpressions) == 0 { + out.Selector = in.Selector.MatchLabels + } + + selector, err := metav1.LabelSelectorAsSelector(in.Selector) + if err != nil { + return fmt.Errorf("invalid label selector: %v", err) + } + out.TargetSelector = selector.String() + } + + return nil +} + +func Convert_v1beta1_ScaleStatus_To_scheme_ScaleStatus(in *v1beta1.ScaleStatus, out *scheme.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + + // Normally when 2 fields map to the same internal value we favor the old field, since + // old clients can't be expected to know about new fields but clients that know about the + // new field can be expected to know about the old field (though that's not quite true, due + // to kubectl apply). However, these fields are readonly, so any non-nil value should work. + if in.TargetSelector != "" { + labelSelector, err := metav1.ParseToLabelSelector(in.TargetSelector) + if err != nil { + out.Selector = nil + return fmt.Errorf("failed to parse target selector: %v", err) + } + out.Selector = labelSelector + } else if in.Selector != nil { + out.Selector = new(metav1.LabelSelector) + selector := make(map[string]string) + for key, val := range in.Selector { + selector[key] = val + } + out.Selector.MatchLabels = selector + } else { + out.Selector = nil + } + + return nil +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/doc.go b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/doc.go new file mode 100644 index 00000000000..40d0fc0e959 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:conversion-gen=k8s.io/kubernetes/vendor/k8s.io/client-go/scale/scheme +// +k8s:conversion-gen-external-types=../../../../../k8s.io/api/extensions/v1beta1 + +package extensionsv1beta1 // import "k8s.io/client-go/scale/scheme/extensionsv1beta1" diff --git a/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/register.go b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/register.go new file mode 100644 index 00000000000..aed1174e023 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package extensionsv1beta1 + +import ( + extensionsapiv1beta1 "k8s.io/api/extensions/v1beta1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = extensionsapiv1beta1.GroupName + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + localSchemeBuilder = &extensionsapiv1beta1.SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addConversionFuncs) +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/zz_generated.conversion.go b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/zz_generated.conversion.go new file mode 100644 index 00000000000..848cb8d2aa3 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/extensionsv1beta1/zz_generated.conversion.go @@ -0,0 +1,110 @@ +// +build !ignore_autogenerated + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file was autogenerated by conversion-gen. Do not edit it manually! + +package extensionsv1beta1 + +import ( + v1beta1 "k8s.io/api/extensions/v1beta1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + scheme "k8s.io/client-go/scale/scheme" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(scheme *runtime.Scheme) error { + return scheme.AddGeneratedConversionFuncs( + Convert_v1beta1_Scale_To_scheme_Scale, + Convert_scheme_Scale_To_v1beta1_Scale, + Convert_v1beta1_ScaleSpec_To_scheme_ScaleSpec, + Convert_scheme_ScaleSpec_To_v1beta1_ScaleSpec, + Convert_v1beta1_ScaleStatus_To_scheme_ScaleStatus, + Convert_scheme_ScaleStatus_To_v1beta1_ScaleStatus, + ) +} + +func autoConvert_v1beta1_Scale_To_scheme_Scale(in *v1beta1.Scale, out *scheme.Scale, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1beta1_ScaleSpec_To_scheme_ScaleSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1beta1_ScaleStatus_To_scheme_ScaleStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta1_Scale_To_scheme_Scale is an autogenerated conversion function. +func Convert_v1beta1_Scale_To_scheme_Scale(in *v1beta1.Scale, out *scheme.Scale, s conversion.Scope) error { + return autoConvert_v1beta1_Scale_To_scheme_Scale(in, out, s) +} + +func autoConvert_scheme_Scale_To_v1beta1_Scale(in *scheme.Scale, out *v1beta1.Scale, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_scheme_ScaleSpec_To_v1beta1_ScaleSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_scheme_ScaleStatus_To_v1beta1_ScaleStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_scheme_Scale_To_v1beta1_Scale is an autogenerated conversion function. +func Convert_scheme_Scale_To_v1beta1_Scale(in *scheme.Scale, out *v1beta1.Scale, s conversion.Scope) error { + return autoConvert_scheme_Scale_To_v1beta1_Scale(in, out, s) +} + +func autoConvert_v1beta1_ScaleSpec_To_scheme_ScaleSpec(in *v1beta1.ScaleSpec, out *scheme.ScaleSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + return nil +} + +// Convert_v1beta1_ScaleSpec_To_scheme_ScaleSpec is an autogenerated conversion function. +func Convert_v1beta1_ScaleSpec_To_scheme_ScaleSpec(in *v1beta1.ScaleSpec, out *scheme.ScaleSpec, s conversion.Scope) error { + return autoConvert_v1beta1_ScaleSpec_To_scheme_ScaleSpec(in, out, s) +} + +func autoConvert_scheme_ScaleSpec_To_v1beta1_ScaleSpec(in *scheme.ScaleSpec, out *v1beta1.ScaleSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + return nil +} + +// Convert_scheme_ScaleSpec_To_v1beta1_ScaleSpec is an autogenerated conversion function. +func Convert_scheme_ScaleSpec_To_v1beta1_ScaleSpec(in *scheme.ScaleSpec, out *v1beta1.ScaleSpec, s conversion.Scope) error { + return autoConvert_scheme_ScaleSpec_To_v1beta1_ScaleSpec(in, out, s) +} + +func autoConvert_v1beta1_ScaleStatus_To_scheme_ScaleStatus(in *v1beta1.ScaleStatus, out *scheme.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + // WARNING: in.Selector requires manual conversion: inconvertible types (map[string]string vs *k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector) + // WARNING: in.TargetSelector requires manual conversion: does not exist in peer-type + return nil +} + +func autoConvert_scheme_ScaleStatus_To_v1beta1_ScaleStatus(in *scheme.ScaleStatus, out *v1beta1.ScaleStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + // WARNING: in.Selector requires manual conversion: inconvertible types (*k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector vs map[string]string) + return nil +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/register.go b/staging/src/k8s.io/client-go/scale/scheme/register.go new file mode 100644 index 00000000000..7e6decfff5f --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/register.go @@ -0,0 +1,52 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scheme + +import ( + autoscalingv1 "k8s.io/api/autoscaling/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = autoscalingv1.GroupName + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Scale{}, + ) + return nil +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/types.go b/staging/src/k8s.io/client-go/scale/scheme/types.go new file mode 100644 index 00000000000..13aec2b3c3c --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/types.go @@ -0,0 +1,60 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scheme + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// This file contains our own "internal" version of scale that we use for conversions, +// since we can't use the main Kubernetes internal versions. + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Scale represents a scaling request for a resource. +type Scale struct { + metav1.TypeMeta + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata. + // +optional + metav1.ObjectMeta + + // defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. + // +optional + Spec ScaleSpec + + // current status of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. Read-only. + // +optional + Status ScaleStatus +} + +// ScaleSpec describes the attributes of a scale subresource. +type ScaleSpec struct { + // desired number of instances for the scaled object. + // +optional + Replicas int32 +} + +// ScaleStatus represents the current status of a scale subresource. +type ScaleStatus struct { + // actual number of observed instances of the scaled object. + Replicas int32 + + // label query over pods that should match the replicas count. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + Selector *metav1.LabelSelector +} diff --git a/staging/src/k8s.io/client-go/scale/scheme/zz_generated.deepcopy.go b/staging/src/k8s.io/client-go/scale/scheme/zz_generated.deepcopy.go new file mode 100644 index 00000000000..ec9f5f95ed1 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/scheme/zz_generated.deepcopy.go @@ -0,0 +1,123 @@ +// +build !ignore_autogenerated + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file was autogenerated by deepcopy-gen. Do not edit it manually! + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + reflect "reflect" +) + +func init() { + SchemeBuilder.Register(RegisterDeepCopies) +} + +// RegisterDeepCopies adds deep-copy functions to the given scheme. Public +// to allow building arbitrary schemes. +// +// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented. +func RegisterDeepCopies(scheme *runtime.Scheme) error { + return scheme.AddGeneratedDeepCopyFuncs( + conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error { + in.(*Scale).DeepCopyInto(out.(*Scale)) + return nil + }, InType: reflect.TypeOf(&Scale{})}, + conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error { + in.(*ScaleSpec).DeepCopyInto(out.(*ScaleSpec)) + return nil + }, InType: reflect.TypeOf(&ScaleSpec{})}, + conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error { + in.(*ScaleStatus).DeepCopyInto(out.(*ScaleStatus)) + return nil + }, InType: reflect.TypeOf(&ScaleStatus{})}, + ) +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Scale) DeepCopyInto(out *Scale) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scale. +func (in *Scale) DeepCopy() *Scale { + if in == nil { + return nil + } + out := new(Scale) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Scale) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } else { + return nil + } +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScaleSpec) DeepCopyInto(out *ScaleSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleSpec. +func (in *ScaleSpec) DeepCopy() *ScaleSpec { + if in == nil { + return nil + } + out := new(ScaleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScaleStatus) DeepCopyInto(out *ScaleStatus) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + if *in == nil { + *out = nil + } else { + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleStatus. +func (in *ScaleStatus) DeepCopy() *ScaleStatus { + if in == nil { + return nil + } + out := new(ScaleStatus) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/client-go/scale/util.go b/staging/src/k8s.io/client-go/scale/util.go new file mode 100644 index 00000000000..f5de4bc9a33 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/util.go @@ -0,0 +1,159 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scale + +import ( + "fmt" + "strings" + "sync" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + scalescheme "k8s.io/client-go/scale/scheme" + scaleautoscaling "k8s.io/client-go/scale/scheme/autoscalingv1" + scaleextint "k8s.io/client-go/scale/scheme/extensionsint" + scaleext "k8s.io/client-go/scale/scheme/extensionsv1beta1" +) + +// ScaleKindResolver knows about the relationship between +// resources and the GroupVersionKind of their scale subresources. +type ScaleKindResolver interface { + // ScaleForResource returns the GroupVersionKind of the + // scale subresource for the given GroupVersionResource. + ScaleForResource(resource schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error) +} + +// discoveryScaleResolver is a ScaleKindResolver that uses +// a DiscoveryInterface to associate resources with their +// scale-kinds +type discoveryScaleResolver struct { + discoveryClient discovery.ServerResourcesInterface +} + +func (r *discoveryScaleResolver) ScaleForResource(inputRes schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error) { + groupVerResources, err := r.discoveryClient.ServerResourcesForGroupVersion(inputRes.GroupVersion().String()) + if err != nil { + return schema.GroupVersionKind{}, fmt.Errorf("unable to fetch discovery information for %s: %v", inputRes.String(), err) + } + + for _, resource := range groupVerResources.APIResources { + resourceParts := strings.SplitN(resource.Name, "/", 2) + if len(resourceParts) != 2 || resourceParts[0] != inputRes.Resource || resourceParts[1] != "scale" { + // skip non-scale resources, or scales for resources that we're not looking for + continue + } + + scaleGV := inputRes.GroupVersion() + if resource.Group != "" && resource.Version != "" { + scaleGV = schema.GroupVersion{ + Group: resource.Group, + Version: resource.Version, + } + } + + return scaleGV.WithKind(resource.Kind), nil + } + + return schema.GroupVersionKind{}, fmt.Errorf("could not find scale subresource for %s in discovery information", inputRes.String()) +} + +// cachedScaleKindResolver is a ScaleKindResolver that caches results +// from another ScaleKindResolver, re-fetching on cache misses. +type cachedScaleKindResolver struct { + base ScaleKindResolver + + cache map[schema.GroupVersionResource]schema.GroupVersionKind + mu sync.RWMutex +} + +func (r *cachedScaleKindResolver) ScaleForResource(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { + r.mu.RLock() + gvk, isCached := r.cache[resource] + r.mu.RUnlock() + if isCached { + return gvk, nil + } + + // we could have multiple fetches of the same resources, but that's probably + // better than limiting to only one reader at once (mu.Mutex), + // or blocking checks for other resources while we fetch + // (mu.Lock before fetch). + gvk, err := r.base.ScaleForResource(resource) + if err != nil { + return schema.GroupVersionKind{}, err + } + + r.mu.Lock() + defer r.mu.Unlock() + r.cache[resource] = gvk + + return gvk, nil +} + +// NewDiscoveryScaleKindResolver creates a new ScaleKindResolver which uses information from the given +// disovery client to resolve the correct Scale GroupVersionKind for different resources. +func NewDiscoveryScaleKindResolver(client discovery.ServerResourcesInterface) ScaleKindResolver { + base := &discoveryScaleResolver{ + discoveryClient: client, + } + + return &cachedScaleKindResolver{ + base: base, + cache: make(map[schema.GroupVersionResource]schema.GroupVersionKind), + } +} + +// ScaleConverter knows how to convert between external scale versions. +type ScaleConverter struct { + scheme *runtime.Scheme + internalVersioner runtime.GroupVersioner +} + +// NewScaleConverter creates a new ScaleConverter for converting between +// Scales in autoscaling/v1 and extensions/v1beta1. +func NewScaleConverter() *ScaleConverter { + scheme := runtime.NewScheme() + scaleautoscaling.AddToScheme(scheme) + scalescheme.AddToScheme(scheme) + scaleext.AddToScheme(scheme) + scaleextint.AddToScheme(scheme) + + return &ScaleConverter{ + scheme: scheme, + internalVersioner: runtime.NewMultiGroupVersioner( + scalescheme.SchemeGroupVersion, + schema.GroupKind{Group: scaleext.GroupName, Kind: "Scale"}, + schema.GroupKind{Group: scaleautoscaling.GroupName, Kind: "Scale"}, + ), + } +} + +// Scheme returns the scheme used by this scale converter. +func (c *ScaleConverter) Scheme() *runtime.Scheme { + return c.scheme +} + +// ConvertToVersion converts the given *external* input object to the given output *external* output group-version. +func (c *ScaleConverter) ConvertToVersion(in runtime.Object, outVersion schema.GroupVersion) (runtime.Object, error) { + scaleInt, err := c.scheme.ConvertToVersion(in, c.internalVersioner) + if err != nil { + return nil, err + } + + return c.scheme.ConvertToVersion(scaleInt, outVersion) +} From ef583aeed2ad38197e14c4fc7b2621af6d91ff1b Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Fri, 13 Oct 2017 14:57:28 -0400 Subject: [PATCH 4/8] Fuzz label selectors Previously, we did not have custom code for fuzzing label selectors. Anything that used a label selector (like Scale) had to manually bypass fuzzing the selector, or write its own fuzzer. This introduces a fuzzer for label selectors which generates random correct selectors with random keys and values. --- pkg/api/testing/serialization_test.go | 9 ++ .../pkg/apis/meta/fuzzer/fuzzer.go | 127 ++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/pkg/api/testing/serialization_test.go b/pkg/api/testing/serialization_test.go index cc97b76e246..4106f0209a6 100644 --- a/pkg/api/testing/serialization_test.go +++ b/pkg/api/testing/serialization_test.go @@ -104,6 +104,15 @@ func TestSetControllerConversion(t *testing.T) { fuzzInternalObject(t, extGroup.InternalGroupVersion(), rs, rand.Int63()) + // explicitly set the selector to something that is convertible to old-style selectors + // (since normally we'll fuzz the selectors with things that aren't convertible) + rs.Spec.Selector = &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", + "baz": "quux", + }, + } + t.Logf("rs._internal.extensions -> rs.v1beta1.extensions") data, err := runtime.Encode(extGroup.Codec(), rs) if err != nil { diff --git a/staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer/fuzzer.go b/staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer/fuzzer.go index e5f5bd4c796..27dfb3d9e90 100644 --- a/staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer/fuzzer.go +++ b/staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer/fuzzer.go @@ -18,7 +18,10 @@ package fuzzer import ( "fmt" + "math/rand" + "sort" "strconv" + "strings" "github.com/google/gofuzz" @@ -96,7 +99,80 @@ func genericFuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} { } } +// taken from gofuzz internals for RandString +type charRange struct { + first, last rune +} + +func (c *charRange) choose(r *rand.Rand) rune { + count := int64(c.last - c.first + 1) + ch := c.first + rune(r.Int63n(count)) + + return ch +} + +// randomLabelPart produces a valid random label value or name-part +// of a label key. +func randomLabelPart(c fuzz.Continue, canBeEmpty bool) string { + validStartEnd := []charRange{{'0', '9'}, {'a', 'z'}, {'A', 'Z'}} + validMiddle := []charRange{{'0', '9'}, {'a', 'z'}, {'A', 'Z'}, + {'.', '.'}, {'-', '-'}, {'_', '_'}} + + partLen := c.Rand.Intn(64) // len is [0, 63] + if !canBeEmpty { + partLen = c.Rand.Intn(63) + 1 // len is [1, 63] + } + + runes := make([]rune, partLen) + if partLen == 0 { + return string(runes) + } + + runes[0] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand) + for i := range runes[1:] { + runes[i+1] = validMiddle[c.Rand.Intn(len(validMiddle))].choose(c.Rand) + } + runes[len(runes)-1] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand) + + return string(runes) +} + +func randomDNSLabel(c fuzz.Continue) string { + validStartEnd := []charRange{{'0', '9'}, {'a', 'z'}} + validMiddle := []charRange{{'0', '9'}, {'a', 'z'}, {'-', '-'}} + + partLen := c.Rand.Intn(63) + 1 // len is [1, 63] + runes := make([]rune, partLen) + + runes[0] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand) + for i := range runes[1:] { + runes[i+1] = validMiddle[c.Rand.Intn(len(validMiddle))].choose(c.Rand) + } + runes[len(runes)-1] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand) + + return string(runes) +} + +func randomLabelKey(c fuzz.Continue) string { + namePart := randomLabelPart(c, false) + prefixPart := "" + + usePrefix := c.RandBool() + if usePrefix { + // we can fit, with dots, at most 3 labels in the 253 allotted characters + prefixPartsLen := c.Rand.Intn(2) + 1 + prefixParts := make([]string, prefixPartsLen) + for i := range prefixParts { + prefixParts[i] = randomDNSLabel(c) + } + prefixPart = strings.Join(prefixParts, ".") + "/" + } + + return prefixPart + namePart +} + func v1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} { + return []interface{}{ func(j *metav1.TypeMeta, c fuzz.Continue) { // We have to customize the randomization of TypeMetas because their @@ -120,6 +196,57 @@ func v1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} { j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10) j.SelfLink = c.RandString() }, + func(j *metav1.LabelSelector, c fuzz.Continue) { + c.FuzzNoCustom(j) + // we can't have an entirely empty selector, so force + // use of MatchExpression if necessary + if len(j.MatchLabels) == 0 && len(j.MatchExpressions) == 0 { + j.MatchExpressions = make([]metav1.LabelSelectorRequirement, c.Rand.Intn(2)+1) + } + + if j.MatchLabels != nil { + fuzzedMatchLabels := make(map[string]string, len(j.MatchLabels)) + for i := 0; i < len(j.MatchLabels); i++ { + fuzzedMatchLabels[randomLabelKey(c)] = randomLabelPart(c, true) + } + j.MatchLabels = fuzzedMatchLabels + } + + validOperators := []metav1.LabelSelectorOperator{ + metav1.LabelSelectorOpIn, + metav1.LabelSelectorOpNotIn, + metav1.LabelSelectorOpExists, + metav1.LabelSelectorOpDoesNotExist, + } + + if j.MatchExpressions != nil { + // NB: the label selector parser code sorts match expressions by key, and sorts the values, + // so we need to make sure ours are sorted as well here to preserve round-trip comparision. + // In practice, not sorting doesn't hurt anything... + + for i := range j.MatchExpressions { + req := metav1.LabelSelectorRequirement{} + c.Fuzz(&req) + req.Key = randomLabelKey(c) + req.Operator = validOperators[c.Rand.Intn(len(validOperators))] + if req.Operator == metav1.LabelSelectorOpIn || req.Operator == metav1.LabelSelectorOpNotIn { + if len(req.Values) == 0 { + // we must have some values here, so randomly choose a short length + req.Values = make([]string, c.Rand.Intn(2)+1) + } + for i := range req.Values { + req.Values[i] = randomLabelPart(c, true) + } + sort.Strings(req.Values) + } else { + req.Values = nil + } + j.MatchExpressions[i] = req + } + + sort.Slice(j.MatchExpressions, func(a, b int) bool { return j.MatchExpressions[a].Key < j.MatchExpressions[b].Key }) + } + }, } } From 3f51babdd141290a2cbf2cee2df59df49e4eea10 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Fri, 13 Oct 2017 15:02:58 -0400 Subject: [PATCH 5/8] Update extensions fuzzer to use selector fuzzer This removes the override on the extensions fuzzer so that extensions.Scale will use the full label selector fuzzer. --- pkg/apis/extensions/fuzzer/fuzzer.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/pkg/apis/extensions/fuzzer/fuzzer.go b/pkg/apis/extensions/fuzzer/fuzzer.go index f8f3b3d374a..006d04f9f9c 100644 --- a/pkg/apis/extensions/fuzzer/fuzzer.go +++ b/pkg/apis/extensions/fuzzer/fuzzer.go @@ -21,7 +21,6 @@ import ( fuzz "github.com/google/gofuzz" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/kubernetes/pkg/apis/extensions" @@ -83,25 +82,6 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} { } psp.FSGroup.Rule = fsGroupRules[c.Rand.Intn(len(fsGroupRules))] }, - func(s *extensions.Scale, c fuzz.Continue) { - c.FuzzNoCustom(s) // fuzz self without calling this function again - // TODO: Implement a fuzzer to generate valid keys, values and operators for - // selector requirements. - if s.Status.Selector != nil { - s.Status.Selector = &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "testlabelkey": "testlabelval", - }, - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Key: "testkey", - Operator: metav1.LabelSelectorOpIn, - Values: []string{"val1", "val2", "val3"}, - }, - }, - } - } - }, func(j *extensions.DaemonSetSpec, c fuzz.Continue) { c.FuzzNoCustom(j) // fuzz self without calling this function again rhl := int32(c.Rand.Int31()) From d2b41120ea0779954560e139a1dbcfa1bb36e088 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Wed, 11 Oct 2017 14:31:04 -0400 Subject: [PATCH 6/8] Make HPA controller use polymorphic scale client This updates the HPA controller to use the polymorphic scale client from client-go. This should enable HPAs to work with arbitrary scalable resources, instead of just those in the extensions API group (meaning we can deprecate the copy of ReplicationController in extensions/v1beta1). It also means that the HPA controller now pays attention to the APIVersion field in `scaleTargetRef` (more specifically, the group part of it). Note that currently, discovery information on which resources are available where is only fetched once (the first time that it's requested). In the future, we may want a refreshing discovery REST mapper. --- cmd/kube-controller-manager/app/BUILD | 1 + .../app/autoscaling.go | 26 +- pkg/apis/extensions/fuzzer/BUILD | 1 - pkg/controller/podautoscaler/BUILD | 8 +- pkg/controller/podautoscaler/horizontal.go | 80 ++++-- .../podautoscaler/horizontal_test.go | 272 +++++++++--------- .../podautoscaler/legacy_horizontal_test.go | 220 +++++++------- 7 files changed, 344 insertions(+), 264 deletions(-) diff --git a/cmd/kube-controller-manager/app/BUILD b/cmd/kube-controller-manager/app/BUILD index 6bcd3baa947..d5dcfcc0031 100644 --- a/cmd/kube-controller-manager/app/BUILD +++ b/cmd/kube-controller-manager/app/BUILD @@ -124,6 +124,7 @@ go_library( "//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", + "//vendor/k8s.io/client-go/scale:go_default_library", "//vendor/k8s.io/client-go/tools/clientcmd:go_default_library", "//vendor/k8s.io/client-go/tools/leaderelection:go_default_library", "//vendor/k8s.io/client-go/tools/leaderelection/resourcelock:go_default_library", diff --git a/cmd/kube-controller-manager/app/autoscaling.go b/cmd/kube-controller-manager/app/autoscaling.go index 5af911d7adc..827d767b14b 100644 --- a/cmd/kube-controller-manager/app/autoscaling.go +++ b/cmd/kube-controller-manager/app/autoscaling.go @@ -21,7 +21,12 @@ limitations under the License. package app import ( + apimeta "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + discocache "k8s.io/client-go/discovery/cached" // Saturday Night Fever + "k8s.io/client-go/dynamic" + "k8s.io/client-go/scale" "k8s.io/kubernetes/pkg/controller/podautoscaler" "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics" resourceclient "k8s.io/metrics/pkg/client/clientset_generated/clientset/typed/metrics/v1beta1" @@ -63,16 +68,33 @@ func startHPAControllerWithLegacyClient(ctx ControllerContext) (bool, error) { } func startHPAControllerWithMetricsClient(ctx ControllerContext, metricsClient metrics.MetricsClient) (bool, error) { + hpaClientGoClient := ctx.ClientBuilder.ClientGoClientOrDie("horizontal-pod-autoscaler") hpaClient := ctx.ClientBuilder.ClientOrDie("horizontal-pod-autoscaler") + hpaClientConfig := ctx.ClientBuilder.ConfigOrDie("horizontal-pod-autoscaler") + + // TODO: we need something like deferred discovery REST mapper that calls invalidate + // on cache misses. + cachedDiscovery := discocache.NewMemCacheClient(hpaClientGoClient.Discovery()) + restMapper := discovery.NewDeferredDiscoveryRESTMapper(cachedDiscovery, apimeta.InterfacesForUnstructured) + restMapper.Reset() + // we don't use cached discovery because DiscoveryScaleKindResolver does its own caching, + // so we want to re-fetch every time when we actually ask for it + scaleKindResolver := scale.NewDiscoveryScaleKindResolver(hpaClientGoClient.Discovery()) + scaleClient, err := scale.NewForConfig(hpaClientConfig, restMapper, dynamic.LegacyAPIPathResolverFunc, scaleKindResolver) + if err != nil { + return false, err + } + replicaCalc := podautoscaler.NewReplicaCalculator( metricsClient, hpaClient.Core(), ctx.Options.HorizontalPodAutoscalerTolerance, ) go podautoscaler.NewHorizontalController( - ctx.ClientBuilder.ClientGoClientOrDie("horizontal-pod-autoscaler").Core(), - hpaClient.Extensions(), + hpaClientGoClient.Core(), + scaleClient, hpaClient.Autoscaling(), + restMapper, replicaCalc, ctx.InformerFactory.Autoscaling().V1().HorizontalPodAutoscalers(), ctx.Options.HorizontalPodAutoscalerSyncPeriod.Duration, diff --git a/pkg/apis/extensions/fuzzer/BUILD b/pkg/apis/extensions/fuzzer/BUILD index 4f4bf9cce0f..712d0f4e681 100644 --- a/pkg/apis/extensions/fuzzer/BUILD +++ b/pkg/apis/extensions/fuzzer/BUILD @@ -12,7 +12,6 @@ go_library( deps = [ "//pkg/apis/extensions:go_default_library", "//vendor/github.com/google/gofuzz:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library", ], diff --git a/pkg/controller/podautoscaler/BUILD b/pkg/controller/podautoscaler/BUILD index 2231e891453..b0fa8efaa38 100644 --- a/pkg/controller/podautoscaler/BUILD +++ b/pkg/controller/podautoscaler/BUILD @@ -24,9 +24,9 @@ go_library( "//vendor/k8s.io/api/autoscaling/v1:go_default_library", "//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", - "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", @@ -39,8 +39,8 @@ go_library( "//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", - "//vendor/k8s.io/client-go/kubernetes/typed/extensions/v1beta1:go_default_library", "//vendor/k8s.io/client-go/listers/autoscaling/v1:go_default_library", + "//vendor/k8s.io/client-go/scale:go_default_library", "//vendor/k8s.io/client-go/tools/cache:go_default_library", "//vendor/k8s.io/client-go/tools/record:go_default_library", "//vendor/k8s.io/client-go/util/workqueue:go_default_library", @@ -58,6 +58,7 @@ go_test( importpath = "k8s.io/kubernetes/pkg/controller/podautoscaler", library = ":go_default_library", deps = [ + "//pkg/api/install:go_default_library", "//pkg/api/legacyscheme:go_default_library", "//pkg/apis/autoscaling:go_default_library", "//pkg/apis/autoscaling/install:go_default_library", @@ -69,15 +70,16 @@ go_test( "//vendor/k8s.io/api/autoscaling/v1:go_default_library", "//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", - "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", "//vendor/k8s.io/client-go/informers:go_default_library", "//vendor/k8s.io/client-go/kubernetes/fake:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", + "//vendor/k8s.io/client-go/scale/fake:go_default_library", "//vendor/k8s.io/client-go/testing:go_default_library", "//vendor/k8s.io/heapster/metrics/api/v1/types:go_default_library", "//vendor/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library", diff --git a/pkg/controller/podautoscaler/horizontal.go b/pkg/controller/podautoscaler/horizontal.go index a09d40e8fd3..fbac1816668 100644 --- a/pkg/controller/podautoscaler/horizontal.go +++ b/pkg/controller/podautoscaler/horizontal.go @@ -25,9 +25,9 @@ import ( autoscalingv1 "k8s.io/api/autoscaling/v1" autoscalingv2 "k8s.io/api/autoscaling/v2beta1" "k8s.io/api/core/v1" - extensions "k8s.io/api/extensions/v1beta1" apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" + apimeta "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -39,8 +39,8 @@ import ( "k8s.io/client-go/kubernetes/scheme" autoscalingclient "k8s.io/client-go/kubernetes/typed/autoscaling/v1" v1core "k8s.io/client-go/kubernetes/typed/core/v1" - extensionsclient "k8s.io/client-go/kubernetes/typed/extensions/v1beta1" autoscalinglisters "k8s.io/client-go/listers/autoscaling/v1" + scaleclient "k8s.io/client-go/scale" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" @@ -57,8 +57,9 @@ var ( // in the system with the actual deployments/replication controllers they // control. type HorizontalController struct { - scaleNamespacer extensionsclient.ScalesGetter + scaleNamespacer scaleclient.ScalesGetter hpaNamespacer autoscalingclient.HorizontalPodAutoscalersGetter + mapper apimeta.RESTMapper replicaCalc *ReplicaCalculator eventRecorder record.EventRecorder @@ -78,8 +79,9 @@ type HorizontalController struct { // NewHorizontalController creates a new HorizontalController. func NewHorizontalController( evtNamespacer v1core.EventsGetter, - scaleNamespacer extensionsclient.ScalesGetter, + scaleNamespacer scaleclient.ScalesGetter, hpaNamespacer autoscalingclient.HorizontalPodAutoscalersGetter, + mapper apimeta.RESTMapper, replicaCalc *ReplicaCalculator, hpaInformer autoscalinginformers.HorizontalPodAutoscalerInformer, resyncPeriod time.Duration, @@ -99,7 +101,8 @@ func NewHorizontalController( hpaNamespacer: hpaNamespacer, upscaleForbiddenWindow: upscaleForbiddenWindow, downscaleForbiddenWindow: downscaleForbiddenWindow, - queue: workqueue.NewNamedRateLimitingQueue(NewDefaultHPARateLimiter(resyncPeriod), "horizontalpodautoscaler"), + queue: workqueue.NewNamedRateLimitingQueue(NewDefaultHPARateLimiter(resyncPeriod), "horizontalpodautoscaler"), + mapper: mapper, } hpaInformer.Informer().AddEventHandlerWithResyncPeriod( @@ -189,7 +192,7 @@ func (a *HorizontalController) processNextWorkItem() bool { // Computes the desired number of replicas for the metric specifications listed in the HPA, returning the maximum // of the computed replica counts, a description of the associated metric, and the statuses of all metrics // computed. -func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, scale *extensions.Scale, +func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, scale *autoscalingv1.Scale, metricSpecs []autoscalingv2.MetricSpec) (replicas int32, metric string, statuses []autoscalingv2.MetricStatus, timestamp time.Time, err error) { currentReplicas := scale.Status.Replicas @@ -197,21 +200,14 @@ func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.Hori statuses = make([]autoscalingv2.MetricStatus, len(metricSpecs)) for i, metricSpec := range metricSpecs { - if len(scale.Status.Selector) == 0 && len(scale.Status.TargetSelector) == 0 { + if scale.Status.Selector == "" { errMsg := "selector is required" a.eventRecorder.Event(hpa, v1.EventTypeWarning, "SelectorRequired", errMsg) setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "InvalidSelector", "the HPA target's scale is missing a selector") return 0, "", nil, time.Time{}, fmt.Errorf(errMsg) } - var selector labels.Selector - var err error - if len(scale.Status.Selector) > 0 { - selector = labels.SelectorFromSet(labels.Set(scale.Status.Selector)) - err = nil - } else { - selector, err = labels.Parse(scale.Status.TargetSelector) - } + selector, err := labels.Parse(scale.Status.Selector) if err != nil { errMsg := fmt.Sprintf("couldn't convert selector into a corresponding internal selector object: %v", err) a.eventRecorder.Event(hpa, v1.EventTypeWarning, "InvalidSelector", errMsg) @@ -349,7 +345,28 @@ func (a *HorizontalController) reconcileAutoscaler(hpav1Shared *autoscalingv1.Ho reference := fmt.Sprintf("%s/%s/%s", hpa.Spec.ScaleTargetRef.Kind, hpa.Namespace, hpa.Spec.ScaleTargetRef.Name) - scale, err := a.scaleNamespacer.Scales(hpa.Namespace).Get(hpa.Spec.ScaleTargetRef.Kind, hpa.Spec.ScaleTargetRef.Name) + targetGV, err := schema.ParseGroupVersion(hpa.Spec.ScaleTargetRef.APIVersion) + if err != nil { + a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetScale", err.Error()) + setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err) + a.updateStatusIfNeeded(hpaStatusOriginal, hpa) + return fmt.Errorf("invalid API version in scale target reference: %v", err) + } + + targetGK := schema.GroupKind{ + Group: targetGV.Group, + Kind: hpa.Spec.ScaleTargetRef.Kind, + } + + mappings, err := a.mapper.RESTMappings(targetGK) + if err != nil { + a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetScale", err.Error()) + setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err) + a.updateStatusIfNeeded(hpaStatusOriginal, hpa) + return fmt.Errorf("unable to determine resource for scale target reference: %v", err) + } + + scale, targetGR, err := a.scaleForResourceMappings(hpa.Namespace, hpa.Spec.ScaleTargetRef.Name, mappings) if err != nil { a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetScale", err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedGetScale", "the HPA controller was unable to get the target's current scale: %v", err) @@ -479,7 +496,7 @@ func (a *HorizontalController) reconcileAutoscaler(hpav1Shared *autoscalingv1.Ho if rescale { scale.Spec.Replicas = desiredReplicas - _, err = a.scaleNamespacer.Scales(hpa.Namespace).Update(hpa.Spec.ScaleTargetRef.Kind, scale) + _, err = a.scaleNamespacer.Scales(hpa.Namespace).Update(targetGR, scale) if err != nil { a.eventRecorder.Eventf(hpa, v1.EventTypeWarning, "FailedRescale", "New size: %d; reason: %s; error: %v", desiredReplicas, rescaleReason, err.Error()) setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionFalse, "FailedUpdateScale", "the HPA controller was unable to update the target scale: %v", err) @@ -526,6 +543,35 @@ func (a *HorizontalController) shouldScale(hpa *autoscalingv2.HorizontalPodAutos return false } +// scaleForResourceMappings attempts to fetch the scale for the +// resource with the given name and namespace, trying each RESTMapping +// in turn until a working one is found. If none work, the first error +// is returned. It returns both the scale, as well as the group-resource from +// the working mapping. +func (a *HorizontalController) scaleForResourceMappings(namespace, name string, mappings []*apimeta.RESTMapping) (*autoscalingv1.Scale, schema.GroupResource, error) { + var firstErr error + for i, mapping := range mappings { + targetGR := mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource).GroupResource() + scale, err := a.scaleNamespacer.Scales(namespace).Get(targetGR, name) + if err == nil { + return scale, targetGR, nil + } + + // if this is the first error, remember it, + // then go on and try other mappings until we find a good one + if i == 0 { + firstErr = err + } + } + + // make sure we handle an empty set of mappings + if firstErr == nil { + firstErr = fmt.Errorf("unrecognized resource") + } + + return nil, schema.GroupResource{}, firstErr +} + // setCurrentReplicasInStatus sets the current replica count in the status of the HPA. func (a *HorizontalController) setCurrentReplicasInStatus(hpa *autoscalingv2.HorizontalPodAutoscaler, currentReplicas int32) { a.setStatus(hpa, currentReplicas, hpa.Status.DesiredReplicas, hpa.Status.CurrentMetrics, false) diff --git a/pkg/controller/podautoscaler/horizontal_test.go b/pkg/controller/podautoscaler/horizontal_test.go index 2de54888482..ac840d61bab 100644 --- a/pkg/controller/podautoscaler/horizontal_test.go +++ b/pkg/controller/podautoscaler/horizontal_test.go @@ -27,15 +27,16 @@ import ( autoscalingv1 "k8s.io/api/autoscaling/v1" autoscalingv2 "k8s.io/api/autoscaling/v2beta1" "k8s.io/api/core/v1" - extensions "k8s.io/api/extensions/v1beta1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" clientfake "k8s.io/client-go/kubernetes/fake" + scalefake "k8s.io/client-go/scale/fake" core "k8s.io/client-go/testing" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/autoscaling" @@ -121,6 +122,7 @@ type testCase struct { testClient *fake.Clientset testMetricsClient *metricsfake.Clientset testCMClient *cmfake.FakeCustomMetricsClient + testScaleClient *scalefake.FakeScaleClient } // Needs to be called under a lock. @@ -144,12 +146,12 @@ func init() { scaleUpLimitFactor = 8 } -func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfake.Clientset, *cmfake.FakeCustomMetricsClient) { +func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfake.Clientset, *cmfake.FakeCustomMetricsClient, *scalefake.FakeScaleClient) { namespace := "test-namespace" hpaName := "test-hpa" podNamePrefix := "test-pod" - // TODO: also test with TargetSelector - selector := map[string]string{"name": podNamePrefix} + labelSet := map[string]string{"name": podNamePrefix} + selector := labels.SelectorFromSet(labelSet).String() tc.Lock() @@ -161,13 +163,11 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa tc.computeCPUCurrent() } - // TODO(madhusudancs): HPA only supports resources in extensions/v1beta1 right now. Add - // tests for "v1" replicationcontrollers when HPA adds support for cross-group scale. if tc.resource == nil { tc.resource = &fakeResource{ name: "test-rc", - apiVersion: "extensions/v1beta1", - kind: "replicationcontrollers", + apiVersion: "v1", + kind: "ReplicationController", } } tc.Unlock() @@ -239,66 +239,6 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa return true, objv1, nil }) - fakeClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := &extensions.Scale{ - ObjectMeta: metav1.ObjectMeta{ - Name: tc.resource.name, - Namespace: namespace, - }, - Spec: extensions.ScaleSpec{ - Replicas: tc.initialReplicas, - }, - Status: extensions.ScaleStatus{ - Replicas: tc.initialReplicas, - Selector: selector, - }, - } - return true, obj, nil - }) - - fakeClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := &extensions.Scale{ - ObjectMeta: metav1.ObjectMeta{ - Name: tc.resource.name, - Namespace: namespace, - }, - Spec: extensions.ScaleSpec{ - Replicas: tc.initialReplicas, - }, - Status: extensions.ScaleStatus{ - Replicas: tc.initialReplicas, - Selector: selector, - }, - } - return true, obj, nil - }) - - fakeClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := &extensions.Scale{ - ObjectMeta: metav1.ObjectMeta{ - Name: tc.resource.name, - Namespace: namespace, - }, - Spec: extensions.ScaleSpec{ - Replicas: tc.initialReplicas, - }, - Status: extensions.ScaleStatus{ - Replicas: tc.initialReplicas, - Selector: selector, - }, - } - return true, obj, nil - }) - fakeClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { tc.Lock() defer tc.Unlock() @@ -344,39 +284,6 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa return true, obj, nil }) - fakeClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := action.(core.UpdateAction).GetObject().(*extensions.Scale) - replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas - assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the RC should be as expected") - tc.scaleUpdated = true - return true, obj, nil - }) - - fakeClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := action.(core.UpdateAction).GetObject().(*extensions.Scale) - replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas - assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the deployment should be as expected") - tc.scaleUpdated = true - return true, obj, nil - }) - - fakeClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := action.(core.UpdateAction).GetObject().(*extensions.Scale) - replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas - assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the replicaset should be as expected") - tc.scaleUpdated = true - return true, obj, nil - }) - fakeClient.AddReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) { tc.Lock() defer tc.Unlock() @@ -386,8 +293,9 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected") assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected") if tc.verifyCPUCurrent { - assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") - assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected") + if assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") { + assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected") + } } var actualConditions []autoscalingv1.HorizontalPodAutoscalerCondition if err := json.Unmarshal([]byte(obj.ObjectMeta.Annotations[autoscaling.HorizontalPodAutoscalerConditionsAnnotation]), &actualConditions); err != nil { @@ -411,6 +319,100 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa return true, obj, nil }) + fakeScaleClient := &scalefake.FakeScaleClient{} + fakeScaleClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := &autoscalingv1.Scale{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.resource.name, + Namespace: namespace, + }, + Spec: autoscalingv1.ScaleSpec{ + Replicas: tc.initialReplicas, + }, + Status: autoscalingv1.ScaleStatus{ + Replicas: tc.initialReplicas, + Selector: selector, + }, + } + return true, obj, nil + }) + + fakeScaleClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := &autoscalingv1.Scale{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.resource.name, + Namespace: namespace, + }, + Spec: autoscalingv1.ScaleSpec{ + Replicas: tc.initialReplicas, + }, + Status: autoscalingv1.ScaleStatus{ + Replicas: tc.initialReplicas, + Selector: selector, + }, + } + return true, obj, nil + }) + + fakeScaleClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := &autoscalingv1.Scale{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.resource.name, + Namespace: namespace, + }, + Spec: autoscalingv1.ScaleSpec{ + Replicas: tc.initialReplicas, + }, + Status: autoscalingv1.ScaleStatus{ + Replicas: tc.initialReplicas, + Selector: selector, + }, + } + return true, obj, nil + }) + + fakeScaleClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale) + replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas + assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the RC should be as expected") + tc.scaleUpdated = true + return true, obj, nil + }) + + fakeScaleClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale) + replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas + assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the deployment should be as expected") + tc.scaleUpdated = true + return true, obj, nil + }) + + fakeScaleClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale) + replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas + assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the replicaset should be as expected") + tc.scaleUpdated = true + return true, obj, nil + }) + fakeWatch := watch.NewFake() fakeClient.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatch, nil)) @@ -427,7 +429,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-%d", podNamePrefix, i), Namespace: namespace, - Labels: selector, + Labels: labelSet, }, Timestamp: metav1.Time{Time: time.Now()}, Containers: []metricsapi.ContainerMetrics{ @@ -522,7 +524,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa return true, metrics, nil }) - return fakeClient, fakeMetricsClient, fakeCMClient + return fakeClient, fakeMetricsClient, fakeCMClient, fakeScaleClient } func (tc *testCase) verifyResults(t *testing.T) { @@ -537,7 +539,7 @@ func (tc *testCase) verifyResults(t *testing.T) { } func (tc *testCase) setupController(t *testing.T) (*HorizontalController, informers.SharedInformerFactory) { - testClient, testMetricsClient, testCMClient := tc.prepareTestClient(t) + testClient, testMetricsClient, testCMClient, testScaleClient := tc.prepareTestClient(t) if tc.testClient != nil { testClient = tc.testClient } @@ -547,6 +549,9 @@ func (tc *testCase) setupController(t *testing.T) (*HorizontalController, inform if tc.testCMClient != nil { testCMClient = tc.testCMClient } + if tc.testScaleClient != nil { + testScaleClient = tc.testScaleClient + } metricsClient := metrics.NewRESTMetricsClient( testMetricsClient.MetricsV1beta1(), testCMClient, @@ -587,8 +592,9 @@ func (tc *testCase) setupController(t *testing.T) (*HorizontalController, inform hpaController := NewHorizontalController( eventClient.Core(), - testClient.Extensions(), + testScaleClient, testClient.Autoscaling(), + legacyscheme.Registry.RESTMapper(), replicaCalc, informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(), controller.NoResyncPeriodFunc(), @@ -692,7 +698,7 @@ func TestScaleUpDeployment(t *testing.T) { resource: &fakeResource{ name: "test-dep", apiVersion: "extensions/v1beta1", - kind: "deployments", + kind: "Deployment", }, } tc.runTest(t) @@ -712,7 +718,7 @@ func TestScaleUpReplicaSet(t *testing.T) { resource: &fakeResource{ name: "test-replicaset", apiVersion: "extensions/v1beta1", - kind: "replicasets", + kind: "ReplicaSet", }, } tc.runTest(t) @@ -1267,18 +1273,18 @@ func TestConditionInvalidSelectorMissing(t *testing.T) { }, } - testClient, _, _ := tc.prepareTestClient(t) - tc.testClient = testClient + _, _, _, testScaleClient := tc.prepareTestClient(t) + tc.testScaleClient = testScaleClient - testClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { - obj := &extensions.Scale{ + testScaleClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { + obj := &autoscalingv1.Scale{ ObjectMeta: metav1.ObjectMeta{ Name: tc.resource.name, }, - Spec: extensions.ScaleSpec{ + Spec: autoscalingv1.ScaleSpec{ Replicas: tc.initialReplicas, }, - Status: extensions.ScaleStatus{ + Status: autoscalingv1.ScaleStatus{ Replicas: tc.initialReplicas, }, } @@ -1312,20 +1318,20 @@ func TestConditionInvalidSelectorUnparsable(t *testing.T) { }, } - testClient, _, _ := tc.prepareTestClient(t) - tc.testClient = testClient + _, _, _, testScaleClient := tc.prepareTestClient(t) + tc.testScaleClient = testScaleClient - testClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { - obj := &extensions.Scale{ + testScaleClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { + obj := &autoscalingv1.Scale{ ObjectMeta: metav1.ObjectMeta{ Name: tc.resource.name, }, - Spec: extensions.ScaleSpec{ + Spec: autoscalingv1.ScaleSpec{ Replicas: tc.initialReplicas, }, - Status: extensions.ScaleStatus{ - Replicas: tc.initialReplicas, - TargetSelector: "cheddar cheese", + Status: autoscalingv1.ScaleStatus{ + Replicas: tc.initialReplicas, + Selector: "cheddar cheese", }, } return true, obj, nil @@ -1373,7 +1379,7 @@ func TestConditionFailedGetMetrics(t *testing.T) { reportedCPURequests: []resource.Quantity{resource.MustParse("0.1"), resource.MustParse("0.1"), resource.MustParse("0.1")}, useMetricsAPI: true, } - _, testMetricsClient, testCMClient := tc.prepareTestClient(t) + _, testMetricsClient, testCMClient, _ := tc.prepareTestClient(t) tc.testMetricsClient = testMetricsClient tc.testCMClient = testCMClient @@ -1446,11 +1452,11 @@ func TestConditionFailedGetScale(t *testing.T) { }, } - testClient, _, _ := tc.prepareTestClient(t) - tc.testClient = testClient + _, _, _, testScaleClient := tc.prepareTestClient(t) + tc.testScaleClient = testScaleClient - testClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { - return true, &extensions.Scale{}, fmt.Errorf("something went wrong") + testScaleClient.PrependReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { + return true, &autoscalingv1.Scale{}, fmt.Errorf("something went wrong") }) tc.runTest(t) @@ -1473,11 +1479,11 @@ func TestConditionFailedUpdateScale(t *testing.T) { }), } - testClient, _, _ := tc.prepareTestClient(t) - tc.testClient = testClient + _, _, _, testScaleClient := tc.prepareTestClient(t) + tc.testScaleClient = testScaleClient - testClient.PrependReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { - return true, &extensions.Scale{}, fmt.Errorf("something went wrong") + testScaleClient.PrependReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { + return true, &autoscalingv1.Scale{}, fmt.Errorf("something went wrong") }) tc.runTest(t) @@ -1659,7 +1665,7 @@ func TestAvoidUncessaryUpdates(t *testing.T) { reportedPodReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse}, useMetricsAPI: true, } - testClient, _, _ := tc.prepareTestClient(t) + testClient, _, _, _ := tc.prepareTestClient(t) tc.testClient = testClient var savedHPA *autoscalingv1.HorizontalPodAutoscaler testClient.PrependReactor("list", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) { diff --git a/pkg/controller/podautoscaler/legacy_horizontal_test.go b/pkg/controller/podautoscaler/legacy_horizontal_test.go index b94ce82c6c2..72eeade2114 100644 --- a/pkg/controller/podautoscaler/legacy_horizontal_test.go +++ b/pkg/controller/podautoscaler/legacy_horizontal_test.go @@ -30,16 +30,18 @@ import ( autoscalingv1 "k8s.io/api/autoscaling/v1" autoscalingv2 "k8s.io/api/autoscaling/v2beta1" "k8s.io/api/core/v1" - extensions "k8s.io/api/extensions/v1beta1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" clientfake "k8s.io/client-go/kubernetes/fake" restclient "k8s.io/client-go/rest" + scalefake "k8s.io/client-go/scale/fake" core "k8s.io/client-go/testing" + "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics" @@ -48,6 +50,7 @@ import ( "github.com/stretchr/testify/assert" + _ "k8s.io/kubernetes/pkg/api/install" _ "k8s.io/kubernetes/pkg/apis/autoscaling/install" _ "k8s.io/kubernetes/pkg/apis/extensions/install" ) @@ -114,12 +117,12 @@ func (tc *legacyTestCase) computeCPUCurrent() { tc.CPUCurrent = int32(100 * reported / requested) } -func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset { +func (tc *legacyTestCase) prepareTestClient(t *testing.T) (*fake.Clientset, *scalefake.FakeScaleClient) { namespace := "test-namespace" hpaName := "test-hpa" podNamePrefix := "test-pod" - // TODO: also test with TargetSelector - selector := map[string]string{"name": podNamePrefix} + labelSet := map[string]string{"name": podNamePrefix} + selector := labels.SelectorFromSet(labelSet).String() tc.Lock() @@ -131,13 +134,11 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset { tc.computeCPUCurrent() } - // TODO(madhusudancs): HPA only supports resources in extensions/v1beta1 right now. Add - // tests for "v1" replicationcontrollers when HPA adds support for cross-group scale. if tc.resource == nil { tc.resource = &fakeResource{ name: "test-rc", - apiVersion: "extensions/v1beta1", - kind: "replicationcontrollers", + apiVersion: "v1", + kind: "ReplicationController", } } tc.Unlock() @@ -208,66 +209,6 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset { return true, objv1, nil }) - fakeClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := &extensions.Scale{ - ObjectMeta: metav1.ObjectMeta{ - Name: tc.resource.name, - Namespace: namespace, - }, - Spec: extensions.ScaleSpec{ - Replicas: tc.initialReplicas, - }, - Status: extensions.ScaleStatus{ - Replicas: tc.initialReplicas, - Selector: selector, - }, - } - return true, obj, nil - }) - - fakeClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := &extensions.Scale{ - ObjectMeta: metav1.ObjectMeta{ - Name: tc.resource.name, - Namespace: namespace, - }, - Spec: extensions.ScaleSpec{ - Replicas: tc.initialReplicas, - }, - Status: extensions.ScaleStatus{ - Replicas: tc.initialReplicas, - Selector: selector, - }, - } - return true, obj, nil - }) - - fakeClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := &extensions.Scale{ - ObjectMeta: metav1.ObjectMeta{ - Name: tc.resource.name, - Namespace: namespace, - }, - Spec: extensions.ScaleSpec{ - Replicas: tc.initialReplicas, - }, - Status: extensions.ScaleStatus{ - Replicas: tc.initialReplicas, - Selector: selector, - }, - } - return true, obj, nil - }) - fakeClient.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { tc.Lock() defer tc.Unlock() @@ -386,39 +327,6 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset { return true, newFakeResponseWrapper(heapsterRawMemResponse), nil }) - fakeClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := action.(core.UpdateAction).GetObject().(*extensions.Scale) - replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas - assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the RC should be as expected") - tc.scaleUpdated = true - return true, obj, nil - }) - - fakeClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := action.(core.UpdateAction).GetObject().(*extensions.Scale) - replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas - assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the deployment should be as expected") - tc.scaleUpdated = true - return true, obj, nil - }) - - fakeClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { - tc.Lock() - defer tc.Unlock() - - obj := action.(core.UpdateAction).GetObject().(*extensions.Scale) - replicas := action.(core.UpdateAction).GetObject().(*extensions.Scale).Spec.Replicas - assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the replicaset should be as expected") - tc.scaleUpdated = true - return true, obj, nil - }) - fakeClient.AddReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) { tc.Lock() defer tc.Unlock() @@ -428,8 +336,9 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset { assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected") assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected") if tc.verifyCPUCurrent { - assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") - assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected") + if assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") { + assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected") + } } tc.statusUpdated = true // Every time we reconcile HPA object we are updating status. @@ -437,10 +346,104 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) *fake.Clientset { return true, obj, nil }) + fakeScaleClient := &scalefake.FakeScaleClient{} + fakeScaleClient.AddReactor("get", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := &autoscalingv1.Scale{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.resource.name, + Namespace: namespace, + }, + Spec: autoscalingv1.ScaleSpec{ + Replicas: tc.initialReplicas, + }, + Status: autoscalingv1.ScaleStatus{ + Replicas: tc.initialReplicas, + Selector: selector, + }, + } + return true, obj, nil + }) + + fakeScaleClient.AddReactor("get", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := &autoscalingv1.Scale{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.resource.name, + Namespace: namespace, + }, + Spec: autoscalingv1.ScaleSpec{ + Replicas: tc.initialReplicas, + }, + Status: autoscalingv1.ScaleStatus{ + Replicas: tc.initialReplicas, + Selector: selector, + }, + } + return true, obj, nil + }) + + fakeScaleClient.AddReactor("get", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := &autoscalingv1.Scale{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.resource.name, + Namespace: namespace, + }, + Spec: autoscalingv1.ScaleSpec{ + Replicas: tc.initialReplicas, + }, + Status: autoscalingv1.ScaleStatus{ + Replicas: tc.initialReplicas, + Selector: selector, + }, + } + return true, obj, nil + }) + + fakeScaleClient.AddReactor("update", "replicationcontrollers", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale) + replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas + assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the RC should be as expected") + tc.scaleUpdated = true + return true, obj, nil + }) + + fakeScaleClient.AddReactor("update", "deployments", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale) + replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas + assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the deployment should be as expected") + tc.scaleUpdated = true + return true, obj, nil + }) + + fakeScaleClient.AddReactor("update", "replicasets", func(action core.Action) (handled bool, ret runtime.Object, err error) { + tc.Lock() + defer tc.Unlock() + + obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale) + replicas := action.(core.UpdateAction).GetObject().(*autoscalingv1.Scale).Spec.Replicas + assert.Equal(t, tc.desiredReplicas, replicas, "the replica count of the replicaset should be as expected") + tc.scaleUpdated = true + return true, obj, nil + }) + fakeWatch := watch.NewFake() fakeClient.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatch, nil)) - return fakeClient + return fakeClient, fakeScaleClient } func (tc *legacyTestCase) verifyResults(t *testing.T) { @@ -455,7 +458,7 @@ func (tc *legacyTestCase) verifyResults(t *testing.T) { } func (tc *legacyTestCase) runTest(t *testing.T) { - testClient := tc.prepareTestClient(t) + testClient, testScaleClient := tc.prepareTestClient(t) metricsClient := metrics.NewHeapsterMetricsClient(testClient, metrics.DefaultHeapsterNamespace, metrics.DefaultHeapsterScheme, metrics.DefaultHeapsterService, metrics.DefaultHeapsterPort) eventClient := &clientfake.Clientset{} @@ -493,8 +496,9 @@ func (tc *legacyTestCase) runTest(t *testing.T) { hpaController := NewHorizontalController( eventClient.Core(), - testClient.Extensions(), + testScaleClient, testClient.Autoscaling(), + legacyscheme.Registry.RESTMapper(), replicaCalc, informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(), controller.NoResyncPeriodFunc(), @@ -584,7 +588,7 @@ func LegacyTestScaleUpDeployment(t *testing.T) { resource: &fakeResource{ name: "test-dep", apiVersion: "extensions/v1beta1", - kind: "deployments", + kind: "Deployment", }, } tc.runTest(t) @@ -604,7 +608,7 @@ func LegacyTestScaleUpReplicaSet(t *testing.T) { resource: &fakeResource{ name: "test-replicaset", apiVersion: "extensions/v1beta1", - kind: "replicasets", + kind: "ReplicaSet", }, } tc.runTest(t) From 55e1f6a541f25a6006f2548d64a0cf99cf247036 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Fri, 13 Oct 2017 11:38:05 -0400 Subject: [PATCH 7/8] [make-rules] test grep should treat binary as text The output of `go test` is passed throug a grep filter that's used when producing junit output. Unfortunately, when testing round-trip conversions with random strings, grep can become convinced that the test output is binary, and will truncate a failed test before any output is displayed, showing "binary file (standard input) matches". This forces grep to consider test output to be text, so that we always see test results. --- hack/make-rules/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/make-rules/test.sh b/hack/make-rules/test.sh index 151060ed8b0..c7b5a1481a8 100755 --- a/hack/make-rules/test.sh +++ b/hack/make-rules/test.sh @@ -289,7 +289,7 @@ runTests() { ${KUBE_RACE} ${KUBE_TIMEOUT} "${@}" \ "${testargs[@]:+${testargs[@]}}" \ | tee ${junit_filename_prefix:+"${junit_filename_prefix}.stdout"} \ - | grep "${go_test_grep_pattern}" && rc=$? || rc=$? + | grep --binary-files=text "${go_test_grep_pattern}" && rc=$? || rc=$? produceJUnitXMLReport "${junit_filename_prefix}" return ${rc} fi From f22bfcd65acafc75235665feac3b147f16e30998 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Fri, 13 Oct 2017 17:55:53 -0400 Subject: [PATCH 8/8] [client-go] Add fake scale client This adds a new fake scale client (for use in testing) to match the new polymorphic scale client. --- hack/.golint_failures | 1 + staging/src/k8s.io/client-go/scale/BUILD | 1 + staging/src/k8s.io/client-go/scale/fake/BUILD | 28 ++++++++ .../src/k8s.io/client-go/scale/fake/client.go | 67 +++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 staging/src/k8s.io/client-go/scale/fake/BUILD create mode 100644 staging/src/k8s.io/client-go/scale/fake/client.go diff --git a/hack/.golint_failures b/hack/.golint_failures index 85c525427a7..b3b85493c24 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -716,6 +716,7 @@ staging/src/k8s.io/client-go/plugin/pkg/client/auth/oidc staging/src/k8s.io/client-go/rest staging/src/k8s.io/client-go/rest/fake staging/src/k8s.io/client-go/scale +staging/src/k8s.io/client-go/scale/fake staging/src/k8s.io/client-go/scale/scheme staging/src/k8s.io/client-go/scale/scheme/autoscalingv1 staging/src/k8s.io/client-go/scale/scheme/extensionsint diff --git a/staging/src/k8s.io/client-go/scale/BUILD b/staging/src/k8s.io/client-go/scale/BUILD index ed2bad0b0ee..e3b3cac1a11 100644 --- a/staging/src/k8s.io/client-go/scale/BUILD +++ b/staging/src/k8s.io/client-go/scale/BUILD @@ -65,6 +65,7 @@ filegroup( name = "all-srcs", srcs = [ ":package-srcs", + "//staging/src/k8s.io/client-go/scale/fake:all-srcs", "//staging/src/k8s.io/client-go/scale/scheme:all-srcs", ], tags = ["automanaged"], diff --git a/staging/src/k8s.io/client-go/scale/fake/BUILD b/staging/src/k8s.io/client-go/scale/fake/BUILD new file mode 100644 index 00000000000..8c9374305e2 --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/fake/BUILD @@ -0,0 +1,28 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["client.go"], + importpath = "k8s.io/client-go/scale/fake", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/api/autoscaling/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/client-go/scale:go_default_library", + "//vendor/k8s.io/client-go/testing:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/client-go/scale/fake/client.go b/staging/src/k8s.io/client-go/scale/fake/client.go new file mode 100644 index 00000000000..1736680f14d --- /dev/null +++ b/staging/src/k8s.io/client-go/scale/fake/client.go @@ -0,0 +1,67 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package fake provides a fake client interface to arbitrary Kubernetes +// APIs that exposes common high level operations and exposes common +// metadata. +package fake + +import ( + autoscalingapi "k8s.io/api/autoscaling/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/scale" + "k8s.io/client-go/testing" +) + +// FakeScaleClient provides a fake implementation of scale.ScalesGetter. +type FakeScaleClient struct { + testing.Fake +} + +func (f *FakeScaleClient) Scales(namespace string) scale.ScaleInterface { + return &fakeNamespacedScaleClient{ + namespace: namespace, + fake: &f.Fake, + } +} + +type fakeNamespacedScaleClient struct { + namespace string + fake *testing.Fake +} + +func (f *fakeNamespacedScaleClient) Get(resource schema.GroupResource, name string) (*autoscalingapi.Scale, error) { + obj, err := f.fake. + Invokes(testing.NewGetSubresourceAction(resource.WithVersion(""), f.namespace, "scale", name), &autoscalingapi.Scale{}) + + if err != nil { + return nil, err + } + + return obj.(*autoscalingapi.Scale), err +} + +func (f *fakeNamespacedScaleClient) Update(resource schema.GroupResource, scale *autoscalingapi.Scale) (*autoscalingapi.Scale, error) { + obj, err := f.fake. + Invokes(testing.NewUpdateSubresourceAction(resource.WithVersion(""), f.namespace, "scale", scale), &autoscalingapi.Scale{}) + + if err != nil { + return nil, err + } + + return obj.(*autoscalingapi.Scale), err + +}