mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
Merge pull request #54683 from liggitt/subresource-gvk
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Fix subresource discovery and versioning Fixes https://github.com/kubernetes/kubernetes/issues/54684 Related to https://github.com/kubernetes/kubernetes/pull/54586 Allows distinct subresource group/version/kind to be used for each version (gives us a path to move to autoscaling/v1 for apps, or policy/v1 for eviction, etc) Added tests to ensure scale subresources have expected discovery info, and that the object returned matches discovery, and that the endpoint accepts the advertised version ```release-note Fixes discovery information for scale subresources in the apps API group ```
This commit is contained in:
commit
0c1f25fc1b
@ -35,6 +35,9 @@ go_library(
|
|||||||
importpath = "k8s.io/kubernetes/pkg/registry/apps/statefulset/storage",
|
importpath = "k8s.io/kubernetes/pkg/registry/apps/statefulset/storage",
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/apps:go_default_library",
|
"//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:go_default_library",
|
||||||
"//pkg/apis/extensions/validation:go_default_library",
|
"//pkg/apis/extensions/validation:go_default_library",
|
||||||
"//pkg/printers:go_default_library",
|
"//pkg/printers:go_default_library",
|
||||||
|
@ -28,6 +28,9 @@ import (
|
|||||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps"
|
"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"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
|
extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
@ -125,8 +128,15 @@ type ScaleREST struct {
|
|||||||
var _ = rest.Patcher(&ScaleREST{})
|
var _ = rest.Patcher(&ScaleREST{})
|
||||||
var _ = rest.GroupVersionKindProvider(&ScaleREST{})
|
var _ = rest.GroupVersionKindProvider(&ScaleREST{})
|
||||||
|
|
||||||
func (r *ScaleREST) GroupVersionKind() schema.GroupVersionKind {
|
func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind {
|
||||||
return schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Scale"}
|
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
|
// New creates a new Scale object
|
||||||
|
@ -60,6 +60,7 @@ go_library(
|
|||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/labels:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime: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/apimachinery/pkg/util/wait:go_default_library",
|
||||||
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||||
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
@ -64,6 +65,12 @@ type EvictionREST struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _ = rest.Creater(&EvictionREST{})
|
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
|
// New creates a new eviction resource
|
||||||
func (r *EvictionREST) New() runtime.Object {
|
func (r *EvictionREST) New() runtime.Object {
|
||||||
|
@ -36,7 +36,9 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/apis/autoscaling: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/autoscaling/validation:go_default_library",
|
||||||
|
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||||
"//pkg/printers:go_default_library",
|
"//pkg/printers:go_default_library",
|
||||||
"//pkg/printers/internalversion:go_default_library",
|
"//pkg/printers/internalversion:go_default_library",
|
||||||
"//pkg/printers/storage:go_default_library",
|
"//pkg/printers/storage:go_default_library",
|
||||||
|
@ -32,7 +32,9 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
|
autoscalingv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling/validation"
|
"k8s.io/kubernetes/pkg/apis/autoscaling/validation"
|
||||||
|
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
@ -129,8 +131,13 @@ type ScaleREST struct {
|
|||||||
var _ = rest.Patcher(&ScaleREST{})
|
var _ = rest.Patcher(&ScaleREST{})
|
||||||
var _ = rest.GroupVersionKindProvider(&ScaleREST{})
|
var _ = rest.GroupVersionKindProvider(&ScaleREST{})
|
||||||
|
|
||||||
func (r *ScaleREST) GroupVersionKind() schema.GroupVersionKind {
|
func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind {
|
||||||
return schema.GroupVersionKind{Group: "autoscaling", Version: "v1", Kind: "Scale"}
|
switch containingGV {
|
||||||
|
case extensionsv1beta1.SchemeGroupVersion:
|
||||||
|
return extensionsv1beta1.SchemeGroupVersion.WithKind("Scale")
|
||||||
|
default:
|
||||||
|
return autoscalingv1.SchemeGroupVersion.WithKind("Scale")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Scale object
|
// New creates a new Scale object
|
||||||
|
@ -96,16 +96,10 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
|
|||||||
Scheme: legacyscheme.Scheme,
|
Scheme: legacyscheme.Scheme,
|
||||||
ParameterCodec: legacyscheme.ParameterCodec,
|
ParameterCodec: legacyscheme.ParameterCodec,
|
||||||
NegotiatedSerializer: legacyscheme.Codecs,
|
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var podDisruptionClient policyclient.PodDisruptionBudgetsGetter
|
var podDisruptionClient policyclient.PodDisruptionBudgetsGetter
|
||||||
if policyGroupVersion := (schema.GroupVersion{Group: "policy", Version: "v1beta1"}); legacyscheme.Registry.IsEnabledVersion(policyGroupVersion) {
|
if policyGroupVersion := (schema.GroupVersion{Group: "policy", Version: "v1beta1"}); legacyscheme.Registry.IsEnabledVersion(policyGroupVersion) {
|
||||||
apiGroupInfo.SubresourceGroupVersionKind["pods/eviction"] = policyGroupVersion.WithKind("Eviction")
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
podDisruptionClient, err = policyclient.NewForConfig(c.LoopbackClientConfig)
|
podDisruptionClient, err = policyclient.NewForConfig(c.LoopbackClientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -36,7 +36,11 @@ go_library(
|
|||||||
srcs = ["storage.go"],
|
srcs = ["storage.go"],
|
||||||
importpath = "k8s.io/kubernetes/pkg/registry/extensions/deployment/storage",
|
importpath = "k8s.io/kubernetes/pkg/registry/extensions/deployment/storage",
|
||||||
deps = [
|
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:go_default_library",
|
||||||
|
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||||
"//pkg/apis/extensions/validation:go_default_library",
|
"//pkg/apis/extensions/validation:go_default_library",
|
||||||
"//pkg/registry/extensions/deployment:go_default_library",
|
"//pkg/registry/extensions/deployment:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
|
@ -30,7 +30,11 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
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"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
|
extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
|
||||||
"k8s.io/kubernetes/pkg/registry/extensions/deployment"
|
"k8s.io/kubernetes/pkg/registry/extensions/deployment"
|
||||||
)
|
)
|
||||||
@ -193,8 +197,17 @@ type ScaleREST struct {
|
|||||||
var _ = rest.Patcher(&ScaleREST{})
|
var _ = rest.Patcher(&ScaleREST{})
|
||||||
var _ = rest.GroupVersionKindProvider(&ScaleREST{})
|
var _ = rest.GroupVersionKindProvider(&ScaleREST{})
|
||||||
|
|
||||||
func (r *ScaleREST) GroupVersionKind() schema.GroupVersionKind {
|
func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind {
|
||||||
return schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Scale"}
|
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
|
// New creates a new Scale object
|
||||||
|
@ -34,7 +34,11 @@ go_library(
|
|||||||
srcs = ["storage.go"],
|
srcs = ["storage.go"],
|
||||||
importpath = "k8s.io/kubernetes/pkg/registry/extensions/replicaset/storage",
|
importpath = "k8s.io/kubernetes/pkg/registry/extensions/replicaset/storage",
|
||||||
deps = [
|
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:go_default_library",
|
||||||
|
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||||
"//pkg/apis/extensions/validation:go_default_library",
|
"//pkg/apis/extensions/validation:go_default_library",
|
||||||
"//pkg/printers:go_default_library",
|
"//pkg/printers:go_default_library",
|
||||||
"//pkg/printers/internalversion:go_default_library",
|
"//pkg/printers/internalversion:go_default_library",
|
||||||
|
@ -29,7 +29,11 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"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"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
|
extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
@ -127,8 +131,17 @@ type ScaleREST struct {
|
|||||||
var _ = rest.Patcher(&ScaleREST{})
|
var _ = rest.Patcher(&ScaleREST{})
|
||||||
var _ = rest.GroupVersionKindProvider(&ScaleREST{})
|
var _ = rest.GroupVersionKindProvider(&ScaleREST{})
|
||||||
|
|
||||||
func (r *ScaleREST) GroupVersionKind() schema.GroupVersionKind {
|
func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind {
|
||||||
return schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Scale"}
|
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
|
// New creates a new Scale object
|
||||||
|
@ -3868,6 +3868,7 @@ func TestUpdateChecksAPIVersion(t *testing.T) {
|
|||||||
|
|
||||||
type SimpleXGSubresourceRESTStorage struct {
|
type SimpleXGSubresourceRESTStorage struct {
|
||||||
item genericapitesting.SimpleXGSubresource
|
item genericapitesting.SimpleXGSubresource
|
||||||
|
itemGVK schema.GroupVersionKind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *SimpleXGSubresourceRESTStorage) New() runtime.Object {
|
func (storage *SimpleXGSubresourceRESTStorage) New() runtime.Object {
|
||||||
@ -3878,6 +3879,12 @@ func (storage *SimpleXGSubresourceRESTStorage) Get(ctx request.Context, id strin
|
|||||||
return storage.item.DeepCopyObject(), nil
|
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) {
|
func TestXGSubresource(t *testing.T) {
|
||||||
container := restful.NewContainer()
|
container := restful.NewContainer()
|
||||||
container.Router(restful.CurlyRouter{})
|
container.Router(restful.CurlyRouter{})
|
||||||
@ -3888,6 +3895,7 @@ func TestXGSubresource(t *testing.T) {
|
|||||||
item: genericapitesting.SimpleXGSubresource{
|
item: genericapitesting.SimpleXGSubresource{
|
||||||
SubresourceInfo: "foo",
|
SubresourceInfo: "foo",
|
||||||
},
|
},
|
||||||
|
itemGVK: testGroup2Version.WithKind("SimpleXGSubresource"),
|
||||||
}
|
}
|
||||||
storage := map[string]rest.Storage{
|
storage := map[string]rest.Storage{
|
||||||
"simple": &SimpleRESTStorage{},
|
"simple": &SimpleRESTStorage{},
|
||||||
@ -3913,10 +3921,6 @@ func TestXGSubresource(t *testing.T) {
|
|||||||
GroupVersion: testGroupVersion,
|
GroupVersion: testGroupVersion,
|
||||||
OptionsExternalVersion: &testGroupVersion,
|
OptionsExternalVersion: &testGroupVersion,
|
||||||
Serializer: codecs,
|
Serializer: codecs,
|
||||||
|
|
||||||
SubresourceGroupVersionKind: map[string]schema.GroupVersionKind{
|
|
||||||
"simple/subsimple": testGroup2Version.WithKind("SimpleXGSubresource"),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := (&group).InstallREST(container); err != nil {
|
if err := (&group).InstallREST(container); err != nil {
|
||||||
|
@ -75,12 +75,6 @@ type APIGroupVersion struct {
|
|||||||
|
|
||||||
MinRequestTimeout time.Duration
|
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
|
// EnableAPIResponseCompression indicates whether API Responses should support compression
|
||||||
// if the client requests it via Accept-Encoding
|
// if the client requests it via Accept-Encoding
|
||||||
EnableAPIResponseCompression bool
|
EnableAPIResponseCompression bool
|
||||||
|
@ -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
|
// 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.
|
// the group version kind supplied in the override.
|
||||||
func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schema.GroupVersionKind, error) {
|
func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schema.GroupVersionKind, error) {
|
||||||
if fqKindToRegister, ok := a.group.SubresourceGroupVersionKind[path]; ok {
|
// Let the storage tell us exactly what GVK it has
|
||||||
return fqKindToRegister, nil
|
if gvkProvider, ok := storage.(rest.GroupVersionKindProvider); ok {
|
||||||
|
return gvkProvider.GroupVersionKind(a.group.GroupVersion), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
object := storage.New()
|
object := storage.New()
|
||||||
@ -162,12 +163,6 @@ func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schem
|
|||||||
fqKindToRegister = a.group.GroupVersion.WithKind(fqKind.Kind)
|
fqKindToRegister = a.group.GroupVersion.WithKind(fqKind.Kind)
|
||||||
break
|
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() {
|
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)
|
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)
|
||||||
@ -878,7 +873,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
apiResource.Categories = categoriesProvider.Categories()
|
apiResource.Categories = categoriesProvider.Categories()
|
||||||
}
|
}
|
||||||
if gvkProvider, ok := storage.(rest.GroupVersionKindProvider); ok {
|
if gvkProvider, ok := storage.(rest.GroupVersionKindProvider); ok {
|
||||||
gvk := gvkProvider.GroupVersionKind()
|
gvk := gvkProvider.GroupVersionKind(a.group.GroupVersion)
|
||||||
apiResource.Group = gvk.Group
|
apiResource.Group = gvk.Group
|
||||||
apiResource.Version = gvk.Version
|
apiResource.Version = gvk.Version
|
||||||
apiResource.Kind = gvk.Kind
|
apiResource.Kind = gvk.Kind
|
||||||
|
@ -82,7 +82,7 @@ type CategoriesProvider interface {
|
|||||||
// This trumps KindProvider since it is capable of providing the information required.
|
// 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.
|
// 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 {
|
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.
|
// Lister is an object that can retrieve resources that match the provided field and label criteria.
|
||||||
|
@ -70,12 +70,6 @@ type APIGroupInfo struct {
|
|||||||
NegotiatedSerializer runtime.NegotiatedSerializer
|
NegotiatedSerializer runtime.NegotiatedSerializer
|
||||||
// ParameterCodec performs conversions for query parameters passed to API calls
|
// ParameterCodec performs conversions for query parameters passed to API calls
|
||||||
ParameterCodec runtime.ParameterCodec
|
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.
|
// GenericAPIServer contains state for a Kubernetes cluster api server.
|
||||||
@ -435,7 +429,6 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
|
|||||||
UnsafeConvertor: runtime.UnsafeObjectConvertor(apiGroupInfo.Scheme),
|
UnsafeConvertor: runtime.UnsafeObjectConvertor(apiGroupInfo.Scheme),
|
||||||
Defaulter: apiGroupInfo.Scheme,
|
Defaulter: apiGroupInfo.Scheme,
|
||||||
Typer: apiGroupInfo.Scheme,
|
Typer: apiGroupInfo.Scheme,
|
||||||
SubresourceGroupVersionKind: apiGroupInfo.SubresourceGroupVersionKind,
|
|
||||||
Linker: apiGroupInfo.GroupMeta.SelfLinker,
|
Linker: apiGroupInfo.GroupMeta.SelfLinker,
|
||||||
Mapper: apiGroupInfo.GroupMeta.RESTMapper,
|
Mapper: apiGroupInfo.GroupMeta.RESTMapper,
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ filegroup(
|
|||||||
"//test/integration/quota:all-srcs",
|
"//test/integration/quota:all-srcs",
|
||||||
"//test/integration/replicaset:all-srcs",
|
"//test/integration/replicaset:all-srcs",
|
||||||
"//test/integration/replicationcontroller:all-srcs",
|
"//test/integration/replicationcontroller:all-srcs",
|
||||||
|
"//test/integration/scale:all-srcs",
|
||||||
"//test/integration/scheduler:all-srcs",
|
"//test/integration/scheduler:all-srcs",
|
||||||
"//test/integration/scheduler_perf:all-srcs",
|
"//test/integration/scheduler_perf:all-srcs",
|
||||||
"//test/integration/secrets:all-srcs",
|
"//test/integration/secrets:all-srcs",
|
||||||
|
37
test/integration/scale/BUILD
Normal file
37
test/integration/scale/BUILD
Normal file
@ -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"],
|
||||||
|
)
|
236
test/integration/scale/scale_test.go
Normal file
236
test/integration/scale/scale_test.go
Normal file
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user