mirror of https://github.com/k3s-io/k3s
Merge pull request #46407 from liggitt/namespace-delete-collection
Automatic merge from submit-queue (batch tested with PRs 46407, 46457) Remove deletecollection support from namespace object Namespace storage accidentally picked up deletecollection support from embedding the generic store. If invoked, it skips the custom namespace `Delete()` storage method that enforces finalization, and skips the namespace lifecycle admission plugin that protects immortal namespaces from deletion. Given the data integrity implications of skipping namespace finalization, I'd backport this as far as we're releasing patch releases. ```release-note The namespace API object no longer supports the deletecollection operation. ```pull/6/head
commit
66a1d07ef4
|
@ -702,85 +702,6 @@
|
|||
"Kind": "Namespace"
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "delete collection of Namespace",
|
||||
"consumes": [
|
||||
"*/*"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf"
|
||||
],
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"tags": [
|
||||
"core_v1"
|
||||
],
|
||||
"operationId": "deleteCoreV1CollectionNamespace",
|
||||
"parameters": [
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "string",
|
||||
"description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.",
|
||||
"name": "fieldSelector",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "boolean",
|
||||
"description": "If true, partially initialized resources are included in the response.",
|
||||
"name": "includeUninitialized",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "string",
|
||||
"description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.",
|
||||
"name": "labelSelector",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "string",
|
||||
"description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.",
|
||||
"name": "resourceVersion",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "integer",
|
||||
"description": "Timeout for the list/watch call.",
|
||||
"name": "timeoutSeconds",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "boolean",
|
||||
"description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.",
|
||||
"name": "watch",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"x-kubernetes-action": "DELETECOLLECTION",
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"Group": "",
|
||||
"Version": "v1",
|
||||
"Kind": "Namespace"
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"uniqueItems": true,
|
||||
|
|
|
@ -3760,85 +3760,6 @@
|
|||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Status",
|
||||
"method": "DELETE",
|
||||
"summary": "delete collection of Namespace",
|
||||
"nickname": "deletecollectionNamespace",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "pretty",
|
||||
"description": "If 'true', then the output is pretty printed.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "labelSelector",
|
||||
"description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "fieldSelector",
|
||||
"description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"paramType": "query",
|
||||
"name": "includeUninitialized",
|
||||
"description": "If true, partially initialized resources are included in the response.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"paramType": "query",
|
||||
"name": "watch",
|
||||
"description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "resourceVersion",
|
||||
"description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"paramType": "query",
|
||||
"name": "timeoutSeconds",
|
||||
"description": "Timeout for the list/watch call.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Status"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -378,85 +378,6 @@
|
|||
"Kind": "Namespace"
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "delete collection of Namespace",
|
||||
"consumes": [
|
||||
"*/*"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf"
|
||||
],
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"tags": [
|
||||
"core_v1"
|
||||
],
|
||||
"operationId": "deleteCoreV1CollectionNamespace",
|
||||
"parameters": [
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "string",
|
||||
"description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.",
|
||||
"name": "fieldSelector",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "boolean",
|
||||
"description": "If true, partially initialized resources are included in the response.",
|
||||
"name": "includeUninitialized",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "string",
|
||||
"description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.",
|
||||
"name": "labelSelector",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "string",
|
||||
"description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.",
|
||||
"name": "resourceVersion",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "integer",
|
||||
"description": "Timeout for the list/watch call.",
|
||||
"name": "timeoutSeconds",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"uniqueItems": true,
|
||||
"type": "boolean",
|
||||
"description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.",
|
||||
"name": "watch",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"x-kubernetes-action": "DELETECOLLECTION",
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"Group": "",
|
||||
"Version": "v1",
|
||||
"Kind": "Namespace"
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"uniqueItems": true,
|
||||
|
|
|
@ -1853,85 +1853,6 @@
|
|||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "v1.Status",
|
||||
"method": "DELETE",
|
||||
"summary": "delete collection of Namespace",
|
||||
"nickname": "deletecollectionNamespace",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "pretty",
|
||||
"description": "If 'true', then the output is pretty printed.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "labelSelector",
|
||||
"description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "fieldSelector",
|
||||
"description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"paramType": "query",
|
||||
"name": "includeUninitialized",
|
||||
"description": "If true, partially initialized resources are included in the response.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"paramType": "query",
|
||||
"name": "watch",
|
||||
"description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"paramType": "query",
|
||||
"name": "resourceVersion",
|
||||
"description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"paramType": "query",
|
||||
"name": "timeoutSeconds",
|
||||
"description": "Timeout for the list/watch call.",
|
||||
"required": false,
|
||||
"allowMultiple": false
|
||||
}
|
||||
],
|
||||
"responseMessages": [
|
||||
{
|
||||
"code": 200,
|
||||
"message": "OK",
|
||||
"responseModel": "v1.Status"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf"
|
||||
],
|
||||
"consumes": [
|
||||
"*/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,8 +34,10 @@ go_library(
|
|||
"//pkg/registry/cachesize:go_default_library",
|
||||
"//pkg/registry/core/namespace:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch: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/registry:go_default_library",
|
||||
|
|
|
@ -20,8 +20,10 @@ import (
|
|||
"fmt"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
|
@ -35,7 +37,7 @@ import (
|
|||
|
||||
// rest implements a RESTStorage for namespaces
|
||||
type REST struct {
|
||||
*genericregistry.Store
|
||||
store *genericregistry.Store
|
||||
status *genericregistry.Store
|
||||
}
|
||||
|
||||
|
@ -75,7 +77,39 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *Finaliz
|
|||
finalizeStore := *store
|
||||
finalizeStore.UpdateStrategy = namespace.FinalizeStrategy
|
||||
|
||||
return &REST{Store: store, status: &statusStore}, &StatusREST{store: &statusStore}, &FinalizeREST{store: &finalizeStore}
|
||||
return &REST{store: store, status: &statusStore}, &StatusREST{store: &statusStore}, &FinalizeREST{store: &finalizeStore}
|
||||
}
|
||||
|
||||
func (r *REST) New() runtime.Object {
|
||||
return r.store.New()
|
||||
}
|
||||
|
||||
func (r *REST) NewList() runtime.Object {
|
||||
return r.store.NewList()
|
||||
}
|
||||
|
||||
func (r *REST) List(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (runtime.Object, error) {
|
||||
return r.store.List(ctx, options)
|
||||
}
|
||||
|
||||
func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
return r.store.Create(ctx, obj)
|
||||
}
|
||||
|
||||
func (r *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||
return r.store.Update(ctx, name, objInfo)
|
||||
}
|
||||
|
||||
func (r *REST) Get(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
return r.store.Get(ctx, name, options)
|
||||
}
|
||||
|
||||
func (r *REST) Watch(ctx genericapirequest.Context, options *metainternalversion.ListOptions) (watch.Interface, error) {
|
||||
return r.store.Watch(ctx, options)
|
||||
}
|
||||
|
||||
func (r *REST) Export(ctx genericapirequest.Context, name string, opts metav1.ExportOptions) (runtime.Object, error) {
|
||||
return r.store.Export(ctx, name, opts)
|
||||
}
|
||||
|
||||
// Delete enforces life-cycle rules for namespace termination
|
||||
|
@ -108,15 +142,15 @@ func (r *REST) Delete(ctx genericapirequest.Context, name string, options *metav
|
|||
// upon first request to delete, we switch the phase to start namespace termination
|
||||
// TODO: enhance graceful deletion's calls to DeleteStrategy to allow phase change and finalizer patterns
|
||||
if namespace.DeletionTimestamp.IsZero() {
|
||||
key, err := r.Store.KeyFunc(ctx, name)
|
||||
key, err := r.store.KeyFunc(ctx, name)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
preconditions := storage.Preconditions{UID: options.Preconditions.UID}
|
||||
|
||||
out := r.Store.NewFunc()
|
||||
err = r.Store.Storage.GuaranteedUpdate(
|
||||
out := r.store.NewFunc()
|
||||
err = r.store.Storage.GuaranteedUpdate(
|
||||
ctx, key, out, false, &preconditions,
|
||||
storage.SimpleUpdate(func(existing runtime.Object) (runtime.Object, error) {
|
||||
existingNamespace, ok := existing.(*api.Namespace)
|
||||
|
@ -167,7 +201,7 @@ func (r *REST) Delete(ctx genericapirequest.Context, name string, options *metav
|
|||
err = apierrors.NewConflict(api.Resource("namespaces"), namespace.Name, fmt.Errorf("The system is ensuring all content is removed from this namespace. Upon completion, this namespace will automatically be purged by the system."))
|
||||
return nil, false, err
|
||||
}
|
||||
return r.Store.Delete(ctx, name, options)
|
||||
return r.store.Delete(ctx, name, options)
|
||||
}
|
||||
|
||||
// Implement ShortNamesProvider
|
||||
|
|
|
@ -47,8 +47,8 @@ func validNewNamespace() *api.Namespace {
|
|||
func TestCreate(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.Store).ClusterScope()
|
||||
defer storage.store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.store).ClusterScope()
|
||||
namespace := validNewNamespace()
|
||||
namespace.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"}
|
||||
test.TestCreate(
|
||||
|
@ -64,7 +64,7 @@ func TestCreate(t *testing.T) {
|
|||
func TestCreateSetsFields(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
defer storage.store.DestroyFunc()
|
||||
namespace := validNewNamespace()
|
||||
ctx := genericapirequest.NewContext()
|
||||
_, err := storage.Create(ctx, namespace)
|
||||
|
@ -91,32 +91,32 @@ func TestCreateSetsFields(t *testing.T) {
|
|||
func TestDelete(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.Store).ClusterScope().ReturnDeletedObject()
|
||||
defer storage.store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.store).ClusterScope().ReturnDeletedObject()
|
||||
test.TestDelete(validNewNamespace())
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.Store).ClusterScope()
|
||||
defer storage.store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.store).ClusterScope()
|
||||
test.TestGet(validNewNamespace())
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.Store).ClusterScope()
|
||||
defer storage.store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.store).ClusterScope()
|
||||
test.TestList(validNewNamespace())
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.Store).ClusterScope()
|
||||
defer storage.store.DestroyFunc()
|
||||
test := registrytest.New(t, storage.store).ClusterScope()
|
||||
test.TestWatch(
|
||||
validNewNamespace(),
|
||||
// matching labels
|
||||
|
@ -140,7 +140,7 @@ func TestWatch(t *testing.T) {
|
|||
func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
defer storage.store.DestroyFunc()
|
||||
key := "namespaces/foo"
|
||||
ctx := genericapirequest.NewContext()
|
||||
now := metav1.Now()
|
||||
|
@ -154,7 +154,7 @@ func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) {
|
|||
},
|
||||
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
|
||||
}
|
||||
if err := storage.Storage.Create(ctx, key, namespace, nil, 0); err != nil {
|
||||
if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if _, _, err := storage.Delete(ctx, "foo", nil); err == nil {
|
||||
|
@ -165,7 +165,7 @@ func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) {
|
|||
func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
defer storage.store.DestroyFunc()
|
||||
key := "namespaces/foo"
|
||||
ctx := genericapirequest.NewContext()
|
||||
now := metav1.Now()
|
||||
|
@ -179,7 +179,7 @@ func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) {
|
|||
},
|
||||
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
|
||||
}
|
||||
if err := storage.Storage.Create(ctx, key, namespace, nil, 0); err != nil {
|
||||
if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if _, _, err := storage.Delete(ctx, "foo", nil); err != nil {
|
||||
|
@ -190,7 +190,7 @@ func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) {
|
|||
func TestShortNames(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
defer storage.store.DestroyFunc()
|
||||
expected := []string{"ns"}
|
||||
registrytest.AssertShortNames(t, storage, expected)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue