From 729a0da155871de445ea2116cf6457e29e313d08 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Fri, 27 Oct 2017 04:22:39 -0400 Subject: [PATCH 1/3] Specify correct subresource discovery info --- pkg/registry/apps/statefulset/storage/BUILD | 3 +++ .../apps/statefulset/storage/storage.go | 14 ++++++++++++-- pkg/registry/core/pod/storage/eviction.go | 7 +++++++ .../core/replicationcontroller/storage/BUILD | 2 ++ .../replicationcontroller/storage/storage.go | 11 +++++++++-- .../extensions/deployment/storage/BUILD | 4 ++++ .../extensions/deployment/storage/storage.go | 17 +++++++++++++++-- .../extensions/replicaset/storage/BUILD | 4 ++++ .../extensions/replicaset/storage/storage.go | 17 +++++++++++++++-- .../k8s.io/apiserver/pkg/endpoints/installer.go | 2 +- .../k8s.io/apiserver/pkg/registry/rest/rest.go | 2 +- 11 files changed, 73 insertions(+), 10 deletions(-) diff --git a/pkg/registry/apps/statefulset/storage/BUILD b/pkg/registry/apps/statefulset/storage/BUILD index ccb4be21a0a..f9bccc8b9c2 100644 --- a/pkg/registry/apps/statefulset/storage/BUILD +++ b/pkg/registry/apps/statefulset/storage/BUILD @@ -35,6 +35,9 @@ go_library( importpath = "k8s.io/kubernetes/pkg/registry/apps/statefulset/storage", deps = [ "//pkg/apis/apps:go_default_library", + "//pkg/apis/apps/v1beta1:go_default_library", + "//pkg/apis/apps/v1beta2:go_default_library", + "//pkg/apis/autoscaling/v1:go_default_library", "//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions/validation:go_default_library", "//pkg/printers:go_default_library", diff --git a/pkg/registry/apps/statefulset/storage/storage.go b/pkg/registry/apps/statefulset/storage/storage.go index 94360f4c096..1eba35293a5 100644 --- a/pkg/registry/apps/statefulset/storage/storage.go +++ b/pkg/registry/apps/statefulset/storage/storage.go @@ -28,6 +28,9 @@ import ( genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" "k8s.io/kubernetes/pkg/apis/apps" + appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1" + appsv1beta2 "k8s.io/kubernetes/pkg/apis/apps/v1beta2" + autoscalingv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1" "k8s.io/kubernetes/pkg/apis/extensions" extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" "k8s.io/kubernetes/pkg/printers" @@ -125,8 +128,15 @@ type ScaleREST struct { var _ = rest.Patcher(&ScaleREST{}) var _ = rest.GroupVersionKindProvider(&ScaleREST{}) -func (r *ScaleREST) GroupVersionKind() schema.GroupVersionKind { - return schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Scale"} +func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + switch containingGV { + case appsv1beta1.SchemeGroupVersion: + return appsv1beta1.SchemeGroupVersion.WithKind("Scale") + case appsv1beta2.SchemeGroupVersion: + return appsv1beta2.SchemeGroupVersion.WithKind("Scale") + default: + return autoscalingv1.SchemeGroupVersion.WithKind("Scale") + } } // New creates a new Scale object diff --git a/pkg/registry/core/pod/storage/eviction.go b/pkg/registry/core/pod/storage/eviction.go index 36b97350ffc..405d1b8666e 100644 --- a/pkg/registry/core/pod/storage/eviction.go +++ b/pkg/registry/core/pod/storage/eviction.go @@ -24,6 +24,7 @@ import ( 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/util/wait" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" @@ -64,6 +65,12 @@ type EvictionREST struct { } var _ = rest.Creater(&EvictionREST{}) +var _ = rest.GroupVersionKindProvider(&EvictionREST{}) + +// GroupVersionKind specifies a particular GroupVersionKind to discovery +func (r *EvictionREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + return schema.GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "Eviction"} +} // New creates a new eviction resource func (r *EvictionREST) New() runtime.Object { diff --git a/pkg/registry/core/replicationcontroller/storage/BUILD b/pkg/registry/core/replicationcontroller/storage/BUILD index 7dde8812ab6..4ff72af6121 100644 --- a/pkg/registry/core/replicationcontroller/storage/BUILD +++ b/pkg/registry/core/replicationcontroller/storage/BUILD @@ -36,7 +36,9 @@ go_library( deps = [ "//pkg/api:go_default_library", "//pkg/apis/autoscaling:go_default_library", + "//pkg/apis/autoscaling/v1:go_default_library", "//pkg/apis/autoscaling/validation:go_default_library", + "//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/printers:go_default_library", "//pkg/printers/internalversion:go_default_library", "//pkg/printers/storage:go_default_library", diff --git a/pkg/registry/core/replicationcontroller/storage/storage.go b/pkg/registry/core/replicationcontroller/storage/storage.go index 65f1214690e..686b9448755 100644 --- a/pkg/registry/core/replicationcontroller/storage/storage.go +++ b/pkg/registry/core/replicationcontroller/storage/storage.go @@ -32,7 +32,9 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/autoscaling" + autoscalingv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1" "k8s.io/kubernetes/pkg/apis/autoscaling/validation" + extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" printerstorage "k8s.io/kubernetes/pkg/printers/storage" @@ -129,8 +131,13 @@ type ScaleREST struct { var _ = rest.Patcher(&ScaleREST{}) var _ = rest.GroupVersionKindProvider(&ScaleREST{}) -func (r *ScaleREST) GroupVersionKind() schema.GroupVersionKind { - return schema.GroupVersionKind{Group: "autoscaling", Version: "v1", Kind: "Scale"} +func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + switch containingGV { + case extensionsv1beta1.SchemeGroupVersion: + return extensionsv1beta1.SchemeGroupVersion.WithKind("Scale") + default: + return autoscalingv1.SchemeGroupVersion.WithKind("Scale") + } } // New creates a new Scale object diff --git a/pkg/registry/extensions/deployment/storage/BUILD b/pkg/registry/extensions/deployment/storage/BUILD index 1d8064b0dc1..cb4d1ed8e75 100644 --- a/pkg/registry/extensions/deployment/storage/BUILD +++ b/pkg/registry/extensions/deployment/storage/BUILD @@ -36,7 +36,11 @@ go_library( srcs = ["storage.go"], importpath = "k8s.io/kubernetes/pkg/registry/extensions/deployment/storage", deps = [ + "//pkg/apis/apps/v1beta1:go_default_library", + "//pkg/apis/apps/v1beta2:go_default_library", + "//pkg/apis/autoscaling/v1:go_default_library", "//pkg/apis/extensions:go_default_library", + "//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/extensions/validation:go_default_library", "//pkg/registry/extensions/deployment:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", diff --git a/pkg/registry/extensions/deployment/storage/storage.go b/pkg/registry/extensions/deployment/storage/storage.go index ec2f08744c2..23eb69bd329 100644 --- a/pkg/registry/extensions/deployment/storage/storage.go +++ b/pkg/registry/extensions/deployment/storage/storage.go @@ -30,7 +30,11 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" storeerr "k8s.io/apiserver/pkg/storage/errors" + appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1" + appsv1beta2 "k8s.io/kubernetes/pkg/apis/apps/v1beta2" + autoscalingv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1" "k8s.io/kubernetes/pkg/apis/extensions" + extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" "k8s.io/kubernetes/pkg/registry/extensions/deployment" ) @@ -193,8 +197,17 @@ type ScaleREST struct { var _ = rest.Patcher(&ScaleREST{}) var _ = rest.GroupVersionKindProvider(&ScaleREST{}) -func (r *ScaleREST) GroupVersionKind() schema.GroupVersionKind { - return schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Scale"} +func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + switch containingGV { + case extensionsv1beta1.SchemeGroupVersion: + return extensionsv1beta1.SchemeGroupVersion.WithKind("Scale") + case appsv1beta1.SchemeGroupVersion: + return appsv1beta1.SchemeGroupVersion.WithKind("Scale") + case appsv1beta2.SchemeGroupVersion: + return appsv1beta2.SchemeGroupVersion.WithKind("Scale") + default: + return autoscalingv1.SchemeGroupVersion.WithKind("Scale") + } } // New creates a new Scale object diff --git a/pkg/registry/extensions/replicaset/storage/BUILD b/pkg/registry/extensions/replicaset/storage/BUILD index 842735674eb..8c6c095b14c 100644 --- a/pkg/registry/extensions/replicaset/storage/BUILD +++ b/pkg/registry/extensions/replicaset/storage/BUILD @@ -34,7 +34,11 @@ go_library( srcs = ["storage.go"], importpath = "k8s.io/kubernetes/pkg/registry/extensions/replicaset/storage", deps = [ + "//pkg/apis/apps/v1beta1:go_default_library", + "//pkg/apis/apps/v1beta2:go_default_library", + "//pkg/apis/autoscaling/v1:go_default_library", "//pkg/apis/extensions:go_default_library", + "//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/extensions/validation:go_default_library", "//pkg/printers:go_default_library", "//pkg/printers/internalversion:go_default_library", diff --git a/pkg/registry/extensions/replicaset/storage/storage.go b/pkg/registry/extensions/replicaset/storage/storage.go index c443a89e072..9eff35bcea7 100644 --- a/pkg/registry/extensions/replicaset/storage/storage.go +++ b/pkg/registry/extensions/replicaset/storage/storage.go @@ -29,7 +29,11 @@ import ( "k8s.io/apiserver/pkg/registry/generic" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" + appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1" + appsv1beta2 "k8s.io/kubernetes/pkg/apis/apps/v1beta2" + autoscalingv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1" "k8s.io/kubernetes/pkg/apis/extensions" + extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -127,8 +131,17 @@ type ScaleREST struct { var _ = rest.Patcher(&ScaleREST{}) var _ = rest.GroupVersionKindProvider(&ScaleREST{}) -func (r *ScaleREST) GroupVersionKind() schema.GroupVersionKind { - return schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Scale"} +func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + switch containingGV { + case extensionsv1beta1.SchemeGroupVersion: + return extensionsv1beta1.SchemeGroupVersion.WithKind("Scale") + case appsv1beta1.SchemeGroupVersion: + return appsv1beta1.SchemeGroupVersion.WithKind("Scale") + case appsv1beta2.SchemeGroupVersion: + return appsv1beta2.SchemeGroupVersion.WithKind("Scale") + default: + return autoscalingv1.SchemeGroupVersion.WithKind("Scale") + } } // New creates a new Scale object diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go index b6c0ccad496..bb82e41393a 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go @@ -878,7 +878,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag apiResource.Categories = categoriesProvider.Categories() } if gvkProvider, ok := storage.(rest.GroupVersionKindProvider); ok { - gvk := gvkProvider.GroupVersionKind() + gvk := gvkProvider.GroupVersionKind(a.group.GroupVersion) apiResource.Group = gvk.Group apiResource.Version = gvk.Version apiResource.Kind = gvk.Kind diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go index 42a3b0973c3..21673110fd5 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go @@ -82,7 +82,7 @@ type CategoriesProvider interface { // This trumps KindProvider since it is capable of providing the information required. // TODO KindProvider (only used by federation) should be removed and replaced with this, but that presents greater risk late in 1.8. type GroupVersionKindProvider interface { - GroupVersionKind() schema.GroupVersionKind + GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind } // Lister is an object that can retrieve resources that match the provided field and label criteria. From 5913fccada6097c984b168ab15c243a8b20876e5 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Fri, 27 Oct 2017 04:29:04 -0400 Subject: [PATCH 2/3] Use GVK from storage in API registration --- pkg/registry/core/pod/storage/BUILD | 1 + pkg/registry/core/rest/storage_core.go | 12 +++--------- .../apiserver/pkg/endpoints/apiserver_test.go | 14 +++++++++----- .../k8s.io/apiserver/pkg/endpoints/groupversion.go | 6 ------ .../k8s.io/apiserver/pkg/endpoints/installer.go | 11 +++-------- .../apiserver/pkg/server/genericapiserver.go | 11 ++--------- 6 files changed, 18 insertions(+), 37 deletions(-) diff --git a/pkg/registry/core/pod/storage/BUILD b/pkg/registry/core/pod/storage/BUILD index 79246a4d200..02ccdf8ba60 100644 --- a/pkg/registry/core/pod/storage/BUILD +++ b/pkg/registry/core/pod/storage/BUILD @@ -60,6 +60,7 @@ go_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/util/wait:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library", diff --git a/pkg/registry/core/rest/storage_core.go b/pkg/registry/core/rest/storage_core.go index 2888b19d37f..241c6965ae7 100644 --- a/pkg/registry/core/rest/storage_core.go +++ b/pkg/registry/core/rest/storage_core.go @@ -93,19 +93,13 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *legacyscheme.Registry.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{}, - Scheme: legacyscheme.Scheme, - ParameterCodec: legacyscheme.ParameterCodec, - NegotiatedSerializer: legacyscheme.Codecs, - SubresourceGroupVersionKind: map[string]schema.GroupVersionKind{}, - } - if autoscalingGroupVersion := (schema.GroupVersion{Group: "autoscaling", Version: "v1"}); legacyscheme.Registry.IsEnabledVersion(autoscalingGroupVersion) { - apiGroupInfo.SubresourceGroupVersionKind["replicationcontrollers/scale"] = autoscalingGroupVersion.WithKind("Scale") + Scheme: legacyscheme.Scheme, + ParameterCodec: legacyscheme.ParameterCodec, + NegotiatedSerializer: legacyscheme.Codecs, } var podDisruptionClient policyclient.PodDisruptionBudgetsGetter if policyGroupVersion := (schema.GroupVersion{Group: "policy", Version: "v1beta1"}); legacyscheme.Registry.IsEnabledVersion(policyGroupVersion) { - apiGroupInfo.SubresourceGroupVersionKind["pods/eviction"] = policyGroupVersion.WithKind("Eviction") - var err error podDisruptionClient, err = policyclient.NewForConfig(c.LoopbackClientConfig) if err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/apiserver_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/apiserver_test.go index f6ac5353ff8..4dd05a8beea 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/apiserver_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/apiserver_test.go @@ -3867,7 +3867,8 @@ func TestUpdateChecksAPIVersion(t *testing.T) { } type SimpleXGSubresourceRESTStorage struct { - item genericapitesting.SimpleXGSubresource + item genericapitesting.SimpleXGSubresource + itemGVK schema.GroupVersionKind } func (storage *SimpleXGSubresourceRESTStorage) New() runtime.Object { @@ -3878,6 +3879,12 @@ func (storage *SimpleXGSubresourceRESTStorage) Get(ctx request.Context, id strin return storage.item.DeepCopyObject(), nil } +var _ = rest.GroupVersionKindProvider(&SimpleXGSubresourceRESTStorage{}) + +func (storage *SimpleXGSubresourceRESTStorage) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + return storage.itemGVK +} + func TestXGSubresource(t *testing.T) { container := restful.NewContainer() container.Router(restful.CurlyRouter{}) @@ -3888,6 +3895,7 @@ func TestXGSubresource(t *testing.T) { item: genericapitesting.SimpleXGSubresource{ SubresourceInfo: "foo", }, + itemGVK: testGroup2Version.WithKind("SimpleXGSubresource"), } storage := map[string]rest.Storage{ "simple": &SimpleRESTStorage{}, @@ -3913,10 +3921,6 @@ func TestXGSubresource(t *testing.T) { GroupVersion: testGroupVersion, OptionsExternalVersion: &testGroupVersion, Serializer: codecs, - - SubresourceGroupVersionKind: map[string]schema.GroupVersionKind{ - "simple/subsimple": testGroup2Version.WithKind("SimpleXGSubresource"), - }, } if err := (&group).InstallREST(container); err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/groupversion.go b/staging/src/k8s.io/apiserver/pkg/endpoints/groupversion.go index a60e4563125..4b882375817 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/groupversion.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/groupversion.go @@ -75,12 +75,6 @@ type APIGroupVersion struct { MinRequestTimeout time.Duration - // SubresourceGroupVersionKind contains the GroupVersionKind overrides for each subresource that is - // accessible from this API group version. The GroupVersionKind is that of the external version of - // the subresource. The key of this map should be the path of the subresource. The keys here should - // match the keys in the Storage map above for subresources. - SubresourceGroupVersionKind map[string]schema.GroupVersionKind - // EnableAPIResponseCompression indicates whether API Responses should support compression // if the client requests it via Accept-Encoding EnableAPIResponseCompression bool diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go index bb82e41393a..87bf1700d2b 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go @@ -144,8 +144,9 @@ func (a *APIInstaller) newWebService() *restful.WebService { // object. If the storage object is a subresource and has an override supplied for it, it returns // the group version kind supplied in the override. func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schema.GroupVersionKind, error) { - if fqKindToRegister, ok := a.group.SubresourceGroupVersionKind[path]; ok { - return fqKindToRegister, nil + // Let the storage tell us exactly what GVK it has + if gvkProvider, ok := storage.(rest.GroupVersionKindProvider); ok { + return gvkProvider.GroupVersionKind(a.group.GroupVersion), nil } object := storage.New() @@ -162,12 +163,6 @@ func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schem fqKindToRegister = a.group.GroupVersion.WithKind(fqKind.Kind) break } - - // TODO: keep rid of extensions api group dependency here - // This keeps it doing what it was doing before, but it doesn't feel right. - if fqKind.Group == "extensions" && fqKind.Kind == "ThirdPartyResourceData" { - fqKindToRegister = a.group.GroupVersion.WithKind(fqKind.Kind) - } } if fqKindToRegister.Empty() { return schema.GroupVersionKind{}, fmt.Errorf("unable to locate fully qualified kind for %v: found %v when registering for %v", reflect.TypeOf(object), fqKinds, a.group.GroupVersion) diff --git a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go index 6dc65a20c87..3109bb35667 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go +++ b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go @@ -70,12 +70,6 @@ type APIGroupInfo struct { NegotiatedSerializer runtime.NegotiatedSerializer // ParameterCodec performs conversions for query parameters passed to API calls ParameterCodec runtime.ParameterCodec - - // SubresourceGroupVersionKind contains the GroupVersionKind overrides for each subresource that is - // accessible from this API group version. The GroupVersionKind is that of the external version of - // the subresource. The key of this map should be the path of the subresource. The keys here should - // match the keys in the Storage map above for subresources. - SubresourceGroupVersionKind map[string]schema.GroupVersionKind } // GenericAPIServer contains state for a Kubernetes cluster api server. @@ -435,9 +429,8 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV UnsafeConvertor: runtime.UnsafeObjectConvertor(apiGroupInfo.Scheme), Defaulter: apiGroupInfo.Scheme, Typer: apiGroupInfo.Scheme, - SubresourceGroupVersionKind: apiGroupInfo.SubresourceGroupVersionKind, - Linker: apiGroupInfo.GroupMeta.SelfLinker, - Mapper: apiGroupInfo.GroupMeta.RESTMapper, + Linker: apiGroupInfo.GroupMeta.SelfLinker, + Mapper: apiGroupInfo.GroupMeta.RESTMapper, Admit: s.admissionControl, Context: s.RequestContextMapper(), From 1a8bed4b7e86beff1ae8a8c8cf50d38300700f44 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Fri, 27 Oct 2017 22:01:32 -0400 Subject: [PATCH 3/3] Test scale subresource discovery --- test/integration/BUILD | 1 + test/integration/scale/BUILD | 37 +++++ test/integration/scale/scale_test.go | 236 +++++++++++++++++++++++++++ 3 files changed, 274 insertions(+) create mode 100644 test/integration/scale/BUILD create mode 100644 test/integration/scale/scale_test.go diff --git a/test/integration/BUILD b/test/integration/BUILD index 706d30a8b87..045c0f38c23 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -51,6 +51,7 @@ filegroup( "//test/integration/quota:all-srcs", "//test/integration/replicaset:all-srcs", "//test/integration/replicationcontroller:all-srcs", + "//test/integration/scale:all-srcs", "//test/integration/scheduler:all-srcs", "//test/integration/scheduler_perf:all-srcs", "//test/integration/secrets:all-srcs", diff --git a/test/integration/scale/BUILD b/test/integration/scale/BUILD new file mode 100644 index 00000000000..6f55ba0de37 --- /dev/null +++ b/test/integration/scale/BUILD @@ -0,0 +1,37 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_test", +) + +go_test( + name = "go_default_test", + size = "large", + srcs = ["scale_test.go"], + importpath = "k8s.io/kubernetes/test/integration/scale", + tags = ["integration"], + deps = [ + "//cmd/kube-apiserver/app/testing:go_default_library", + "//vendor/github.com/coreos/pkg/capnslog:go_default_library", + "//vendor/k8s.io/api/apps/v1beta2:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/client-go/kubernetes:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/test/integration/scale/scale_test.go b/test/integration/scale/scale_test.go new file mode 100644 index 00000000000..c08c1575fe3 --- /dev/null +++ b/test/integration/scale/scale_test.go @@ -0,0 +1,236 @@ +/* +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 ( + "encoding/json" + "path" + "strings" + "testing" + + "github.com/coreos/pkg/capnslog" + + appsv1beta2 "k8s.io/api/apps/v1beta2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes" + apitesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing" +) + +type subresourceTest struct { + resource schema.GroupVersionResource + kind schema.GroupVersionKind +} + +func makeGVR(group, version, resource string) schema.GroupVersionResource { + return schema.GroupVersionResource{Group: group, Version: version, Resource: resource} +} +func makeGVK(group, version, kind string) schema.GroupVersionKind { + return schema.GroupVersionKind{Group: group, Version: version, Kind: kind} +} + +func TestScaleSubresources(t *testing.T) { + clientSet, tearDown := setup(t) + defer tearDown() + + resourceLists, err := clientSet.Discovery().ServerResources() + if err != nil { + t.Fatal(err) + } + + expectedScaleSubresources := map[schema.GroupVersionResource]schema.GroupVersionKind{ + makeGVR("", "v1", "replicationcontrollers/scale"): makeGVK("autoscaling", "v1", "Scale"), + + makeGVR("extensions", "v1beta1", "deployments/scale"): makeGVK("extensions", "v1beta1", "Scale"), + makeGVR("extensions", "v1beta1", "replicationcontrollers/scale"): makeGVK("extensions", "v1beta1", "Scale"), + makeGVR("extensions", "v1beta1", "replicasets/scale"): makeGVK("extensions", "v1beta1", "Scale"), + + makeGVR("apps", "v1beta1", "deployments/scale"): makeGVK("apps", "v1beta1", "Scale"), + makeGVR("apps", "v1beta1", "statefulsets/scale"): makeGVK("apps", "v1beta1", "Scale"), + + makeGVR("apps", "v1beta2", "deployments/scale"): makeGVK("apps", "v1beta2", "Scale"), + makeGVR("apps", "v1beta2", "replicasets/scale"): makeGVK("apps", "v1beta2", "Scale"), + makeGVR("apps", "v1beta2", "statefulsets/scale"): makeGVK("apps", "v1beta2", "Scale"), + + // makeGVR("apps", "v1", "deployments/scale"): makeGVK("autoscaling", "v1", "Scale"), + // makeGVR("apps", "v1", "replicasets/scale"): makeGVK("autoscaling", "v1", "Scale"), + // makeGVR("apps", "v1", "statefulsets/scale"): makeGVK("autoscaling", "v1", "Scale"), + } + + autoscalingGVK := schema.GroupVersionKind{Group: "autoscaling", Version: "v1", Kind: "Scale"} + + discoveredScaleSubresources := map[schema.GroupVersionResource]schema.GroupVersionKind{} + for _, resourceList := range resourceLists { + containingGV, err := schema.ParseGroupVersion(resourceList.GroupVersion) + if err != nil { + t.Fatalf("error getting group version for %#v: %v", resourceList, err) + } + + for _, resource := range resourceList.APIResources { + if !strings.HasSuffix(resource.Name, "/scale") { + continue + } + + gvr := containingGV.WithResource(resource.Name) + if _, exists := discoveredScaleSubresources[gvr]; exists { + t.Errorf("scale subresource %#v listed multiple times in discovery", gvr) + continue + } + + gvk := containingGV.WithKind(resource.Kind) + if resource.Group != "" { + gvk.Group = resource.Group + } + if resource.Version != "" { + gvk.Version = resource.Version + } + discoveredScaleSubresources[gvr] = gvk + } + } + + // Ensure nothing is missing + for gvr, gvk := range expectedScaleSubresources { + if _, ok := discoveredScaleSubresources[gvr]; !ok { + t.Errorf("expected scale subresource %#v of kind %#v was missing from discovery", gvr, gvk) + } + } + + // Ensure discovery lists expected types + for gvr, gvk := range discoveredScaleSubresources { + if expectedGVK, expected := expectedScaleSubresources[gvr]; !expected { + if gvk == autoscalingGVK { + t.Errorf("unexpected scale subresource %#v of kind %#v. new scale subresource should be added to expectedScaleSubresources", gvr, gvk) + } else { + t.Errorf("unexpected scale subresource %#v of kind %#v. new scale resources are expected to use Scale from the autoscaling/v1 API group", gvr, gvk) + } + continue + } else if expectedGVK != gvk { + t.Errorf("scale subresource %#v should be of kind %#v, but %#v was listed in discovery", gvr, expectedGVK, gvk) + continue + } + } + + // Create objects required to exercise scale subresources + if _, err := clientSet.CoreV1().ReplicationControllers("default").Create(rcStub); err != nil { + t.Fatal(err) + } + if _, err := clientSet.AppsV1beta2().ReplicaSets("default").Create(rsStub); err != nil { + t.Fatal(err) + } + if _, err := clientSet.AppsV1beta2().Deployments("default").Create(deploymentStub); err != nil { + t.Fatal(err) + } + if _, err := clientSet.AppsV1beta2().StatefulSets("default").Create(ssStub); err != nil { + t.Fatal(err) + } + + // Ensure scale subresources return and accept expected kinds + for gvr, gvk := range discoveredScaleSubresources { + prefix := "/apis" + if gvr.Group == corev1.GroupName { + prefix = "/api" + } + + resourceParts := strings.SplitN(gvr.Resource, "/", 2) + + urlPath := path.Join(prefix, gvr.Group, gvr.Version, "namespaces", "default", resourceParts[0], "test", resourceParts[1]) + obj := &unstructured.Unstructured{} + + getData, err := clientSet.CoreV1().RESTClient().Get().AbsPath(urlPath).DoRaw() + if err != nil { + t.Errorf("error fetching %s: %v", urlPath, err) + continue + } + if err := json.Unmarshal(getData, obj); err != nil { + t.Errorf("error decoding %s: %v", urlPath, err) + t.Log(string(getData)) + continue + } + + if obj.GetObjectKind().GroupVersionKind() != gvk { + t.Errorf("expected %#v, got %#v from %s", gvk, obj.GetObjectKind().GroupVersionKind(), urlPath) + t.Log(string(getData)) + continue + } + + updateData, err := clientSet.CoreV1().RESTClient().Put().AbsPath(urlPath).Body(getData).DoRaw() + if err != nil { + t.Errorf("error putting to %s: %v", urlPath, err) + t.Log(string(getData)) + t.Log(string(updateData)) + continue + } + } +} + +var ( + replicas = int32(1) + + podStub = corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}}, + Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "test", Image: "busybox"}}}, + } + + rcStub = &corev1.ReplicationController{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: corev1.ReplicationControllerSpec{Selector: podStub.Labels, Replicas: &replicas, Template: &podStub}, + } + + rsStub = &appsv1beta2.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: appsv1beta2.ReplicaSetSpec{Selector: &metav1.LabelSelector{MatchLabels: podStub.Labels}, Replicas: &replicas, Template: podStub}, + } + + deploymentStub = &appsv1beta2.Deployment{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: appsv1beta2.DeploymentSpec{Selector: &metav1.LabelSelector{MatchLabels: podStub.Labels}, Replicas: &replicas, Template: podStub}, + } + + ssStub = &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: appsv1beta2.StatefulSetSpec{Selector: &metav1.LabelSelector{MatchLabels: podStub.Labels}, Replicas: &replicas, Template: podStub}, + } +) + +func setup(t *testing.T) (client kubernetes.Interface, tearDown func()) { + masterConfig, tearDownMaster := apitesting.StartTestServerOrDie(t) + + // TODO: Disable logging here until we resolve teardown issues which result in + // massive log spam. Another path forward would be to refactor + // StartTestServerOrDie to work with the etcd instance already started by the + // integration test scripts. + // See https://github.com/kubernetes/kubernetes/issues/49489. + repo, err := capnslog.GetRepoLogger("github.com/coreos/etcd") + if err != nil { + t.Fatalf("couldn't configure logging: %v", err) + } + repo.SetLogLevel(map[string]capnslog.LogLevel{ + "etcdserver/api/v3rpc": capnslog.CRITICAL, + }) + + masterConfig.AcceptContentTypes = "" + masterConfig.ContentType = "" + masterConfig.NegotiatedSerializer = nil + clientSet, err := kubernetes.NewForConfig(masterConfig) + if err != nil { + t.Fatalf("error creating clientset: %v", err) + } + + return clientSet, tearDownMaster +}