From 0990ba1cc92449bbbd9b25a4391f1da834f8c5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arda=20G=C3=BC=C3=A7l=C3=BC?= Date: Wed, 2 Nov 2022 12:53:56 +0300 Subject: [PATCH] Introduce singularNameProvider for core types This introduces `singularNameProvider`. This provider will be used by core types to have their singular names are defined in discovery endpoint. Thanks to that, core resources singular name always have higher precedence than CRDs shortcuts or singular names. --- .../apps/daemonset/storage/storage.go | 7 +++++ .../apps/daemonset/storage/storage_test.go | 8 +++++ .../apps/deployment/storage/storage.go | 7 +++++ .../apps/deployment/storage/storage_test.go | 8 +++++ .../apps/replicaset/storage/storage.go | 7 +++++ .../apps/replicaset/storage/storage_test.go | 8 +++++ .../apps/statefulset/storage/storage.go | 7 +++++ .../apps/statefulset/storage/storage_test.go | 8 +++++ .../storage/storage.go | 7 +++++ .../storage/storage_test.go | 8 +++++ pkg/registry/batch/cronjob/storage/storage.go | 7 +++++ pkg/registry/batch/job/storage/storage.go | 7 +++++ .../batch/job/storage/storage_test.go | 8 +++++ .../certificates/storage/storage.go | 7 +++++ .../coordination/lease/storage/storage.go | 8 +++++ .../core/configmap/storage/storage.go | 7 +++++ .../core/configmap/storage/storage_test.go | 8 +++++ pkg/registry/core/endpoint/storage/storage.go | 7 +++++ pkg/registry/core/event/storage/storage.go | 7 +++++ .../core/event/storage/storage_test.go | 8 +++++ .../core/limitrange/storage/storage.go | 7 +++++ .../core/limitrange/storage/storage_test.go | 8 +++++ .../core/namespace/storage/storage.go | 7 +++++ .../core/namespace/storage/storage_test.go | 8 +++++ pkg/registry/core/node/storage/storage.go | 10 +++++++ .../core/persistentvolume/storage/storage.go | 7 +++++ .../persistentvolume/storage/storage_test.go | 8 +++++ .../persistentvolumeclaim/storage/storage.go | 7 +++++ .../storage/storage_test.go | 8 +++++ pkg/registry/core/pod/storage/storage.go | 7 +++++ pkg/registry/core/pod/storage/storage_test.go | 8 +++++ .../core/podtemplate/storage/storage.go | 8 +++++ .../core/podtemplate/storage/storage_test.go | 8 +++++ .../replicationcontroller/storage/storage.go | 7 +++++ .../storage/storage_test.go | 8 +++++ .../core/resourcequota/storage/storage.go | 7 +++++ .../resourcequota/storage/storage_test.go | 8 +++++ pkg/registry/core/secret/storage/storage.go | 8 +++++ .../core/secret/storage/storage_test.go | 8 +++++ pkg/registry/core/service/storage/storage.go | 7 +++++ .../core/service/storage/storage_test.go | 8 +++++ .../core/serviceaccount/storage/storage.go | 7 +++++ .../serviceaccount/storage/storage_test.go | 8 +++++ .../endpointslice/storage/storage.go | 8 +++++ .../networking/ingress/storage/storage.go | 7 +++++ .../ingress/storage/storage_test.go | 8 +++++ .../ingressclass/storage/storage.go | 8 +++++ .../networkpolicy/storage/storage.go | 7 +++++ .../networkpolicy/storage/storage_test.go | 8 +++++ .../poddisruptionbudget/storage/storage.go | 7 +++++ .../rbac/clusterrole/storage/storage.go | 7 +++++ .../clusterrolebinding/storage/storage.go | 8 +++++ pkg/registry/rbac/role/storage/storage.go | 7 +++++ .../rbac/rolebinding/storage/storage.go | 8 +++++ .../registrytest/singularNameProvider.go | 30 +++++++++++++++++++ .../priorityclass/storage/storage.go | 7 +++++ .../priorityclass/storage/storage_test.go | 8 +++++ .../storage/storageclass/storage/storage.go | 7 +++++ .../storageclass/storage/storage_test.go | 8 +++++ .../volumeattachment/storage/storage.go | 7 +++++ .../volumeattachment/storage/storage_test.go | 8 +++++ .../registry/customresourcedefinition/etcd.go | 7 +++++ .../apiserver/pkg/endpoints/installer.go | 3 ++ .../apiserver/pkg/registry/rest/rest.go | 6 ++++ test/cmd/discovery.sh | 2 +- 65 files changed, 501 insertions(+), 1 deletion(-) create mode 100644 pkg/registry/registrytest/singularNameProvider.go diff --git a/pkg/registry/apps/daemonset/storage/storage.go b/pkg/registry/apps/daemonset/storage/storage.go index 84df2450283..c40ac6fc36d 100644 --- a/pkg/registry/apps/daemonset/storage/storage.go +++ b/pkg/registry/apps/daemonset/storage/storage.go @@ -78,6 +78,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "daemonset" +} + // StatusREST implements the REST endpoint for changing the status of a daemonset type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/apps/daemonset/storage/storage_test.go b/pkg/registry/apps/daemonset/storage/storage_test.go index eaf15ffcdae..fcd06c180dd 100644 --- a/pkg/registry/apps/daemonset/storage/storage_test.go +++ b/pkg/registry/apps/daemonset/storage/storage_test.go @@ -197,4 +197,12 @@ func TestShortNames(t *testing.T) { registrytest.AssertShortNames(t, storage, expected) } +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "daemonset" + registrytest.AssertSingularName(t, storage, expected) +} + // TODO TestUpdateStatus diff --git a/pkg/registry/apps/deployment/storage/storage.go b/pkg/registry/apps/deployment/storage/storage.go index 8b05dd0b663..3da212d0974 100644 --- a/pkg/registry/apps/deployment/storage/storage.go +++ b/pkg/registry/apps/deployment/storage/storage.go @@ -130,6 +130,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "deployment" +} + // StatusREST implements the REST endpoint for changing the status of a deployment type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/apps/deployment/storage/storage_test.go b/pkg/registry/apps/deployment/storage/storage_test.go index d7b371040d2..05b14b0b45e 100644 --- a/pkg/registry/apps/deployment/storage/storage_test.go +++ b/pkg/registry/apps/deployment/storage/storage_test.go @@ -455,6 +455,14 @@ func TestCategories(t *testing.T) { registrytest.AssertCategories(t, storage.Deployment, expected) } +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Deployment.Store.DestroyFunc() + expected := "deployment" + registrytest.AssertSingularName(t, storage.Deployment, expected) +} + func TestScalePatchErrors(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) diff --git a/pkg/registry/apps/replicaset/storage/storage.go b/pkg/registry/apps/replicaset/storage/storage.go index 0c467d37327..97592c1d770 100644 --- a/pkg/registry/apps/replicaset/storage/storage.go +++ b/pkg/registry/apps/replicaset/storage/storage.go @@ -126,6 +126,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "replicaset" +} + // StatusREST implements the REST endpoint for changing the status of a ReplicaSet type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/apps/replicaset/storage/storage_test.go b/pkg/registry/apps/replicaset/storage/storage_test.go index 392c1f95b21..d6223bbe849 100644 --- a/pkg/registry/apps/replicaset/storage/storage_test.go +++ b/pkg/registry/apps/replicaset/storage/storage_test.go @@ -399,6 +399,14 @@ func TestCategories(t *testing.T) { registrytest.AssertCategories(t, storage.ReplicaSet, expected) } +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.ReplicaSet.Store.DestroyFunc() + expected := "replicaset" + registrytest.AssertSingularName(t, storage.ReplicaSet, expected) +} + func TestScalePatchErrors(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) diff --git a/pkg/registry/apps/statefulset/storage/storage.go b/pkg/registry/apps/statefulset/storage/storage.go index 47558534cdd..cf834362f9f 100644 --- a/pkg/registry/apps/statefulset/storage/storage.go +++ b/pkg/registry/apps/statefulset/storage/storage.go @@ -114,6 +114,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "statefulset" +} + // StatusREST implements the REST endpoint for changing the status of an statefulSet type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/apps/statefulset/storage/storage_test.go b/pkg/registry/apps/statefulset/storage/storage_test.go index cdce909bd77..649ffffed15 100644 --- a/pkg/registry/apps/statefulset/storage/storage_test.go +++ b/pkg/registry/apps/statefulset/storage/storage_test.go @@ -199,6 +199,14 @@ func TestCategories(t *testing.T) { registrytest.AssertCategories(t, storage.StatefulSet, expected) } +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.StatefulSet.Store.DestroyFunc() + expected := "statefulset" + registrytest.AssertSingularName(t, storage.StatefulSet, expected) +} + func TestShortNames(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) diff --git a/pkg/registry/autoscaling/horizontalpodautoscaler/storage/storage.go b/pkg/registry/autoscaling/horizontalpodautoscaler/storage/storage.go index 03171ed1ff0..44a7911eea3 100644 --- a/pkg/registry/autoscaling/horizontalpodautoscaler/storage/storage.go +++ b/pkg/registry/autoscaling/horizontalpodautoscaler/storage/storage.go @@ -78,6 +78,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "horizontalpodautoscaler" +} + // StatusREST implements the REST endpoint for changing the status of a daemonset type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/autoscaling/horizontalpodautoscaler/storage/storage_test.go b/pkg/registry/autoscaling/horizontalpodautoscaler/storage/storage_test.go index 589932db37f..bf269222cd9 100644 --- a/pkg/registry/autoscaling/horizontalpodautoscaler/storage/storage_test.go +++ b/pkg/registry/autoscaling/horizontalpodautoscaler/storage/storage_test.go @@ -176,6 +176,14 @@ func TestCategories(t *testing.T) { registrytest.AssertCategories(t, storage, expected) } +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "horizontalpodautoscaler" + registrytest.AssertSingularName(t, storage, expected) +} + func TestUpdateStatus(t *testing.T) { storage, statusStorage, server := newStorage(t) defer server.Terminate(t) diff --git a/pkg/registry/batch/cronjob/storage/storage.go b/pkg/registry/batch/cronjob/storage/storage.go index 637dc8f3754..51d453bfe74 100644 --- a/pkg/registry/batch/cronjob/storage/storage.go +++ b/pkg/registry/batch/cronjob/storage/storage.go @@ -76,6 +76,13 @@ func (r *REST) ShortNames() []string { return []string{"cj"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "cronjob" +} + // StatusREST implements the REST endpoint for changing the status of a resourcequota. type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/batch/job/storage/storage.go b/pkg/registry/batch/job/storage/storage.go index f6cfa679536..93c6eb8b606 100644 --- a/pkg/registry/batch/job/storage/storage.go +++ b/pkg/registry/batch/job/storage/storage.go @@ -96,6 +96,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "job" +} + func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { //nolint:staticcheck // SA1019 backwards compatibility //nolint: staticcheck diff --git a/pkg/registry/batch/job/storage/storage_test.go b/pkg/registry/batch/job/storage/storage_test.go index 765b3179509..5b9b991f61c 100644 --- a/pkg/registry/batch/job/storage/storage_test.go +++ b/pkg/registry/batch/job/storage/storage_test.go @@ -375,3 +375,11 @@ func TestCategories(t *testing.T) { expected := []string{"all"} registrytest.AssertCategories(t, storage.Job, expected) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Job.Store.DestroyFunc() + expected := "job" + registrytest.AssertSingularName(t, storage.Job, expected) +} diff --git a/pkg/registry/certificates/certificates/storage/storage.go b/pkg/registry/certificates/certificates/storage/storage.go index 8de7828efde..5c72cc2be68 100644 --- a/pkg/registry/certificates/certificates/storage/storage.go +++ b/pkg/registry/certificates/certificates/storage/storage.go @@ -79,6 +79,13 @@ func (r *REST) ShortNames() []string { return []string{"csr"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "certificatesigningrequest" +} + // StatusREST implements the REST endpoint for changing the status of a CSR. type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/coordination/lease/storage/storage.go b/pkg/registry/coordination/lease/storage/storage.go index 8989a293a6d..a0f67bc2ff4 100644 --- a/pkg/registry/coordination/lease/storage/storage.go +++ b/pkg/registry/coordination/lease/storage/storage.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/generic" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" coordinationapi "k8s.io/kubernetes/pkg/apis/coordination" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -52,3 +53,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "lease" +} diff --git a/pkg/registry/core/configmap/storage/storage.go b/pkg/registry/core/configmap/storage/storage.go index 8180c56e830..47648ded842 100644 --- a/pkg/registry/core/configmap/storage/storage.go +++ b/pkg/registry/core/configmap/storage/storage.go @@ -66,3 +66,10 @@ var _ rest.ShortNamesProvider = &REST{} func (r *REST) ShortNames() []string { return []string{"cm"} } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "configmap" +} diff --git a/pkg/registry/core/configmap/storage/storage_test.go b/pkg/registry/core/configmap/storage/storage_test.go index 04ccc8d8999..78b927d4586 100644 --- a/pkg/registry/core/configmap/storage/storage_test.go +++ b/pkg/registry/core/configmap/storage/storage_test.go @@ -172,3 +172,11 @@ func TestShortNames(t *testing.T) { expected := []string{"cm"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "configmap" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/endpoint/storage/storage.go b/pkg/registry/core/endpoint/storage/storage.go index ff082994cea..e0f36f29e73 100644 --- a/pkg/registry/core/endpoint/storage/storage.go +++ b/pkg/registry/core/endpoint/storage/storage.go @@ -60,3 +60,10 @@ var _ rest.ShortNamesProvider = &REST{} func (r *REST) ShortNames() []string { return []string{"ep"} } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "endpoint" +} diff --git a/pkg/registry/core/event/storage/storage.go b/pkg/registry/core/event/storage/storage.go index ee4498934d1..7be63d0ce60 100644 --- a/pkg/registry/core/event/storage/storage.go +++ b/pkg/registry/core/event/storage/storage.go @@ -64,3 +64,10 @@ var _ rest.ShortNamesProvider = &REST{} func (r *REST) ShortNames() []string { return []string{"ev"} } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "event" +} diff --git a/pkg/registry/core/event/storage/storage_test.go b/pkg/registry/core/event/storage/storage_test.go index 134de72b8bf..854c7776050 100644 --- a/pkg/registry/core/event/storage/storage_test.go +++ b/pkg/registry/core/event/storage/storage_test.go @@ -123,3 +123,11 @@ func TestShortNames(t *testing.T) { expected := []string{"ev"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "event" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/limitrange/storage/storage.go b/pkg/registry/core/limitrange/storage/storage.go index b3fd401f701..b286f7f9230 100644 --- a/pkg/registry/core/limitrange/storage/storage.go +++ b/pkg/registry/core/limitrange/storage/storage.go @@ -58,3 +58,10 @@ var _ rest.ShortNamesProvider = &REST{} func (r *REST) ShortNames() []string { return []string{"limits"} } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "limitrange" +} diff --git a/pkg/registry/core/limitrange/storage/storage_test.go b/pkg/registry/core/limitrange/storage/storage_test.go index 3bbcad7f5e3..38b16a3b7d0 100644 --- a/pkg/registry/core/limitrange/storage/storage_test.go +++ b/pkg/registry/core/limitrange/storage/storage_test.go @@ -171,3 +171,11 @@ func TestShortNames(t *testing.T) { expected := []string{"limits"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "limitrange" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/namespace/storage/storage.go b/pkg/registry/core/namespace/storage/storage.go index 37b130092ca..3201ca45498 100644 --- a/pkg/registry/core/namespace/storage/storage.go +++ b/pkg/registry/core/namespace/storage/storage.go @@ -291,6 +291,13 @@ func (r *REST) ShortNames() []string { return []string{"ns"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "namespace" +} + var _ rest.StorageVersionProvider = &REST{} func (r *REST) StorageVersion() runtime.GroupVersioner { diff --git a/pkg/registry/core/namespace/storage/storage_test.go b/pkg/registry/core/namespace/storage/storage_test.go index a1bfd9e9af8..e94c9b3fb33 100644 --- a/pkg/registry/core/namespace/storage/storage_test.go +++ b/pkg/registry/core/namespace/storage/storage_test.go @@ -628,3 +628,11 @@ func TestShortNames(t *testing.T) { expected := []string{"ns"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.store.DestroyFunc() + expected := "namespace" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/node/storage/storage.go b/pkg/registry/core/node/storage/storage.go index 56e806770f4..e8ecf8b9fe4 100644 --- a/pkg/registry/core/node/storage/storage.go +++ b/pkg/registry/core/node/storage/storage.go @@ -167,7 +167,17 @@ func (r *REST) ResourceLocation(ctx context.Context, id string) (*url.URL, http. return node.ResourceLocation(r, r.connection, r.proxyTransport, ctx, id) } +// Implement ShortNamesProvider +var _ rest.ShortNamesProvider = &REST{} + // ShortNames implements the ShortNamesProvider interface. Returns a list of short names for a resource. func (r *REST) ShortNames() []string { return []string{"no"} } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "node" +} diff --git a/pkg/registry/core/persistentvolume/storage/storage.go b/pkg/registry/core/persistentvolume/storage/storage.go index df65eabc879..06bd7beeb4c 100644 --- a/pkg/registry/core/persistentvolume/storage/storage.go +++ b/pkg/registry/core/persistentvolume/storage/storage.go @@ -73,6 +73,13 @@ func (r *REST) ShortNames() []string { return []string{"pv"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "persistentvolume" +} + // StatusREST implements the REST endpoint for changing the status of a persistentvolume. type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/core/persistentvolume/storage/storage_test.go b/pkg/registry/core/persistentvolume/storage/storage_test.go index c03fa3248a9..5c8a7b5bdce 100644 --- a/pkg/registry/core/persistentvolume/storage/storage_test.go +++ b/pkg/registry/core/persistentvolume/storage/storage_test.go @@ -208,3 +208,11 @@ func TestShortNames(t *testing.T) { expected := []string{"pv"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "persistentvolume" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/persistentvolumeclaim/storage/storage.go b/pkg/registry/core/persistentvolumeclaim/storage/storage.go index d472bbd8ef3..26e6d80c867 100644 --- a/pkg/registry/core/persistentvolumeclaim/storage/storage.go +++ b/pkg/registry/core/persistentvolumeclaim/storage/storage.go @@ -77,6 +77,13 @@ func (r *REST) ShortNames() []string { return []string{"pvc"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "persistentvolumeclaim" +} + // defaultOnRead sets interlinked fields that were not previously set on read. // We can't do this in the normal defaulting path because that same logic // applies on Get, Create, and Update, but we need to distinguish between them. diff --git a/pkg/registry/core/persistentvolumeclaim/storage/storage_test.go b/pkg/registry/core/persistentvolumeclaim/storage/storage_test.go index 54c0ca625f5..d94fed0fcfe 100644 --- a/pkg/registry/core/persistentvolumeclaim/storage/storage_test.go +++ b/pkg/registry/core/persistentvolumeclaim/storage/storage_test.go @@ -212,6 +212,14 @@ func TestShortNames(t *testing.T) { registrytest.AssertShortNames(t, storage, expected) } +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "persistentvolumeclaim" + registrytest.AssertSingularName(t, storage, expected) +} + func TestDefaultOnReadPvc(t *testing.T) { storage, _, server := newStorage(t) defer server.Terminate(t) diff --git a/pkg/registry/core/pod/storage/storage.go b/pkg/registry/core/pod/storage/storage.go index 3960918de62..034884960d9 100644 --- a/pkg/registry/core/pod/storage/storage.go +++ b/pkg/registry/core/pod/storage/storage.go @@ -142,6 +142,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "pod" +} + // BindingREST implements the REST endpoint for binding pods to nodes when etcd is in use. type BindingREST struct { store *genericregistry.Store diff --git a/pkg/registry/core/pod/storage/storage_test.go b/pkg/registry/core/pod/storage/storage_test.go index 1e15ca8a834..dc7160078c4 100644 --- a/pkg/registry/core/pod/storage/storage_test.go +++ b/pkg/registry/core/pod/storage/storage_test.go @@ -1274,3 +1274,11 @@ func TestCategories(t *testing.T) { expected := []string{"all"} registrytest.AssertCategories(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, _, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "pod" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/podtemplate/storage/storage.go b/pkg/registry/core/podtemplate/storage/storage.go index d7dca23868a..66d267d6777 100644 --- a/pkg/registry/core/podtemplate/storage/storage.go +++ b/pkg/registry/core/podtemplate/storage/storage.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/generic" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -53,3 +54,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { } return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "podtemplate" +} diff --git a/pkg/registry/core/podtemplate/storage/storage_test.go b/pkg/registry/core/podtemplate/storage/storage_test.go index 785fc6fcb62..59c3413f902 100644 --- a/pkg/registry/core/podtemplate/storage/storage_test.go +++ b/pkg/registry/core/podtemplate/storage/storage_test.go @@ -153,3 +153,11 @@ func TestWatch(t *testing.T) { }, ) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "podtemplate" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/replicationcontroller/storage/storage.go b/pkg/registry/core/replicationcontroller/storage/storage.go index 39a59f4a73e..d5fca9c0f96 100644 --- a/pkg/registry/core/replicationcontroller/storage/storage.go +++ b/pkg/registry/core/replicationcontroller/storage/storage.go @@ -122,6 +122,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "replicationcontroller" +} + // StatusREST implements the REST endpoint for changing the status of a replication controller type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/core/replicationcontroller/storage/storage_test.go b/pkg/registry/core/replicationcontroller/storage/storage_test.go index 009fed33b1a..60e133cb26a 100644 --- a/pkg/registry/core/replicationcontroller/storage/storage_test.go +++ b/pkg/registry/core/replicationcontroller/storage/storage_test.go @@ -352,6 +352,14 @@ func TestCategories(t *testing.T) { registrytest.AssertCategories(t, storage.Controller, expected) } +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Controller.Store.DestroyFunc() + expected := "replicationcontroller" + registrytest.AssertSingularName(t, storage.Controller, expected) +} + func TestScalePatchErrors(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) diff --git a/pkg/registry/core/resourcequota/storage/storage.go b/pkg/registry/core/resourcequota/storage/storage.go index d438ec792e2..76b71dd2096 100644 --- a/pkg/registry/core/resourcequota/storage/storage.go +++ b/pkg/registry/core/resourcequota/storage/storage.go @@ -72,6 +72,13 @@ func (r *REST) ShortNames() []string { return []string{"quota"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "resourcequota" +} + // StatusREST implements the REST endpoint for changing the status of a resourcequota. type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/core/resourcequota/storage/storage_test.go b/pkg/registry/core/resourcequota/storage/storage_test.go index 9b750553f83..8459c32bf7f 100644 --- a/pkg/registry/core/resourcequota/storage/storage_test.go +++ b/pkg/registry/core/resourcequota/storage/storage_test.go @@ -217,3 +217,11 @@ func TestShortNames(t *testing.T) { expected := []string{"quota"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "resourcequota" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/secret/storage/storage.go b/pkg/registry/core/secret/storage/storage.go index 81e2892df57..b02cb83546c 100644 --- a/pkg/registry/core/secret/storage/storage.go +++ b/pkg/registry/core/secret/storage/storage.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/generic" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/printers" @@ -57,3 +58,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { } return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "secret" +} diff --git a/pkg/registry/core/secret/storage/storage_test.go b/pkg/registry/core/secret/storage/storage_test.go index a3850a2dafe..68bc7dcb5fb 100644 --- a/pkg/registry/core/secret/storage/storage_test.go +++ b/pkg/registry/core/secret/storage/storage_test.go @@ -143,3 +143,11 @@ func TestWatch(t *testing.T) { }, ) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "secret" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/core/service/storage/storage.go b/pkg/registry/core/service/storage/storage.go index 4ee5428e819..172135ed88e 100644 --- a/pkg/registry/core/service/storage/storage.go +++ b/pkg/registry/core/service/storage/storage.go @@ -153,6 +153,13 @@ func (r *REST) Categories() []string { return []string{"all"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "service" +} + // Destroy cleans up everything on shutdown. func (r *REST) Destroy() { r.Store.Destroy() diff --git a/pkg/registry/core/service/storage/storage_test.go b/pkg/registry/core/service/storage/storage_test.go index 1345ed519fa..1cb514132df 100644 --- a/pkg/registry/core/service/storage/storage_test.go +++ b/pkg/registry/core/service/storage/storage_test.go @@ -279,6 +279,14 @@ func TestGenericCategories(t *testing.T) { registrytest.AssertCategories(t, storage, expected) } +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t, []api.IPFamily{api.IPv4Protocol}) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "service" + registrytest.AssertSingularName(t, storage, expected) +} + // // Tests of internal functions // diff --git a/pkg/registry/core/serviceaccount/storage/storage.go b/pkg/registry/core/serviceaccount/storage/storage.go index 60f83b74133..d44573bf607 100644 --- a/pkg/registry/core/serviceaccount/storage/storage.go +++ b/pkg/registry/core/serviceaccount/storage/storage.go @@ -84,3 +84,10 @@ var _ rest.ShortNamesProvider = &REST{} func (r *REST) ShortNames() []string { return []string{"sa"} } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "serviceaccount" +} diff --git a/pkg/registry/core/serviceaccount/storage/storage_test.go b/pkg/registry/core/serviceaccount/storage/storage_test.go index 220f5053047..dfaaa30b315 100644 --- a/pkg/registry/core/serviceaccount/storage/storage_test.go +++ b/pkg/registry/core/serviceaccount/storage/storage_test.go @@ -146,3 +146,11 @@ func TestShortNames(t *testing.T) { expected := []string{"sa"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "serviceaccount" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/discovery/endpointslice/storage/storage.go b/pkg/registry/discovery/endpointslice/storage/storage.go index 756553ad580..d8b4d1b9113 100644 --- a/pkg/registry/discovery/endpointslice/storage/storage.go +++ b/pkg/registry/discovery/endpointslice/storage/storage.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/generic" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/kubernetes/pkg/apis/discovery" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -51,3 +52,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { } return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "endpointslice" +} diff --git a/pkg/registry/networking/ingress/storage/storage.go b/pkg/registry/networking/ingress/storage/storage.go index 71ab37c455e..dd82551cb1d 100644 --- a/pkg/registry/networking/ingress/storage/storage.go +++ b/pkg/registry/networking/ingress/storage/storage.go @@ -70,6 +70,13 @@ func (r *REST) ShortNames() []string { return []string{"ing"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "ingress" +} + // StatusREST implements the REST endpoint for changing the status of an ingress type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/networking/ingress/storage/storage_test.go b/pkg/registry/networking/ingress/storage/storage_test.go index 28c42ea1c48..199ea5002e9 100644 --- a/pkg/registry/networking/ingress/storage/storage_test.go +++ b/pkg/registry/networking/ingress/storage/storage_test.go @@ -250,4 +250,12 @@ func TestShortNames(t *testing.T) { registrytest.AssertShortNames(t, storage, expected) } +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "ingress" + registrytest.AssertSingularName(t, storage, expected) +} + // TODO TestUpdateStatus diff --git a/pkg/registry/networking/ingressclass/storage/storage.go b/pkg/registry/networking/ingressclass/storage/storage.go index 187c7317cba..889b7398011 100644 --- a/pkg/registry/networking/ingressclass/storage/storage.go +++ b/pkg/registry/networking/ingressclass/storage/storage.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/generic" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/kubernetes/pkg/apis/networking" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -52,3 +53,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "ingressclass" +} diff --git a/pkg/registry/networking/networkpolicy/storage/storage.go b/pkg/registry/networking/networkpolicy/storage/storage.go index 0101077b662..8f2ed82fc16 100644 --- a/pkg/registry/networking/networkpolicy/storage/storage.go +++ b/pkg/registry/networking/networkpolicy/storage/storage.go @@ -72,6 +72,13 @@ func (r *REST) ShortNames() []string { return []string{"netpol"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "networkpolicy" +} + // StatusREST implements the REST endpoint for changing the status of an ingress type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/networking/networkpolicy/storage/storage_test.go b/pkg/registry/networking/networkpolicy/storage/storage_test.go index 15ab8780910..57685615099 100644 --- a/pkg/registry/networking/networkpolicy/storage/storage_test.go +++ b/pkg/registry/networking/networkpolicy/storage/storage_test.go @@ -198,6 +198,14 @@ func TestShortNames(t *testing.T) { registrytest.AssertShortNames(t, storage, expected) } +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "networkpolicy" + registrytest.AssertSingularName(t, storage, expected) +} + func TestStatusUpdate(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NetworkPolicyStatus, true)() storage, statusStorage, server := newStorage(t) diff --git a/pkg/registry/policy/poddisruptionbudget/storage/storage.go b/pkg/registry/policy/poddisruptionbudget/storage/storage.go index 4af2ea2429f..55fb2e360f6 100644 --- a/pkg/registry/policy/poddisruptionbudget/storage/storage.go +++ b/pkg/registry/policy/poddisruptionbudget/storage/storage.go @@ -67,6 +67,13 @@ func (r *REST) ShortNames() []string { return []string{"pdb"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "poddisruptionbudget" +} + // StatusREST implements the REST endpoint for changing the status of an podDisruptionBudget. type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/rbac/clusterrole/storage/storage.go b/pkg/registry/rbac/clusterrole/storage/storage.go index 59347f767a4..aa04dd376b4 100644 --- a/pkg/registry/rbac/clusterrole/storage/storage.go +++ b/pkg/registry/rbac/clusterrole/storage/storage.go @@ -51,3 +51,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "clusterrole" +} diff --git a/pkg/registry/rbac/clusterrolebinding/storage/storage.go b/pkg/registry/rbac/clusterrolebinding/storage/storage.go index 762730788b6..7d662fd726a 100644 --- a/pkg/registry/rbac/clusterrolebinding/storage/storage.go +++ b/pkg/registry/rbac/clusterrolebinding/storage/storage.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/generic" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -52,3 +53,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "clusterrolebinding" +} diff --git a/pkg/registry/rbac/role/storage/storage.go b/pkg/registry/rbac/role/storage/storage.go index 6e6700ede98..1eb312c12bf 100644 --- a/pkg/registry/rbac/role/storage/storage.go +++ b/pkg/registry/rbac/role/storage/storage.go @@ -51,3 +51,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "role" +} diff --git a/pkg/registry/rbac/rolebinding/storage/storage.go b/pkg/registry/rbac/rolebinding/storage/storage.go index 0cbcfa0f644..8a6ee171a3d 100644 --- a/pkg/registry/rbac/rolebinding/storage/storage.go +++ b/pkg/registry/rbac/rolebinding/storage/storage.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/generic" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -52,3 +53,10 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) { return &REST{store}, nil } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "rolebinding" +} diff --git a/pkg/registry/registrytest/singularNameProvider.go b/pkg/registry/registrytest/singularNameProvider.go new file mode 100644 index 00000000000..5056b0dd477 --- /dev/null +++ b/pkg/registry/registrytest/singularNameProvider.go @@ -0,0 +1,30 @@ +/* +Copyright 2014 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 registrytest + +import ( + "testing" + + "k8s.io/apiserver/pkg/registry/rest" +) + +func AssertSingularName(t *testing.T, storage rest.SingularNameProvider, expected string) { + actual := storage.SingularName() + if actual != expected { + t.Errorf("singular name not equal. expected = %v actual = %v", expected, actual) + } +} diff --git a/pkg/registry/scheduling/priorityclass/storage/storage.go b/pkg/registry/scheduling/priorityclass/storage/storage.go index b84a573a12e..b2e78035b19 100644 --- a/pkg/registry/scheduling/priorityclass/storage/storage.go +++ b/pkg/registry/scheduling/priorityclass/storage/storage.go @@ -67,6 +67,13 @@ func (r *REST) ShortNames() []string { return []string{"pc"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "priorityclass" +} + // Delete ensures that system priority classes are not deleted. func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { for _, spc := range schedulingapiv1.SystemPriorityClasses() { diff --git a/pkg/registry/scheduling/priorityclass/storage/storage_test.go b/pkg/registry/scheduling/priorityclass/storage/storage_test.go index de6eba80999..a0a0ae65de0 100644 --- a/pkg/registry/scheduling/priorityclass/storage/storage_test.go +++ b/pkg/registry/scheduling/priorityclass/storage/storage_test.go @@ -179,3 +179,11 @@ func TestShortNames(t *testing.T) { expected := []string{"pc"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "priorityclass" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/storage/storageclass/storage/storage.go b/pkg/registry/storage/storageclass/storage/storage.go index fb4394e6641..fbac3a484ef 100644 --- a/pkg/registry/storage/storageclass/storage/storage.go +++ b/pkg/registry/storage/storageclass/storage/storage.go @@ -62,3 +62,10 @@ var _ rest.ShortNamesProvider = &REST{} func (r *REST) ShortNames() []string { return []string{"sc"} } + +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "storageclass" +} diff --git a/pkg/registry/storage/storageclass/storage/storage_test.go b/pkg/registry/storage/storageclass/storage/storage_test.go index fb1a20dba23..8196e5225dd 100644 --- a/pkg/registry/storage/storageclass/storage/storage_test.go +++ b/pkg/registry/storage/storageclass/storage/storage_test.go @@ -160,3 +160,11 @@ func TestShortNames(t *testing.T) { expected := []string{"sc"} registrytest.AssertShortNames(t, storage, expected) } + +func TestSingularName(t *testing.T) { + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "storageclass" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/pkg/registry/storage/volumeattachment/storage/storage.go b/pkg/registry/storage/volumeattachment/storage/storage.go index 91c1c2a1142..e82338fbd7f 100644 --- a/pkg/registry/storage/volumeattachment/storage/storage.go +++ b/pkg/registry/storage/volumeattachment/storage/storage.go @@ -73,6 +73,13 @@ func NewStorage(optsGetter generic.RESTOptionsGetter) (*VolumeAttachmentStorage, }, nil } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "volumeattachment" +} + // StatusREST implements the REST endpoint for changing the status of a VolumeAttachment type StatusREST struct { store *genericregistry.Store diff --git a/pkg/registry/storage/volumeattachment/storage/storage_test.go b/pkg/registry/storage/volumeattachment/storage/storage_test.go index 6ff5c9f749a..22c13985fed 100644 --- a/pkg/registry/storage/volumeattachment/storage/storage_test.go +++ b/pkg/registry/storage/volumeattachment/storage/storage_test.go @@ -200,3 +200,11 @@ func TestEtcdStatusUpdate(t *testing.T) { t.Errorf("objects differ: %v", diff.ObjectDiff(attachmentOut.Status, attachmentIn.Status)) } } + +func TestSingularName(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + expected := "volumeattachment" + registrytest.AssertSingularName(t, storage, expected) +} diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/etcd.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/etcd.go index 2523076edf9..55a7cbbf8cf 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/etcd.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition/etcd.go @@ -79,6 +79,13 @@ func (r *REST) Categories() []string { return []string{"api-extensions"} } +var _ rest.SingularNameProvider = &REST{} + +// SingularName implements the SingularNameProvider interfaces. This returns singular name of core resource. +func (r *REST) SingularName() string { + return "customresourcedefinition" +} + // Delete adds the CRD finalizer to the list func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { obj, err := r.Get(ctx, name, &metav1.GetOptions{}) diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go index b0af449f09b..50c59277539 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go @@ -1080,6 +1080,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if categoriesProvider, ok := storage.(rest.CategoriesProvider); ok { apiResource.Categories = categoriesProvider.Categories() } + if singularNameProvider, ok := storage.(rest.SingularNameProvider); ok { + apiResource.SingularName = singularNameProvider.SingularName() + } if gvkProvider, ok := storage.(rest.GroupVersionKindProvider); ok { gvk := gvkProvider.GroupVersionKind(a.group.GroupVersion) apiResource.Group = gvk.Group 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 6330ea8f531..c55ae9675af 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go @@ -89,6 +89,12 @@ type CategoriesProvider interface { Categories() []string } +// SingularNameProvider returns singular name of resources. This is used by kubectl discovery to have singular +// name representation of resources. In case of shortcut conflicts(with CRD shortcuts) singular name should always map to this resource. +type SingularNameProvider interface { + SingularName() string +} + // GroupVersionKindProvider is used to specify a particular GroupVersionKind to discovery. This is used for polymorphic endpoints // which generally point to foreign versions. Scale refers to Scale.v1beta1.extensions for instance. // This trumps KindProvider since it is capable of providing the information required. diff --git a/test/cmd/discovery.sh b/test/cmd/discovery.sh index 4308d9d216b..56aa7859fb1 100755 --- a/test/cmd/discovery.sh +++ b/test/cmd/discovery.sh @@ -55,7 +55,7 @@ run_assert_short_name_tests() { output_message=$(kubectl get --raw=/api/v1) ## test if a short name is exported during discovery - kube::test::if_has_string "${output_message}" '{"name":"configmaps","singularName":"","namespaced":true,"kind":"ConfigMap","verbs":\["create","delete","deletecollection","get","list","patch","update","watch"\],"shortNames":\["cm"\],"storageVersionHash":' + kube::test::if_has_string "${output_message}" '{"name":"configmaps","singularName":"configmap","namespaced":true,"kind":"ConfigMap","verbs":\["create","delete","deletecollection","get","list","patch","update","watch"\],"shortNames":\["cm"\],"storageVersionHash":' # check that there is no pod with the name test-crd-example output_message=$(kubectl get pod)