Make Service storage a wrapper around other storages

The registry abstraction is unnecessary and adds direct coupling to the core types. By using a wrapper, we carry through the default implementations of the non-mutating operations. The DeleteCollection method is explicitly patched out since it cannot be correctly implemented on the storage currently. As a result, TableConvertor is now exposed. A few other minor refactorings * Corrected the case of some variables * Used functions instead of methods for several helper methods * Removed the legacy Deleter - service was the only remaining consumer
parent da564ef4
...@@ -44,7 +44,6 @@ import ( ...@@ -44,7 +44,6 @@ import (
"k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/master/ports"
"k8s.io/kubernetes/pkg/registry/core/componentstatus" "k8s.io/kubernetes/pkg/registry/core/componentstatus"
configmapstore "k8s.io/kubernetes/pkg/registry/core/configmap/storage" configmapstore "k8s.io/kubernetes/pkg/registry/core/configmap/storage"
"k8s.io/kubernetes/pkg/registry/core/endpoint"
endpointsstore "k8s.io/kubernetes/pkg/registry/core/endpoint/storage" endpointsstore "k8s.io/kubernetes/pkg/registry/core/endpoint/storage"
eventstore "k8s.io/kubernetes/pkg/registry/core/event/storage" eventstore "k8s.io/kubernetes/pkg/registry/core/event/storage"
limitrangestore "k8s.io/kubernetes/pkg/registry/core/limitrange/storage" limitrangestore "k8s.io/kubernetes/pkg/registry/core/limitrange/storage"
...@@ -58,7 +57,6 @@ import ( ...@@ -58,7 +57,6 @@ import (
controllerstore "k8s.io/kubernetes/pkg/registry/core/replicationcontroller/storage" controllerstore "k8s.io/kubernetes/pkg/registry/core/replicationcontroller/storage"
resourcequotastore "k8s.io/kubernetes/pkg/registry/core/resourcequota/storage" resourcequotastore "k8s.io/kubernetes/pkg/registry/core/resourcequota/storage"
secretstore "k8s.io/kubernetes/pkg/registry/core/secret/storage" secretstore "k8s.io/kubernetes/pkg/registry/core/secret/storage"
"k8s.io/kubernetes/pkg/registry/core/service"
"k8s.io/kubernetes/pkg/registry/core/service/allocator" "k8s.io/kubernetes/pkg/registry/core/service/allocator"
serviceallocator "k8s.io/kubernetes/pkg/registry/core/service/allocator/storage" serviceallocator "k8s.io/kubernetes/pkg/registry/core/service/allocator/storage"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator" "k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
...@@ -127,7 +125,6 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi ...@@ -127,7 +125,6 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespacestore.NewREST(restOptionsGetter) namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespacestore.NewREST(restOptionsGetter)
endpointsStorage := endpointsstore.NewREST(restOptionsGetter) endpointsStorage := endpointsstore.NewREST(restOptionsGetter)
endpointRegistry := endpoint.NewRegistry(endpointsStorage)
nodeStorage, err := nodestore.NewStorage(restOptionsGetter, c.KubeletClientConfig, c.ProxyTransport) nodeStorage, err := nodestore.NewStorage(restOptionsGetter, c.KubeletClientConfig, c.ProxyTransport)
if err != nil { if err != nil {
...@@ -148,8 +145,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi ...@@ -148,8 +145,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
serviceAccountStorage = serviceaccountstore.NewREST(restOptionsGetter, nil, nil, nil) serviceAccountStorage = serviceaccountstore.NewREST(restOptionsGetter, nil, nil, nil)
} }
serviceRESTStorage, serviceStatusStorage := servicestore.NewREST(restOptionsGetter) serviceRESTStorage, serviceStatusStorage := servicestore.NewGenericREST(restOptionsGetter)
serviceRegistry := service.NewRegistry(serviceRESTStorage)
var serviceClusterIPRegistry rangeallocation.RangeRegistry var serviceClusterIPRegistry rangeallocation.RangeRegistry
serviceClusterIPRange := c.ServiceIPRange serviceClusterIPRange := c.ServiceIPRange
...@@ -162,7 +158,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi ...@@ -162,7 +158,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err
} }
ServiceClusterIPAllocator := ipallocator.NewAllocatorCIDRRange(&serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { serviceClusterIPAllocator := ipallocator.NewAllocatorCIDRRange(&serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface {
mem := allocator.NewAllocationMap(max, rangeSpec) mem := allocator.NewAllocationMap(max, rangeSpec)
// TODO etcdallocator package to return a storage interface via the storageFactory // TODO etcdallocator package to return a storage interface via the storageFactory
etcd := serviceallocator.NewEtcd(mem, "/ranges/serviceips", api.Resource("serviceipallocations"), serviceStorageConfig) etcd := serviceallocator.NewEtcd(mem, "/ranges/serviceips", api.Resource("serviceipallocations"), serviceStorageConfig)
...@@ -172,7 +168,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi ...@@ -172,7 +168,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
restStorage.ServiceClusterIPAllocator = serviceClusterIPRegistry restStorage.ServiceClusterIPAllocator = serviceClusterIPRegistry
var serviceNodePortRegistry rangeallocation.RangeRegistry var serviceNodePortRegistry rangeallocation.RangeRegistry
ServiceNodePortAllocator := portallocator.NewPortAllocatorCustom(c.ServiceNodePortRange, func(max int, rangeSpec string) allocator.Interface { serviceNodePortAllocator := portallocator.NewPortAllocatorCustom(c.ServiceNodePortRange, func(max int, rangeSpec string) allocator.Interface {
mem := allocator.NewAllocationMap(max, rangeSpec) mem := allocator.NewAllocationMap(max, rangeSpec)
// TODO etcdallocator package to return a storage interface via the storageFactory // TODO etcdallocator package to return a storage interface via the storageFactory
etcd := serviceallocator.NewEtcd(mem, "/ranges/servicenodeports", api.Resource("servicenodeportallocations"), serviceStorageConfig) etcd := serviceallocator.NewEtcd(mem, "/ranges/servicenodeports", api.Resource("servicenodeportallocations"), serviceStorageConfig)
...@@ -183,7 +179,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi ...@@ -183,7 +179,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
controllerStorage := controllerstore.NewStorage(restOptionsGetter) controllerStorage := controllerstore.NewStorage(restOptionsGetter)
serviceRest := service.NewStorage(serviceRegistry, endpointRegistry, podStorage.Pod, ServiceClusterIPAllocator, ServiceNodePortAllocator, c.ProxyTransport) serviceRest, serviceRestProxy := servicestore.NewREST(serviceRESTStorage, endpointsStorage, podStorage.Pod, serviceClusterIPAllocator, serviceNodePortAllocator, c.ProxyTransport)
restStorageMap := map[string]rest.Storage{ restStorageMap := map[string]rest.Storage{
"pods": podStorage.Pod, "pods": podStorage.Pod,
...@@ -201,8 +197,8 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi ...@@ -201,8 +197,8 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
"replicationControllers": controllerStorage.Controller, "replicationControllers": controllerStorage.Controller,
"replicationControllers/status": controllerStorage.Status, "replicationControllers/status": controllerStorage.Status,
"services": serviceRest.Service, "services": serviceRest,
"services/proxy": serviceRest.Proxy, "services/proxy": serviceRestProxy,
"services/status": serviceStatusStorage, "services/status": serviceStatusStorage,
"endpoints": endpointsStorage, "endpoints": endpointsStorage,
......
...@@ -32,7 +32,6 @@ import ( ...@@ -32,7 +32,6 @@ import (
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/registry/core/rangeallocation" "k8s.io/kubernetes/pkg/registry/core/rangeallocation"
"k8s.io/kubernetes/pkg/registry/core/service"
"k8s.io/kubernetes/pkg/registry/core/service/portallocator" "k8s.io/kubernetes/pkg/registry/core/service/portallocator"
) )
...@@ -126,7 +125,7 @@ func (c *Repair) runOnce() error { ...@@ -126,7 +125,7 @@ func (c *Repair) runOnce() error {
// Check every Service's ports, and rebuild the state as we think it should be. // Check every Service's ports, and rebuild the state as we think it should be.
for i := range list.Items { for i := range list.Items {
svc := &list.Items[i] svc := &list.Items[i]
ports := service.CollectServiceNodePorts(svc) ports := collectServiceNodePorts(svc)
if len(ports) == 0 { if len(ports) == 0 {
continue continue
} }
...@@ -196,3 +195,14 @@ func (c *Repair) runOnce() error { ...@@ -196,3 +195,14 @@ func (c *Repair) runOnce() error {
} }
return nil return nil
} }
func collectServiceNodePorts(service *api.Service) []int {
servicePorts := []int{}
for i := range service.Spec.Ports {
servicePort := &service.Spec.Ports[i]
if servicePort.NodePort != 0 {
servicePorts = append(servicePorts, int(servicePort.NodePort))
}
}
return servicePorts
}
...@@ -32,7 +32,7 @@ import ( ...@@ -32,7 +32,7 @@ import (
// ProxyREST implements the proxy subresource for a Service // ProxyREST implements the proxy subresource for a Service
type ProxyREST struct { type ProxyREST struct {
ServiceRest *REST Redirector rest.Redirector
ProxyTransport http.RoundTripper ProxyTransport http.RoundTripper
} }
...@@ -62,7 +62,7 @@ func (r *ProxyREST) Connect(ctx genericapirequest.Context, id string, opts runti ...@@ -62,7 +62,7 @@ func (r *ProxyREST) Connect(ctx genericapirequest.Context, id string, opts runti
if !ok { if !ok {
return nil, fmt.Errorf("Invalid options object: %#v", opts) return nil, fmt.Errorf("Invalid options object: %#v", opts)
} }
location, transport, err := r.ServiceRest.ResourceLocation(ctx, id) location, transport, err := r.Redirector.ResourceLocation(ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -30,16 +30,17 @@ import ( ...@@ -30,16 +30,17 @@ import (
"k8s.io/kubernetes/pkg/registry/core/service" "k8s.io/kubernetes/pkg/registry/core/service"
) )
type REST struct { type GenericREST struct {
*genericregistry.Store *genericregistry.Store
} }
// NewREST returns a RESTStorage object that will work against services. // NewREST returns a RESTStorage object that will work against services.
func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST) { func NewGenericREST(optsGetter generic.RESTOptionsGetter) (*GenericREST, *StatusREST) {
store := &genericregistry.Store{ store := &genericregistry.Store{
NewFunc: func() runtime.Object { return &api.Service{} }, NewFunc: func() runtime.Object { return &api.Service{} },
NewListFunc: func() runtime.Object { return &api.ServiceList{} }, NewListFunc: func() runtime.Object { return &api.ServiceList{} },
DefaultQualifiedResource: api.Resource("services"), DefaultQualifiedResource: api.Resource("services"),
ReturnDeletedObject: true,
CreateStrategy: service.Strategy, CreateStrategy: service.Strategy,
UpdateStrategy: service.Strategy, UpdateStrategy: service.Strategy,
...@@ -55,26 +56,25 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST) { ...@@ -55,26 +56,25 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST) {
statusStore := *store statusStore := *store
statusStore.UpdateStrategy = service.StatusStrategy statusStore.UpdateStrategy = service.StatusStrategy
return &REST{store}, &StatusREST{store: &statusStore} return &GenericREST{store}, &StatusREST{store: &statusStore}
} }
// Implement ShortNamesProvider var (
var _ rest.ShortNamesProvider = &REST{} _ rest.ShortNamesProvider = &GenericREST{}
_ rest.CategoriesProvider = &GenericREST{}
)
// ShortNames implements the ShortNamesProvider interface. Returns a list of short names for a resource. // ShortNames implements the ShortNamesProvider interface. Returns a list of short names for a resource.
func (r *REST) ShortNames() []string { func (r *GenericREST) ShortNames() []string {
return []string{"svc"} return []string{"svc"}
} }
// Implement CategoriesProvider
var _ rest.CategoriesProvider = &REST{}
// Categories implements the CategoriesProvider interface. Returns a list of categories a resource is part of. // Categories implements the CategoriesProvider interface. Returns a list of categories a resource is part of.
func (r *REST) Categories() []string { func (r *GenericREST) Categories() []string {
return []string{"all"} return []string{"all"}
} }
// StatusREST implements the REST endpoint for changing the status of a service. // StatusREST implements the GenericREST endpoint for changing the status of a service.
type StatusREST struct { type StatusREST struct {
store *genericregistry.Store store *genericregistry.Store
} }
......
...@@ -31,7 +31,7 @@ import ( ...@@ -31,7 +31,7 @@ import (
"k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/registrytest"
) )
func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) { func newStorage(t *testing.T) (*GenericREST, *StatusREST, *etcdtesting.EtcdTestServer) {
etcdStorage, server := registrytest.NewEtcdStorage(t, "") etcdStorage, server := registrytest.NewEtcdStorage(t, "")
restOptions := generic.RESTOptions{ restOptions := generic.RESTOptions{
StorageConfig: etcdStorage, StorageConfig: etcdStorage,
...@@ -39,7 +39,7 @@ func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) ...@@ -39,7 +39,7 @@ func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer)
DeleteCollectionWorkers: 1, DeleteCollectionWorkers: 1,
ResourcePrefix: "services", ResourcePrefix: "services",
} }
serviceStorage, statusStorage := NewREST(restOptions) serviceStorage, statusStorage := NewGenericREST(restOptions)
return serviceStorage, statusStorage, server return serviceStorage, statusStorage, server
} }
...@@ -125,7 +125,7 @@ func TestDelete(t *testing.T) { ...@@ -125,7 +125,7 @@ func TestDelete(t *testing.T) {
storage, _, server := newStorage(t) storage, _, server := newStorage(t)
defer server.Terminate(t) defer server.Terminate(t)
defer storage.Store.DestroyFunc() defer storage.Store.DestroyFunc()
test := genericregistrytest.New(t, storage.Store).AllowCreateOnUpdate() test := genericregistrytest.New(t, storage.Store).AllowCreateOnUpdate().ReturnDeletedObject()
test.TestDelete(validService()) test.TestDelete(validService())
} }
......
...@@ -27,6 +27,7 @@ import ( ...@@ -27,6 +27,7 @@ import (
genericapirequest "k8s.io/apiserver/pkg/endpoints/request" genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
_ "k8s.io/kubernetes/pkg/apis/core/install"
) )
func TestExportService(t *testing.T) { func TestExportService(t *testing.T) {
...@@ -111,17 +112,17 @@ func TestExportService(t *testing.T) { ...@@ -111,17 +112,17 @@ func TestExportService(t *testing.T) {
func TestCheckGeneratedNameError(t *testing.T) { func TestCheckGeneratedNameError(t *testing.T) {
expect := errors.NewNotFound(api.Resource("foos"), "bar") expect := errors.NewNotFound(api.Resource("foos"), "bar")
if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Pod{}); err != expect { if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Service{}); err != expect {
t.Errorf("NotFoundError should be ignored: %v", err) t.Errorf("NotFoundError should be ignored: %v", err)
} }
expect = errors.NewAlreadyExists(api.Resource("foos"), "bar") expect = errors.NewAlreadyExists(api.Resource("foos"), "bar")
if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Pod{}); err != expect { if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Service{}); err != expect {
t.Errorf("AlreadyExists should be returned when no GenerateName field: %v", err) t.Errorf("AlreadyExists should be returned when no GenerateName field: %v", err)
} }
expect = errors.NewAlreadyExists(api.Resource("foos"), "bar") expect = errors.NewAlreadyExists(api.Resource("foos"), "bar")
if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Pod{ObjectMeta: metav1.ObjectMeta{GenerateName: "foo"}}); err == nil || !errors.IsServerTimeout(err) { if err := rest.CheckGeneratedNameError(Strategy, expect, &api.Service{ObjectMeta: metav1.ObjectMeta{GenerateName: "foo"}}); err == nil || !errors.IsServerTimeout(err) {
t.Errorf("expected try again later error: %v", err) t.Errorf("expected try again later error: %v", err)
} }
} }
......
...@@ -2839,65 +2839,6 @@ func TestDeleteWithOptionsQueryAndBody(t *testing.T) { ...@@ -2839,65 +2839,6 @@ func TestDeleteWithOptionsQueryAndBody(t *testing.T) {
} }
} }
func TestLegacyDelete(t *testing.T) {
storage := map[string]rest.Storage{}
simpleStorage := SimpleRESTStorage{}
ID := "id"
storage["simple"] = LegacyRESTStorage{&simpleStorage}
var _ rest.Deleter = storage["simple"].(LegacyRESTStorage)
handler := handle(storage)
server := httptest.NewServer(handler)
defer server.Close()
client := http.Client{}
request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, nil)
res, err := client.Do(request)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if res.StatusCode != http.StatusOK {
t.Errorf("unexpected response: %#v", res)
}
if simpleStorage.deleted != ID {
t.Errorf("Unexpected delete: %s, expected %s", simpleStorage.deleted, ID)
}
if simpleStorage.deleteOptions != nil {
t.Errorf("unexpected delete options: %#v", simpleStorage.deleteOptions)
}
}
func TestLegacyDeleteIgnoresOptions(t *testing.T) {
storage := map[string]rest.Storage{}
simpleStorage := SimpleRESTStorage{}
ID := "id"
storage["simple"] = LegacyRESTStorage{&simpleStorage}
handler := handle(storage)
server := httptest.NewServer(handler)
defer server.Close()
item := metav1.NewDeleteOptions(300)
body, err := runtime.Encode(codec, item)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
client := http.Client{}
request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body))
res, err := client.Do(request)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if res.StatusCode != http.StatusOK {
t.Errorf("unexpected response: %#v", res)
}
if simpleStorage.deleted != ID {
t.Errorf("Unexpected delete: %s, expected %s", simpleStorage.deleted, ID)
}
if simpleStorage.deleteOptions != nil {
t.Errorf("unexpected delete options: %#v", simpleStorage.deleteOptions)
}
}
func TestDeleteInvokesAdmissionControl(t *testing.T) { func TestDeleteInvokesAdmissionControl(t *testing.T) {
// TODO: remove mutating deny when we removed it from the endpoint implementation and ported all plugins // TODO: remove mutating deny when we removed it from the endpoint implementation and ported all plugins
for _, admit := range []admission.Interface{alwaysMutatingDeny{}, alwaysValidatingDeny{}} { for _, admit := range []admission.Interface{alwaysMutatingDeny{}, alwaysValidatingDeny{}} {
......
...@@ -227,7 +227,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag ...@@ -227,7 +227,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
lister, isLister := storage.(rest.Lister) lister, isLister := storage.(rest.Lister)
getter, isGetter := storage.(rest.Getter) getter, isGetter := storage.(rest.Getter)
getterWithOptions, isGetterWithOptions := storage.(rest.GetterWithOptions) getterWithOptions, isGetterWithOptions := storage.(rest.GetterWithOptions)
deleter, isDeleter := storage.(rest.Deleter)
gracefulDeleter, isGracefulDeleter := storage.(rest.GracefulDeleter) gracefulDeleter, isGracefulDeleter := storage.(rest.GracefulDeleter)
collectionDeleter, isCollectionDeleter := storage.(rest.CollectionDeleter) collectionDeleter, isCollectionDeleter := storage.(rest.CollectionDeleter)
updater, isUpdater := storage.(rest.Updater) updater, isUpdater := storage.(rest.Updater)
...@@ -273,16 +272,12 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag ...@@ -273,16 +272,12 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
var versionedDeleteOptions runtime.Object var versionedDeleteOptions runtime.Object
var versionedDeleterObject interface{} var versionedDeleterObject interface{}
switch { if isGracefulDeleter {
case isGracefulDeleter:
versionedDeleteOptions, err = a.group.Creater.New(optionsExternalVersion.WithKind("DeleteOptions")) versionedDeleteOptions, err = a.group.Creater.New(optionsExternalVersion.WithKind("DeleteOptions"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
versionedDeleterObject = indirectArbitraryPointer(versionedDeleteOptions) versionedDeleterObject = indirectArbitraryPointer(versionedDeleteOptions)
isDeleter = true
case isDeleter:
gracefulDeleter = rest.GracefulDeleteAdapter{Deleter: deleter}
} }
versionedStatusPtr, err := a.group.Creater.New(optionsExternalVersion.WithKind("Status")) versionedStatusPtr, err := a.group.Creater.New(optionsExternalVersion.WithKind("Status"))
...@@ -416,7 +411,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag ...@@ -416,7 +411,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
} }
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer, false}, isUpdater) actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer, false}, isUpdater)
actions = appendIf(actions, action{"PATCH", itemPath, nameParams, namer, false}, isPatcher) actions = appendIf(actions, action{"PATCH", itemPath, nameParams, namer, false}, isPatcher)
actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer, false}, isDeleter) actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer, false}, isGracefulDeleter)
actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer, false}, isWatcher) actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer, false}, isWatcher)
actions = appendIf(actions, action{"CONNECT", itemPath, nameParams, namer, false}, isConnecter) actions = appendIf(actions, action{"CONNECT", itemPath, nameParams, namer, false}, isConnecter)
actions = appendIf(actions, action{"CONNECT", itemPath + "/{path:*}", proxyParams, namer, false}, isConnecter && connectSubpath) actions = appendIf(actions, action{"CONNECT", itemPath + "/{path:*}", proxyParams, namer, false}, isConnecter && connectSubpath)
...@@ -462,7 +457,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag ...@@ -462,7 +457,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
} }
actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer, false}, isUpdater) actions = appendIf(actions, action{"PUT", itemPath, nameParams, namer, false}, isUpdater)
actions = appendIf(actions, action{"PATCH", itemPath, nameParams, namer, false}, isPatcher) actions = appendIf(actions, action{"PATCH", itemPath, nameParams, namer, false}, isPatcher)
actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer, false}, isDeleter) actions = appendIf(actions, action{"DELETE", itemPath, nameParams, namer, false}, isGracefulDeleter)
actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer, false}, isWatcher) actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer, false}, isWatcher)
actions = appendIf(actions, action{"CONNECT", itemPath, nameParams, namer, false}, isConnecter) actions = appendIf(actions, action{"CONNECT", itemPath, nameParams, namer, false}, isConnecter)
actions = appendIf(actions, action{"CONNECT", itemPath + "/{path:*}", proxyParams, namer, false}, isConnecter && connectSubpath) actions = appendIf(actions, action{"CONNECT", itemPath + "/{path:*}", proxyParams, namer, false}, isConnecter && connectSubpath)
......
...@@ -137,16 +137,6 @@ type TableConvertor interface { ...@@ -137,16 +137,6 @@ type TableConvertor interface {
ConvertToTable(ctx genericapirequest.Context, object runtime.Object, tableOptions runtime.Object) (*metav1beta1.Table, error) ConvertToTable(ctx genericapirequest.Context, object runtime.Object, tableOptions runtime.Object) (*metav1beta1.Table, error)
} }
// Deleter is an object that can delete a named RESTful resource.
type Deleter interface {
// Delete finds a resource in the storage and deletes it.
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
// returned error value err when the specified resource is not found.
// Delete *may* return the object that was deleted, or a status object indicating additional
// information about deletion.
Delete(ctx genericapirequest.Context, name string) (runtime.Object, error)
}
// GracefulDeleter knows how to pass deletion options to allow delayed deletion of a // GracefulDeleter knows how to pass deletion options to allow delayed deletion of a
// RESTful object. // RESTful object.
type GracefulDeleter interface { type GracefulDeleter interface {
...@@ -162,17 +152,6 @@ type GracefulDeleter interface { ...@@ -162,17 +152,6 @@ type GracefulDeleter interface {
Delete(ctx genericapirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) Delete(ctx genericapirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error)
} }
// GracefulDeleteAdapter adapts the Deleter interface to GracefulDeleter
type GracefulDeleteAdapter struct {
Deleter
}
// Delete implements RESTGracefulDeleter in terms of Deleter
func (w GracefulDeleteAdapter) Delete(ctx genericapirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
obj, err := w.Deleter.Delete(ctx, name)
return obj, true, err
}
// CollectionDeleter is an object that can delete a collection // CollectionDeleter is an object that can delete a collection
// of RESTful resources. // of RESTful resources.
type CollectionDeleter interface { type CollectionDeleter interface {
......
...@@ -24,11 +24,13 @@ import ( ...@@ -24,11 +24,13 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
authorizationv1 "k8s.io/api/authorization/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
"k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/framework"
imageutils "k8s.io/kubernetes/test/utils/image" imageutils "k8s.io/kubernetes/test/utils/image"
...@@ -142,7 +144,15 @@ var _ = SIGDescribe("Servers with support for Table transformation", func() { ...@@ -142,7 +144,15 @@ var _ = SIGDescribe("Servers with support for Table transformation", func() {
c := f.ClientSet c := f.ClientSet
table := &metav1beta1.Table{} table := &metav1beta1.Table{}
err := c.CoreV1().RESTClient().Get().Resource("services").SetHeader("Accept", "application/json;as=Table;v=v1beta1;g=meta.k8s.io").Do().Into(table) sar := &authorizationv1.SelfSubjectAccessReview{
Spec: authorizationv1.SelfSubjectAccessReviewSpec{
NonResourceAttributes: &authorizationv1.NonResourceAttributes{
Path: "/",
Verb: "get",
},
},
}
err := c.AuthorizationV1().RESTClient().Post().Resource("selfsubjectaccessreviews").SetHeader("Accept", "application/json;as=Table;v=v1beta1;g=meta.k8s.io").Body(sar).Do().Into(table)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.(errors.APIStatus).Status().Code).To(Equal(int32(406))) Expect(err.(errors.APIStatus).Status().Code).To(Equal(int32(406)))
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment