mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-11 14:11:14 +00:00
Move REST* interfaces into pkg/api/rest
Dependency chain is now api -> api/rest -> apiserver. Makes the interfaces much cleaner to read, and cleans up some inconsistenties that crept in along the way.
This commit is contained in:
147
pkg/api/rest/rest.go
Normal file
147
pkg/api/rest/rest.go
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
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 rest
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
// RESTStorage is a generic interface for RESTful storage services.
|
||||
// Resources which are exported to the RESTful API of apiserver need to implement this interface. It is expected
|
||||
// that objects may implement any of the below interfaces.
|
||||
type Storage interface {
|
||||
// New returns an empty object that can be used with Create and Update after request data has been put into it.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
New() runtime.Object
|
||||
}
|
||||
|
||||
// Lister is an object that can retrieve resources that match the provided field and label criteria.
|
||||
type Lister interface {
|
||||
// NewList returns an empty object that can be used with the List call.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
NewList() runtime.Object
|
||||
// List selects resources in the storage which match to the selector.
|
||||
List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// Getter is an object that can retrieve a named RESTful resource.
|
||||
type Getter interface {
|
||||
// Get finds a resource in the storage by name and returns 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.
|
||||
Get(ctx api.Context, name string) (runtime.Object, 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 api.Context, name string) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// GracefulDeleter knows how to pass deletion options to allow delayed deletion of a
|
||||
// RESTful object.
|
||||
type GracefulDeleter interface {
|
||||
// Delete finds a resource in the storage and deletes it.
|
||||
// If options are provided, the resource will attempt to honor them or return an invalid
|
||||
// request error.
|
||||
// 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 api.Context, name string, options *api.DeleteOptions) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// GracefulDeleteAdapter adapts the Deleter interface to GracefulDeleter
|
||||
type GracefulDeleteAdapter struct {
|
||||
Deleter
|
||||
}
|
||||
|
||||
// Delete implements RESTGracefulDeleter in terms of Deleter
|
||||
func (w GracefulDeleteAdapter) Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error) {
|
||||
return w.Deleter.Delete(ctx, name)
|
||||
}
|
||||
|
||||
// Creater is an object that can create an instance of a RESTful object.
|
||||
type Creater interface {
|
||||
// New returns an empty object that can be used with Create after request data has been put into it.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
New() runtime.Object
|
||||
|
||||
// Create creates a new version of a resource.
|
||||
Create(ctx api.Context, obj runtime.Object) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// Updater is an object that can update an instance of a RESTful object.
|
||||
type Updater interface {
|
||||
// New returns an empty object that can be used with Update after request data has been put into it.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
New() runtime.Object
|
||||
|
||||
// Update finds a resource in the storage and updates it. Some implementations
|
||||
// may allow updates creates the object - they should set the created boolean
|
||||
// to true.
|
||||
Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
|
||||
}
|
||||
|
||||
// CreaterUpdater is a storage object that must support both create and update.
|
||||
// Go prevents embedded interfaces that implement the same method.
|
||||
type CreaterUpdater interface {
|
||||
Creater
|
||||
Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
|
||||
}
|
||||
|
||||
// CreaterUpdater must satisfy the Updater interface.
|
||||
var _ Updater = CreaterUpdater(nil)
|
||||
|
||||
type Patcher interface {
|
||||
Getter
|
||||
Updater
|
||||
}
|
||||
|
||||
// Watcher should be implemented by all Storage objects that
|
||||
// want to offer the ability to watch for changes through the watch api.
|
||||
type Watcher interface {
|
||||
// 'label' selects on labels; 'field' selects on the object's fields. Not all fields
|
||||
// are supported; an error should be returned if 'field' tries to select on a field that
|
||||
// isn't supported. 'resourceVersion' allows for continuing/starting a watch at a
|
||||
// particular version.
|
||||
Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// StandardStorage is an interface covering the common verbs. Provided for testing whether a
|
||||
// resource satisfies the normal storage methods. Use Storage when passing opaque storage objects.
|
||||
type StandardStorage interface {
|
||||
Getter
|
||||
Lister
|
||||
CreaterUpdater
|
||||
GracefulDeleter
|
||||
Watcher
|
||||
}
|
||||
|
||||
// Redirector know how to return a remote resource's location.
|
||||
type Redirector interface {
|
||||
// ResourceLocation should return the remote location of the given resource, or an error.
|
||||
ResourceLocation(ctx api.Context, name string) (remoteLocation string, err error)
|
||||
}
|
@@ -22,21 +22,21 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
type Tester struct {
|
||||
*testing.T
|
||||
storage apiserver.RESTStorage
|
||||
storage rest.Storage
|
||||
storageError injectErrorFunc
|
||||
clusterScope bool
|
||||
}
|
||||
|
||||
type injectErrorFunc func(err error)
|
||||
|
||||
func New(t *testing.T, storage apiserver.RESTStorage, storageError injectErrorFunc) *Tester {
|
||||
func New(t *testing.T, storage rest.Storage, storageError injectErrorFunc) *Tester {
|
||||
return &Tester{
|
||||
T: t,
|
||||
storage: storage,
|
||||
@@ -85,7 +85,7 @@ func (t *Tester) TestCreateResetsUserData(valid runtime.Object) {
|
||||
objectMeta.UID = "bad-uid"
|
||||
objectMeta.CreationTimestamp = now
|
||||
|
||||
obj, err := t.storage.(apiserver.RESTCreater).Create(api.NewDefaultContext(), valid)
|
||||
obj, err := t.storage.(rest.Creater).Create(api.NewDefaultContext(), valid)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
@@ -111,7 +111,7 @@ func (t *Tester) TestCreateHasMetadata(valid runtime.Object) {
|
||||
context = api.NewContext()
|
||||
}
|
||||
|
||||
obj, err := t.storage.(apiserver.RESTCreater).Create(context, valid)
|
||||
obj, err := t.storage.(rest.Creater).Create(context, valid)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
@@ -131,7 +131,7 @@ func (t *Tester) TestCreateGeneratesName(valid runtime.Object) {
|
||||
|
||||
objectMeta.GenerateName = "test-"
|
||||
|
||||
_, err = t.storage.(apiserver.RESTCreater).Create(api.NewDefaultContext(), valid)
|
||||
_, err = t.storage.(rest.Creater).Create(api.NewDefaultContext(), valid)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
@@ -148,7 +148,7 @@ func (t *Tester) TestCreateGeneratesNameReturnsServerTimeout(valid runtime.Objec
|
||||
|
||||
objectMeta.GenerateName = "test-"
|
||||
t.withStorageError(errors.NewAlreadyExists("kind", "thing"), func() {
|
||||
_, err := t.storage.(apiserver.RESTCreater).Create(api.NewDefaultContext(), valid)
|
||||
_, err := t.storage.(rest.Creater).Create(api.NewDefaultContext(), valid)
|
||||
if err == nil || !errors.IsServerTimeout(err) {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
@@ -158,7 +158,7 @@ func (t *Tester) TestCreateGeneratesNameReturnsServerTimeout(valid runtime.Objec
|
||||
func (t *Tester) TestCreateInvokesValidation(invalid ...runtime.Object) {
|
||||
for i, obj := range invalid {
|
||||
ctx := api.NewDefaultContext()
|
||||
_, err := t.storage.(apiserver.RESTCreater).Create(ctx, obj)
|
||||
_, err := t.storage.(rest.Creater).Create(ctx, obj)
|
||||
if !errors.IsInvalid(err) {
|
||||
t.Errorf("%d: Expected to get an invalid resource error, got %v", i, err)
|
||||
}
|
||||
@@ -173,7 +173,7 @@ func (t *Tester) TestCreateRejectsMismatchedNamespace(valid runtime.Object) {
|
||||
|
||||
objectMeta.Namespace = "not-default"
|
||||
|
||||
_, err = t.storage.(apiserver.RESTCreater).Create(api.NewDefaultContext(), valid)
|
||||
_, err = t.storage.(rest.Creater).Create(api.NewDefaultContext(), valid)
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, but we didn't get one")
|
||||
} else if strings.Contains(err.Error(), "Controller.Namespace does not match the provided context") {
|
||||
@@ -189,7 +189,7 @@ func (t *Tester) TestCreateRejectsNamespace(valid runtime.Object) {
|
||||
|
||||
objectMeta.Namespace = "not-default"
|
||||
|
||||
_, err = t.storage.(apiserver.RESTCreater).Create(api.NewDefaultContext(), valid)
|
||||
_, err = t.storage.(rest.Creater).Create(api.NewDefaultContext(), valid)
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error, but we didn't get one")
|
||||
} else if strings.Contains(err.Error(), "Controller.Namespace does not match the provided context") {
|
||||
@@ -210,11 +210,11 @@ func (t *Tester) TestDeleteNoGraceful(createFn func() runtime.Object, wasGracefu
|
||||
}
|
||||
|
||||
ctx := api.WithNamespace(api.NewContext(), objectMeta.Namespace)
|
||||
_, err = t.storage.(apiserver.RESTGracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(10))
|
||||
_, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(10))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if _, err := t.storage.(apiserver.RESTGetter).Get(ctx, objectMeta.Name); !errors.IsNotFound(err) {
|
||||
if _, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name); !errors.IsNotFound(err) {
|
||||
t.Errorf("unexpected error, object should not exist: %v", err)
|
||||
}
|
||||
if wasGracefulFn() {
|
||||
@@ -229,11 +229,11 @@ func (t *Tester) TestDeleteGracefulHasDefault(existing runtime.Object, expectedG
|
||||
}
|
||||
|
||||
ctx := api.WithNamespace(api.NewContext(), objectMeta.Namespace)
|
||||
_, err = t.storage.(apiserver.RESTGracefulDeleter).Delete(ctx, objectMeta.Name, &api.DeleteOptions{})
|
||||
_, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, &api.DeleteOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if _, err := t.storage.(apiserver.RESTGetter).Get(ctx, objectMeta.Name); err != nil {
|
||||
if _, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name); err != nil {
|
||||
t.Errorf("unexpected error, object should exist: %v", err)
|
||||
}
|
||||
if !wasGracefulFn() {
|
||||
@@ -248,11 +248,11 @@ func (t *Tester) TestDeleteGracefulUsesZeroOnNil(existing runtime.Object, expect
|
||||
}
|
||||
|
||||
ctx := api.WithNamespace(api.NewContext(), objectMeta.Namespace)
|
||||
_, err = t.storage.(apiserver.RESTGracefulDeleter).Delete(ctx, objectMeta.Name, nil)
|
||||
_, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if _, err := t.storage.(apiserver.RESTGetter).Get(ctx, objectMeta.Name); !errors.IsNotFound(err) {
|
||||
if _, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name); !errors.IsNotFound(err) {
|
||||
t.Errorf("unexpected error, object should exist: %v", err)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user